blob: 956fab133624f4e45e8b62d8d65609cc8d37b2dd [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;
Jian Li7fe7eaf2018-12-31 17:00:33 +090060import org.onosproject.openstacktelemetry.api.DefaultFlowInfo;
61import org.onosproject.openstacktelemetry.api.DefaultStatsFlowRule;
62import org.onosproject.openstacktelemetry.api.DefaultStatsInfo;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090063import org.onosproject.openstacktelemetry.api.FlowInfo;
Jian Li0bbbb1c2018-06-22 22:01:17 +090064import org.onosproject.openstacktelemetry.api.OpenstackTelemetryService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090065import org.onosproject.openstacktelemetry.api.StatsFlowRule;
66import org.onosproject.openstacktelemetry.api.StatsFlowRuleAdminService;
67import org.onosproject.openstacktelemetry.api.StatsInfo;
Jian Li753280e2018-07-03 02:24:34 +090068import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070069import org.osgi.service.component.annotations.Activate;
70import org.osgi.service.component.annotations.Component;
71import org.osgi.service.component.annotations.Deactivate;
72import org.osgi.service.component.annotations.Modified;
73import org.osgi.service.component.annotations.Reference;
74import org.osgi.service.component.annotations.ReferenceCardinality;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090075import org.slf4j.Logger;
76import org.slf4j.LoggerFactory;
77
Jian Lif8b8c7f2018-08-27 18:49:04 +090078import java.util.ArrayList;
Jian Li753280e2018-07-03 02:24:34 +090079import java.util.Dictionary;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090080import java.util.LinkedList;
Jian Lia4947682018-07-07 14:53:32 +090081import java.util.List;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090082import java.util.Map;
Jian Li85573f42018-06-27 22:29:14 +090083import java.util.Optional;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090084import java.util.Queue;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090085import java.util.Set;
Jian Lia4947682018-07-07 14:53:32 +090086import java.util.concurrent.ScheduledFuture;
87import java.util.concurrent.TimeUnit;
88import java.util.stream.Collectors;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090089
Jian Li0bbbb1c2018-06-22 22:01:17 +090090import static org.onlab.packet.Ethernet.TYPE_IPV4;
91import static org.onlab.packet.IPv4.PROTOCOL_TCP;
92import static org.onlab.packet.IPv4.PROTOCOL_UDP;
Jian Lif8b8c7f2018-08-27 18:49:04 +090093import static org.onosproject.net.Device.Type.SWITCH;
Jian Li0bbbb1c2018-06-22 22:01:17 +090094import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
95import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC;
96import static org.onosproject.net.flow.criteria.Criterion.Type.IP_PROTO;
97import static org.onosproject.net.flow.criteria.Criterion.Type.TCP_DST;
98import static org.onosproject.net.flow.criteria.Criterion.Type.TCP_SRC;
99import static org.onosproject.net.flow.criteria.Criterion.Type.UDP_DST;
100import static org.onosproject.net.flow.criteria.Criterion.Type.UDP_SRC;
Jian Li753280e2018-07-03 02:24:34 +0900101import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900102import static org.onosproject.openstacknetworking.api.Constants.STAT_INBOUND_TABLE;
103import static org.onosproject.openstacknetworking.api.Constants.STAT_OUTBOUND_TABLE;
Jian Li753280e2018-07-03 02:24:34 +0900104import static org.onosproject.openstacknetworking.api.Constants.VTAP_FLAT_OUTBOUND_TABLE;
Jian Li87ded822018-07-02 18:31:22 +0900105import static org.onosproject.openstacknetworking.api.Constants.VTAP_INBOUND_TABLE;
106import static org.onosproject.openstacknetworking.api.Constants.VTAP_OUTBOUND_TABLE;
Jian Lia4947682018-07-07 14:53:32 +0900107import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Jian Lif8b8c7f2018-08-27 18:49:04 +0900108import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900109import static org.onosproject.openstacktelemetry.api.Constants.DEFAULT_DATA_POINT_SIZE;
Jian Lie6110b72018-07-06 19:06:36 +0900110import static org.onosproject.openstacktelemetry.api.Constants.FLAT;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900111import static org.onosproject.openstacktelemetry.api.Constants.OPENSTACK_TELEMETRY_APP_ID;
Jian Lie6110b72018-07-06 19:06:36 +0900112import static org.onosproject.openstacktelemetry.api.Constants.VLAN;
113import static org.onosproject.openstacktelemetry.api.Constants.VXLAN;
Ray Milkey8e406512018-10-24 15:56:50 -0700114import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_EGRESS_STATS;
115import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_EGRESS_STATS_DEFAULT;
116import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_MONITOR_OVERLAY;
117import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_MONITOR_OVERLAY_DEFAULT;
118import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_MONITOR_UNDERLAY;
119import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_MONITOR_UNDERLAY_DEFAULT;
120import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_PORT_STATS;
121import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_PORT_STATS_DEFAULT;
122import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_REVERSE_PATH_STATS;
123import static org.onosproject.openstacktelemetry.impl.OsgiPropertyConstants.PROP_REVERSE_PATH_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900124import static org.onosproject.openstacktelemetry.util.OpenstackTelemetryUtil.getBooleanProperty;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900125
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900126/**
127 * Flow rule manager for network statistics of a VM.
128 */
Ray Milkey8e406512018-10-24 15:56:50 -0700129@Component(
130 immediate = true,
131 service = StatsFlowRuleAdminService.class,
132 property = {
133 PROP_REVERSE_PATH_STATS + ":Boolean=" + PROP_REVERSE_PATH_STATS_DEFAULT,
134 PROP_EGRESS_STATS + ":Boolean=" + PROP_EGRESS_STATS_DEFAULT,
135 PROP_PORT_STATS + ":Boolean=" + PROP_PORT_STATS_DEFAULT,
136 PROP_MONITOR_OVERLAY + ":Boolean=" + PROP_MONITOR_OVERLAY_DEFAULT,
137 PROP_MONITOR_UNDERLAY + ":Boolean=" + PROP_MONITOR_UNDERLAY_DEFAULT
138 }
139)
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900140public class StatsFlowRuleManager implements StatsFlowRuleAdminService {
141
142 private final Logger log = LoggerFactory.getLogger(getClass());
143
boyoung2a8549d22018-11-23 20:42:37 +0900144 private static final byte FLOW_TYPE_SONA = 1;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900145
Ray Milkeybcc53d32018-07-02 10:22:57 -0700146 private static final long MILLISECONDS = 1000L;
Jian Lia4947682018-07-07 14:53:32 +0900147 private static final long INITIAL_DELAY = 5L;
Ray Milkeybcc53d32018-07-02 10:22:57 -0700148 private static final long REFRESH_INTERVAL = 5L;
Jian Lia4947682018-07-07 14:53:32 +0900149 private static final TimeUnit TIME_UNIT_SECOND = TimeUnit.SECONDS;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900150
Jian Lif8b8c7f2018-08-27 18:49:04 +0900151 private static final String OVS_DRIVER_NAME = "ovs";
152
Jian Lia4947682018-07-07 14:53:32 +0900153 private static final String ARBITRARY_IP = "0.0.0.0/32";
Jian Lib2a58882019-02-20 17:39:41 +0900154 private static final int ARBITRARY_PROTOCOL = 0x0;
Jian Lia4947682018-07-07 14:53:32 +0900155 private static final int ARBITRARY_LENGTH = 32;
156 private static final String ARBITRARY_MAC = "00:00:00:00:00:00";
Jian Lif8b8c7f2018-08-27 18:49:04 +0900157 private static final IpAddress NO_HOST_IP = IpAddress.valueOf("255.255.255.255");
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900158 private static final MacAddress NO_HOST_MAC = MacAddress.valueOf(ARBITRARY_MAC);
Jian Lia4947682018-07-07 14:53:32 +0900159 private static final int ARBITRARY_IN_INTF = 0;
160 private static final int ARBITRARY_OUT_INTF = 0;
161
162 private static final boolean RECOVER_FROM_FAILURE = true;
163
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900165 protected CoreService coreService;
166
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700167 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900168 protected FlowRuleService flowRuleService;
169
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700170 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900171 protected HostService hostService;
172
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700173 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia4947682018-07-07 14:53:32 +0900174 protected DeviceService deviceService;
175
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700176 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900177 protected DriverService driverService;
178
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700179 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lie6110b72018-07-06 19:06:36 +0900180 protected ComponentConfigService componentConfigService;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900181
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700182 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li85573f42018-06-27 22:29:14 +0900183 protected MastershipService mastershipService;
184
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700185 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li753280e2018-07-03 02:24:34 +0900186 protected OpenstackNetworkService osNetworkService;
187
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700188 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia4947682018-07-07 14:53:32 +0900189 protected InstancePortService instPortService;
190
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700191 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia4947682018-07-07 14:53:32 +0900192 protected OpenstackNodeService osNodeService;
193
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700194 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li0bbbb1c2018-06-22 22:01:17 +0900195 protected OpenstackTelemetryService telemetryService;
196
Ray Milkey8e406512018-10-24 15:56:50 -0700197 /** A flag which indicates whether to install the rules for collecting the flow-based stats for reversed path. */
198 private boolean reversePathStats = PROP_REVERSE_PATH_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900199
Ray Milkey8e406512018-10-24 15:56:50 -0700200 /** A flag which indicates whether to install the rules for collecting the flow-based stats for egress port. */
201 private boolean egressStats = PROP_EGRESS_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900202
Ray Milkey8e406512018-10-24 15:56:50 -0700203 /** A flag which indicates whether to collect port TX & RX stats. */
204 private boolean portStats = PROP_PORT_STATS_DEFAULT;
Jian Lia4947682018-07-07 14:53:32 +0900205
Ray Milkey8e406512018-10-24 15:56:50 -0700206 /** A flag which indicates whether to monitor overlay network port stats. */
207 private boolean monitorOverlay = PROP_MONITOR_OVERLAY_DEFAULT;
Jian Lif8b8c7f2018-08-27 18:49:04 +0900208
Ray Milkey8e406512018-10-24 15:56:50 -0700209 /** A flag which indicates whether to monitor underlay network port stats. */
210 private boolean monitorUnderlay = PROP_MONITOR_UNDERLAY_DEFAULT;
Jian Lif8b8c7f2018-08-27 18:49:04 +0900211
212 private ApplicationId telemetryAppId;
Jian Lia4947682018-07-07 14:53:32 +0900213 private TelemetryCollector collector;
Jian Lia4947682018-07-07 14:53:32 +0900214 private ScheduledFuture result;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900215
Jian Li0bbbb1c2018-06-22 22:01:17 +0900216 private final Set<FlowInfo> gFlowInfoSet = Sets.newHashSet();
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900217 private final Map<String, Queue<FlowInfo>> flowInfoMap = Maps.newConcurrentMap();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900218
219 private static final int SOURCE_ID = 1;
220 private static final int TARGET_ID = 2;
221 private static final int PRIORITY_BASE = 10000;
222 private static final int METRIC_PRIORITY_SOURCE = SOURCE_ID * PRIORITY_BASE;
223 private static final int METRIC_PRIORITY_TARGET = TARGET_ID * PRIORITY_BASE;
224
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900225 @Activate
226 protected void activate() {
Jian Lif8b8c7f2018-08-27 18:49:04 +0900227 telemetryAppId = coreService.registerApplication(OPENSTACK_TELEMETRY_APP_ID);
228
Jian Lie6110b72018-07-06 19:06:36 +0900229 componentConfigService.registerProperties(getClass());
Jian Libd295cd2018-07-22 11:53:57 +0900230 start();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900231
232 log.info("Started");
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900233 }
234
235 @Deactivate
236 protected void deactivate() {
Jian Lie6110b72018-07-06 19:06:36 +0900237 componentConfigService.unregisterProperties(getClass(), false);
Jian Lif8b8c7f2018-08-27 18:49:04 +0900238 flowRuleService.removeFlowRulesById(telemetryAppId);
Jian Libd295cd2018-07-22 11:53:57 +0900239 stop();
Jian Lia4947682018-07-07 14:53:32 +0900240
Jian Li0bbbb1c2018-06-22 22:01:17 +0900241 log.info("Stopped");
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900242 }
243
Jian Li753280e2018-07-03 02:24:34 +0900244 @Modified
245 protected void modified(ComponentContext context) {
246 readComponentConfiguration(context);
247
248 log.info("Modified");
249 }
250
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900251 @Override
252 public void start() {
253 log.info("Start publishing thread");
Jian Lia4947682018-07-07 14:53:32 +0900254 collector = new TelemetryCollector();
255
Jian Libd295cd2018-07-22 11:53:57 +0900256 result = SharedScheduledExecutors.getSingleThreadExecutor()
257 .scheduleAtFixedRate(collector, INITIAL_DELAY,
Jian Lia4947682018-07-07 14:53:32 +0900258 REFRESH_INTERVAL, TIME_UNIT_SECOND, RECOVER_FROM_FAILURE);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900259 }
260
261 @Override
262 public void stop() {
263 log.info("Stop data publishing thread");
Jian Lia4947682018-07-07 14:53:32 +0900264 result.cancel(true);
265 collector = null;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900266 }
267
Jian Li0bbbb1c2018-06-22 22:01:17 +0900268 @Override
boyoung27b444122018-09-01 17:28:13 +0900269 public void createStatFlowRule(StatsFlowRule statsFlowRule) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900270 setStatFlowRule(statsFlowRule, true);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900271 }
272
273 @Override
274 public void deleteStatFlowRule(StatsFlowRule statsFlowRule) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900275 setStatFlowRule(statsFlowRule, false);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900276 }
277
Jian Lif8b8c7f2018-08-27 18:49:04 +0900278
Jian Lia4947682018-07-07 14:53:32 +0900279 @Override
Jian Lif8b8c7f2018-08-27 18:49:04 +0900280 public Map<String, Queue<FlowInfo>> getFlowInfoMap() {
281 return flowInfoMap;
282 }
283
284
285 @Override
286 public Set<FlowInfo> getUnderlayFlowInfos() {
287
288 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
289
290 for (Device device : getUnderlayDevices()) {
291
292 if (!isEdgeSwitch(device.id())) {
293 continue;
294 }
295
296 for (FlowEntry entry : flowRuleService.getFlowEntries(device.id())) {
297 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
298 TrafficSelector selector = entry.selector();
299 Criterion inPort = selector.getCriterion(Criterion.Type.IN_PORT);
300 Criterion dstIpCriterion = selector.getCriterion(Criterion.Type.IPV4_DST);
301 if (inPort != null && dstIpCriterion != null) {
302 IpAddress srcIp = getIpAddress(device, (PortCriterion) inPort);
303 IpAddress dstIp = ((IPCriterion) dstIpCriterion).ip().address();
304
305 if (srcIp == null) {
306 continue;
307 }
308
309 fBuilder.withFlowType(FLOW_TYPE_SONA)
310 .withSrcIp(IpPrefix.valueOf(srcIp, ARBITRARY_LENGTH))
311 .withDstIp(IpPrefix.valueOf(dstIp, ARBITRARY_LENGTH))
312 .withSrcMac(getMacAddress(srcIp))
313 .withDstMac(getMacAddress(dstIp))
314 .withInputInterfaceId(getInterfaceId(srcIp))
315 .withOutputInterfaceId(getInterfaceId(dstIp))
316 .withDeviceId(entry.deviceId());
317
318 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
319
320 sBuilder.withStartupTime(System.currentTimeMillis())
321 .withFstPktArrTime(System.currentTimeMillis())
322 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
323 .withCurrAccPkts((int) entry.packets())
324 .withCurrAccBytes(entry.bytes())
325 .withErrorPkts((short) 0)
326 .withDropPkts((short) 0);
327
328 fBuilder.withStatsInfo(sBuilder.build());
329
330 FlowInfo flowInfo = mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
331
332 flowInfos.add(flowInfo);
333 }
334 }
335 }
336
337 return flowInfos;
338 }
339
340 @Override
341 public Set<FlowInfo> getOverlayFlowInfos() {
342
Jian Lia4947682018-07-07 14:53:32 +0900343 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
344
345 // obtain all flow rule entries installed by telemetry app
Jian Lif8b8c7f2018-08-27 18:49:04 +0900346 for (FlowEntry entry : flowRuleService.getFlowEntriesById(telemetryAppId)) {
Jian Lia4947682018-07-07 14:53:32 +0900347 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
348 TrafficSelector selector = entry.selector();
Jian Lia4947682018-07-07 14:53:32 +0900349 IPCriterion srcIp = (IPCriterion) selector.getCriterion(IPV4_SRC);
350 IPCriterion dstIp = (IPCriterion) selector.getCriterion(IPV4_DST);
351 IPProtocolCriterion ipProtocol =
352 (IPProtocolCriterion) selector.getCriterion(IP_PROTO);
353
Jian Lia4947682018-07-07 14:53:32 +0900354 fBuilder.withFlowType(FLOW_TYPE_SONA)
355 .withSrcIp(srcIp.ip())
356 .withDstIp(dstIp.ip());
357
358 if (ipProtocol != null) {
359 fBuilder.withProtocol((byte) ipProtocol.protocol());
360
361 if (ipProtocol.protocol() == PROTOCOL_TCP) {
362 TcpPortCriterion tcpSrc =
363 (TcpPortCriterion) selector.getCriterion(TCP_SRC);
364 TcpPortCriterion tcpDst =
365 (TcpPortCriterion) selector.getCriterion(TCP_DST);
Jian Lia4947682018-07-07 14:53:32 +0900366 fBuilder.withSrcPort(tcpSrc.tcpPort());
367 fBuilder.withDstPort(tcpDst.tcpPort());
Jian Lia4947682018-07-07 14:53:32 +0900368 } else if (ipProtocol.protocol() == PROTOCOL_UDP) {
Jian Lia4947682018-07-07 14:53:32 +0900369 UdpPortCriterion udpSrc =
370 (UdpPortCriterion) selector.getCriterion(UDP_SRC);
371 UdpPortCriterion udpDst =
372 (UdpPortCriterion) selector.getCriterion(UDP_DST);
Jian Lia4947682018-07-07 14:53:32 +0900373 fBuilder.withSrcPort(udpSrc.udpPort());
374 fBuilder.withDstPort(udpDst.udpPort());
375 } else {
376 log.debug("Other protocol: {}", ipProtocol.protocol());
377 }
378 }
379
380 fBuilder.withSrcMac(getMacAddress(srcIp.ip().address()))
381 .withDstMac(getMacAddress(dstIp.ip().address()))
382 .withInputInterfaceId(getInterfaceId(srcIp.ip().address()))
383 .withOutputInterfaceId(getInterfaceId(dstIp.ip().address()))
384 .withVlanId(getVlanId(srcIp.ip().address()))
385 .withDeviceId(entry.deviceId());
386
387 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
388
Jian Lia4947682018-07-07 14:53:32 +0900389 sBuilder.withStartupTime(System.currentTimeMillis())
390 .withFstPktArrTime(System.currentTimeMillis())
391 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
392 .withCurrAccPkts((int) entry.packets())
393 .withCurrAccBytes(entry.bytes())
394 .withErrorPkts((short) 0)
395 .withDropPkts((short) 0);
396
397 fBuilder.withStatsInfo(sBuilder.build());
398
399 FlowInfo flowInfo = mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
400
401 flowInfos.add(flowInfo);
402
403 log.debug("FlowInfo: \n{}", flowInfo.toString());
404 }
405
406 return flowInfos;
407 }
408
409 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900410 * Gets a set of flow infos by referring to overlay destination VM port.
Jian Lia4947682018-07-07 14:53:32 +0900411 *
412 * @return flow infos
413 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900414 private Set<FlowInfo> getOverlayDstPortBasedFlowInfos() {
Jian Lia4947682018-07-07 14:53:32 +0900415 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
416 Set<PortNumber> instPortNums = instPortService.instancePorts()
417 .stream()
418 .map(InstancePort::portNumber)
419 .collect(Collectors.toSet());
420 Set<DeviceId> deviceIds = osNodeService.completeNodes(COMPUTE)
421 .stream()
422 .map(OpenstackNode::intgBridge)
423 .collect(Collectors.toSet());
424
425 deviceIds.forEach(d -> {
426 List<PortStatistics> stats =
427 deviceService.getPortStatistics(d)
428 .stream()
429 .filter(s -> instPortNums.contains(s.portNumber()))
430 .collect(Collectors.toList());
431
432 stats.forEach(s -> {
433 InstancePort instPort = getInstancePort(d, s.portNumber());
boyoung2a8549d22018-11-23 20:42:37 +0900434 if (instPort != null) {
435 flowInfos.add(buildTxFlowInfoFromInstancePort(instPort, s));
436 flowInfos.add(buildRxFlowInfoFromInstancePort(instPort, s));
437 }
Jian Lia4947682018-07-07 14:53:32 +0900438 });
439 });
440
441 return flowInfos;
442 }
443
444 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900445 * Gets a set of flow infos by referring to underlay destination port.
446 *
447 * @return flow infos
448 */
449 private Set<FlowInfo> getUnderlayDstPortBasedFlowInfos() {
450 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
451
452 for (Device d : getUnderlayDevices()) {
453 List<PortStatistics> stats =
454 new ArrayList<>(deviceService.getPortStatistics(d.id()));
455 stats.forEach(s -> {
456 Host host = hostService.getConnectedHosts(new ConnectPoint(d.id(), s.portNumber()))
457 .stream().findFirst().orElse(null);
458 if (host != null) {
459 flowInfos.add(buildTxFlowInfoFromHost(host, s));
460 flowInfos.add(buildRxFlowInfoFromHost(host, s));
461 }
462 });
463 }
464
465 return flowInfos;
466 }
467
468 /**
469 * Obtains a set of device instances which construct underlay network.
470 *
471 * @return a set of device instances
472 */
473 private Set<Device> getUnderlayDevices() {
474
475 Set<Device> underlayDevices = Sets.newConcurrentHashSet();
476
477 Set<DeviceId> overlayDeviceIds = osNodeService.completeNodes()
478 .stream()
479 .filter(n -> n.type() != CONTROLLER)
480 .map(OpenstackNode::intgBridge)
481 .collect(Collectors.toSet());
482
483 for (Device d : deviceService.getAvailableDevices(SWITCH)) {
484 if (overlayDeviceIds.contains(d.id())) {
485 continue;
486 }
487
488 underlayDevices.add(d);
489 }
490
491 return underlayDevices;
492 }
493
494 /**
495 * Checks whether the given drivers contains OVS driver.
496 *
497 * @param drivers a set of drivers
498 * @return true if the given drivers contain any OVS driver, false otherwise
499 */
500 private boolean hasOvsDriver(List<Driver> drivers) {
501
502 for (Driver driver : drivers) {
503 if (OVS_DRIVER_NAME.equals(driver.name())) {
504 return true;
505 }
506 }
507
508 return false;
509 }
510
511 /**
512 * Obtains the flow info generated by TX port from instance port.
Jian Lia4947682018-07-07 14:53:32 +0900513 *
514 * @param instPort instance port
515 * @param stat port statistics
516 * @return flow info
517 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900518 private FlowInfo buildTxFlowInfoFromInstancePort(InstancePort instPort,
519 PortStatistics stat) {
520 return buildTxFlowInfo(instPort.ipAddress(), instPort.macAddress(),
521 instPort.deviceId(), stat);
522 }
523
524 /**
525 * Obtains the flow info generated from RX port from instance port.
526 *
527 * @param instPort instance port
528 * @param stat port statistics
529 * @return flow info
530 */
531 private FlowInfo buildRxFlowInfoFromInstancePort(InstancePort instPort,
532 PortStatistics stat) {
533 return buildRxFlowInfo(instPort.ipAddress(), instPort.macAddress(),
534 instPort.deviceId(), stat);
535 }
536
537 /**
538 * Obtains the flow info generated by TX port from host.
539 *
540 * @param host host
541 * @param stat port statistics
542 * @return flow info
543 */
544 private FlowInfo buildTxFlowInfoFromHost(Host host, PortStatistics stat) {
545 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
546
547 if (ip != null) {
548 return buildTxFlowInfo(ip, host.mac(), host.location().deviceId(), stat);
549 }
550 return null;
551 }
552
553 /**
554 * Obtains the flow info generated by RX @param host host.
555 *
556 * @param host host
557 * @param stat port statistics
558 * @return flow info
559 */
560 private FlowInfo buildRxFlowInfoFromHost(Host host, PortStatistics stat) {
561 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
562
563 if (ip != null) {
564 return buildRxFlowInfo(ip, host.mac(), host.location().deviceId(), stat);
565 }
566 return null;
567 }
568
569 /**
570 * Obtains the flow info generated from TX port.
571 *
572 * @param ipAddress IP address
573 * @param macAddress MAC address
574 * @param deviceId device identifier
575 * @param stat port statistics
576 * @return flow info
577 */
578 private FlowInfo buildTxFlowInfo(IpAddress ipAddress,
579 MacAddress macAddress,
580 DeviceId deviceId,
581 PortStatistics stat) {
Jian Lia4947682018-07-07 14:53:32 +0900582 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
583
584 fBuilder.withFlowType(FLOW_TYPE_SONA)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900585 .withSrcIp(IpPrefix.valueOf(ipAddress, ARBITRARY_LENGTH))
Jian Lia4947682018-07-07 14:53:32 +0900586 .withDstIp(IpPrefix.valueOf(ARBITRARY_IP))
Jian Lif8b8c7f2018-08-27 18:49:04 +0900587 .withSrcMac(macAddress)
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900588 .withDstMac(NO_HOST_MAC)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900589 .withDeviceId(deviceId)
Jian Lida8867f2019-01-31 01:17:36 +0900590 .withInputInterfaceId(getInterfaceId(ipAddress))
Jian Lia4947682018-07-07 14:53:32 +0900591 .withOutputInterfaceId(ARBITRARY_OUT_INTF)
592 .withVlanId(VlanId.vlanId());
593
594 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
595 sBuilder.withStartupTime(System.currentTimeMillis())
596 .withFstPktArrTime(System.currentTimeMillis())
597 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
598 .withCurrAccPkts((int) stat.packetsSent())
599 .withCurrAccBytes(stat.bytesSent())
600 .withErrorPkts((short) stat.packetsTxErrors())
601 .withDropPkts((short) stat.packetsTxDropped());
602
603 fBuilder.withStatsInfo(sBuilder.build());
604
605 return mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
606 }
607
608 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900609 * Obtains the flow info generated from RX port.
Jian Lia4947682018-07-07 14:53:32 +0900610 *
Jian Lif8b8c7f2018-08-27 18:49:04 +0900611 * @param ipAddress IP address
612 * @param macAddress MAC address
613 * @param deviceId Device identifier
Jian Lia4947682018-07-07 14:53:32 +0900614 * @param stat port statistics
615 * @return flow info
616 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900617 private FlowInfo buildRxFlowInfo(IpAddress ipAddress,
618 MacAddress macAddress,
619 DeviceId deviceId,
620 PortStatistics stat) {
Jian Lia4947682018-07-07 14:53:32 +0900621 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
622
623 fBuilder.withFlowType(FLOW_TYPE_SONA)
624 .withSrcIp(IpPrefix.valueOf(ARBITRARY_IP))
Jian Lif8b8c7f2018-08-27 18:49:04 +0900625 .withDstIp(IpPrefix.valueOf(ipAddress, ARBITRARY_LENGTH))
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900626 .withSrcMac(NO_HOST_MAC)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900627 .withDstMac(macAddress)
628 .withDeviceId(deviceId)
Jian Lia4947682018-07-07 14:53:32 +0900629 .withInputInterfaceId(ARBITRARY_IN_INTF)
630 .withOutputInterfaceId(ARBITRARY_OUT_INTF)
631 .withVlanId(VlanId.vlanId());
632
633 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
634 sBuilder.withStartupTime(System.currentTimeMillis())
635 .withFstPktArrTime(System.currentTimeMillis())
636 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
637 .withCurrAccPkts((int) stat.packetsReceived())
638 .withCurrAccBytes(stat.bytesReceived())
639 .withErrorPkts((short) stat.packetsRxErrors())
640 .withDropPkts((short) stat.packetsRxDropped());
641
642 fBuilder.withStatsInfo(sBuilder.build());
643
644 return mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
645 }
646
647 /**
648 * Obtains instance port which associated with the given device identifier
649 * and port number.
650 *
651 * @param deviceId device identifier
652 * @param portNumber port number
653 * @return instance port
654 */
655 private InstancePort getInstancePort(DeviceId deviceId, PortNumber portNumber) {
656 return instPortService.instancePorts().stream()
657 .filter(p -> p.deviceId().equals(deviceId))
658 .filter(p -> p.portNumber().equals(portNumber))
659 .findFirst().orElse(null);
660 }
661
Jian Lif8b8c7f2018-08-27 18:49:04 +0900662 /**
663 * Installs a flow rule where the source table is fromTable, while destination
664 * table is toTable.
665 *
666 * @param deviceId device identifier
667 * @param fromTable source table
668 * @param toTable destination table
669 * @param statsFlowRule stats flow rule
670 * @param rulePriority rule priority
671 * @param install installation flag
672 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900673 private void connectTables(DeviceId deviceId, int fromTable, int toTable,
674 StatsFlowRule statsFlowRule, int rulePriority,
675 boolean install) {
676
Jian Li0bbbb1c2018-06-22 22:01:17 +0900677 int srcPrefixLength = statsFlowRule.srcIpPrefix().prefixLength();
678 int dstPrefixLength = statsFlowRule.dstIpPrefix().prefixLength();
679 int prefixLength = rulePriority + srcPrefixLength + dstPrefixLength;
680 byte protocol = statsFlowRule.ipProtocol();
681
682 TrafficSelector.Builder selectorBuilder =
Jian Li753280e2018-07-03 02:24:34 +0900683 DefaultTrafficSelector.builder()
684 .matchEthType(TYPE_IPV4)
685 .matchIPSrc(statsFlowRule.srcIpPrefix())
686 .matchIPDst(statsFlowRule.dstIpPrefix());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900687
688 if (protocol == PROTOCOL_TCP) {
689 selectorBuilder = selectorBuilder
Jian Li753280e2018-07-03 02:24:34 +0900690 .matchIPProtocol(statsFlowRule.ipProtocol())
691 .matchTcpSrc(statsFlowRule.srcTpPort())
692 .matchTcpDst(statsFlowRule.dstTpPort());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900693
694 } else if (protocol == PROTOCOL_UDP) {
695 selectorBuilder = selectorBuilder
Jian Li753280e2018-07-03 02:24:34 +0900696 .matchIPProtocol(statsFlowRule.ipProtocol())
697 .matchUdpSrc(statsFlowRule.srcTpPort())
698 .matchUdpDst(statsFlowRule.dstTpPort());
Jian Lib2a58882019-02-20 17:39:41 +0900699 } else if (protocol == ARBITRARY_PROTOCOL) {
700 log.debug("IP protocol type is not specified.");
Jian Li0bbbb1c2018-06-22 22:01:17 +0900701 } else {
702 log.warn("Unsupported protocol {}", statsFlowRule.ipProtocol());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900703 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900704
705 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
706
707 treatmentBuilder.transition(toTable);
708
709 FlowRule flowRule = DefaultFlowRule.builder()
Jian Li753280e2018-07-03 02:24:34 +0900710 .forDevice(deviceId)
711 .withSelector(selectorBuilder.build())
712 .withTreatment(treatmentBuilder.build())
713 .withPriority(prefixLength)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900714 .fromApp(telemetryAppId)
Jian Li753280e2018-07-03 02:24:34 +0900715 .makePermanent()
716 .forTable(fromTable)
717 .build();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900718
719 applyRule(flowRule, install);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900720 }
721
722 /**
Jian Li0bbbb1c2018-06-22 22:01:17 +0900723 * Installs stats related flow rule to switch.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900724 *
Jian Li0bbbb1c2018-06-22 22:01:17 +0900725 * @param flowRule flow rule
726 * @param install flag to install or not
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900727 */
728 private void applyRule(FlowRule flowRule, boolean install) {
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900729 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900730 flowOpsBuilder = install ?
731 flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900732
733 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
734 @Override
735 public void onSuccess(FlowRuleOperations ops) {
Jian Lia4947682018-07-07 14:53:32 +0900736 log.debug("Install rules for telemetry stats: \n {}",
737 ops.toString());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900738 }
739
740 @Override
741 public void onError(FlowRuleOperations ops) {
Jian Lia4947682018-07-07 14:53:32 +0900742 log.debug("Failed to install rules for telemetry stats: \n {}",
743 ops.toString());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900744 }
745 }));
746 }
747
748 /**
Jian Li0bbbb1c2018-06-22 22:01:17 +0900749 * Merges old FlowInfo.StatsInfo and current FlowInfo.StatsInfo.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900750 *
751 * @param flowInfo current FlowInfo object
752 * @param fBuilder Builder for FlowInfo
753 * @param sBuilder Builder for StatsInfo
754 * @return Merged FlowInfo object
755 */
756 private FlowInfo mergeFlowInfo(FlowInfo flowInfo,
757 FlowInfo.Builder fBuilder,
758 StatsInfo.Builder sBuilder) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900759 for (FlowInfo gFlowInfo : gFlowInfoSet) {
760 log.debug("Old FlowInfo:\n{}", gFlowInfo.toString());
761 if (gFlowInfo.roughEquals(flowInfo)) {
762
763 // Get old StatsInfo object and merge the value to current object.
764 StatsInfo oldStatsInfo = gFlowInfo.statsInfo();
765 sBuilder.withPrevAccPkts(oldStatsInfo.currAccPkts());
766 sBuilder.withPrevAccBytes(oldStatsInfo.currAccBytes());
767 FlowInfo newFlowInfo = fBuilder.withStatsInfo(sBuilder.build())
768 .build();
769
770 gFlowInfoSet.remove(gFlowInfo);
771 gFlowInfoSet.add(newFlowInfo);
Jian Li85573f42018-06-27 22:29:14 +0900772 log.debug("Old FlowInfo found, Merge this {}", newFlowInfo.toString());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900773 return newFlowInfo;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900774 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900775 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900776
777 // No such record, then build the FlowInfo object and return this object.
Jian Li85573f42018-06-27 22:29:14 +0900778 log.debug("No FlowInfo found, add new FlowInfo {}", flowInfo.toString());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900779 FlowInfo newFlowInfo = fBuilder.withStatsInfo(sBuilder.build()).build();
780 gFlowInfoSet.add(newFlowInfo);
781 return newFlowInfo;
782 }
783
Jian Li753280e2018-07-03 02:24:34 +0900784 /**
785 * Installs flow rules for collecting both normal and reverse path flow stats.
786 *
787 * @param statsFlowRule flow rule used for collecting stats
788 * @param install flow rule installation flag
789 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900790 private void setStatFlowRule(StatsFlowRule statsFlowRule, boolean install) {
Jian Li753280e2018-07-03 02:24:34 +0900791 setStatFlowRuleBase(statsFlowRule, install);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900792
Jian Li753280e2018-07-03 02:24:34 +0900793 // if reverse path stats is enabled, we will install flow rules for
794 // collecting reverse path vFlow stats
795 if (reversePathStats) {
796 StatsFlowRule reverseFlowRule = DefaultStatsFlowRule.builder()
797 .srcIpPrefix(statsFlowRule.dstIpPrefix())
798 .dstIpPrefix(statsFlowRule.srcIpPrefix())
799 .ipProtocol(statsFlowRule.ipProtocol())
800 .srcTpPort(statsFlowRule.dstTpPort())
801 .dstTpPort(statsFlowRule.srcTpPort())
802 .build();
803 setStatFlowRuleBase(reverseFlowRule, install);
804 }
805 }
806
807 /**
808 * A base method which is for installing flow rules for collecting stats.
809 *
810 * @param statsFlowRule flow rule used for collecting stats
811 * @param install flow rule installation flag
812 */
813 private void setStatFlowRuleBase(StatsFlowRule statsFlowRule, boolean install) {
Jian Lie6110b72018-07-06 19:06:36 +0900814
815 IpPrefix srcIp = statsFlowRule.srcIpPrefix();
816 IpPrefix dstIp = statsFlowRule.dstIpPrefix();
817 DeviceId srcDeviceId = getDeviceId(srcIp.address());
818 DeviceId dstDeviceId = getDeviceId(dstIp.address());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900819
Jian Li998ec7b2018-06-29 15:15:49 +0900820 if (srcDeviceId == null && dstDeviceId == null) {
Jian Li85573f42018-06-27 22:29:14 +0900821 return;
822 }
823
Jian Li998ec7b2018-06-29 15:15:49 +0900824 if (srcDeviceId != null) {
Jian Li87ded822018-07-02 18:31:22 +0900825 connectTables(srcDeviceId, STAT_INBOUND_TABLE, VTAP_INBOUND_TABLE,
Jian Li998ec7b2018-06-29 15:15:49 +0900826 statsFlowRule, METRIC_PRIORITY_SOURCE, install);
Jian Li998ec7b2018-06-29 15:15:49 +0900827
Jian Lie6110b72018-07-06 19:06:36 +0900828 if (install) {
829 log.info("Install ingress stat flow rule for SrcIp:{} DstIp:{}",
830 srcIp.toString(), dstIp.toString());
831 } else {
832 log.info("Remove ingress stat flow rule for SrcIp:{} DstIp:{}",
833 srcIp.toString(), dstIp.toString());
Jian Li753280e2018-07-03 02:24:34 +0900834 }
Jian Li998ec7b2018-06-29 15:15:49 +0900835 }
Jian Li85573f42018-06-27 22:29:14 +0900836
Jian Lie6110b72018-07-06 19:06:36 +0900837 Set<IpPrefix> vxlanIps = osNetworkService.getFixedIpsByNetworkType(VXLAN);
838 Set<IpPrefix> vlanIps = osNetworkService.getFixedIpsByNetworkType(VLAN);
839 Set<IpPrefix> flatIps = osNetworkService.getFixedIpsByNetworkType(FLAT);
Jian Li753280e2018-07-03 02:24:34 +0900840
Jian Lie6110b72018-07-06 19:06:36 +0900841 int fromTable, toTable;
Jian Li753280e2018-07-03 02:24:34 +0900842
Jian Lie6110b72018-07-06 19:06:36 +0900843 if (dstDeviceId != null && egressStats) {
844
845 IpPrefix dstIpPrefix = statsFlowRule.dstIpPrefix();
846
847 if (vxlanIps.contains(dstIpPrefix) || vlanIps.contains(dstIpPrefix)) {
848 fromTable = STAT_OUTBOUND_TABLE;
849 toTable = VTAP_OUTBOUND_TABLE;
850 } else if (flatIps.contains(dstIpPrefix)) {
851 fromTable = STAT_FLAT_OUTBOUND_TABLE;
852 toTable = VTAP_FLAT_OUTBOUND_TABLE;
853 } else {
854 return;
855 }
856
857 connectTables(dstDeviceId, fromTable, toTable,
858 statsFlowRule, METRIC_PRIORITY_TARGET, install);
859
860 if (install) {
861 log.info("Install egress stat flow rule for SrcIp:{} DstIp:{}",
862 srcIp.toString(), dstIp.toString());
863 } else {
864 log.info("Remove egress stat flow rule for SrcIp:{} DstIp:{}",
865 srcIp.toString(), dstIp.toString());
866 }
Jian Li753280e2018-07-03 02:24:34 +0900867 }
Jian Li753280e2018-07-03 02:24:34 +0900868 }
869
870 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900871 * Gets Device ID which the VM is located.
Jian Li85573f42018-06-27 22:29:14 +0900872 *
873 * @param ipAddress IP Address of host
874 * @return Device ID
875 */
876 private DeviceId getDeviceId(IpAddress ipAddress) {
877 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
878 Optional<Host> host = hostService.getHostsByIp(ipAddress).stream().findAny();
879 return host.map(host1 -> host1.location().deviceId()).orElse(null);
880 } else {
Jian Lia4947682018-07-07 14:53:32 +0900881 log.debug("No DeviceID is associated to {}", ipAddress.toString());
Jian Li85573f42018-06-27 22:29:14 +0900882 return null;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900883 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900884 }
885
886 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900887 * Gets VLAN ID with respect to IP Address.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900888 *
889 * @param ipAddress IP Address of host
890 * @return VLAN ID
891 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900892 private VlanId getVlanId(IpAddress ipAddress) {
893 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
894 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
895 return host.vlan();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900896 }
897 return VlanId.vlanId();
898 }
899
900 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900901 * Gets Interface ID of Switch which is connected to a host.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900902 *
903 * @param ipAddress IP Address of host
904 * @return Interface ID of Switch
905 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900906 private int getInterfaceId(IpAddress ipAddress) {
907 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
908 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
909 return (int) host.location().port().toLong();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900910 }
911 return -1;
912 }
913
914 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900915 * Gets MAC Address of host.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900916 *
917 * @param ipAddress IP Address of host
918 * @return MAC Address of host
919 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900920 private MacAddress getMacAddress(IpAddress ipAddress) {
921 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
922 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
923 return host.mac();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900924 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900925
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900926 return NO_HOST_MAC;
927 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900928
Jian Lif8b8c7f2018-08-27 18:49:04 +0900929 /**
930 * Gets IP address of the host which is attached to the given device and port.
931 *
932 * @param device device
933 * @param inPort IN port number
934 * @return IP address
935 */
936 private IpAddress getIpAddress(Device device, PortCriterion inPort) {
937
938 Host host = hostService.getConnectedHosts(device.id()).stream()
939 .filter(h -> h.location().port().equals(inPort.port()))
940 .findAny().orElse(null);
941
942 if (host != null) {
943 return host.ipAddresses().stream().findAny().get();
944 }
945
946 return NO_HOST_IP;
947 }
948
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900949 private void enqFlowInfo(FlowInfo flowInfo) {
950 String key = flowInfo.uniqueFlowInfoKey();
951 Queue<FlowInfo> queue = flowInfoMap.get(key);
952 if (queue == null) {
953 Queue<FlowInfo> newQueue = new LinkedList<FlowInfo>();
954 newQueue.offer(flowInfo);
955 flowInfoMap.put(key, newQueue);
956 return;
957 }
958 queue.offer(flowInfo);
959
960 while (queue.size() > DEFAULT_DATA_POINT_SIZE) {
961 queue.remove(); // Removes a garbage data in the queue.
962 }
963 }
964
Jian Lif8b8c7f2018-08-27 18:49:04 +0900965 /**
966 * Checks whether the given device is edge switch or not.
967 *
968 * @param id device identifier
969 * @return true if the given device is edge switch, false otherwise
970 */
971 private boolean isEdgeSwitch(DeviceId id) {
972
973 return !hostService.getConnectedHosts(id).isEmpty();
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900974 }
975
Jian Li753280e2018-07-03 02:24:34 +0900976 /**
977 * Extracts properties from the component configuration context.
978 *
979 * @param context the component context
980 */
981 private void readComponentConfiguration(ComponentContext context) {
982 Dictionary<?, ?> properties = context.getProperties();
983
984 Boolean reversePathStatsConfigured =
Ray Milkey8e406512018-10-24 15:56:50 -0700985 getBooleanProperty(properties, PROP_REVERSE_PATH_STATS);
Jian Li753280e2018-07-03 02:24:34 +0900986 if (reversePathStatsConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -0700987 reversePathStats = PROP_REVERSE_PATH_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900988 log.info("Reversed path stats flag is NOT " +
989 "configured, default value is {}", reversePathStats);
990 } else {
991 reversePathStats = reversePathStatsConfigured;
992 log.info("Configured. Reversed path stats flag is {}", reversePathStats);
993 }
994
Ray Milkey8e406512018-10-24 15:56:50 -0700995 Boolean egressStatsConfigured = getBooleanProperty(properties, PROP_EGRESS_STATS);
Jian Li753280e2018-07-03 02:24:34 +0900996 if (egressStatsConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -0700997 egressStats = PROP_EGRESS_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900998 log.info("Egress stats flag is NOT " +
999 "configured, default value is {}", egressStats);
1000 } else {
1001 egressStats = egressStatsConfigured;
1002 log.info("Configured. Egress stats flag is {}", egressStats);
1003 }
Jian Lia4947682018-07-07 14:53:32 +09001004
Ray Milkey8e406512018-10-24 15:56:50 -07001005 Boolean portStatsConfigured = getBooleanProperty(properties, PROP_PORT_STATS);
Jian Lia4947682018-07-07 14:53:32 +09001006 if (portStatsConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -07001007 portStats = PROP_PORT_STATS_DEFAULT;
Jian Lia4947682018-07-07 14:53:32 +09001008 log.info("Port stats flag is NOT " +
1009 "configured, default value is {}", portStats);
1010 } else {
1011 portStats = portStatsConfigured;
1012 log.info("Configured. Port stats flag is {}", portStats);
1013 }
Jian Lif8b8c7f2018-08-27 18:49:04 +09001014
Ray Milkey8e406512018-10-24 15:56:50 -07001015 Boolean monitorOverlayConfigured = getBooleanProperty(properties, PROP_MONITOR_OVERLAY);
Jian Lif8b8c7f2018-08-27 18:49:04 +09001016 if (monitorOverlayConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -07001017 monitorOverlay = PROP_MONITOR_OVERLAY_DEFAULT;
Jian Lif8b8c7f2018-08-27 18:49:04 +09001018 log.info("Monitor overlay flag is NOT " +
1019 "configured, default value is {}", monitorOverlay);
1020 } else {
1021 monitorOverlay = monitorOverlayConfigured;
1022 log.info("Configured. Monitor overlay flag is {}", monitorOverlay);
1023 }
1024
Ray Milkey8e406512018-10-24 15:56:50 -07001025 Boolean monitorUnderlayConfigured = getBooleanProperty(properties, PROP_MONITOR_UNDERLAY);
Jian Lif8b8c7f2018-08-27 18:49:04 +09001026 if (monitorUnderlayConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -07001027 monitorUnderlay = PROP_MONITOR_UNDERLAY_DEFAULT;
Jian Lif8b8c7f2018-08-27 18:49:04 +09001028 log.info("Monitor underlay flag is NOT " +
1029 "configured, default value is {}", monitorUnderlay);
1030 } else {
1031 monitorUnderlay = monitorUnderlayConfigured;
1032 log.info("Configured. Monitor underlay flag is {}", monitorUnderlay);
1033 }
Jian Li753280e2018-07-03 02:24:34 +09001034 }
1035
Jian Lia4947682018-07-07 14:53:32 +09001036 private class TelemetryCollector implements Runnable {
Jian Li0bbbb1c2018-06-22 22:01:17 +09001037 @Override
1038 public void run() {
Jian Lif8b8c7f2018-08-27 18:49:04 +09001039 Set<FlowInfo> filteredOverlayFlowInfos = Sets.newConcurrentHashSet();
1040 Set<FlowInfo> filteredUnderlayFlowInfos = Sets.newConcurrentHashSet();
Jian Li85573f42018-06-27 22:29:14 +09001041
1042 // we only let the master controller of the device where the
Jian Lia4947682018-07-07 14:53:32 +09001043 // stats flow rules are installed send stats message
Jian Lif8b8c7f2018-08-27 18:49:04 +09001044 if (monitorOverlay) {
1045 getOverlayFlowInfos().forEach(f -> {
Jian Lia4947682018-07-07 14:53:32 +09001046 if (checkSrcDstLocalMaster(f)) {
Jian Lif8b8c7f2018-08-27 18:49:04 +09001047 filteredOverlayFlowInfos.add(f);
1048 }
1049 });
1050 }
1051 if (monitorUnderlay) {
1052 getUnderlayFlowInfos().forEach(f -> {
1053 if (checkSrcDstLocalMaster(f)) {
1054 filteredUnderlayFlowInfos.add(f);
Jian Lia4947682018-07-07 14:53:32 +09001055 }
1056 });
Jian Li0bbbb1c2018-06-22 22:01:17 +09001057 }
Jian Lia4947682018-07-07 14:53:32 +09001058
Jian Lif8b8c7f2018-08-27 18:49:04 +09001059 // we only let the master controller of the device where the port
1060 // is located to send stats message
1061 if (portStats) {
1062 if (monitorOverlay) {
1063 getOverlayDstPortBasedFlowInfos().forEach(f -> {
1064 if (checkSrcDstLocalMaster(f)) {
1065 filteredOverlayFlowInfos.add(f);
1066 }
1067 });
1068 }
Boyoung Jeong1cca5e82018-08-01 21:00:08 +09001069
Jian Lif8b8c7f2018-08-27 18:49:04 +09001070 if (monitorUnderlay) {
1071 getUnderlayDstPortBasedFlowInfos().forEach(f -> {
1072 if (checkSrcDstLocalMaster(f)) {
1073 filteredUnderlayFlowInfos.add(f);
1074 }
1075 });
1076 }
1077 }
1078
1079
1080 if (monitorOverlay) {
1081 telemetryService.publish(filteredOverlayFlowInfos);
1082
1083 // TODO: Refactor the following code to "TelemetryService" style.
1084 filteredOverlayFlowInfos.forEach(StatsFlowRuleManager.this::enqFlowInfo);
1085 }
1086
1087 if (monitorUnderlay) {
1088 telemetryService.publish(filteredUnderlayFlowInfos);
1089 }
Jian Lia4947682018-07-07 14:53:32 +09001090 }
1091
1092 private boolean checkSrcDstLocalMaster(FlowInfo info) {
1093 DeviceId srcDeviceId = getDeviceId(info.srcIp().address());
1094 DeviceId dstDeviceId = getDeviceId(info.dstIp().address());
1095
1096 boolean isSrcLocalMaster = srcDeviceId != null &&
1097 mastershipService.isLocalMaster(srcDeviceId);
1098 boolean isDstLocalMaster = dstDeviceId != null &&
1099 mastershipService.isLocalMaster(dstDeviceId);
1100
1101 return isSrcLocalMaster || isDstLocalMaster;
Jian Li0bbbb1c2018-06-22 22:01:17 +09001102 }
1103 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +09001104}