blob: 3d9f577e84192c3ca31159b57496a42446a77d7b [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.onlab.packet.IpAddress;
Jian Li753280e2018-07-03 02:24:34 +090021import org.onlab.packet.IpPrefix;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090022import org.onlab.packet.MacAddress;
23import org.onlab.packet.VlanId;
Jian Lia4947682018-07-07 14:53:32 +090024import org.onlab.util.SharedScheduledExecutors;
Jian Lie6110b72018-07-06 19:06:36 +090025import org.onosproject.cfg.ComponentConfigService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090026import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
Jian Li85573f42018-06-27 22:29:14 +090028import org.onosproject.mastership.MastershipService;
Jian Lif8b8c7f2018-08-27 18:49:04 +090029import org.onosproject.net.ConnectPoint;
30import org.onosproject.net.Device;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090031import org.onosproject.net.DeviceId;
32import org.onosproject.net.Host;
Jian Lia4947682018-07-07 14:53:32 +090033import org.onosproject.net.PortNumber;
34import org.onosproject.net.device.DeviceService;
35import org.onosproject.net.device.PortStatistics;
Jian Lif8b8c7f2018-08-27 18:49:04 +090036import org.onosproject.net.driver.Driver;
37import org.onosproject.net.driver.DriverService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090038import org.onosproject.net.flow.DefaultFlowRule;
39import org.onosproject.net.flow.DefaultTrafficSelector;
40import org.onosproject.net.flow.DefaultTrafficTreatment;
41import org.onosproject.net.flow.FlowEntry;
42import org.onosproject.net.flow.FlowRule;
43import org.onosproject.net.flow.FlowRuleOperations;
44import org.onosproject.net.flow.FlowRuleOperationsContext;
45import org.onosproject.net.flow.FlowRuleService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090046import org.onosproject.net.flow.TrafficSelector;
47import org.onosproject.net.flow.TrafficTreatment;
Jian Lif8b8c7f2018-08-27 18:49:04 +090048import org.onosproject.net.flow.criteria.Criterion;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090049import org.onosproject.net.flow.criteria.IPCriterion;
50import org.onosproject.net.flow.criteria.IPProtocolCriterion;
Jian Lif8b8c7f2018-08-27 18:49:04 +090051import org.onosproject.net.flow.criteria.PortCriterion;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090052import org.onosproject.net.flow.criteria.TcpPortCriterion;
53import org.onosproject.net.flow.criteria.UdpPortCriterion;
54import org.onosproject.net.host.HostService;
Jian Lia4947682018-07-07 14:53:32 +090055import org.onosproject.openstacknetworking.api.InstancePort;
56import org.onosproject.openstacknetworking.api.InstancePortService;
Jian Li753280e2018-07-03 02:24:34 +090057import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lia4947682018-07-07 14:53:32 +090058import org.onosproject.openstacknode.api.OpenstackNode;
59import org.onosproject.openstacknode.api.OpenstackNodeService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090060import org.onosproject.openstacktelemetry.api.FlowInfo;
Jian Li0bbbb1c2018-06-22 22:01:17 +090061import org.onosproject.openstacktelemetry.api.OpenstackTelemetryService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090062import org.onosproject.openstacktelemetry.api.StatsFlowRule;
63import org.onosproject.openstacktelemetry.api.StatsFlowRuleAdminService;
64import org.onosproject.openstacktelemetry.api.StatsInfo;
Jian Li753280e2018-07-03 02:24:34 +090065import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070066import org.osgi.service.component.annotations.Activate;
67import org.osgi.service.component.annotations.Component;
68import org.osgi.service.component.annotations.Deactivate;
69import org.osgi.service.component.annotations.Modified;
70import org.osgi.service.component.annotations.Reference;
71import org.osgi.service.component.annotations.ReferenceCardinality;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090072import org.slf4j.Logger;
73import org.slf4j.LoggerFactory;
74
Jian Lif8b8c7f2018-08-27 18:49:04 +090075import java.util.ArrayList;
Jian Li753280e2018-07-03 02:24:34 +090076import java.util.Dictionary;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090077import java.util.LinkedList;
Jian Lia4947682018-07-07 14:53:32 +090078import java.util.List;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090079import java.util.Map;
Jian Li85573f42018-06-27 22:29:14 +090080import java.util.Optional;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090081import java.util.Queue;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090082import java.util.Set;
Jian Lia4947682018-07-07 14:53:32 +090083import java.util.concurrent.ScheduledFuture;
84import java.util.concurrent.TimeUnit;
85import java.util.stream.Collectors;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090086
Jian Li0bbbb1c2018-06-22 22:01:17 +090087import static org.onlab.packet.Ethernet.TYPE_IPV4;
88import static org.onlab.packet.IPv4.PROTOCOL_TCP;
89import static org.onlab.packet.IPv4.PROTOCOL_UDP;
Jian Lif8b8c7f2018-08-27 18:49:04 +090090import static org.onosproject.net.Device.Type.SWITCH;
Jian Li0bbbb1c2018-06-22 22:01:17 +090091import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
92import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC;
93import static org.onosproject.net.flow.criteria.Criterion.Type.IP_PROTO;
94import static org.onosproject.net.flow.criteria.Criterion.Type.TCP_DST;
95import static org.onosproject.net.flow.criteria.Criterion.Type.TCP_SRC;
96import static org.onosproject.net.flow.criteria.Criterion.Type.UDP_DST;
97import static org.onosproject.net.flow.criteria.Criterion.Type.UDP_SRC;
Jian Li753280e2018-07-03 02:24:34 +090098import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
Jian Li0bbbb1c2018-06-22 22:01:17 +090099import static org.onosproject.openstacknetworking.api.Constants.STAT_INBOUND_TABLE;
100import static org.onosproject.openstacknetworking.api.Constants.STAT_OUTBOUND_TABLE;
Jian Li753280e2018-07-03 02:24:34 +0900101import static org.onosproject.openstacknetworking.api.Constants.VTAP_FLAT_OUTBOUND_TABLE;
Jian Li87ded822018-07-02 18:31:22 +0900102import static org.onosproject.openstacknetworking.api.Constants.VTAP_INBOUND_TABLE;
103import static org.onosproject.openstacknetworking.api.Constants.VTAP_OUTBOUND_TABLE;
Jian Lia4947682018-07-07 14:53:32 +0900104import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Jian Lif8b8c7f2018-08-27 18:49:04 +0900105import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900106import static org.onosproject.openstacktelemetry.api.Constants.DEFAULT_DATA_POINT_SIZE;
Jian Lie6110b72018-07-06 19:06:36 +0900107import static org.onosproject.openstacktelemetry.api.Constants.FLAT;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900108import static org.onosproject.openstacktelemetry.api.Constants.OPENSTACK_TELEMETRY_APP_ID;
Jian Lie6110b72018-07-06 19:06:36 +0900109import static org.onosproject.openstacktelemetry.api.Constants.VLAN;
110import static org.onosproject.openstacktelemetry.api.Constants.VXLAN;
Ray Milkey8e406512018-10-24 15:56:50 -0700111import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_EGRESS_STATS;
112import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_EGRESS_STATS_DEFAULT;
113import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_MONITOR_OVERLAY;
114import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_MONITOR_OVERLAY_DEFAULT;
115import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_MONITOR_UNDERLAY;
116import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_MONITOR_UNDERLAY_DEFAULT;
117import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_PORT_STATS;
118import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_PORT_STATS_DEFAULT;
119import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_REVERSE_PATH_STATS;
120import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_REVERSE_PATH_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900121import static org.onosproject.openstacktelemetry.util.OpenstackTelemetryUtil.getBooleanProperty;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900122
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900123/**
124 * Flow rule manager for network statistics of a VM.
125 */
Ray Milkey8e406512018-10-24 15:56:50 -0700126@Component(
127 immediate = true,
128 service = StatsFlowRuleAdminService.class,
129 property = {
130 PROP_REVERSE_PATH_STATS + ":Boolean=" + PROP_REVERSE_PATH_STATS_DEFAULT,
131 PROP_EGRESS_STATS + ":Boolean=" + PROP_EGRESS_STATS_DEFAULT,
132 PROP_PORT_STATS + ":Boolean=" + PROP_PORT_STATS_DEFAULT,
133 PROP_MONITOR_OVERLAY + ":Boolean=" + PROP_MONITOR_OVERLAY_DEFAULT,
134 PROP_MONITOR_UNDERLAY + ":Boolean=" + PROP_MONITOR_UNDERLAY_DEFAULT
135 }
136)
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900137public class StatsFlowRuleManager implements StatsFlowRuleAdminService {
138
139 private final Logger log = LoggerFactory.getLogger(getClass());
140
boyoung2a8549d22018-11-23 20:42:37 +0900141 private static final byte FLOW_TYPE_SONA = 1;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900142
Ray Milkeybcc53d32018-07-02 10:22:57 -0700143 private static final long MILLISECONDS = 1000L;
Jian Lia4947682018-07-07 14:53:32 +0900144 private static final long INITIAL_DELAY = 5L;
Ray Milkeybcc53d32018-07-02 10:22:57 -0700145 private static final long REFRESH_INTERVAL = 5L;
Jian Lia4947682018-07-07 14:53:32 +0900146 private static final TimeUnit TIME_UNIT_SECOND = TimeUnit.SECONDS;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900147
Jian Lif8b8c7f2018-08-27 18:49:04 +0900148 private static final String OVS_DRIVER_NAME = "ovs";
149
Jian Lia4947682018-07-07 14:53:32 +0900150 private static final String ARBITRARY_IP = "0.0.0.0/32";
151 private static final int ARBITRARY_LENGTH = 32;
152 private static final String ARBITRARY_MAC = "00:00:00:00:00:00";
Jian Lif8b8c7f2018-08-27 18:49:04 +0900153 private static final IpAddress NO_HOST_IP = IpAddress.valueOf("255.255.255.255");
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900154 private static final MacAddress NO_HOST_MAC = MacAddress.valueOf(ARBITRARY_MAC);
Jian Lia4947682018-07-07 14:53:32 +0900155 private static final int ARBITRARY_IN_INTF = 0;
156 private static final int ARBITRARY_OUT_INTF = 0;
157
158 private static final boolean RECOVER_FROM_FAILURE = true;
159
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700160 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900161 protected CoreService coreService;
162
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700163 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900164 protected FlowRuleService flowRuleService;
165
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700166 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900167 protected HostService hostService;
168
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700169 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia4947682018-07-07 14:53:32 +0900170 protected DeviceService deviceService;
171
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700172 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900173 protected DriverService driverService;
174
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700175 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lie6110b72018-07-06 19:06:36 +0900176 protected ComponentConfigService componentConfigService;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900177
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700178 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li85573f42018-06-27 22:29:14 +0900179 protected MastershipService mastershipService;
180
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700181 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li753280e2018-07-03 02:24:34 +0900182 protected OpenstackNetworkService osNetworkService;
183
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700184 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia4947682018-07-07 14:53:32 +0900185 protected InstancePortService instPortService;
186
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700187 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia4947682018-07-07 14:53:32 +0900188 protected OpenstackNodeService osNodeService;
189
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700190 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li0bbbb1c2018-06-22 22:01:17 +0900191 protected OpenstackTelemetryService telemetryService;
192
Ray Milkey8e406512018-10-24 15:56:50 -0700193 /** A flag which indicates whether to install the rules for collecting the flow-based stats for reversed path. */
194 private boolean reversePathStats = PROP_REVERSE_PATH_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900195
Ray Milkey8e406512018-10-24 15:56:50 -0700196 /** A flag which indicates whether to install the rules for collecting the flow-based stats for egress port. */
197 private boolean egressStats = PROP_EGRESS_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900198
Ray Milkey8e406512018-10-24 15:56:50 -0700199 /** A flag which indicates whether to collect port TX & RX stats. */
200 private boolean portStats = PROP_PORT_STATS_DEFAULT;
Jian Lia4947682018-07-07 14:53:32 +0900201
Ray Milkey8e406512018-10-24 15:56:50 -0700202 /** A flag which indicates whether to monitor overlay network port stats. */
203 private boolean monitorOverlay = PROP_MONITOR_OVERLAY_DEFAULT;
Jian Lif8b8c7f2018-08-27 18:49:04 +0900204
Ray Milkey8e406512018-10-24 15:56:50 -0700205 /** A flag which indicates whether to monitor underlay network port stats. */
206 private boolean monitorUnderlay = PROP_MONITOR_UNDERLAY_DEFAULT;
Jian Lif8b8c7f2018-08-27 18:49:04 +0900207
208 private ApplicationId telemetryAppId;
Jian Lia4947682018-07-07 14:53:32 +0900209 private TelemetryCollector collector;
Jian Lia4947682018-07-07 14:53:32 +0900210 private ScheduledFuture result;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900211
Jian Li0bbbb1c2018-06-22 22:01:17 +0900212 private final Set<FlowInfo> gFlowInfoSet = Sets.newHashSet();
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900213 private final Map<String, Queue<FlowInfo>> flowInfoMap = Maps.newConcurrentMap();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900214
215 private static final int SOURCE_ID = 1;
216 private static final int TARGET_ID = 2;
217 private static final int PRIORITY_BASE = 10000;
218 private static final int METRIC_PRIORITY_SOURCE = SOURCE_ID * PRIORITY_BASE;
219 private static final int METRIC_PRIORITY_TARGET = TARGET_ID * PRIORITY_BASE;
220
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900221 @Activate
222 protected void activate() {
Jian Lif8b8c7f2018-08-27 18:49:04 +0900223 telemetryAppId = coreService.registerApplication(OPENSTACK_TELEMETRY_APP_ID);
224
Jian Lie6110b72018-07-06 19:06:36 +0900225 componentConfigService.registerProperties(getClass());
Jian Libd295cd2018-07-22 11:53:57 +0900226 start();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900227
228 log.info("Started");
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900229 }
230
231 @Deactivate
232 protected void deactivate() {
Jian Lie6110b72018-07-06 19:06:36 +0900233 componentConfigService.unregisterProperties(getClass(), false);
Jian Lif8b8c7f2018-08-27 18:49:04 +0900234 flowRuleService.removeFlowRulesById(telemetryAppId);
Jian Libd295cd2018-07-22 11:53:57 +0900235 stop();
Jian Lia4947682018-07-07 14:53:32 +0900236
Jian Li0bbbb1c2018-06-22 22:01:17 +0900237 log.info("Stopped");
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900238 }
239
Jian Li753280e2018-07-03 02:24:34 +0900240 @Modified
241 protected void modified(ComponentContext context) {
242 readComponentConfiguration(context);
243
244 log.info("Modified");
245 }
246
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900247 @Override
248 public void start() {
249 log.info("Start publishing thread");
Jian Lia4947682018-07-07 14:53:32 +0900250 collector = new TelemetryCollector();
251
Jian Libd295cd2018-07-22 11:53:57 +0900252 result = SharedScheduledExecutors.getSingleThreadExecutor()
253 .scheduleAtFixedRate(collector, INITIAL_DELAY,
Jian Lia4947682018-07-07 14:53:32 +0900254 REFRESH_INTERVAL, TIME_UNIT_SECOND, RECOVER_FROM_FAILURE);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900255 }
256
257 @Override
258 public void stop() {
259 log.info("Stop data publishing thread");
Jian Lia4947682018-07-07 14:53:32 +0900260 result.cancel(true);
261 collector = null;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900262 }
263
Jian Li0bbbb1c2018-06-22 22:01:17 +0900264 @Override
boyoung27b444122018-09-01 17:28:13 +0900265 public void createStatFlowRule(StatsFlowRule statsFlowRule) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900266 setStatFlowRule(statsFlowRule, true);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900267 }
268
269 @Override
270 public void deleteStatFlowRule(StatsFlowRule statsFlowRule) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900271 setStatFlowRule(statsFlowRule, false);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900272 }
273
Jian Lif8b8c7f2018-08-27 18:49:04 +0900274
Jian Lia4947682018-07-07 14:53:32 +0900275 @Override
Jian Lif8b8c7f2018-08-27 18:49:04 +0900276 public Map<String, Queue<FlowInfo>> getFlowInfoMap() {
277 return flowInfoMap;
278 }
279
280
281 @Override
282 public Set<FlowInfo> getUnderlayFlowInfos() {
283
284 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
285
286 for (Device device : getUnderlayDevices()) {
287
288 if (!isEdgeSwitch(device.id())) {
289 continue;
290 }
291
292 for (FlowEntry entry : flowRuleService.getFlowEntries(device.id())) {
293 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
294 TrafficSelector selector = entry.selector();
295 Criterion inPort = selector.getCriterion(Criterion.Type.IN_PORT);
296 Criterion dstIpCriterion = selector.getCriterion(Criterion.Type.IPV4_DST);
297 if (inPort != null && dstIpCriterion != null) {
298 IpAddress srcIp = getIpAddress(device, (PortCriterion) inPort);
299 IpAddress dstIp = ((IPCriterion) dstIpCriterion).ip().address();
300
301 if (srcIp == null) {
302 continue;
303 }
304
305 fBuilder.withFlowType(FLOW_TYPE_SONA)
306 .withSrcIp(IpPrefix.valueOf(srcIp, ARBITRARY_LENGTH))
307 .withDstIp(IpPrefix.valueOf(dstIp, ARBITRARY_LENGTH))
308 .withSrcMac(getMacAddress(srcIp))
309 .withDstMac(getMacAddress(dstIp))
310 .withInputInterfaceId(getInterfaceId(srcIp))
311 .withOutputInterfaceId(getInterfaceId(dstIp))
312 .withDeviceId(entry.deviceId());
313
314 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
315
316 sBuilder.withStartupTime(System.currentTimeMillis())
317 .withFstPktArrTime(System.currentTimeMillis())
318 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
319 .withCurrAccPkts((int) entry.packets())
320 .withCurrAccBytes(entry.bytes())
321 .withErrorPkts((short) 0)
322 .withDropPkts((short) 0);
323
324 fBuilder.withStatsInfo(sBuilder.build());
325
326 FlowInfo flowInfo = mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
327
328 flowInfos.add(flowInfo);
329 }
330 }
331 }
332
333 return flowInfos;
334 }
335
336 @Override
337 public Set<FlowInfo> getOverlayFlowInfos() {
338
Jian Lia4947682018-07-07 14:53:32 +0900339 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
340
341 // obtain all flow rule entries installed by telemetry app
Jian Lif8b8c7f2018-08-27 18:49:04 +0900342 for (FlowEntry entry : flowRuleService.getFlowEntriesById(telemetryAppId)) {
Jian Lia4947682018-07-07 14:53:32 +0900343 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
344 TrafficSelector selector = entry.selector();
Jian Lia4947682018-07-07 14:53:32 +0900345 IPCriterion srcIp = (IPCriterion) selector.getCriterion(IPV4_SRC);
346 IPCriterion dstIp = (IPCriterion) selector.getCriterion(IPV4_DST);
347 IPProtocolCriterion ipProtocol =
348 (IPProtocolCriterion) selector.getCriterion(IP_PROTO);
349
Jian Lia4947682018-07-07 14:53:32 +0900350 fBuilder.withFlowType(FLOW_TYPE_SONA)
351 .withSrcIp(srcIp.ip())
352 .withDstIp(dstIp.ip());
353
354 if (ipProtocol != null) {
355 fBuilder.withProtocol((byte) ipProtocol.protocol());
356
357 if (ipProtocol.protocol() == PROTOCOL_TCP) {
358 TcpPortCriterion tcpSrc =
359 (TcpPortCriterion) selector.getCriterion(TCP_SRC);
360 TcpPortCriterion tcpDst =
361 (TcpPortCriterion) selector.getCriterion(TCP_DST);
Jian Lia4947682018-07-07 14:53:32 +0900362 fBuilder.withSrcPort(tcpSrc.tcpPort());
363 fBuilder.withDstPort(tcpDst.tcpPort());
Jian Lia4947682018-07-07 14:53:32 +0900364 } else if (ipProtocol.protocol() == PROTOCOL_UDP) {
Jian Lia4947682018-07-07 14:53:32 +0900365 UdpPortCriterion udpSrc =
366 (UdpPortCriterion) selector.getCriterion(UDP_SRC);
367 UdpPortCriterion udpDst =
368 (UdpPortCriterion) selector.getCriterion(UDP_DST);
Jian Lia4947682018-07-07 14:53:32 +0900369 fBuilder.withSrcPort(udpSrc.udpPort());
370 fBuilder.withDstPort(udpDst.udpPort());
371 } else {
372 log.debug("Other protocol: {}", ipProtocol.protocol());
373 }
374 }
375
376 fBuilder.withSrcMac(getMacAddress(srcIp.ip().address()))
377 .withDstMac(getMacAddress(dstIp.ip().address()))
378 .withInputInterfaceId(getInterfaceId(srcIp.ip().address()))
379 .withOutputInterfaceId(getInterfaceId(dstIp.ip().address()))
380 .withVlanId(getVlanId(srcIp.ip().address()))
381 .withDeviceId(entry.deviceId());
382
383 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
384
Jian Lia4947682018-07-07 14:53:32 +0900385 sBuilder.withStartupTime(System.currentTimeMillis())
386 .withFstPktArrTime(System.currentTimeMillis())
387 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
388 .withCurrAccPkts((int) entry.packets())
389 .withCurrAccBytes(entry.bytes())
390 .withErrorPkts((short) 0)
391 .withDropPkts((short) 0);
392
393 fBuilder.withStatsInfo(sBuilder.build());
394
395 FlowInfo flowInfo = mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
396
397 flowInfos.add(flowInfo);
398
399 log.debug("FlowInfo: \n{}", flowInfo.toString());
400 }
401
402 return flowInfos;
403 }
404
405 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900406 * Gets a set of flow infos by referring to overlay destination VM port.
Jian Lia4947682018-07-07 14:53:32 +0900407 *
408 * @return flow infos
409 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900410 private Set<FlowInfo> getOverlayDstPortBasedFlowInfos() {
Jian Lia4947682018-07-07 14:53:32 +0900411 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
412 Set<PortNumber> instPortNums = instPortService.instancePorts()
413 .stream()
414 .map(InstancePort::portNumber)
415 .collect(Collectors.toSet());
416 Set<DeviceId> deviceIds = osNodeService.completeNodes(COMPUTE)
417 .stream()
418 .map(OpenstackNode::intgBridge)
419 .collect(Collectors.toSet());
420
421 deviceIds.forEach(d -> {
422 List<PortStatistics> stats =
423 deviceService.getPortStatistics(d)
424 .stream()
425 .filter(s -> instPortNums.contains(s.portNumber()))
426 .collect(Collectors.toList());
427
428 stats.forEach(s -> {
429 InstancePort instPort = getInstancePort(d, s.portNumber());
boyoung2a8549d22018-11-23 20:42:37 +0900430 if (instPort != null) {
431 flowInfos.add(buildTxFlowInfoFromInstancePort(instPort, s));
432 flowInfos.add(buildRxFlowInfoFromInstancePort(instPort, s));
433 }
Jian Lia4947682018-07-07 14:53:32 +0900434 });
435 });
436
437 return flowInfos;
438 }
439
440 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900441 * Gets a set of flow infos by referring to underlay destination port.
442 *
443 * @return flow infos
444 */
445 private Set<FlowInfo> getUnderlayDstPortBasedFlowInfos() {
446 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
447
448 for (Device d : getUnderlayDevices()) {
449 List<PortStatistics> stats =
450 new ArrayList<>(deviceService.getPortStatistics(d.id()));
451 stats.forEach(s -> {
452 Host host = hostService.getConnectedHosts(new ConnectPoint(d.id(), s.portNumber()))
453 .stream().findFirst().orElse(null);
454 if (host != null) {
455 flowInfos.add(buildTxFlowInfoFromHost(host, s));
456 flowInfos.add(buildRxFlowInfoFromHost(host, s));
457 }
458 });
459 }
460
461 return flowInfos;
462 }
463
464 /**
465 * Obtains a set of device instances which construct underlay network.
466 *
467 * @return a set of device instances
468 */
469 private Set<Device> getUnderlayDevices() {
470
471 Set<Device> underlayDevices = Sets.newConcurrentHashSet();
472
473 Set<DeviceId> overlayDeviceIds = osNodeService.completeNodes()
474 .stream()
475 .filter(n -> n.type() != CONTROLLER)
476 .map(OpenstackNode::intgBridge)
477 .collect(Collectors.toSet());
478
479 for (Device d : deviceService.getAvailableDevices(SWITCH)) {
480 if (overlayDeviceIds.contains(d.id())) {
481 continue;
482 }
483
484 underlayDevices.add(d);
485 }
486
487 return underlayDevices;
488 }
489
490 /**
491 * Checks whether the given drivers contains OVS driver.
492 *
493 * @param drivers a set of drivers
494 * @return true if the given drivers contain any OVS driver, false otherwise
495 */
496 private boolean hasOvsDriver(List<Driver> drivers) {
497
498 for (Driver driver : drivers) {
499 if (OVS_DRIVER_NAME.equals(driver.name())) {
500 return true;
501 }
502 }
503
504 return false;
505 }
506
507 /**
508 * Obtains the flow info generated by TX port from instance port.
Jian Lia4947682018-07-07 14:53:32 +0900509 *
510 * @param instPort instance port
511 * @param stat port statistics
512 * @return flow info
513 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900514 private FlowInfo buildTxFlowInfoFromInstancePort(InstancePort instPort,
515 PortStatistics stat) {
516 return buildTxFlowInfo(instPort.ipAddress(), instPort.macAddress(),
517 instPort.deviceId(), stat);
518 }
519
520 /**
521 * Obtains the flow info generated from RX port from instance port.
522 *
523 * @param instPort instance port
524 * @param stat port statistics
525 * @return flow info
526 */
527 private FlowInfo buildRxFlowInfoFromInstancePort(InstancePort instPort,
528 PortStatistics stat) {
529 return buildRxFlowInfo(instPort.ipAddress(), instPort.macAddress(),
530 instPort.deviceId(), stat);
531 }
532
533 /**
534 * Obtains the flow info generated by TX port from host.
535 *
536 * @param host host
537 * @param stat port statistics
538 * @return flow info
539 */
540 private FlowInfo buildTxFlowInfoFromHost(Host host, PortStatistics stat) {
541 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
542
543 if (ip != null) {
544 return buildTxFlowInfo(ip, host.mac(), host.location().deviceId(), stat);
545 }
546 return null;
547 }
548
549 /**
550 * Obtains the flow info generated by RX @param host host.
551 *
552 * @param host host
553 * @param stat port statistics
554 * @return flow info
555 */
556 private FlowInfo buildRxFlowInfoFromHost(Host host, PortStatistics stat) {
557 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
558
559 if (ip != null) {
560 return buildRxFlowInfo(ip, host.mac(), host.location().deviceId(), stat);
561 }
562 return null;
563 }
564
565 /**
566 * Obtains the flow info generated from TX port.
567 *
568 * @param ipAddress IP address
569 * @param macAddress MAC address
570 * @param deviceId device identifier
571 * @param stat port statistics
572 * @return flow info
573 */
574 private FlowInfo buildTxFlowInfo(IpAddress ipAddress,
575 MacAddress macAddress,
576 DeviceId deviceId,
577 PortStatistics stat) {
Jian Lia4947682018-07-07 14:53:32 +0900578 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
579
580 fBuilder.withFlowType(FLOW_TYPE_SONA)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900581 .withSrcIp(IpPrefix.valueOf(ipAddress, ARBITRARY_LENGTH))
Jian Lia4947682018-07-07 14:53:32 +0900582 .withDstIp(IpPrefix.valueOf(ARBITRARY_IP))
Jian Lif8b8c7f2018-08-27 18:49:04 +0900583 .withSrcMac(macAddress)
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900584 .withDstMac(NO_HOST_MAC)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900585 .withDeviceId(deviceId)
Jian Lia4947682018-07-07 14:53:32 +0900586 .withInputInterfaceId(ARBITRARY_IN_INTF)
587 .withOutputInterfaceId(ARBITRARY_OUT_INTF)
588 .withVlanId(VlanId.vlanId());
589
590 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
591 sBuilder.withStartupTime(System.currentTimeMillis())
592 .withFstPktArrTime(System.currentTimeMillis())
593 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
594 .withCurrAccPkts((int) stat.packetsSent())
595 .withCurrAccBytes(stat.bytesSent())
596 .withErrorPkts((short) stat.packetsTxErrors())
597 .withDropPkts((short) stat.packetsTxDropped());
598
599 fBuilder.withStatsInfo(sBuilder.build());
600
601 return mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
602 }
603
604 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900605 * Obtains the flow info generated from RX port.
Jian Lia4947682018-07-07 14:53:32 +0900606 *
Jian Lif8b8c7f2018-08-27 18:49:04 +0900607 * @param ipAddress IP address
608 * @param macAddress MAC address
609 * @param deviceId Device identifier
Jian Lia4947682018-07-07 14:53:32 +0900610 * @param stat port statistics
611 * @return flow info
612 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900613 private FlowInfo buildRxFlowInfo(IpAddress ipAddress,
614 MacAddress macAddress,
615 DeviceId deviceId,
616 PortStatistics stat) {
Jian Lia4947682018-07-07 14:53:32 +0900617 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
618
619 fBuilder.withFlowType(FLOW_TYPE_SONA)
620 .withSrcIp(IpPrefix.valueOf(ARBITRARY_IP))
Jian Lif8b8c7f2018-08-27 18:49:04 +0900621 .withDstIp(IpPrefix.valueOf(ipAddress, ARBITRARY_LENGTH))
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900622 .withSrcMac(NO_HOST_MAC)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900623 .withDstMac(macAddress)
624 .withDeviceId(deviceId)
Jian Lia4947682018-07-07 14:53:32 +0900625 .withInputInterfaceId(ARBITRARY_IN_INTF)
626 .withOutputInterfaceId(ARBITRARY_OUT_INTF)
627 .withVlanId(VlanId.vlanId());
628
629 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
630 sBuilder.withStartupTime(System.currentTimeMillis())
631 .withFstPktArrTime(System.currentTimeMillis())
632 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
633 .withCurrAccPkts((int) stat.packetsReceived())
634 .withCurrAccBytes(stat.bytesReceived())
635 .withErrorPkts((short) stat.packetsRxErrors())
636 .withDropPkts((short) stat.packetsRxDropped());
637
638 fBuilder.withStatsInfo(sBuilder.build());
639
640 return mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
641 }
642
643 /**
644 * Obtains instance port which associated with the given device identifier
645 * and port number.
646 *
647 * @param deviceId device identifier
648 * @param portNumber port number
649 * @return instance port
650 */
651 private InstancePort getInstancePort(DeviceId deviceId, PortNumber portNumber) {
652 return instPortService.instancePorts().stream()
653 .filter(p -> p.deviceId().equals(deviceId))
654 .filter(p -> p.portNumber().equals(portNumber))
655 .findFirst().orElse(null);
656 }
657
Jian Lif8b8c7f2018-08-27 18:49:04 +0900658 /**
659 * Installs a flow rule where the source table is fromTable, while destination
660 * table is toTable.
661 *
662 * @param deviceId device identifier
663 * @param fromTable source table
664 * @param toTable destination table
665 * @param statsFlowRule stats flow rule
666 * @param rulePriority rule priority
667 * @param install installation flag
668 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900669 private void connectTables(DeviceId deviceId, int fromTable, int toTable,
670 StatsFlowRule statsFlowRule, int rulePriority,
671 boolean install) {
672
Jian Li0bbbb1c2018-06-22 22:01:17 +0900673 int srcPrefixLength = statsFlowRule.srcIpPrefix().prefixLength();
674 int dstPrefixLength = statsFlowRule.dstIpPrefix().prefixLength();
675 int prefixLength = rulePriority + srcPrefixLength + dstPrefixLength;
676 byte protocol = statsFlowRule.ipProtocol();
677
678 TrafficSelector.Builder selectorBuilder =
Jian Li753280e2018-07-03 02:24:34 +0900679 DefaultTrafficSelector.builder()
680 .matchEthType(TYPE_IPV4)
681 .matchIPSrc(statsFlowRule.srcIpPrefix())
682 .matchIPDst(statsFlowRule.dstIpPrefix());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900683
684 if (protocol == PROTOCOL_TCP) {
685 selectorBuilder = selectorBuilder
Jian Li753280e2018-07-03 02:24:34 +0900686 .matchIPProtocol(statsFlowRule.ipProtocol())
687 .matchTcpSrc(statsFlowRule.srcTpPort())
688 .matchTcpDst(statsFlowRule.dstTpPort());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900689
690 } else if (protocol == PROTOCOL_UDP) {
691 selectorBuilder = selectorBuilder
Jian Li753280e2018-07-03 02:24:34 +0900692 .matchIPProtocol(statsFlowRule.ipProtocol())
693 .matchUdpSrc(statsFlowRule.srcTpPort())
694 .matchUdpDst(statsFlowRule.dstTpPort());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900695 } else {
696 log.warn("Unsupported protocol {}", statsFlowRule.ipProtocol());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900697 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900698
699 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
700
701 treatmentBuilder.transition(toTable);
702
703 FlowRule flowRule = DefaultFlowRule.builder()
Jian Li753280e2018-07-03 02:24:34 +0900704 .forDevice(deviceId)
705 .withSelector(selectorBuilder.build())
706 .withTreatment(treatmentBuilder.build())
707 .withPriority(prefixLength)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900708 .fromApp(telemetryAppId)
Jian Li753280e2018-07-03 02:24:34 +0900709 .makePermanent()
710 .forTable(fromTable)
711 .build();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900712
713 applyRule(flowRule, install);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900714 }
715
716 /**
Jian Li0bbbb1c2018-06-22 22:01:17 +0900717 * Installs stats related flow rule to switch.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900718 *
Jian Li0bbbb1c2018-06-22 22:01:17 +0900719 * @param flowRule flow rule
720 * @param install flag to install or not
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900721 */
722 private void applyRule(FlowRule flowRule, boolean install) {
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900723 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900724 flowOpsBuilder = install ?
725 flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900726
727 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
728 @Override
729 public void onSuccess(FlowRuleOperations ops) {
Jian Lia4947682018-07-07 14:53:32 +0900730 log.debug("Install rules for telemetry stats: \n {}",
731 ops.toString());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900732 }
733
734 @Override
735 public void onError(FlowRuleOperations ops) {
Jian Lia4947682018-07-07 14:53:32 +0900736 log.debug("Failed to install rules for telemetry stats: \n {}",
737 ops.toString());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900738 }
739 }));
740 }
741
742 /**
Jian Li0bbbb1c2018-06-22 22:01:17 +0900743 * Merges old FlowInfo.StatsInfo and current FlowInfo.StatsInfo.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900744 *
745 * @param flowInfo current FlowInfo object
746 * @param fBuilder Builder for FlowInfo
747 * @param sBuilder Builder for StatsInfo
748 * @return Merged FlowInfo object
749 */
750 private FlowInfo mergeFlowInfo(FlowInfo flowInfo,
751 FlowInfo.Builder fBuilder,
752 StatsInfo.Builder sBuilder) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900753 for (FlowInfo gFlowInfo : gFlowInfoSet) {
754 log.debug("Old FlowInfo:\n{}", gFlowInfo.toString());
755 if (gFlowInfo.roughEquals(flowInfo)) {
756
757 // Get old StatsInfo object and merge the value to current object.
758 StatsInfo oldStatsInfo = gFlowInfo.statsInfo();
759 sBuilder.withPrevAccPkts(oldStatsInfo.currAccPkts());
760 sBuilder.withPrevAccBytes(oldStatsInfo.currAccBytes());
761 FlowInfo newFlowInfo = fBuilder.withStatsInfo(sBuilder.build())
762 .build();
763
764 gFlowInfoSet.remove(gFlowInfo);
765 gFlowInfoSet.add(newFlowInfo);
Jian Li85573f42018-06-27 22:29:14 +0900766 log.debug("Old FlowInfo found, Merge this {}", newFlowInfo.toString());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900767 return newFlowInfo;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900768 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900769 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900770
771 // No such record, then build the FlowInfo object and return this object.
Jian Li85573f42018-06-27 22:29:14 +0900772 log.debug("No FlowInfo found, add new FlowInfo {}", flowInfo.toString());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900773 FlowInfo newFlowInfo = fBuilder.withStatsInfo(sBuilder.build()).build();
774 gFlowInfoSet.add(newFlowInfo);
775 return newFlowInfo;
776 }
777
Jian Li753280e2018-07-03 02:24:34 +0900778 /**
779 * Installs flow rules for collecting both normal and reverse path flow stats.
780 *
781 * @param statsFlowRule flow rule used for collecting stats
782 * @param install flow rule installation flag
783 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900784 private void setStatFlowRule(StatsFlowRule statsFlowRule, boolean install) {
Jian Li753280e2018-07-03 02:24:34 +0900785 setStatFlowRuleBase(statsFlowRule, install);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900786
Jian Li753280e2018-07-03 02:24:34 +0900787 // if reverse path stats is enabled, we will install flow rules for
788 // collecting reverse path vFlow stats
789 if (reversePathStats) {
790 StatsFlowRule reverseFlowRule = DefaultStatsFlowRule.builder()
791 .srcIpPrefix(statsFlowRule.dstIpPrefix())
792 .dstIpPrefix(statsFlowRule.srcIpPrefix())
793 .ipProtocol(statsFlowRule.ipProtocol())
794 .srcTpPort(statsFlowRule.dstTpPort())
795 .dstTpPort(statsFlowRule.srcTpPort())
796 .build();
797 setStatFlowRuleBase(reverseFlowRule, install);
798 }
799 }
800
801 /**
802 * A base method which is for installing flow rules for collecting stats.
803 *
804 * @param statsFlowRule flow rule used for collecting stats
805 * @param install flow rule installation flag
806 */
807 private void setStatFlowRuleBase(StatsFlowRule statsFlowRule, boolean install) {
Jian Lie6110b72018-07-06 19:06:36 +0900808
809 IpPrefix srcIp = statsFlowRule.srcIpPrefix();
810 IpPrefix dstIp = statsFlowRule.dstIpPrefix();
811 DeviceId srcDeviceId = getDeviceId(srcIp.address());
812 DeviceId dstDeviceId = getDeviceId(dstIp.address());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900813
Jian Li998ec7b2018-06-29 15:15:49 +0900814 if (srcDeviceId == null && dstDeviceId == null) {
Jian Li85573f42018-06-27 22:29:14 +0900815 return;
816 }
817
Jian Li998ec7b2018-06-29 15:15:49 +0900818 if (srcDeviceId != null) {
Jian Li87ded822018-07-02 18:31:22 +0900819 connectTables(srcDeviceId, STAT_INBOUND_TABLE, VTAP_INBOUND_TABLE,
Jian Li998ec7b2018-06-29 15:15:49 +0900820 statsFlowRule, METRIC_PRIORITY_SOURCE, install);
Jian Li998ec7b2018-06-29 15:15:49 +0900821
Jian Lie6110b72018-07-06 19:06:36 +0900822 if (install) {
823 log.info("Install ingress stat flow rule for SrcIp:{} DstIp:{}",
824 srcIp.toString(), dstIp.toString());
825 } else {
826 log.info("Remove ingress stat flow rule for SrcIp:{} DstIp:{}",
827 srcIp.toString(), dstIp.toString());
Jian Li753280e2018-07-03 02:24:34 +0900828 }
Jian Li998ec7b2018-06-29 15:15:49 +0900829 }
Jian Li85573f42018-06-27 22:29:14 +0900830
Jian Lie6110b72018-07-06 19:06:36 +0900831 Set<IpPrefix> vxlanIps = osNetworkService.getFixedIpsByNetworkType(VXLAN);
832 Set<IpPrefix> vlanIps = osNetworkService.getFixedIpsByNetworkType(VLAN);
833 Set<IpPrefix> flatIps = osNetworkService.getFixedIpsByNetworkType(FLAT);
Jian Li753280e2018-07-03 02:24:34 +0900834
Jian Lie6110b72018-07-06 19:06:36 +0900835 int fromTable, toTable;
Jian Li753280e2018-07-03 02:24:34 +0900836
Jian Lie6110b72018-07-06 19:06:36 +0900837 if (dstDeviceId != null && egressStats) {
838
839 IpPrefix dstIpPrefix = statsFlowRule.dstIpPrefix();
840
841 if (vxlanIps.contains(dstIpPrefix) || vlanIps.contains(dstIpPrefix)) {
842 fromTable = STAT_OUTBOUND_TABLE;
843 toTable = VTAP_OUTBOUND_TABLE;
844 } else if (flatIps.contains(dstIpPrefix)) {
845 fromTable = STAT_FLAT_OUTBOUND_TABLE;
846 toTable = VTAP_FLAT_OUTBOUND_TABLE;
847 } else {
848 return;
849 }
850
851 connectTables(dstDeviceId, fromTable, toTable,
852 statsFlowRule, METRIC_PRIORITY_TARGET, install);
853
854 if (install) {
855 log.info("Install egress stat flow rule for SrcIp:{} DstIp:{}",
856 srcIp.toString(), dstIp.toString());
857 } else {
858 log.info("Remove egress stat flow rule for SrcIp:{} DstIp:{}",
859 srcIp.toString(), dstIp.toString());
860 }
Jian Li753280e2018-07-03 02:24:34 +0900861 }
Jian Li753280e2018-07-03 02:24:34 +0900862 }
863
864 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900865 * Gets Device ID which the VM is located.
Jian Li85573f42018-06-27 22:29:14 +0900866 *
867 * @param ipAddress IP Address of host
868 * @return Device ID
869 */
870 private DeviceId getDeviceId(IpAddress ipAddress) {
871 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
872 Optional<Host> host = hostService.getHostsByIp(ipAddress).stream().findAny();
873 return host.map(host1 -> host1.location().deviceId()).orElse(null);
874 } else {
Jian Lia4947682018-07-07 14:53:32 +0900875 log.debug("No DeviceID is associated to {}", ipAddress.toString());
Jian Li85573f42018-06-27 22:29:14 +0900876 return null;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900877 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900878 }
879
880 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900881 * Gets VLAN ID with respect to IP Address.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900882 *
883 * @param ipAddress IP Address of host
884 * @return VLAN ID
885 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900886 private VlanId getVlanId(IpAddress ipAddress) {
887 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
888 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
889 return host.vlan();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900890 }
891 return VlanId.vlanId();
892 }
893
894 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900895 * Gets Interface ID of Switch which is connected to a host.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900896 *
897 * @param ipAddress IP Address of host
898 * @return Interface ID of Switch
899 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900900 private int getInterfaceId(IpAddress ipAddress) {
901 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
902 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
903 return (int) host.location().port().toLong();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900904 }
905 return -1;
906 }
907
908 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900909 * Gets MAC Address of host.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900910 *
911 * @param ipAddress IP Address of host
912 * @return MAC Address of host
913 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900914 private MacAddress getMacAddress(IpAddress ipAddress) {
915 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
916 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
917 return host.mac();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900918 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900919
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900920 return NO_HOST_MAC;
921 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900922
Jian Lif8b8c7f2018-08-27 18:49:04 +0900923 /**
924 * Gets IP address of the host which is attached to the given device and port.
925 *
926 * @param device device
927 * @param inPort IN port number
928 * @return IP address
929 */
930 private IpAddress getIpAddress(Device device, PortCriterion inPort) {
931
932 Host host = hostService.getConnectedHosts(device.id()).stream()
933 .filter(h -> h.location().port().equals(inPort.port()))
934 .findAny().orElse(null);
935
936 if (host != null) {
937 return host.ipAddresses().stream().findAny().get();
938 }
939
940 return NO_HOST_IP;
941 }
942
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900943 private void enqFlowInfo(FlowInfo flowInfo) {
944 String key = flowInfo.uniqueFlowInfoKey();
945 Queue<FlowInfo> queue = flowInfoMap.get(key);
946 if (queue == null) {
947 Queue<FlowInfo> newQueue = new LinkedList<FlowInfo>();
948 newQueue.offer(flowInfo);
949 flowInfoMap.put(key, newQueue);
950 return;
951 }
952 queue.offer(flowInfo);
953
954 while (queue.size() > DEFAULT_DATA_POINT_SIZE) {
955 queue.remove(); // Removes a garbage data in the queue.
956 }
957 }
958
Jian Lif8b8c7f2018-08-27 18:49:04 +0900959 /**
960 * Checks whether the given device is edge switch or not.
961 *
962 * @param id device identifier
963 * @return true if the given device is edge switch, false otherwise
964 */
965 private boolean isEdgeSwitch(DeviceId id) {
966
967 return !hostService.getConnectedHosts(id).isEmpty();
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900968 }
969
Jian Li753280e2018-07-03 02:24:34 +0900970 /**
971 * Extracts properties from the component configuration context.
972 *
973 * @param context the component context
974 */
975 private void readComponentConfiguration(ComponentContext context) {
976 Dictionary<?, ?> properties = context.getProperties();
977
978 Boolean reversePathStatsConfigured =
Ray Milkey8e406512018-10-24 15:56:50 -0700979 getBooleanProperty(properties, PROP_REVERSE_PATH_STATS);
Jian Li753280e2018-07-03 02:24:34 +0900980 if (reversePathStatsConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -0700981 reversePathStats = PROP_REVERSE_PATH_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900982 log.info("Reversed path stats flag is NOT " +
983 "configured, default value is {}", reversePathStats);
984 } else {
985 reversePathStats = reversePathStatsConfigured;
986 log.info("Configured. Reversed path stats flag is {}", reversePathStats);
987 }
988
Ray Milkey8e406512018-10-24 15:56:50 -0700989 Boolean egressStatsConfigured = getBooleanProperty(properties, PROP_EGRESS_STATS);
Jian Li753280e2018-07-03 02:24:34 +0900990 if (egressStatsConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -0700991 egressStats = PROP_EGRESS_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900992 log.info("Egress stats flag is NOT " +
993 "configured, default value is {}", egressStats);
994 } else {
995 egressStats = egressStatsConfigured;
996 log.info("Configured. Egress stats flag is {}", egressStats);
997 }
Jian Lia4947682018-07-07 14:53:32 +0900998
Ray Milkey8e406512018-10-24 15:56:50 -0700999 Boolean portStatsConfigured = getBooleanProperty(properties, PROP_PORT_STATS);
Jian Lia4947682018-07-07 14:53:32 +09001000 if (portStatsConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -07001001 portStats = PROP_PORT_STATS_DEFAULT;
Jian Lia4947682018-07-07 14:53:32 +09001002 log.info("Port stats flag is NOT " +
1003 "configured, default value is {}", portStats);
1004 } else {
1005 portStats = portStatsConfigured;
1006 log.info("Configured. Port stats flag is {}", portStats);
1007 }
Jian Lif8b8c7f2018-08-27 18:49:04 +09001008
Ray Milkey8e406512018-10-24 15:56:50 -07001009 Boolean monitorOverlayConfigured = getBooleanProperty(properties, PROP_MONITOR_OVERLAY);
Jian Lif8b8c7f2018-08-27 18:49:04 +09001010 if (monitorOverlayConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -07001011 monitorOverlay = PROP_MONITOR_OVERLAY_DEFAULT;
Jian Lif8b8c7f2018-08-27 18:49:04 +09001012 log.info("Monitor overlay flag is NOT " +
1013 "configured, default value is {}", monitorOverlay);
1014 } else {
1015 monitorOverlay = monitorOverlayConfigured;
1016 log.info("Configured. Monitor overlay flag is {}", monitorOverlay);
1017 }
1018
Ray Milkey8e406512018-10-24 15:56:50 -07001019 Boolean monitorUnderlayConfigured = getBooleanProperty(properties, PROP_MONITOR_UNDERLAY);
Jian Lif8b8c7f2018-08-27 18:49:04 +09001020 if (monitorUnderlayConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -07001021 monitorUnderlay = PROP_MONITOR_UNDERLAY_DEFAULT;
Jian Lif8b8c7f2018-08-27 18:49:04 +09001022 log.info("Monitor underlay flag is NOT " +
1023 "configured, default value is {}", monitorUnderlay);
1024 } else {
1025 monitorUnderlay = monitorUnderlayConfigured;
1026 log.info("Configured. Monitor underlay flag is {}", monitorUnderlay);
1027 }
Jian Li753280e2018-07-03 02:24:34 +09001028 }
1029
Jian Lia4947682018-07-07 14:53:32 +09001030 private class TelemetryCollector implements Runnable {
Jian Li0bbbb1c2018-06-22 22:01:17 +09001031 @Override
1032 public void run() {
Jian Lif8b8c7f2018-08-27 18:49:04 +09001033 Set<FlowInfo> filteredOverlayFlowInfos = Sets.newConcurrentHashSet();
1034 Set<FlowInfo> filteredUnderlayFlowInfos = Sets.newConcurrentHashSet();
Jian Li85573f42018-06-27 22:29:14 +09001035
1036 // we only let the master controller of the device where the
Jian Lia4947682018-07-07 14:53:32 +09001037 // stats flow rules are installed send stats message
Jian Lif8b8c7f2018-08-27 18:49:04 +09001038 if (monitorOverlay) {
1039 getOverlayFlowInfos().forEach(f -> {
Jian Lia4947682018-07-07 14:53:32 +09001040 if (checkSrcDstLocalMaster(f)) {
Jian Lif8b8c7f2018-08-27 18:49:04 +09001041 filteredOverlayFlowInfos.add(f);
1042 }
1043 });
1044 }
1045 if (monitorUnderlay) {
1046 getUnderlayFlowInfos().forEach(f -> {
1047 if (checkSrcDstLocalMaster(f)) {
1048 filteredUnderlayFlowInfos.add(f);
Jian Lia4947682018-07-07 14:53:32 +09001049 }
1050 });
Jian Li0bbbb1c2018-06-22 22:01:17 +09001051 }
Jian Lia4947682018-07-07 14:53:32 +09001052
Jian Lif8b8c7f2018-08-27 18:49:04 +09001053 // we only let the master controller of the device where the port
1054 // is located to send stats message
1055 if (portStats) {
1056 if (monitorOverlay) {
1057 getOverlayDstPortBasedFlowInfos().forEach(f -> {
1058 if (checkSrcDstLocalMaster(f)) {
1059 filteredOverlayFlowInfos.add(f);
1060 }
1061 });
1062 }
Boyoung Jeong1cca5e82018-08-01 21:00:08 +09001063
Jian Lif8b8c7f2018-08-27 18:49:04 +09001064 if (monitorUnderlay) {
1065 getUnderlayDstPortBasedFlowInfos().forEach(f -> {
1066 if (checkSrcDstLocalMaster(f)) {
1067 filteredUnderlayFlowInfos.add(f);
1068 }
1069 });
1070 }
1071 }
1072
1073
1074 if (monitorOverlay) {
1075 telemetryService.publish(filteredOverlayFlowInfos);
1076
1077 // TODO: Refactor the following code to "TelemetryService" style.
1078 filteredOverlayFlowInfos.forEach(StatsFlowRuleManager.this::enqFlowInfo);
1079 }
1080
1081 if (monitorUnderlay) {
1082 telemetryService.publish(filteredUnderlayFlowInfos);
1083 }
Jian Lia4947682018-07-07 14:53:32 +09001084 }
1085
1086 private boolean checkSrcDstLocalMaster(FlowInfo info) {
1087 DeviceId srcDeviceId = getDeviceId(info.srcIp().address());
1088 DeviceId dstDeviceId = getDeviceId(info.dstIp().address());
1089
1090 boolean isSrcLocalMaster = srcDeviceId != null &&
1091 mastershipService.isLocalMaster(srcDeviceId);
1092 boolean isDstLocalMaster = dstDeviceId != null &&
1093 mastershipService.isLocalMaster(dstDeviceId);
1094
1095 return isSrcLocalMaster || isDstLocalMaster;
Jian Li0bbbb1c2018-06-22 22:01:17 +09001096 }
1097 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +09001098}