Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 1 | /* |
Brian O'Connor | a09fe5b | 2017-08-03 21:12:30 -0700 | [diff] [blame] | 2 | * Copyright 2015-present Open Networking Foundation |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | * |
| 16 | */ |
| 17 | |
| 18 | package org.onosproject.ui.impl; |
| 19 | |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 20 | import org.onosproject.net.Device; |
| 21 | import org.onosproject.net.DeviceId; |
| 22 | import org.onosproject.net.Host; |
| 23 | import org.onosproject.net.Link; |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 24 | import org.onosproject.net.PortNumber; |
| 25 | import org.onosproject.net.flow.FlowEntry; |
| 26 | import org.onosproject.net.flow.TrafficTreatment; |
| 27 | import org.onosproject.net.flow.instructions.Instruction; |
| 28 | import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; |
Simon Hunt | ed804d5 | 2016-03-30 09:51:40 -0700 | [diff] [blame] | 29 | import org.onosproject.ui.impl.topo.util.ServicesBundle; |
Simon Hunt | ed804d5 | 2016-03-30 09:51:40 -0700 | [diff] [blame] | 30 | import org.onosproject.ui.impl.topo.util.TrafficLink; |
| 31 | import org.onosproject.ui.impl.topo.util.TrafficLink.StatsType; |
| 32 | import org.onosproject.ui.impl.topo.util.TrafficLinkMap; |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 33 | import org.onosproject.ui.topo.Highlights; |
| 34 | import org.slf4j.Logger; |
| 35 | import org.slf4j.LoggerFactory; |
| 36 | |
| 37 | import java.util.ArrayList; |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 38 | import java.util.HashMap; |
| 39 | import java.util.HashSet; |
| 40 | import java.util.List; |
| 41 | import java.util.Map; |
| 42 | import java.util.Set; |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 43 | |
Pier | 59266bc | 2018-03-15 12:10:24 -0700 | [diff] [blame] | 44 | import static org.onosproject.net.DefaultEdgeLink.createEdgeLinks; |
Simon Hunt | 1911fe4 | 2017-05-02 18:25:58 -0700 | [diff] [blame] | 45 | import static org.onosproject.ui.impl.TrafficMonitorBase.Mode.RELATED_INTENTS; |
| 46 | import static org.onosproject.ui.impl.TrafficMonitorBase.Mode.SELECTED_INTENT; |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 47 | |
| 48 | /** |
| 49 | * Encapsulates the behavior of monitoring specific traffic patterns. |
| 50 | */ |
Simon Hunt | 1911fe4 | 2017-05-02 18:25:58 -0700 | [diff] [blame] | 51 | public class TrafficMonitor extends TrafficMonitorBase { |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 52 | |
| 53 | private static final Logger log = |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 54 | LoggerFactory.getLogger(TrafficMonitor.class); |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 55 | |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 56 | private final TopologyViewMessageHandler msgHandler; |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 57 | |
| 58 | |
| 59 | /** |
| 60 | * Constructs a traffic monitor. |
| 61 | * |
Simon Hunt | 5328f79 | 2017-01-11 17:43:31 -0800 | [diff] [blame] | 62 | * @param trafficPeriod traffic task period in ms |
| 63 | * @param servicesBundle bundle of services |
| 64 | * @param msgHandler our message handler |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 65 | */ |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 66 | public TrafficMonitor(long trafficPeriod, ServicesBundle servicesBundle, |
| 67 | TopologyViewMessageHandler msgHandler) { |
Sean Condon | adeb716 | 2019-04-13 20:56:14 +0100 | [diff] [blame] | 68 | super(trafficPeriod, servicesBundle, msgHandler); |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 69 | this.msgHandler = msgHandler; |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 70 | |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 71 | } |
| 72 | |
| 73 | // ======================================================================= |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 74 | // === API === |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 75 | |
Simon Hunt | a7aea84 | 2017-05-03 19:42:50 -0700 | [diff] [blame] | 76 | // monitor(Mode) is now implemented in the super class |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 77 | |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 78 | // TODO: move this out to the "h2h/multi-intent app" |
Simon Hunt | 5328f79 | 2017-01-11 17:43:31 -0800 | [diff] [blame] | 79 | |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 80 | /** |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 81 | * Selects the next intent in the select group (if there is one), |
| 82 | * and sends highlighting data back to the web client to display |
| 83 | * which path is selected. |
| 84 | */ |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 85 | public synchronized void selectNextIntent() { |
| 86 | if (selectedIntents != null) { |
| 87 | selectedIntents.next(); |
| 88 | sendSelectedIntents(); |
Simon Hunt | 5783017 | 2015-08-26 13:25:17 -0700 | [diff] [blame] | 89 | if (mode == SELECTED_INTENT) { |
| 90 | mode = RELATED_INTENTS; |
| 91 | } |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 92 | } |
| 93 | } |
| 94 | |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 95 | /** |
| 96 | * Selects the previous intent in the select group (if there is one), |
| 97 | * and sends highlighting data back to the web client to display |
| 98 | * which path is selected. |
| 99 | */ |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 100 | public synchronized void selectPreviousIntent() { |
| 101 | if (selectedIntents != null) { |
| 102 | selectedIntents.prev(); |
| 103 | sendSelectedIntents(); |
Simon Hunt | 5783017 | 2015-08-26 13:25:17 -0700 | [diff] [blame] | 104 | if (mode == SELECTED_INTENT) { |
| 105 | mode = RELATED_INTENTS; |
| 106 | } |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 107 | } |
| 108 | } |
| 109 | |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 110 | /** |
| 111 | * Resends selected intent traffic data. This is called, for example, |
| 112 | * when the system detects an intent update happened. |
| 113 | */ |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 114 | public synchronized void pokeIntent() { |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 115 | if (mode == SELECTED_INTENT) { |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 116 | sendSelectedIntentTraffic(); |
| 117 | } |
| 118 | } |
| 119 | |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 120 | // ======================================================================= |
Simon Hunt | 1911fe4 | 2017-05-02 18:25:58 -0700 | [diff] [blame] | 121 | // === Abstract method implementations === |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 122 | |
Simon Hunt | 1911fe4 | 2017-05-02 18:25:58 -0700 | [diff] [blame] | 123 | @Override |
| 124 | protected void sendAllFlowTraffic() { |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 125 | log.debug("sendAllFlowTraffic"); |
Simon Hunt | 5783017 | 2015-08-26 13:25:17 -0700 | [diff] [blame] | 126 | msgHandler.sendHighlights(trafficSummary(StatsType.FLOW_STATS)); |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 127 | } |
| 128 | |
Simon Hunt | 1911fe4 | 2017-05-02 18:25:58 -0700 | [diff] [blame] | 129 | @Override |
| 130 | protected void sendAllPortTrafficBits() { |
| 131 | log.debug("sendAllPortTrafficBits"); |
| 132 | msgHandler.sendHighlights(trafficSummary(StatsType.PORT_STATS)); |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 133 | } |
| 134 | |
Simon Hunt | 1911fe4 | 2017-05-02 18:25:58 -0700 | [diff] [blame] | 135 | @Override |
| 136 | protected void sendAllPortTrafficPackets() { |
| 137 | log.debug("sendAllPortTrafficPackets"); |
| 138 | msgHandler.sendHighlights(trafficSummary(StatsType.PORT_PACKET_STATS)); |
| 139 | } |
| 140 | |
| 141 | @Override |
| 142 | protected void sendDeviceLinkFlows() { |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 143 | log.debug("sendDeviceLinkFlows: {}", selectedNodes); |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 144 | msgHandler.sendHighlights(deviceLinkFlows()); |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 145 | } |
| 146 | |
Simon Hunt | 1911fe4 | 2017-05-02 18:25:58 -0700 | [diff] [blame] | 147 | @Override |
| 148 | protected void sendSelectedIntentTraffic() { |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 149 | log.debug("sendSelectedIntentTraffic: {}", selectedIntents); |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 150 | msgHandler.sendHighlights(intentTraffic()); |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 151 | } |
| 152 | |
Simon Hunt | 1911fe4 | 2017-05-02 18:25:58 -0700 | [diff] [blame] | 153 | @Override |
| 154 | protected void sendClearHighlights() { |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 155 | log.debug("sendClearHighlights"); |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 156 | msgHandler.sendHighlights(new Highlights()); |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 157 | } |
| 158 | |
Simon Hunt | 1911fe4 | 2017-05-02 18:25:58 -0700 | [diff] [blame] | 159 | @Override |
| 160 | protected void clearSelection() { |
| 161 | selectedNodes = null; |
| 162 | selectedIntents = null; |
| 163 | } |
| 164 | |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 165 | // ======================================================================= |
| 166 | // === Generate messages in JSON object node format |
| 167 | |
Simon Hunt | a7aea84 | 2017-05-03 19:42:50 -0700 | [diff] [blame] | 168 | // NOTE: trafficSummary(StatsType) => Highlights |
| 169 | // has been moved to the superclass |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 170 | |
| 171 | // create highlights for links, showing flows for selected devices. |
| 172 | private Highlights deviceLinkFlows() { |
| 173 | Highlights highlights = new Highlights(); |
| 174 | |
Simon Hunt | 7229721 | 2015-08-25 10:15:33 -0700 | [diff] [blame] | 175 | if (selectedNodes != null && !selectedNodes.devicesWithHover().isEmpty()) { |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 176 | // capture flow counts on bilinks |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 177 | TrafficLinkMap linkMap = new TrafficLinkMap(); |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 178 | |
Simon Hunt | 7229721 | 2015-08-25 10:15:33 -0700 | [diff] [blame] | 179 | for (Device device : selectedNodes.devicesWithHover()) { |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 180 | Map<Link, Integer> counts = getLinkFlowCounts(device.id()); |
| 181 | for (Link link : counts.keySet()) { |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 182 | TrafficLink tlink = linkMap.add(link); |
| 183 | tlink.addFlows(counts.get(link)); |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 184 | } |
| 185 | } |
| 186 | |
| 187 | // now report on our collated links |
Simon Hunt | 4fc8685 | 2015-08-20 17:57:52 -0700 | [diff] [blame] | 188 | for (TrafficLink tlink : linkMap.biLinks()) { |
Simon Hunt | 5783017 | 2015-08-26 13:25:17 -0700 | [diff] [blame] | 189 | highlights.add(tlink.highlight(StatsType.FLOW_COUNT)); |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 190 | } |
| 191 | |
| 192 | } |
| 193 | return highlights; |
| 194 | } |
| 195 | |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 196 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 197 | |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 198 | // Counts all flow entries that egress on the links of the given device. |
| 199 | private Map<Link, Integer> getLinkFlowCounts(DeviceId deviceId) { |
| 200 | // get the flows for the device |
| 201 | List<FlowEntry> entries = new ArrayList<>(); |
Simon Hunt | 1911fe4 | 2017-05-02 18:25:58 -0700 | [diff] [blame] | 202 | for (FlowEntry flowEntry : services.flow().getFlowEntries(deviceId)) { |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 203 | entries.add(flowEntry); |
| 204 | } |
| 205 | |
| 206 | // get egress links from device, and include edge links |
Simon Hunt | 1911fe4 | 2017-05-02 18:25:58 -0700 | [diff] [blame] | 207 | Set<Link> links = new HashSet<>(services.link() |
| 208 | .getDeviceEgressLinks(deviceId)); |
| 209 | Set<Host> hosts = services.host().getConnectedHosts(deviceId); |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 210 | if (hosts != null) { |
| 211 | for (Host host : hosts) { |
Pier | 59266bc | 2018-03-15 12:10:24 -0700 | [diff] [blame] | 212 | links.addAll(createEdgeLinks(host, false)); |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 213 | } |
| 214 | } |
| 215 | |
| 216 | // compile flow counts per link |
| 217 | Map<Link, Integer> counts = new HashMap<>(); |
| 218 | for (Link link : links) { |
| 219 | counts.put(link, getEgressFlows(link, entries)); |
| 220 | } |
| 221 | return counts; |
| 222 | } |
| 223 | |
| 224 | // Counts all entries that egress on the link source port. |
| 225 | private int getEgressFlows(Link link, List<FlowEntry> entries) { |
| 226 | int count = 0; |
| 227 | PortNumber out = link.src().port(); |
| 228 | for (FlowEntry entry : entries) { |
| 229 | TrafficTreatment treatment = entry.treatment(); |
| 230 | for (Instruction instruction : treatment.allInstructions()) { |
| 231 | if (instruction.type() == Instruction.Type.OUTPUT && |
| 232 | ((OutputInstruction) instruction).port().equals(out)) { |
| 233 | count++; |
| 234 | } |
| 235 | } |
| 236 | } |
| 237 | return count; |
| 238 | } |
| 239 | |
Simon Hunt | a17fa67 | 2015-08-19 18:42:22 -0700 | [diff] [blame] | 240 | } |