blob: f1318de97061288fa6be728becf0f8ea720f8c70 [file] [log] [blame]
Boyoung Jeong9e8faec2018-06-17 21:19:23 +09001/*
2 * Copyright 2018-present Open Networking Foundation
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 */
16package org.onosproject.openstacktelemetry.impl;
17
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090018import com.google.common.collect.Maps;
Jian Li0bbbb1c2018-06-22 22:01:17 +090019import com.google.common.collect.Sets;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
Jian Li753280e2018-07-03 02:24:34 +090023import org.apache.felix.scr.annotations.Modified;
24import org.apache.felix.scr.annotations.Property;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090025import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.apache.felix.scr.annotations.Service;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090028import org.onlab.packet.IpAddress;
Jian Li753280e2018-07-03 02:24:34 +090029import org.onlab.packet.IpPrefix;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090030import org.onlab.packet.MacAddress;
31import org.onlab.packet.VlanId;
Jian Lia4947682018-07-07 14:53:32 +090032import org.onlab.util.SharedScheduledExecutors;
Jian Lie6110b72018-07-06 19:06:36 +090033import org.onosproject.cfg.ComponentConfigService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090034import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
Jian Li85573f42018-06-27 22:29:14 +090036import org.onosproject.mastership.MastershipService;
Jian Lif8b8c7f2018-08-27 18:49:04 +090037import org.onosproject.net.ConnectPoint;
38import org.onosproject.net.Device;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090039import org.onosproject.net.DeviceId;
40import org.onosproject.net.Host;
Jian Lia4947682018-07-07 14:53:32 +090041import org.onosproject.net.PortNumber;
42import org.onosproject.net.device.DeviceService;
43import org.onosproject.net.device.PortStatistics;
Jian Lif8b8c7f2018-08-27 18:49:04 +090044import org.onosproject.net.driver.Driver;
45import org.onosproject.net.driver.DriverService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090046import org.onosproject.net.flow.DefaultFlowRule;
47import org.onosproject.net.flow.DefaultTrafficSelector;
48import org.onosproject.net.flow.DefaultTrafficTreatment;
49import org.onosproject.net.flow.FlowEntry;
50import org.onosproject.net.flow.FlowRule;
51import org.onosproject.net.flow.FlowRuleOperations;
52import org.onosproject.net.flow.FlowRuleOperationsContext;
53import org.onosproject.net.flow.FlowRuleService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090054import org.onosproject.net.flow.TrafficSelector;
55import org.onosproject.net.flow.TrafficTreatment;
Jian Lif8b8c7f2018-08-27 18:49:04 +090056import org.onosproject.net.flow.criteria.Criterion;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090057import org.onosproject.net.flow.criteria.IPCriterion;
58import org.onosproject.net.flow.criteria.IPProtocolCriterion;
Jian Lif8b8c7f2018-08-27 18:49:04 +090059import org.onosproject.net.flow.criteria.PortCriterion;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090060import org.onosproject.net.flow.criteria.TcpPortCriterion;
61import org.onosproject.net.flow.criteria.UdpPortCriterion;
62import org.onosproject.net.host.HostService;
Jian Lia4947682018-07-07 14:53:32 +090063import org.onosproject.openstacknetworking.api.InstancePort;
64import org.onosproject.openstacknetworking.api.InstancePortService;
Jian Li753280e2018-07-03 02:24:34 +090065import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lia4947682018-07-07 14:53:32 +090066import org.onosproject.openstacknode.api.OpenstackNode;
67import org.onosproject.openstacknode.api.OpenstackNodeService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090068import org.onosproject.openstacktelemetry.api.FlowInfo;
Jian Li0bbbb1c2018-06-22 22:01:17 +090069import org.onosproject.openstacktelemetry.api.OpenstackTelemetryService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090070import org.onosproject.openstacktelemetry.api.StatsFlowRule;
71import org.onosproject.openstacktelemetry.api.StatsFlowRuleAdminService;
72import org.onosproject.openstacktelemetry.api.StatsInfo;
Jian Li753280e2018-07-03 02:24:34 +090073import org.osgi.service.component.ComponentContext;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090074import org.slf4j.Logger;
75import org.slf4j.LoggerFactory;
76
Jian Lif8b8c7f2018-08-27 18:49:04 +090077import java.util.ArrayList;
Jian Li753280e2018-07-03 02:24:34 +090078import java.util.Dictionary;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090079import java.util.LinkedList;
Jian Lia4947682018-07-07 14:53:32 +090080import java.util.List;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090081import java.util.Map;
Jian Li85573f42018-06-27 22:29:14 +090082import java.util.Optional;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090083import java.util.Queue;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090084import java.util.Set;
Jian Lia4947682018-07-07 14:53:32 +090085import java.util.concurrent.ScheduledFuture;
86import java.util.concurrent.TimeUnit;
87import java.util.stream.Collectors;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090088
Jian Li0bbbb1c2018-06-22 22:01:17 +090089import static org.onlab.packet.Ethernet.TYPE_IPV4;
90import static org.onlab.packet.IPv4.PROTOCOL_TCP;
91import static org.onlab.packet.IPv4.PROTOCOL_UDP;
Jian Lif8b8c7f2018-08-27 18:49:04 +090092import static org.onosproject.net.Device.Type.SWITCH;
Jian Li0bbbb1c2018-06-22 22:01:17 +090093import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
94import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC;
95import static org.onosproject.net.flow.criteria.Criterion.Type.IP_PROTO;
96import static org.onosproject.net.flow.criteria.Criterion.Type.TCP_DST;
97import static org.onosproject.net.flow.criteria.Criterion.Type.TCP_SRC;
98import static org.onosproject.net.flow.criteria.Criterion.Type.UDP_DST;
99import static org.onosproject.net.flow.criteria.Criterion.Type.UDP_SRC;
Jian Li753280e2018-07-03 02:24:34 +0900100import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900101import static org.onosproject.openstacknetworking.api.Constants.STAT_INBOUND_TABLE;
102import static org.onosproject.openstacknetworking.api.Constants.STAT_OUTBOUND_TABLE;
Jian Li753280e2018-07-03 02:24:34 +0900103import static org.onosproject.openstacknetworking.api.Constants.VTAP_FLAT_OUTBOUND_TABLE;
Jian Li87ded822018-07-02 18:31:22 +0900104import static org.onosproject.openstacknetworking.api.Constants.VTAP_INBOUND_TABLE;
105import static org.onosproject.openstacknetworking.api.Constants.VTAP_OUTBOUND_TABLE;
Jian Lia4947682018-07-07 14:53:32 +0900106import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Jian Lif8b8c7f2018-08-27 18:49:04 +0900107import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900108import static org.onosproject.openstacktelemetry.api.Constants.DEFAULT_DATA_POINT_SIZE;
Jian Lie6110b72018-07-06 19:06:36 +0900109import static org.onosproject.openstacktelemetry.api.Constants.FLAT;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900110import static org.onosproject.openstacktelemetry.api.Constants.OPENSTACK_TELEMETRY_APP_ID;
Jian Lie6110b72018-07-06 19:06:36 +0900111import static org.onosproject.openstacktelemetry.api.Constants.VLAN;
112import static org.onosproject.openstacktelemetry.api.Constants.VXLAN;
Jian Li753280e2018-07-03 02:24:34 +0900113import static org.onosproject.openstacktelemetry.util.OpenstackTelemetryUtil.getBooleanProperty;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900114
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900115/**
116 * Flow rule manager for network statistics of a VM.
117 */
118@Component(immediate = true)
119@Service
120public class StatsFlowRuleManager implements StatsFlowRuleAdminService {
121
122 private final Logger log = LoggerFactory.getLogger(getClass());
123
124 private static final byte FLOW_TYPE_SONA = 1; // VLAN
125
Ray Milkeybcc53d32018-07-02 10:22:57 -0700126 private static final long MILLISECONDS = 1000L;
Jian Lia4947682018-07-07 14:53:32 +0900127 private static final long INITIAL_DELAY = 5L;
Ray Milkeybcc53d32018-07-02 10:22:57 -0700128 private static final long REFRESH_INTERVAL = 5L;
Jian Lia4947682018-07-07 14:53:32 +0900129 private static final TimeUnit TIME_UNIT_SECOND = TimeUnit.SECONDS;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900130
Jian Li753280e2018-07-03 02:24:34 +0900131 private static final String REVERSE_PATH_STATS = "reversePathStats";
132 private static final String EGRESS_STATS = "egressStats";
Jian Lia4947682018-07-07 14:53:32 +0900133 private static final String PORT_STATS = "portStats";
Jian Li753280e2018-07-03 02:24:34 +0900134
Jian Lif8b8c7f2018-08-27 18:49:04 +0900135 private static final String MONITOR_OVERLAY = "monitorOverlay";
136 private static final String MONITOR_UNDERLAY = "monitorUnderlay";
137
138 private static final String OVS_DRIVER_NAME = "ovs";
139
Jian Li753280e2018-07-03 02:24:34 +0900140 private static final boolean DEFAULT_REVERSE_PATH_STATS = false;
141 private static final boolean DEFAULT_EGRESS_STATS = false;
Jian Lia4947682018-07-07 14:53:32 +0900142 private static final boolean DEFAULT_PORT_STATS = true;
Jian Li753280e2018-07-03 02:24:34 +0900143
Jian Lif8b8c7f2018-08-27 18:49:04 +0900144 private static final boolean DEFAULT_MONITOR_OVERLAY = true;
145 private static final boolean DEFAULT_MONITOR_UNDERLAY = true;
146
Jian Lia4947682018-07-07 14:53:32 +0900147 private static final String ARBITRARY_IP = "0.0.0.0/32";
boyoung27b444122018-09-01 17:28:13 +0900148 private static final int ARBITRARY_PROTOCOL = 0x0;
Jian Lia4947682018-07-07 14:53:32 +0900149 private static final int ARBITRARY_LENGTH = 32;
150 private static final String ARBITRARY_MAC = "00:00:00:00:00:00";
Jian Lif8b8c7f2018-08-27 18:49:04 +0900151 private static final IpAddress NO_HOST_IP = IpAddress.valueOf("255.255.255.255");
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900152 private static final MacAddress NO_HOST_MAC = MacAddress.valueOf(ARBITRARY_MAC);
Jian Lia4947682018-07-07 14:53:32 +0900153 private static final int ARBITRARY_IN_INTF = 0;
154 private static final int ARBITRARY_OUT_INTF = 0;
155
156 private static final boolean RECOVER_FROM_FAILURE = true;
157
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900158 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
159 protected CoreService coreService;
160
161 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
162 protected FlowRuleService flowRuleService;
163
164 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
165 protected HostService hostService;
166
Jian Li0bbbb1c2018-06-22 22:01:17 +0900167 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lia4947682018-07-07 14:53:32 +0900168 protected DeviceService deviceService;
169
170 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900171 protected DriverService driverService;
172
173 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lie6110b72018-07-06 19:06:36 +0900174 protected ComponentConfigService componentConfigService;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900175
176 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li85573f42018-06-27 22:29:14 +0900177 protected MastershipService mastershipService;
178
179 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li753280e2018-07-03 02:24:34 +0900180 protected OpenstackNetworkService osNetworkService;
181
182 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lia4947682018-07-07 14:53:32 +0900183 protected InstancePortService instPortService;
184
185 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
186 protected OpenstackNodeService osNodeService;
187
188 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li0bbbb1c2018-06-22 22:01:17 +0900189 protected OpenstackTelemetryService telemetryService;
190
Jian Li753280e2018-07-03 02:24:34 +0900191 @Property(name = REVERSE_PATH_STATS, boolValue = DEFAULT_REVERSE_PATH_STATS,
192 label = "A flag which indicates whether to install the rules for " +
193 "collecting the flow-based stats for reversed path.")
194 private boolean reversePathStats = DEFAULT_REVERSE_PATH_STATS;
195
196 @Property(name = EGRESS_STATS, boolValue = DEFAULT_EGRESS_STATS,
197 label = "A flag which indicates whether to install the rules for " +
198 "collecting the flow-based stats for egress port.")
199 private boolean egressStats = DEFAULT_EGRESS_STATS;
200
Jian Lia4947682018-07-07 14:53:32 +0900201 @Property(name = PORT_STATS, boolValue = DEFAULT_PORT_STATS,
202 label = "A flag which indicates whether to collect port TX & RX stats.")
203 private boolean portStats = DEFAULT_PORT_STATS;
204
Jian Lif8b8c7f2018-08-27 18:49:04 +0900205 @Property(name = MONITOR_OVERLAY, boolValue = DEFAULT_MONITOR_OVERLAY,
206 label = "A flag which indicates whether to monitor overlay network port stats.")
207 private boolean monitorOverlay = DEFAULT_MONITOR_OVERLAY;
208
209 @Property(name = MONITOR_UNDERLAY, boolValue = DEFAULT_MONITOR_UNDERLAY,
210 label = "A flag which indicates whether to monitor underlay network port stats.")
211 private boolean monitorUnderlay = DEFAULT_MONITOR_UNDERLAY;
212
213 private ApplicationId telemetryAppId;
Jian Lia4947682018-07-07 14:53:32 +0900214 private TelemetryCollector collector;
Jian Lia4947682018-07-07 14:53:32 +0900215 private ScheduledFuture result;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900216
Jian Li0bbbb1c2018-06-22 22:01:17 +0900217 private final Set<FlowInfo> gFlowInfoSet = Sets.newHashSet();
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900218 private final Map<String, Queue<FlowInfo>> flowInfoMap = Maps.newConcurrentMap();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900219
220 private static final int SOURCE_ID = 1;
221 private static final int TARGET_ID = 2;
222 private static final int PRIORITY_BASE = 10000;
223 private static final int METRIC_PRIORITY_SOURCE = SOURCE_ID * PRIORITY_BASE;
224 private static final int METRIC_PRIORITY_TARGET = TARGET_ID * PRIORITY_BASE;
225
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900226 @Activate
227 protected void activate() {
Jian Lif8b8c7f2018-08-27 18:49:04 +0900228 telemetryAppId = coreService.registerApplication(OPENSTACK_TELEMETRY_APP_ID);
229
Jian Lie6110b72018-07-06 19:06:36 +0900230 componentConfigService.registerProperties(getClass());
Jian Libd295cd2018-07-22 11:53:57 +0900231 start();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900232
233 log.info("Started");
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900234 }
235
236 @Deactivate
237 protected void deactivate() {
Jian Lie6110b72018-07-06 19:06:36 +0900238 componentConfigService.unregisterProperties(getClass(), false);
Jian Lif8b8c7f2018-08-27 18:49:04 +0900239 flowRuleService.removeFlowRulesById(telemetryAppId);
Jian Libd295cd2018-07-22 11:53:57 +0900240 stop();
Jian Lia4947682018-07-07 14:53:32 +0900241
Jian Li0bbbb1c2018-06-22 22:01:17 +0900242 log.info("Stopped");
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900243 }
244
Jian Li753280e2018-07-03 02:24:34 +0900245 @Modified
246 protected void modified(ComponentContext context) {
247 readComponentConfiguration(context);
248
249 log.info("Modified");
250 }
251
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900252 @Override
253 public void start() {
254 log.info("Start publishing thread");
Jian Lia4947682018-07-07 14:53:32 +0900255 collector = new TelemetryCollector();
256
Jian Libd295cd2018-07-22 11:53:57 +0900257 result = SharedScheduledExecutors.getSingleThreadExecutor()
258 .scheduleAtFixedRate(collector, INITIAL_DELAY,
Jian Lia4947682018-07-07 14:53:32 +0900259 REFRESH_INTERVAL, TIME_UNIT_SECOND, RECOVER_FROM_FAILURE);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900260 }
261
262 @Override
263 public void stop() {
264 log.info("Stop data publishing thread");
Jian Lia4947682018-07-07 14:53:32 +0900265 result.cancel(true);
266 collector = null;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900267 }
268
Jian Li0bbbb1c2018-06-22 22:01:17 +0900269 @Override
boyoung27b444122018-09-01 17:28:13 +0900270 public void setStatFlowL2Rule(String srcIp, String dstIp, Boolean install) {
271 StatsFlowRule statsFlowRule = DefaultStatsFlowRule.builder()
272 .srcIpPrefix(IpPrefix.valueOf(IpAddress.valueOf(srcIp), ARBITRARY_LENGTH))
273 .dstIpPrefix(IpPrefix.valueOf(IpAddress.valueOf(dstIp), ARBITRARY_LENGTH))
274 .ipProtocol((byte) ARBITRARY_PROTOCOL)
275 .build();
276 setStatFlowRule(statsFlowRule, install);
277 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900278
boyoung27b444122018-09-01 17:28:13 +0900279 @Override
280 public void createStatFlowRule(StatsFlowRule statsFlowRule) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900281 setStatFlowRule(statsFlowRule, true);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900282 }
283
284 @Override
285 public void deleteStatFlowRule(StatsFlowRule statsFlowRule) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900286 setStatFlowRule(statsFlowRule, false);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900287 }
288
Jian Lif8b8c7f2018-08-27 18:49:04 +0900289
Jian Lia4947682018-07-07 14:53:32 +0900290 @Override
Jian Lif8b8c7f2018-08-27 18:49:04 +0900291 public Map<String, Queue<FlowInfo>> getFlowInfoMap() {
292 return flowInfoMap;
293 }
294
295
296 @Override
297 public Set<FlowInfo> getUnderlayFlowInfos() {
298
299 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
300
301 for (Device device : getUnderlayDevices()) {
302
303 if (!isEdgeSwitch(device.id())) {
304 continue;
305 }
306
307 for (FlowEntry entry : flowRuleService.getFlowEntries(device.id())) {
308 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
309 TrafficSelector selector = entry.selector();
310 Criterion inPort = selector.getCriterion(Criterion.Type.IN_PORT);
311 Criterion dstIpCriterion = selector.getCriterion(Criterion.Type.IPV4_DST);
312 if (inPort != null && dstIpCriterion != null) {
313 IpAddress srcIp = getIpAddress(device, (PortCriterion) inPort);
314 IpAddress dstIp = ((IPCriterion) dstIpCriterion).ip().address();
315
316 if (srcIp == null) {
317 continue;
318 }
319
320 fBuilder.withFlowType(FLOW_TYPE_SONA)
321 .withSrcIp(IpPrefix.valueOf(srcIp, ARBITRARY_LENGTH))
322 .withDstIp(IpPrefix.valueOf(dstIp, ARBITRARY_LENGTH))
323 .withSrcMac(getMacAddress(srcIp))
324 .withDstMac(getMacAddress(dstIp))
325 .withInputInterfaceId(getInterfaceId(srcIp))
326 .withOutputInterfaceId(getInterfaceId(dstIp))
327 .withDeviceId(entry.deviceId());
328
329 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
330
331 sBuilder.withStartupTime(System.currentTimeMillis())
332 .withFstPktArrTime(System.currentTimeMillis())
333 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
334 .withCurrAccPkts((int) entry.packets())
335 .withCurrAccBytes(entry.bytes())
336 .withErrorPkts((short) 0)
337 .withDropPkts((short) 0);
338
339 fBuilder.withStatsInfo(sBuilder.build());
340
341 FlowInfo flowInfo = mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
342
343 flowInfos.add(flowInfo);
344 }
345 }
346 }
347
348 return flowInfos;
349 }
350
351 @Override
352 public Set<FlowInfo> getOverlayFlowInfos() {
353
Jian Lia4947682018-07-07 14:53:32 +0900354 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
355
356 // obtain all flow rule entries installed by telemetry app
Jian Lif8b8c7f2018-08-27 18:49:04 +0900357 for (FlowEntry entry : flowRuleService.getFlowEntriesById(telemetryAppId)) {
Jian Lia4947682018-07-07 14:53:32 +0900358 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
359 TrafficSelector selector = entry.selector();
Jian Lia4947682018-07-07 14:53:32 +0900360 IPCriterion srcIp = (IPCriterion) selector.getCriterion(IPV4_SRC);
361 IPCriterion dstIp = (IPCriterion) selector.getCriterion(IPV4_DST);
362 IPProtocolCriterion ipProtocol =
363 (IPProtocolCriterion) selector.getCriterion(IP_PROTO);
364
Jian Lia4947682018-07-07 14:53:32 +0900365 fBuilder.withFlowType(FLOW_TYPE_SONA)
366 .withSrcIp(srcIp.ip())
367 .withDstIp(dstIp.ip());
368
369 if (ipProtocol != null) {
370 fBuilder.withProtocol((byte) ipProtocol.protocol());
371
372 if (ipProtocol.protocol() == PROTOCOL_TCP) {
373 TcpPortCriterion tcpSrc =
374 (TcpPortCriterion) selector.getCriterion(TCP_SRC);
375 TcpPortCriterion tcpDst =
376 (TcpPortCriterion) selector.getCriterion(TCP_DST);
Jian Lia4947682018-07-07 14:53:32 +0900377 fBuilder.withSrcPort(tcpSrc.tcpPort());
378 fBuilder.withDstPort(tcpDst.tcpPort());
Jian Lia4947682018-07-07 14:53:32 +0900379 } else if (ipProtocol.protocol() == PROTOCOL_UDP) {
Jian Lia4947682018-07-07 14:53:32 +0900380 UdpPortCriterion udpSrc =
381 (UdpPortCriterion) selector.getCriterion(UDP_SRC);
382 UdpPortCriterion udpDst =
383 (UdpPortCriterion) selector.getCriterion(UDP_DST);
Jian Lia4947682018-07-07 14:53:32 +0900384 fBuilder.withSrcPort(udpSrc.udpPort());
385 fBuilder.withDstPort(udpDst.udpPort());
386 } else {
387 log.debug("Other protocol: {}", ipProtocol.protocol());
388 }
389 }
390
391 fBuilder.withSrcMac(getMacAddress(srcIp.ip().address()))
392 .withDstMac(getMacAddress(dstIp.ip().address()))
393 .withInputInterfaceId(getInterfaceId(srcIp.ip().address()))
394 .withOutputInterfaceId(getInterfaceId(dstIp.ip().address()))
395 .withVlanId(getVlanId(srcIp.ip().address()))
396 .withDeviceId(entry.deviceId());
397
398 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
399
Jian Lia4947682018-07-07 14:53:32 +0900400 sBuilder.withStartupTime(System.currentTimeMillis())
401 .withFstPktArrTime(System.currentTimeMillis())
402 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
403 .withCurrAccPkts((int) entry.packets())
404 .withCurrAccBytes(entry.bytes())
405 .withErrorPkts((short) 0)
406 .withDropPkts((short) 0);
407
408 fBuilder.withStatsInfo(sBuilder.build());
409
410 FlowInfo flowInfo = mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
411
412 flowInfos.add(flowInfo);
413
414 log.debug("FlowInfo: \n{}", flowInfo.toString());
415 }
416
417 return flowInfos;
418 }
419
420 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900421 * Gets a set of flow infos by referring to overlay destination VM port.
Jian Lia4947682018-07-07 14:53:32 +0900422 *
423 * @return flow infos
424 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900425 private Set<FlowInfo> getOverlayDstPortBasedFlowInfos() {
Jian Lia4947682018-07-07 14:53:32 +0900426 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
427 Set<PortNumber> instPortNums = instPortService.instancePorts()
428 .stream()
429 .map(InstancePort::portNumber)
430 .collect(Collectors.toSet());
431 Set<DeviceId> deviceIds = osNodeService.completeNodes(COMPUTE)
432 .stream()
433 .map(OpenstackNode::intgBridge)
434 .collect(Collectors.toSet());
435
436 deviceIds.forEach(d -> {
437 List<PortStatistics> stats =
438 deviceService.getPortStatistics(d)
439 .stream()
440 .filter(s -> instPortNums.contains(s.portNumber()))
441 .collect(Collectors.toList());
442
443 stats.forEach(s -> {
444 InstancePort instPort = getInstancePort(d, s.portNumber());
Jian Lif8b8c7f2018-08-27 18:49:04 +0900445 flowInfos.add(buildTxFlowInfoFromInstancePort(instPort, s));
446 flowInfos.add(buildRxFlowInfoFromInstancePort(instPort, s));
Jian Lia4947682018-07-07 14:53:32 +0900447 });
448 });
449
450 return flowInfos;
451 }
452
453 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900454 * Gets a set of flow infos by referring to underlay destination port.
455 *
456 * @return flow infos
457 */
458 private Set<FlowInfo> getUnderlayDstPortBasedFlowInfos() {
459 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
460
461 for (Device d : getUnderlayDevices()) {
462 List<PortStatistics> stats =
463 new ArrayList<>(deviceService.getPortStatistics(d.id()));
464 stats.forEach(s -> {
465 Host host = hostService.getConnectedHosts(new ConnectPoint(d.id(), s.portNumber()))
466 .stream().findFirst().orElse(null);
467 if (host != null) {
468 flowInfos.add(buildTxFlowInfoFromHost(host, s));
469 flowInfos.add(buildRxFlowInfoFromHost(host, s));
470 }
471 });
472 }
473
474 return flowInfos;
475 }
476
477 /**
478 * Obtains a set of device instances which construct underlay network.
479 *
480 * @return a set of device instances
481 */
482 private Set<Device> getUnderlayDevices() {
483
484 Set<Device> underlayDevices = Sets.newConcurrentHashSet();
485
486 Set<DeviceId> overlayDeviceIds = osNodeService.completeNodes()
487 .stream()
488 .filter(n -> n.type() != CONTROLLER)
489 .map(OpenstackNode::intgBridge)
490 .collect(Collectors.toSet());
491
492 for (Device d : deviceService.getAvailableDevices(SWITCH)) {
493 if (overlayDeviceIds.contains(d.id())) {
494 continue;
495 }
496
497 underlayDevices.add(d);
498 }
499
500 return underlayDevices;
501 }
502
503 /**
504 * Checks whether the given drivers contains OVS driver.
505 *
506 * @param drivers a set of drivers
507 * @return true if the given drivers contain any OVS driver, false otherwise
508 */
509 private boolean hasOvsDriver(List<Driver> drivers) {
510
511 for (Driver driver : drivers) {
512 if (OVS_DRIVER_NAME.equals(driver.name())) {
513 return true;
514 }
515 }
516
517 return false;
518 }
519
520 /**
521 * Obtains the flow info generated by TX port from instance port.
Jian Lia4947682018-07-07 14:53:32 +0900522 *
523 * @param instPort instance port
524 * @param stat port statistics
525 * @return flow info
526 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900527 private FlowInfo buildTxFlowInfoFromInstancePort(InstancePort instPort,
528 PortStatistics stat) {
529 return buildTxFlowInfo(instPort.ipAddress(), instPort.macAddress(),
530 instPort.deviceId(), stat);
531 }
532
533 /**
534 * Obtains the flow info generated from RX port from instance port.
535 *
536 * @param instPort instance port
537 * @param stat port statistics
538 * @return flow info
539 */
540 private FlowInfo buildRxFlowInfoFromInstancePort(InstancePort instPort,
541 PortStatistics stat) {
542 return buildRxFlowInfo(instPort.ipAddress(), instPort.macAddress(),
543 instPort.deviceId(), stat);
544 }
545
546 /**
547 * Obtains the flow info generated by TX port from host.
548 *
549 * @param host host
550 * @param stat port statistics
551 * @return flow info
552 */
553 private FlowInfo buildTxFlowInfoFromHost(Host host, PortStatistics stat) {
554 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
555
556 if (ip != null) {
557 return buildTxFlowInfo(ip, host.mac(), host.location().deviceId(), stat);
558 }
559 return null;
560 }
561
562 /**
563 * Obtains the flow info generated by RX @param host host.
564 *
565 * @param host host
566 * @param stat port statistics
567 * @return flow info
568 */
569 private FlowInfo buildRxFlowInfoFromHost(Host host, PortStatistics stat) {
570 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
571
572 if (ip != null) {
573 return buildRxFlowInfo(ip, host.mac(), host.location().deviceId(), stat);
574 }
575 return null;
576 }
577
578 /**
579 * Obtains the flow info generated from TX port.
580 *
581 * @param ipAddress IP address
582 * @param macAddress MAC address
583 * @param deviceId device identifier
584 * @param stat port statistics
585 * @return flow info
586 */
587 private FlowInfo buildTxFlowInfo(IpAddress ipAddress,
588 MacAddress macAddress,
589 DeviceId deviceId,
590 PortStatistics stat) {
Jian Lia4947682018-07-07 14:53:32 +0900591 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
592
593 fBuilder.withFlowType(FLOW_TYPE_SONA)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900594 .withSrcIp(IpPrefix.valueOf(ipAddress, ARBITRARY_LENGTH))
Jian Lia4947682018-07-07 14:53:32 +0900595 .withDstIp(IpPrefix.valueOf(ARBITRARY_IP))
Jian Lif8b8c7f2018-08-27 18:49:04 +0900596 .withSrcMac(macAddress)
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900597 .withDstMac(NO_HOST_MAC)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900598 .withDeviceId(deviceId)
Jian Lia4947682018-07-07 14:53:32 +0900599 .withInputInterfaceId(ARBITRARY_IN_INTF)
600 .withOutputInterfaceId(ARBITRARY_OUT_INTF)
601 .withVlanId(VlanId.vlanId());
602
603 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
604 sBuilder.withStartupTime(System.currentTimeMillis())
605 .withFstPktArrTime(System.currentTimeMillis())
606 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
607 .withCurrAccPkts((int) stat.packetsSent())
608 .withCurrAccBytes(stat.bytesSent())
609 .withErrorPkts((short) stat.packetsTxErrors())
610 .withDropPkts((short) stat.packetsTxDropped());
611
612 fBuilder.withStatsInfo(sBuilder.build());
613
614 return mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
615 }
616
617 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900618 * Obtains the flow info generated from RX port.
Jian Lia4947682018-07-07 14:53:32 +0900619 *
Jian Lif8b8c7f2018-08-27 18:49:04 +0900620 * @param ipAddress IP address
621 * @param macAddress MAC address
622 * @param deviceId Device identifier
Jian Lia4947682018-07-07 14:53:32 +0900623 * @param stat port statistics
624 * @return flow info
625 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900626 private FlowInfo buildRxFlowInfo(IpAddress ipAddress,
627 MacAddress macAddress,
628 DeviceId deviceId,
629 PortStatistics stat) {
Jian Lia4947682018-07-07 14:53:32 +0900630 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
631
632 fBuilder.withFlowType(FLOW_TYPE_SONA)
633 .withSrcIp(IpPrefix.valueOf(ARBITRARY_IP))
Jian Lif8b8c7f2018-08-27 18:49:04 +0900634 .withDstIp(IpPrefix.valueOf(ipAddress, ARBITRARY_LENGTH))
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900635 .withSrcMac(NO_HOST_MAC)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900636 .withDstMac(macAddress)
637 .withDeviceId(deviceId)
Jian Lia4947682018-07-07 14:53:32 +0900638 .withInputInterfaceId(ARBITRARY_IN_INTF)
639 .withOutputInterfaceId(ARBITRARY_OUT_INTF)
640 .withVlanId(VlanId.vlanId());
641
642 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
643 sBuilder.withStartupTime(System.currentTimeMillis())
644 .withFstPktArrTime(System.currentTimeMillis())
645 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
646 .withCurrAccPkts((int) stat.packetsReceived())
647 .withCurrAccBytes(stat.bytesReceived())
648 .withErrorPkts((short) stat.packetsRxErrors())
649 .withDropPkts((short) stat.packetsRxDropped());
650
651 fBuilder.withStatsInfo(sBuilder.build());
652
653 return mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
654 }
655
656 /**
657 * Obtains instance port which associated with the given device identifier
658 * and port number.
659 *
660 * @param deviceId device identifier
661 * @param portNumber port number
662 * @return instance port
663 */
664 private InstancePort getInstancePort(DeviceId deviceId, PortNumber portNumber) {
665 return instPortService.instancePorts().stream()
666 .filter(p -> p.deviceId().equals(deviceId))
667 .filter(p -> p.portNumber().equals(portNumber))
668 .findFirst().orElse(null);
669 }
670
Jian Lif8b8c7f2018-08-27 18:49:04 +0900671 /**
672 * Installs a flow rule where the source table is fromTable, while destination
673 * table is toTable.
674 *
675 * @param deviceId device identifier
676 * @param fromTable source table
677 * @param toTable destination table
678 * @param statsFlowRule stats flow rule
679 * @param rulePriority rule priority
680 * @param install installation flag
681 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900682 private void connectTables(DeviceId deviceId, int fromTable, int toTable,
683 StatsFlowRule statsFlowRule, int rulePriority,
684 boolean install) {
685
Jian Li0bbbb1c2018-06-22 22:01:17 +0900686 int srcPrefixLength = statsFlowRule.srcIpPrefix().prefixLength();
687 int dstPrefixLength = statsFlowRule.dstIpPrefix().prefixLength();
688 int prefixLength = rulePriority + srcPrefixLength + dstPrefixLength;
689 byte protocol = statsFlowRule.ipProtocol();
690
691 TrafficSelector.Builder selectorBuilder =
Jian Li753280e2018-07-03 02:24:34 +0900692 DefaultTrafficSelector.builder()
693 .matchEthType(TYPE_IPV4)
694 .matchIPSrc(statsFlowRule.srcIpPrefix())
695 .matchIPDst(statsFlowRule.dstIpPrefix());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900696
697 if (protocol == PROTOCOL_TCP) {
698 selectorBuilder = selectorBuilder
Jian Li753280e2018-07-03 02:24:34 +0900699 .matchIPProtocol(statsFlowRule.ipProtocol())
700 .matchTcpSrc(statsFlowRule.srcTpPort())
701 .matchTcpDst(statsFlowRule.dstTpPort());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900702
703 } else if (protocol == PROTOCOL_UDP) {
704 selectorBuilder = selectorBuilder
Jian Li753280e2018-07-03 02:24:34 +0900705 .matchIPProtocol(statsFlowRule.ipProtocol())
706 .matchUdpSrc(statsFlowRule.srcTpPort())
707 .matchUdpDst(statsFlowRule.dstTpPort());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900708 } else {
709 log.warn("Unsupported protocol {}", statsFlowRule.ipProtocol());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900710 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900711
712 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
713
714 treatmentBuilder.transition(toTable);
715
716 FlowRule flowRule = DefaultFlowRule.builder()
Jian Li753280e2018-07-03 02:24:34 +0900717 .forDevice(deviceId)
718 .withSelector(selectorBuilder.build())
719 .withTreatment(treatmentBuilder.build())
720 .withPriority(prefixLength)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900721 .fromApp(telemetryAppId)
Jian Li753280e2018-07-03 02:24:34 +0900722 .makePermanent()
723 .forTable(fromTable)
724 .build();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900725
726 applyRule(flowRule, install);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900727 }
728
729 /**
Jian Li0bbbb1c2018-06-22 22:01:17 +0900730 * Installs stats related flow rule to switch.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900731 *
Jian Li0bbbb1c2018-06-22 22:01:17 +0900732 * @param flowRule flow rule
733 * @param install flag to install or not
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900734 */
735 private void applyRule(FlowRule flowRule, boolean install) {
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900736 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900737 flowOpsBuilder = install ?
738 flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900739
740 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
741 @Override
742 public void onSuccess(FlowRuleOperations ops) {
Jian Lia4947682018-07-07 14:53:32 +0900743 log.debug("Install rules for telemetry stats: \n {}",
744 ops.toString());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900745 }
746
747 @Override
748 public void onError(FlowRuleOperations ops) {
Jian Lia4947682018-07-07 14:53:32 +0900749 log.debug("Failed to install rules for telemetry stats: \n {}",
750 ops.toString());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900751 }
752 }));
753 }
754
755 /**
Jian Li0bbbb1c2018-06-22 22:01:17 +0900756 * Merges old FlowInfo.StatsInfo and current FlowInfo.StatsInfo.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900757 *
758 * @param flowInfo current FlowInfo object
759 * @param fBuilder Builder for FlowInfo
760 * @param sBuilder Builder for StatsInfo
761 * @return Merged FlowInfo object
762 */
763 private FlowInfo mergeFlowInfo(FlowInfo flowInfo,
764 FlowInfo.Builder fBuilder,
765 StatsInfo.Builder sBuilder) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900766 for (FlowInfo gFlowInfo : gFlowInfoSet) {
767 log.debug("Old FlowInfo:\n{}", gFlowInfo.toString());
768 if (gFlowInfo.roughEquals(flowInfo)) {
769
770 // Get old StatsInfo object and merge the value to current object.
771 StatsInfo oldStatsInfo = gFlowInfo.statsInfo();
772 sBuilder.withPrevAccPkts(oldStatsInfo.currAccPkts());
773 sBuilder.withPrevAccBytes(oldStatsInfo.currAccBytes());
774 FlowInfo newFlowInfo = fBuilder.withStatsInfo(sBuilder.build())
775 .build();
776
777 gFlowInfoSet.remove(gFlowInfo);
778 gFlowInfoSet.add(newFlowInfo);
Jian Li85573f42018-06-27 22:29:14 +0900779 log.debug("Old FlowInfo found, Merge this {}", newFlowInfo.toString());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900780 return newFlowInfo;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900781 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900782 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900783
784 // No such record, then build the FlowInfo object and return this object.
Jian Li85573f42018-06-27 22:29:14 +0900785 log.debug("No FlowInfo found, add new FlowInfo {}", flowInfo.toString());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900786 FlowInfo newFlowInfo = fBuilder.withStatsInfo(sBuilder.build()).build();
787 gFlowInfoSet.add(newFlowInfo);
788 return newFlowInfo;
789 }
790
Jian Li753280e2018-07-03 02:24:34 +0900791 /**
792 * Installs flow rules for collecting both normal and reverse path flow stats.
793 *
794 * @param statsFlowRule flow rule used for collecting stats
795 * @param install flow rule installation flag
796 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900797 private void setStatFlowRule(StatsFlowRule statsFlowRule, boolean install) {
Jian Li753280e2018-07-03 02:24:34 +0900798 setStatFlowRuleBase(statsFlowRule, install);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900799
Jian Li753280e2018-07-03 02:24:34 +0900800 // if reverse path stats is enabled, we will install flow rules for
801 // collecting reverse path vFlow stats
802 if (reversePathStats) {
803 StatsFlowRule reverseFlowRule = DefaultStatsFlowRule.builder()
804 .srcIpPrefix(statsFlowRule.dstIpPrefix())
805 .dstIpPrefix(statsFlowRule.srcIpPrefix())
806 .ipProtocol(statsFlowRule.ipProtocol())
807 .srcTpPort(statsFlowRule.dstTpPort())
808 .dstTpPort(statsFlowRule.srcTpPort())
809 .build();
810 setStatFlowRuleBase(reverseFlowRule, install);
811 }
812 }
813
814 /**
815 * A base method which is for installing flow rules for collecting stats.
816 *
817 * @param statsFlowRule flow rule used for collecting stats
818 * @param install flow rule installation flag
819 */
820 private void setStatFlowRuleBase(StatsFlowRule statsFlowRule, boolean install) {
Jian Lie6110b72018-07-06 19:06:36 +0900821
822 IpPrefix srcIp = statsFlowRule.srcIpPrefix();
823 IpPrefix dstIp = statsFlowRule.dstIpPrefix();
824 DeviceId srcDeviceId = getDeviceId(srcIp.address());
825 DeviceId dstDeviceId = getDeviceId(dstIp.address());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900826
Jian Li998ec7b2018-06-29 15:15:49 +0900827 if (srcDeviceId == null && dstDeviceId == null) {
Jian Li85573f42018-06-27 22:29:14 +0900828 return;
829 }
830
Jian Li998ec7b2018-06-29 15:15:49 +0900831 if (srcDeviceId != null) {
Jian Li87ded822018-07-02 18:31:22 +0900832 connectTables(srcDeviceId, STAT_INBOUND_TABLE, VTAP_INBOUND_TABLE,
Jian Li998ec7b2018-06-29 15:15:49 +0900833 statsFlowRule, METRIC_PRIORITY_SOURCE, install);
Jian Li998ec7b2018-06-29 15:15:49 +0900834
Jian Lie6110b72018-07-06 19:06:36 +0900835 if (install) {
836 log.info("Install ingress stat flow rule for SrcIp:{} DstIp:{}",
837 srcIp.toString(), dstIp.toString());
838 } else {
839 log.info("Remove ingress stat flow rule for SrcIp:{} DstIp:{}",
840 srcIp.toString(), dstIp.toString());
Jian Li753280e2018-07-03 02:24:34 +0900841 }
Jian Li998ec7b2018-06-29 15:15:49 +0900842 }
Jian Li85573f42018-06-27 22:29:14 +0900843
Jian Lie6110b72018-07-06 19:06:36 +0900844 Set<IpPrefix> vxlanIps = osNetworkService.getFixedIpsByNetworkType(VXLAN);
845 Set<IpPrefix> vlanIps = osNetworkService.getFixedIpsByNetworkType(VLAN);
846 Set<IpPrefix> flatIps = osNetworkService.getFixedIpsByNetworkType(FLAT);
Jian Li753280e2018-07-03 02:24:34 +0900847
Jian Lie6110b72018-07-06 19:06:36 +0900848 int fromTable, toTable;
Jian Li753280e2018-07-03 02:24:34 +0900849
Jian Lie6110b72018-07-06 19:06:36 +0900850 if (dstDeviceId != null && egressStats) {
851
852 IpPrefix dstIpPrefix = statsFlowRule.dstIpPrefix();
853
854 if (vxlanIps.contains(dstIpPrefix) || vlanIps.contains(dstIpPrefix)) {
855 fromTable = STAT_OUTBOUND_TABLE;
856 toTable = VTAP_OUTBOUND_TABLE;
857 } else if (flatIps.contains(dstIpPrefix)) {
858 fromTable = STAT_FLAT_OUTBOUND_TABLE;
859 toTable = VTAP_FLAT_OUTBOUND_TABLE;
860 } else {
861 return;
862 }
863
864 connectTables(dstDeviceId, fromTable, toTable,
865 statsFlowRule, METRIC_PRIORITY_TARGET, install);
866
867 if (install) {
868 log.info("Install egress stat flow rule for SrcIp:{} DstIp:{}",
869 srcIp.toString(), dstIp.toString());
870 } else {
871 log.info("Remove egress stat flow rule for SrcIp:{} DstIp:{}",
872 srcIp.toString(), dstIp.toString());
873 }
Jian Li753280e2018-07-03 02:24:34 +0900874 }
Jian Li753280e2018-07-03 02:24:34 +0900875 }
876
877 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900878 * Gets Device ID which the VM is located.
Jian Li85573f42018-06-27 22:29:14 +0900879 *
880 * @param ipAddress IP Address of host
881 * @return Device ID
882 */
883 private DeviceId getDeviceId(IpAddress ipAddress) {
884 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
885 Optional<Host> host = hostService.getHostsByIp(ipAddress).stream().findAny();
886 return host.map(host1 -> host1.location().deviceId()).orElse(null);
887 } else {
Jian Lia4947682018-07-07 14:53:32 +0900888 log.debug("No DeviceID is associated to {}", ipAddress.toString());
Jian Li85573f42018-06-27 22:29:14 +0900889 return null;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900890 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900891 }
892
893 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900894 * Gets VLAN ID with respect to IP Address.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900895 *
896 * @param ipAddress IP Address of host
897 * @return VLAN ID
898 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900899 private VlanId getVlanId(IpAddress ipAddress) {
900 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
901 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
902 return host.vlan();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900903 }
904 return VlanId.vlanId();
905 }
906
907 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900908 * Gets Interface ID of Switch which is connected to a host.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900909 *
910 * @param ipAddress IP Address of host
911 * @return Interface ID of Switch
912 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900913 private int getInterfaceId(IpAddress ipAddress) {
914 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
915 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
916 return (int) host.location().port().toLong();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900917 }
918 return -1;
919 }
920
921 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900922 * Gets MAC Address of host.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900923 *
924 * @param ipAddress IP Address of host
925 * @return MAC Address of host
926 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900927 private MacAddress getMacAddress(IpAddress ipAddress) {
928 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
929 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
930 return host.mac();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900931 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900932
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900933 return NO_HOST_MAC;
934 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900935
Jian Lif8b8c7f2018-08-27 18:49:04 +0900936 /**
937 * Gets IP address of the host which is attached to the given device and port.
938 *
939 * @param device device
940 * @param inPort IN port number
941 * @return IP address
942 */
943 private IpAddress getIpAddress(Device device, PortCriterion inPort) {
944
945 Host host = hostService.getConnectedHosts(device.id()).stream()
946 .filter(h -> h.location().port().equals(inPort.port()))
947 .findAny().orElse(null);
948
949 if (host != null) {
950 return host.ipAddresses().stream().findAny().get();
951 }
952
953 return NO_HOST_IP;
954 }
955
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900956 private void enqFlowInfo(FlowInfo flowInfo) {
957 String key = flowInfo.uniqueFlowInfoKey();
958 Queue<FlowInfo> queue = flowInfoMap.get(key);
959 if (queue == null) {
960 Queue<FlowInfo> newQueue = new LinkedList<FlowInfo>();
961 newQueue.offer(flowInfo);
962 flowInfoMap.put(key, newQueue);
963 return;
964 }
965 queue.offer(flowInfo);
966
967 while (queue.size() > DEFAULT_DATA_POINT_SIZE) {
968 queue.remove(); // Removes a garbage data in the queue.
969 }
970 }
971
Jian Lif8b8c7f2018-08-27 18:49:04 +0900972 /**
973 * Checks whether the given device is edge switch or not.
974 *
975 * @param id device identifier
976 * @return true if the given device is edge switch, false otherwise
977 */
978 private boolean isEdgeSwitch(DeviceId id) {
979
980 return !hostService.getConnectedHosts(id).isEmpty();
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900981 }
982
Jian Li753280e2018-07-03 02:24:34 +0900983 /**
984 * Extracts properties from the component configuration context.
985 *
986 * @param context the component context
987 */
988 private void readComponentConfiguration(ComponentContext context) {
989 Dictionary<?, ?> properties = context.getProperties();
990
991 Boolean reversePathStatsConfigured =
992 getBooleanProperty(properties, REVERSE_PATH_STATS);
993 if (reversePathStatsConfigured == null) {
994 reversePathStats = DEFAULT_REVERSE_PATH_STATS;
995 log.info("Reversed path stats flag is NOT " +
996 "configured, default value is {}", reversePathStats);
997 } else {
998 reversePathStats = reversePathStatsConfigured;
999 log.info("Configured. Reversed path stats flag is {}", reversePathStats);
1000 }
1001
1002 Boolean egressStatsConfigured = getBooleanProperty(properties, EGRESS_STATS);
1003 if (egressStatsConfigured == null) {
1004 egressStats = DEFAULT_EGRESS_STATS;
1005 log.info("Egress stats flag is NOT " +
1006 "configured, default value is {}", egressStats);
1007 } else {
1008 egressStats = egressStatsConfigured;
1009 log.info("Configured. Egress stats flag is {}", egressStats);
1010 }
Jian Lia4947682018-07-07 14:53:32 +09001011
1012 Boolean portStatsConfigured = getBooleanProperty(properties, PORT_STATS);
1013 if (portStatsConfigured == null) {
1014 portStats = DEFAULT_PORT_STATS;
1015 log.info("Port stats flag is NOT " +
1016 "configured, default value is {}", portStats);
1017 } else {
1018 portStats = portStatsConfigured;
1019 log.info("Configured. Port stats flag is {}", portStats);
1020 }
Jian Lif8b8c7f2018-08-27 18:49:04 +09001021
1022 Boolean monitorOverlayConfigured = getBooleanProperty(properties, MONITOR_OVERLAY);
1023 if (monitorOverlayConfigured == null) {
1024 monitorOverlay = DEFAULT_MONITOR_OVERLAY;
1025 log.info("Monitor overlay flag is NOT " +
1026 "configured, default value is {}", monitorOverlay);
1027 } else {
1028 monitorOverlay = monitorOverlayConfigured;
1029 log.info("Configured. Monitor overlay flag is {}", monitorOverlay);
1030 }
1031
1032 Boolean monitorUnderlayConfigured = getBooleanProperty(properties, MONITOR_UNDERLAY);
1033 if (monitorUnderlayConfigured == null) {
1034 monitorUnderlay = DEFAULT_MONITOR_UNDERLAY;
1035 log.info("Monitor underlay flag is NOT " +
1036 "configured, default value is {}", monitorUnderlay);
1037 } else {
1038 monitorUnderlay = monitorUnderlayConfigured;
1039 log.info("Configured. Monitor underlay flag is {}", monitorUnderlay);
1040 }
Jian Li753280e2018-07-03 02:24:34 +09001041 }
1042
Jian Lia4947682018-07-07 14:53:32 +09001043 private class TelemetryCollector implements Runnable {
Jian Li0bbbb1c2018-06-22 22:01:17 +09001044 @Override
1045 public void run() {
Jian Lif8b8c7f2018-08-27 18:49:04 +09001046 Set<FlowInfo> filteredOverlayFlowInfos = Sets.newConcurrentHashSet();
1047 Set<FlowInfo> filteredUnderlayFlowInfos = Sets.newConcurrentHashSet();
Jian Li85573f42018-06-27 22:29:14 +09001048
1049 // we only let the master controller of the device where the
Jian Lia4947682018-07-07 14:53:32 +09001050 // stats flow rules are installed send stats message
Jian Lif8b8c7f2018-08-27 18:49:04 +09001051 if (monitorOverlay) {
1052 getOverlayFlowInfos().forEach(f -> {
Jian Lia4947682018-07-07 14:53:32 +09001053 if (checkSrcDstLocalMaster(f)) {
Jian Lif8b8c7f2018-08-27 18:49:04 +09001054 filteredOverlayFlowInfos.add(f);
1055 }
1056 });
1057 }
1058 if (monitorUnderlay) {
1059 getUnderlayFlowInfos().forEach(f -> {
1060 if (checkSrcDstLocalMaster(f)) {
1061 filteredUnderlayFlowInfos.add(f);
Jian Lia4947682018-07-07 14:53:32 +09001062 }
1063 });
Jian Li0bbbb1c2018-06-22 22:01:17 +09001064 }
Jian Lia4947682018-07-07 14:53:32 +09001065
Jian Lif8b8c7f2018-08-27 18:49:04 +09001066 // we only let the master controller of the device where the port
1067 // is located to send stats message
1068 if (portStats) {
1069 if (monitorOverlay) {
1070 getOverlayDstPortBasedFlowInfos().forEach(f -> {
1071 if (checkSrcDstLocalMaster(f)) {
1072 filteredOverlayFlowInfos.add(f);
1073 }
1074 });
1075 }
Boyoung Jeong1cca5e82018-08-01 21:00:08 +09001076
Jian Lif8b8c7f2018-08-27 18:49:04 +09001077 if (monitorUnderlay) {
1078 getUnderlayDstPortBasedFlowInfos().forEach(f -> {
1079 if (checkSrcDstLocalMaster(f)) {
1080 filteredUnderlayFlowInfos.add(f);
1081 }
1082 });
1083 }
1084 }
1085
1086
1087 if (monitorOverlay) {
1088 telemetryService.publish(filteredOverlayFlowInfos);
1089
1090 // TODO: Refactor the following code to "TelemetryService" style.
1091 filteredOverlayFlowInfos.forEach(StatsFlowRuleManager.this::enqFlowInfo);
1092 }
1093
1094 if (monitorUnderlay) {
1095 telemetryService.publish(filteredUnderlayFlowInfos);
1096 }
Jian Lia4947682018-07-07 14:53:32 +09001097 }
1098
1099 private boolean checkSrcDstLocalMaster(FlowInfo info) {
1100 DeviceId srcDeviceId = getDeviceId(info.srcIp().address());
1101 DeviceId dstDeviceId = getDeviceId(info.dstIp().address());
1102
1103 boolean isSrcLocalMaster = srcDeviceId != null &&
1104 mastershipService.isLocalMaster(srcDeviceId);
1105 boolean isDstLocalMaster = dstDeviceId != null &&
1106 mastershipService.isLocalMaster(dstDeviceId);
1107
1108 return isSrcLocalMaster || isDstLocalMaster;
Jian Li0bbbb1c2018-06-22 22:01:17 +09001109 }
1110 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +09001111}