blob: 9bf7994214b4bcf5e8d145ecae48fd84277366e4 [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";
154 private static final int ARBITRARY_LENGTH = 32;
155 private static final String ARBITRARY_MAC = "00:00:00:00:00:00";
Jian Lif8b8c7f2018-08-27 18:49:04 +0900156 private static final IpAddress NO_HOST_IP = IpAddress.valueOf("255.255.255.255");
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900157 private static final MacAddress NO_HOST_MAC = MacAddress.valueOf(ARBITRARY_MAC);
Jian Lia4947682018-07-07 14:53:32 +0900158 private static final int ARBITRARY_IN_INTF = 0;
159 private static final int ARBITRARY_OUT_INTF = 0;
160
161 private static final boolean RECOVER_FROM_FAILURE = true;
162
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700163 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900164 protected CoreService coreService;
165
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700166 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900167 protected FlowRuleService flowRuleService;
168
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700169 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900170 protected HostService hostService;
171
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700172 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia4947682018-07-07 14:53:32 +0900173 protected DeviceService deviceService;
174
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700175 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900176 protected DriverService driverService;
177
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700178 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lie6110b72018-07-06 19:06:36 +0900179 protected ComponentConfigService componentConfigService;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900180
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700181 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li85573f42018-06-27 22:29:14 +0900182 protected MastershipService mastershipService;
183
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700184 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li753280e2018-07-03 02:24:34 +0900185 protected OpenstackNetworkService osNetworkService;
186
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700187 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia4947682018-07-07 14:53:32 +0900188 protected InstancePortService instPortService;
189
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700190 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia4947682018-07-07 14:53:32 +0900191 protected OpenstackNodeService osNodeService;
192
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700193 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li0bbbb1c2018-06-22 22:01:17 +0900194 protected OpenstackTelemetryService telemetryService;
195
Ray Milkey8e406512018-10-24 15:56:50 -0700196 /** A flag which indicates whether to install the rules for collecting the flow-based stats for reversed path. */
197 private boolean reversePathStats = PROP_REVERSE_PATH_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900198
Ray Milkey8e406512018-10-24 15:56:50 -0700199 /** A flag which indicates whether to install the rules for collecting the flow-based stats for egress port. */
200 private boolean egressStats = PROP_EGRESS_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900201
Ray Milkey8e406512018-10-24 15:56:50 -0700202 /** A flag which indicates whether to collect port TX & RX stats. */
203 private boolean portStats = PROP_PORT_STATS_DEFAULT;
Jian Lia4947682018-07-07 14:53:32 +0900204
Ray Milkey8e406512018-10-24 15:56:50 -0700205 /** A flag which indicates whether to monitor overlay network port stats. */
206 private boolean monitorOverlay = PROP_MONITOR_OVERLAY_DEFAULT;
Jian Lif8b8c7f2018-08-27 18:49:04 +0900207
Ray Milkey8e406512018-10-24 15:56:50 -0700208 /** A flag which indicates whether to monitor underlay network port stats. */
209 private boolean monitorUnderlay = PROP_MONITOR_UNDERLAY_DEFAULT;
Jian Lif8b8c7f2018-08-27 18:49:04 +0900210
211 private ApplicationId telemetryAppId;
Jian Lia4947682018-07-07 14:53:32 +0900212 private TelemetryCollector collector;
Jian Lia4947682018-07-07 14:53:32 +0900213 private ScheduledFuture result;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900214
Jian Li0bbbb1c2018-06-22 22:01:17 +0900215 private final Set<FlowInfo> gFlowInfoSet = Sets.newHashSet();
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900216 private final Map<String, Queue<FlowInfo>> flowInfoMap = Maps.newConcurrentMap();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900217
218 private static final int SOURCE_ID = 1;
219 private static final int TARGET_ID = 2;
220 private static final int PRIORITY_BASE = 10000;
221 private static final int METRIC_PRIORITY_SOURCE = SOURCE_ID * PRIORITY_BASE;
222 private static final int METRIC_PRIORITY_TARGET = TARGET_ID * PRIORITY_BASE;
223
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900224 @Activate
225 protected void activate() {
Jian Lif8b8c7f2018-08-27 18:49:04 +0900226 telemetryAppId = coreService.registerApplication(OPENSTACK_TELEMETRY_APP_ID);
227
Jian Lie6110b72018-07-06 19:06:36 +0900228 componentConfigService.registerProperties(getClass());
Jian Libd295cd2018-07-22 11:53:57 +0900229 start();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900230
231 log.info("Started");
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900232 }
233
234 @Deactivate
235 protected void deactivate() {
Jian Lie6110b72018-07-06 19:06:36 +0900236 componentConfigService.unregisterProperties(getClass(), false);
Jian Lif8b8c7f2018-08-27 18:49:04 +0900237 flowRuleService.removeFlowRulesById(telemetryAppId);
Jian Libd295cd2018-07-22 11:53:57 +0900238 stop();
Jian Lia4947682018-07-07 14:53:32 +0900239
Jian Li0bbbb1c2018-06-22 22:01:17 +0900240 log.info("Stopped");
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900241 }
242
Jian Li753280e2018-07-03 02:24:34 +0900243 @Modified
244 protected void modified(ComponentContext context) {
245 readComponentConfiguration(context);
246
247 log.info("Modified");
248 }
249
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900250 @Override
251 public void start() {
252 log.info("Start publishing thread");
Jian Lia4947682018-07-07 14:53:32 +0900253 collector = new TelemetryCollector();
254
Jian Libd295cd2018-07-22 11:53:57 +0900255 result = SharedScheduledExecutors.getSingleThreadExecutor()
256 .scheduleAtFixedRate(collector, INITIAL_DELAY,
Jian Lia4947682018-07-07 14:53:32 +0900257 REFRESH_INTERVAL, TIME_UNIT_SECOND, RECOVER_FROM_FAILURE);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900258 }
259
260 @Override
261 public void stop() {
262 log.info("Stop data publishing thread");
Jian Lia4947682018-07-07 14:53:32 +0900263 result.cancel(true);
264 collector = null;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900265 }
266
Jian Li0bbbb1c2018-06-22 22:01:17 +0900267 @Override
boyoung27b444122018-09-01 17:28:13 +0900268 public void createStatFlowRule(StatsFlowRule statsFlowRule) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900269 setStatFlowRule(statsFlowRule, true);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900270 }
271
272 @Override
273 public void deleteStatFlowRule(StatsFlowRule statsFlowRule) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900274 setStatFlowRule(statsFlowRule, false);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900275 }
276
Jian Lif8b8c7f2018-08-27 18:49:04 +0900277
Jian Lia4947682018-07-07 14:53:32 +0900278 @Override
Jian Lif8b8c7f2018-08-27 18:49:04 +0900279 public Map<String, Queue<FlowInfo>> getFlowInfoMap() {
280 return flowInfoMap;
281 }
282
283
284 @Override
285 public Set<FlowInfo> getUnderlayFlowInfos() {
286
287 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
288
289 for (Device device : getUnderlayDevices()) {
290
291 if (!isEdgeSwitch(device.id())) {
292 continue;
293 }
294
295 for (FlowEntry entry : flowRuleService.getFlowEntries(device.id())) {
296 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
297 TrafficSelector selector = entry.selector();
298 Criterion inPort = selector.getCriterion(Criterion.Type.IN_PORT);
299 Criterion dstIpCriterion = selector.getCriterion(Criterion.Type.IPV4_DST);
300 if (inPort != null && dstIpCriterion != null) {
301 IpAddress srcIp = getIpAddress(device, (PortCriterion) inPort);
302 IpAddress dstIp = ((IPCriterion) dstIpCriterion).ip().address();
303
304 if (srcIp == null) {
305 continue;
306 }
307
308 fBuilder.withFlowType(FLOW_TYPE_SONA)
309 .withSrcIp(IpPrefix.valueOf(srcIp, ARBITRARY_LENGTH))
310 .withDstIp(IpPrefix.valueOf(dstIp, ARBITRARY_LENGTH))
311 .withSrcMac(getMacAddress(srcIp))
312 .withDstMac(getMacAddress(dstIp))
313 .withInputInterfaceId(getInterfaceId(srcIp))
314 .withOutputInterfaceId(getInterfaceId(dstIp))
315 .withDeviceId(entry.deviceId());
316
317 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
318
319 sBuilder.withStartupTime(System.currentTimeMillis())
320 .withFstPktArrTime(System.currentTimeMillis())
321 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
322 .withCurrAccPkts((int) entry.packets())
323 .withCurrAccBytes(entry.bytes())
324 .withErrorPkts((short) 0)
325 .withDropPkts((short) 0);
326
327 fBuilder.withStatsInfo(sBuilder.build());
328
329 FlowInfo flowInfo = mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
330
331 flowInfos.add(flowInfo);
332 }
333 }
334 }
335
336 return flowInfos;
337 }
338
339 @Override
340 public Set<FlowInfo> getOverlayFlowInfos() {
341
Jian Lia4947682018-07-07 14:53:32 +0900342 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
343
344 // obtain all flow rule entries installed by telemetry app
Jian Lif8b8c7f2018-08-27 18:49:04 +0900345 for (FlowEntry entry : flowRuleService.getFlowEntriesById(telemetryAppId)) {
Jian Lia4947682018-07-07 14:53:32 +0900346 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
347 TrafficSelector selector = entry.selector();
Jian Lia4947682018-07-07 14:53:32 +0900348 IPCriterion srcIp = (IPCriterion) selector.getCriterion(IPV4_SRC);
349 IPCriterion dstIp = (IPCriterion) selector.getCriterion(IPV4_DST);
350 IPProtocolCriterion ipProtocol =
351 (IPProtocolCriterion) selector.getCriterion(IP_PROTO);
352
Jian Lia4947682018-07-07 14:53:32 +0900353 fBuilder.withFlowType(FLOW_TYPE_SONA)
354 .withSrcIp(srcIp.ip())
355 .withDstIp(dstIp.ip());
356
357 if (ipProtocol != null) {
358 fBuilder.withProtocol((byte) ipProtocol.protocol());
359
360 if (ipProtocol.protocol() == PROTOCOL_TCP) {
361 TcpPortCriterion tcpSrc =
362 (TcpPortCriterion) selector.getCriterion(TCP_SRC);
363 TcpPortCriterion tcpDst =
364 (TcpPortCriterion) selector.getCriterion(TCP_DST);
Jian Lia4947682018-07-07 14:53:32 +0900365 fBuilder.withSrcPort(tcpSrc.tcpPort());
366 fBuilder.withDstPort(tcpDst.tcpPort());
Jian Lia4947682018-07-07 14:53:32 +0900367 } else if (ipProtocol.protocol() == PROTOCOL_UDP) {
Jian Lia4947682018-07-07 14:53:32 +0900368 UdpPortCriterion udpSrc =
369 (UdpPortCriterion) selector.getCriterion(UDP_SRC);
370 UdpPortCriterion udpDst =
371 (UdpPortCriterion) selector.getCriterion(UDP_DST);
Jian Lia4947682018-07-07 14:53:32 +0900372 fBuilder.withSrcPort(udpSrc.udpPort());
373 fBuilder.withDstPort(udpDst.udpPort());
374 } else {
375 log.debug("Other protocol: {}", ipProtocol.protocol());
376 }
377 }
378
379 fBuilder.withSrcMac(getMacAddress(srcIp.ip().address()))
380 .withDstMac(getMacAddress(dstIp.ip().address()))
381 .withInputInterfaceId(getInterfaceId(srcIp.ip().address()))
382 .withOutputInterfaceId(getInterfaceId(dstIp.ip().address()))
383 .withVlanId(getVlanId(srcIp.ip().address()))
384 .withDeviceId(entry.deviceId());
385
386 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
387
Jian Lia4947682018-07-07 14:53:32 +0900388 sBuilder.withStartupTime(System.currentTimeMillis())
389 .withFstPktArrTime(System.currentTimeMillis())
390 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
391 .withCurrAccPkts((int) entry.packets())
392 .withCurrAccBytes(entry.bytes())
393 .withErrorPkts((short) 0)
394 .withDropPkts((short) 0);
395
396 fBuilder.withStatsInfo(sBuilder.build());
397
398 FlowInfo flowInfo = mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
399
400 flowInfos.add(flowInfo);
401
402 log.debug("FlowInfo: \n{}", flowInfo.toString());
403 }
404
405 return flowInfos;
406 }
407
408 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900409 * Gets a set of flow infos by referring to overlay destination VM port.
Jian Lia4947682018-07-07 14:53:32 +0900410 *
411 * @return flow infos
412 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900413 private Set<FlowInfo> getOverlayDstPortBasedFlowInfos() {
Jian Lia4947682018-07-07 14:53:32 +0900414 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
415 Set<PortNumber> instPortNums = instPortService.instancePorts()
416 .stream()
417 .map(InstancePort::portNumber)
418 .collect(Collectors.toSet());
419 Set<DeviceId> deviceIds = osNodeService.completeNodes(COMPUTE)
420 .stream()
421 .map(OpenstackNode::intgBridge)
422 .collect(Collectors.toSet());
423
424 deviceIds.forEach(d -> {
425 List<PortStatistics> stats =
426 deviceService.getPortStatistics(d)
427 .stream()
428 .filter(s -> instPortNums.contains(s.portNumber()))
429 .collect(Collectors.toList());
430
431 stats.forEach(s -> {
432 InstancePort instPort = getInstancePort(d, s.portNumber());
boyoung2a8549d22018-11-23 20:42:37 +0900433 if (instPort != null) {
434 flowInfos.add(buildTxFlowInfoFromInstancePort(instPort, s));
435 flowInfos.add(buildRxFlowInfoFromInstancePort(instPort, s));
436 }
Jian Lia4947682018-07-07 14:53:32 +0900437 });
438 });
439
440 return flowInfos;
441 }
442
443 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900444 * Gets a set of flow infos by referring to underlay destination port.
445 *
446 * @return flow infos
447 */
448 private Set<FlowInfo> getUnderlayDstPortBasedFlowInfos() {
449 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
450
451 for (Device d : getUnderlayDevices()) {
452 List<PortStatistics> stats =
453 new ArrayList<>(deviceService.getPortStatistics(d.id()));
454 stats.forEach(s -> {
455 Host host = hostService.getConnectedHosts(new ConnectPoint(d.id(), s.portNumber()))
456 .stream().findFirst().orElse(null);
457 if (host != null) {
458 flowInfos.add(buildTxFlowInfoFromHost(host, s));
459 flowInfos.add(buildRxFlowInfoFromHost(host, s));
460 }
461 });
462 }
463
464 return flowInfos;
465 }
466
467 /**
468 * Obtains a set of device instances which construct underlay network.
469 *
470 * @return a set of device instances
471 */
472 private Set<Device> getUnderlayDevices() {
473
474 Set<Device> underlayDevices = Sets.newConcurrentHashSet();
475
476 Set<DeviceId> overlayDeviceIds = osNodeService.completeNodes()
477 .stream()
478 .filter(n -> n.type() != CONTROLLER)
479 .map(OpenstackNode::intgBridge)
480 .collect(Collectors.toSet());
481
482 for (Device d : deviceService.getAvailableDevices(SWITCH)) {
483 if (overlayDeviceIds.contains(d.id())) {
484 continue;
485 }
486
487 underlayDevices.add(d);
488 }
489
490 return underlayDevices;
491 }
492
493 /**
494 * Checks whether the given drivers contains OVS driver.
495 *
496 * @param drivers a set of drivers
497 * @return true if the given drivers contain any OVS driver, false otherwise
498 */
499 private boolean hasOvsDriver(List<Driver> drivers) {
500
501 for (Driver driver : drivers) {
502 if (OVS_DRIVER_NAME.equals(driver.name())) {
503 return true;
504 }
505 }
506
507 return false;
508 }
509
510 /**
511 * Obtains the flow info generated by TX port from instance port.
Jian Lia4947682018-07-07 14:53:32 +0900512 *
513 * @param instPort instance port
514 * @param stat port statistics
515 * @return flow info
516 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900517 private FlowInfo buildTxFlowInfoFromInstancePort(InstancePort instPort,
518 PortStatistics stat) {
519 return buildTxFlowInfo(instPort.ipAddress(), instPort.macAddress(),
520 instPort.deviceId(), stat);
521 }
522
523 /**
524 * Obtains the flow info generated from RX port from instance port.
525 *
526 * @param instPort instance port
527 * @param stat port statistics
528 * @return flow info
529 */
530 private FlowInfo buildRxFlowInfoFromInstancePort(InstancePort instPort,
531 PortStatistics stat) {
532 return buildRxFlowInfo(instPort.ipAddress(), instPort.macAddress(),
533 instPort.deviceId(), stat);
534 }
535
536 /**
537 * Obtains the flow info generated by TX port from host.
538 *
539 * @param host host
540 * @param stat port statistics
541 * @return flow info
542 */
543 private FlowInfo buildTxFlowInfoFromHost(Host host, PortStatistics stat) {
544 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
545
546 if (ip != null) {
547 return buildTxFlowInfo(ip, host.mac(), host.location().deviceId(), stat);
548 }
549 return null;
550 }
551
552 /**
553 * Obtains the flow info generated by RX @param host host.
554 *
555 * @param host host
556 * @param stat port statistics
557 * @return flow info
558 */
559 private FlowInfo buildRxFlowInfoFromHost(Host host, PortStatistics stat) {
560 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
561
562 if (ip != null) {
563 return buildRxFlowInfo(ip, host.mac(), host.location().deviceId(), stat);
564 }
565 return null;
566 }
567
568 /**
569 * Obtains the flow info generated from TX port.
570 *
571 * @param ipAddress IP address
572 * @param macAddress MAC address
573 * @param deviceId device identifier
574 * @param stat port statistics
575 * @return flow info
576 */
577 private FlowInfo buildTxFlowInfo(IpAddress ipAddress,
578 MacAddress macAddress,
579 DeviceId deviceId,
580 PortStatistics stat) {
Jian Lia4947682018-07-07 14:53:32 +0900581 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
582
583 fBuilder.withFlowType(FLOW_TYPE_SONA)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900584 .withSrcIp(IpPrefix.valueOf(ipAddress, ARBITRARY_LENGTH))
Jian Lia4947682018-07-07 14:53:32 +0900585 .withDstIp(IpPrefix.valueOf(ARBITRARY_IP))
Jian Lif8b8c7f2018-08-27 18:49:04 +0900586 .withSrcMac(macAddress)
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900587 .withDstMac(NO_HOST_MAC)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900588 .withDeviceId(deviceId)
Jian Lida8867f2019-01-31 01:17:36 +0900589 .withInputInterfaceId(getInterfaceId(ipAddress))
Jian Lia4947682018-07-07 14:53:32 +0900590 .withOutputInterfaceId(ARBITRARY_OUT_INTF)
591 .withVlanId(VlanId.vlanId());
592
593 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
594 sBuilder.withStartupTime(System.currentTimeMillis())
595 .withFstPktArrTime(System.currentTimeMillis())
596 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
597 .withCurrAccPkts((int) stat.packetsSent())
598 .withCurrAccBytes(stat.bytesSent())
599 .withErrorPkts((short) stat.packetsTxErrors())
600 .withDropPkts((short) stat.packetsTxDropped());
601
602 fBuilder.withStatsInfo(sBuilder.build());
603
604 return mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
605 }
606
607 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900608 * Obtains the flow info generated from RX port.
Jian Lia4947682018-07-07 14:53:32 +0900609 *
Jian Lif8b8c7f2018-08-27 18:49:04 +0900610 * @param ipAddress IP address
611 * @param macAddress MAC address
612 * @param deviceId Device identifier
Jian Lia4947682018-07-07 14:53:32 +0900613 * @param stat port statistics
614 * @return flow info
615 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900616 private FlowInfo buildRxFlowInfo(IpAddress ipAddress,
617 MacAddress macAddress,
618 DeviceId deviceId,
619 PortStatistics stat) {
Jian Lia4947682018-07-07 14:53:32 +0900620 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
621
622 fBuilder.withFlowType(FLOW_TYPE_SONA)
623 .withSrcIp(IpPrefix.valueOf(ARBITRARY_IP))
Jian Lif8b8c7f2018-08-27 18:49:04 +0900624 .withDstIp(IpPrefix.valueOf(ipAddress, ARBITRARY_LENGTH))
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900625 .withSrcMac(NO_HOST_MAC)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900626 .withDstMac(macAddress)
627 .withDeviceId(deviceId)
Jian Lia4947682018-07-07 14:53:32 +0900628 .withInputInterfaceId(ARBITRARY_IN_INTF)
629 .withOutputInterfaceId(ARBITRARY_OUT_INTF)
630 .withVlanId(VlanId.vlanId());
631
632 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
633 sBuilder.withStartupTime(System.currentTimeMillis())
634 .withFstPktArrTime(System.currentTimeMillis())
635 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
636 .withCurrAccPkts((int) stat.packetsReceived())
637 .withCurrAccBytes(stat.bytesReceived())
638 .withErrorPkts((short) stat.packetsRxErrors())
639 .withDropPkts((short) stat.packetsRxDropped());
640
641 fBuilder.withStatsInfo(sBuilder.build());
642
643 return mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
644 }
645
646 /**
647 * Obtains instance port which associated with the given device identifier
648 * and port number.
649 *
650 * @param deviceId device identifier
651 * @param portNumber port number
652 * @return instance port
653 */
654 private InstancePort getInstancePort(DeviceId deviceId, PortNumber portNumber) {
655 return instPortService.instancePorts().stream()
656 .filter(p -> p.deviceId().equals(deviceId))
657 .filter(p -> p.portNumber().equals(portNumber))
658 .findFirst().orElse(null);
659 }
660
Jian Lif8b8c7f2018-08-27 18:49:04 +0900661 /**
662 * Installs a flow rule where the source table is fromTable, while destination
663 * table is toTable.
664 *
665 * @param deviceId device identifier
666 * @param fromTable source table
667 * @param toTable destination table
668 * @param statsFlowRule stats flow rule
669 * @param rulePriority rule priority
670 * @param install installation flag
671 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900672 private void connectTables(DeviceId deviceId, int fromTable, int toTable,
673 StatsFlowRule statsFlowRule, int rulePriority,
674 boolean install) {
675
Jian Li0bbbb1c2018-06-22 22:01:17 +0900676 int srcPrefixLength = statsFlowRule.srcIpPrefix().prefixLength();
677 int dstPrefixLength = statsFlowRule.dstIpPrefix().prefixLength();
678 int prefixLength = rulePriority + srcPrefixLength + dstPrefixLength;
679 byte protocol = statsFlowRule.ipProtocol();
680
681 TrafficSelector.Builder selectorBuilder =
Jian Li753280e2018-07-03 02:24:34 +0900682 DefaultTrafficSelector.builder()
683 .matchEthType(TYPE_IPV4)
684 .matchIPSrc(statsFlowRule.srcIpPrefix())
685 .matchIPDst(statsFlowRule.dstIpPrefix());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900686
687 if (protocol == PROTOCOL_TCP) {
688 selectorBuilder = selectorBuilder
Jian Li753280e2018-07-03 02:24:34 +0900689 .matchIPProtocol(statsFlowRule.ipProtocol())
690 .matchTcpSrc(statsFlowRule.srcTpPort())
691 .matchTcpDst(statsFlowRule.dstTpPort());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900692
693 } else if (protocol == PROTOCOL_UDP) {
694 selectorBuilder = selectorBuilder
Jian Li753280e2018-07-03 02:24:34 +0900695 .matchIPProtocol(statsFlowRule.ipProtocol())
696 .matchUdpSrc(statsFlowRule.srcTpPort())
697 .matchUdpDst(statsFlowRule.dstTpPort());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900698 } else {
699 log.warn("Unsupported protocol {}", statsFlowRule.ipProtocol());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900700 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900701
702 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
703
704 treatmentBuilder.transition(toTable);
705
706 FlowRule flowRule = DefaultFlowRule.builder()
Jian Li753280e2018-07-03 02:24:34 +0900707 .forDevice(deviceId)
708 .withSelector(selectorBuilder.build())
709 .withTreatment(treatmentBuilder.build())
710 .withPriority(prefixLength)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900711 .fromApp(telemetryAppId)
Jian Li753280e2018-07-03 02:24:34 +0900712 .makePermanent()
713 .forTable(fromTable)
714 .build();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900715
716 applyRule(flowRule, install);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900717 }
718
719 /**
Jian Li0bbbb1c2018-06-22 22:01:17 +0900720 * Installs stats related flow rule to switch.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900721 *
Jian Li0bbbb1c2018-06-22 22:01:17 +0900722 * @param flowRule flow rule
723 * @param install flag to install or not
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900724 */
725 private void applyRule(FlowRule flowRule, boolean install) {
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900726 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900727 flowOpsBuilder = install ?
728 flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900729
730 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
731 @Override
732 public void onSuccess(FlowRuleOperations ops) {
Jian Lia4947682018-07-07 14:53:32 +0900733 log.debug("Install rules for telemetry stats: \n {}",
734 ops.toString());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900735 }
736
737 @Override
738 public void onError(FlowRuleOperations ops) {
Jian Lia4947682018-07-07 14:53:32 +0900739 log.debug("Failed to install rules for telemetry stats: \n {}",
740 ops.toString());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900741 }
742 }));
743 }
744
745 /**
Jian Li0bbbb1c2018-06-22 22:01:17 +0900746 * Merges old FlowInfo.StatsInfo and current FlowInfo.StatsInfo.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900747 *
748 * @param flowInfo current FlowInfo object
749 * @param fBuilder Builder for FlowInfo
750 * @param sBuilder Builder for StatsInfo
751 * @return Merged FlowInfo object
752 */
753 private FlowInfo mergeFlowInfo(FlowInfo flowInfo,
754 FlowInfo.Builder fBuilder,
755 StatsInfo.Builder sBuilder) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900756 for (FlowInfo gFlowInfo : gFlowInfoSet) {
757 log.debug("Old FlowInfo:\n{}", gFlowInfo.toString());
758 if (gFlowInfo.roughEquals(flowInfo)) {
759
760 // Get old StatsInfo object and merge the value to current object.
761 StatsInfo oldStatsInfo = gFlowInfo.statsInfo();
762 sBuilder.withPrevAccPkts(oldStatsInfo.currAccPkts());
763 sBuilder.withPrevAccBytes(oldStatsInfo.currAccBytes());
764 FlowInfo newFlowInfo = fBuilder.withStatsInfo(sBuilder.build())
765 .build();
766
767 gFlowInfoSet.remove(gFlowInfo);
768 gFlowInfoSet.add(newFlowInfo);
Jian Li85573f42018-06-27 22:29:14 +0900769 log.debug("Old FlowInfo found, Merge this {}", newFlowInfo.toString());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900770 return newFlowInfo;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900771 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900772 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900773
774 // No such record, then build the FlowInfo object and return this object.
Jian Li85573f42018-06-27 22:29:14 +0900775 log.debug("No FlowInfo found, add new FlowInfo {}", flowInfo.toString());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900776 FlowInfo newFlowInfo = fBuilder.withStatsInfo(sBuilder.build()).build();
777 gFlowInfoSet.add(newFlowInfo);
778 return newFlowInfo;
779 }
780
Jian Li753280e2018-07-03 02:24:34 +0900781 /**
782 * Installs flow rules for collecting both normal and reverse path flow stats.
783 *
784 * @param statsFlowRule flow rule used for collecting stats
785 * @param install flow rule installation flag
786 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900787 private void setStatFlowRule(StatsFlowRule statsFlowRule, boolean install) {
Jian Li753280e2018-07-03 02:24:34 +0900788 setStatFlowRuleBase(statsFlowRule, install);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900789
Jian Li753280e2018-07-03 02:24:34 +0900790 // if reverse path stats is enabled, we will install flow rules for
791 // collecting reverse path vFlow stats
792 if (reversePathStats) {
793 StatsFlowRule reverseFlowRule = DefaultStatsFlowRule.builder()
794 .srcIpPrefix(statsFlowRule.dstIpPrefix())
795 .dstIpPrefix(statsFlowRule.srcIpPrefix())
796 .ipProtocol(statsFlowRule.ipProtocol())
797 .srcTpPort(statsFlowRule.dstTpPort())
798 .dstTpPort(statsFlowRule.srcTpPort())
799 .build();
800 setStatFlowRuleBase(reverseFlowRule, install);
801 }
802 }
803
804 /**
805 * A base method which is for installing flow rules for collecting stats.
806 *
807 * @param statsFlowRule flow rule used for collecting stats
808 * @param install flow rule installation flag
809 */
810 private void setStatFlowRuleBase(StatsFlowRule statsFlowRule, boolean install) {
Jian Lie6110b72018-07-06 19:06:36 +0900811
812 IpPrefix srcIp = statsFlowRule.srcIpPrefix();
813 IpPrefix dstIp = statsFlowRule.dstIpPrefix();
814 DeviceId srcDeviceId = getDeviceId(srcIp.address());
815 DeviceId dstDeviceId = getDeviceId(dstIp.address());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900816
Jian Li998ec7b2018-06-29 15:15:49 +0900817 if (srcDeviceId == null && dstDeviceId == null) {
Jian Li85573f42018-06-27 22:29:14 +0900818 return;
819 }
820
Jian Li998ec7b2018-06-29 15:15:49 +0900821 if (srcDeviceId != null) {
Jian Li87ded822018-07-02 18:31:22 +0900822 connectTables(srcDeviceId, STAT_INBOUND_TABLE, VTAP_INBOUND_TABLE,
Jian Li998ec7b2018-06-29 15:15:49 +0900823 statsFlowRule, METRIC_PRIORITY_SOURCE, install);
Jian Li998ec7b2018-06-29 15:15:49 +0900824
Jian Lie6110b72018-07-06 19:06:36 +0900825 if (install) {
826 log.info("Install ingress stat flow rule for SrcIp:{} DstIp:{}",
827 srcIp.toString(), dstIp.toString());
828 } else {
829 log.info("Remove ingress stat flow rule for SrcIp:{} DstIp:{}",
830 srcIp.toString(), dstIp.toString());
Jian Li753280e2018-07-03 02:24:34 +0900831 }
Jian Li998ec7b2018-06-29 15:15:49 +0900832 }
Jian Li85573f42018-06-27 22:29:14 +0900833
Jian Lie6110b72018-07-06 19:06:36 +0900834 Set<IpPrefix> vxlanIps = osNetworkService.getFixedIpsByNetworkType(VXLAN);
835 Set<IpPrefix> vlanIps = osNetworkService.getFixedIpsByNetworkType(VLAN);
836 Set<IpPrefix> flatIps = osNetworkService.getFixedIpsByNetworkType(FLAT);
Jian Li753280e2018-07-03 02:24:34 +0900837
Jian Lie6110b72018-07-06 19:06:36 +0900838 int fromTable, toTable;
Jian Li753280e2018-07-03 02:24:34 +0900839
Jian Lie6110b72018-07-06 19:06:36 +0900840 if (dstDeviceId != null && egressStats) {
841
842 IpPrefix dstIpPrefix = statsFlowRule.dstIpPrefix();
843
844 if (vxlanIps.contains(dstIpPrefix) || vlanIps.contains(dstIpPrefix)) {
845 fromTable = STAT_OUTBOUND_TABLE;
846 toTable = VTAP_OUTBOUND_TABLE;
847 } else if (flatIps.contains(dstIpPrefix)) {
848 fromTable = STAT_FLAT_OUTBOUND_TABLE;
849 toTable = VTAP_FLAT_OUTBOUND_TABLE;
850 } else {
851 return;
852 }
853
854 connectTables(dstDeviceId, fromTable, toTable,
855 statsFlowRule, METRIC_PRIORITY_TARGET, install);
856
857 if (install) {
858 log.info("Install egress stat flow rule for SrcIp:{} DstIp:{}",
859 srcIp.toString(), dstIp.toString());
860 } else {
861 log.info("Remove egress stat flow rule for SrcIp:{} DstIp:{}",
862 srcIp.toString(), dstIp.toString());
863 }
Jian Li753280e2018-07-03 02:24:34 +0900864 }
Jian Li753280e2018-07-03 02:24:34 +0900865 }
866
867 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900868 * Gets Device ID which the VM is located.
Jian Li85573f42018-06-27 22:29:14 +0900869 *
870 * @param ipAddress IP Address of host
871 * @return Device ID
872 */
873 private DeviceId getDeviceId(IpAddress ipAddress) {
874 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
875 Optional<Host> host = hostService.getHostsByIp(ipAddress).stream().findAny();
876 return host.map(host1 -> host1.location().deviceId()).orElse(null);
877 } else {
Jian Lia4947682018-07-07 14:53:32 +0900878 log.debug("No DeviceID is associated to {}", ipAddress.toString());
Jian Li85573f42018-06-27 22:29:14 +0900879 return null;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900880 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900881 }
882
883 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900884 * Gets VLAN ID with respect to IP Address.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900885 *
886 * @param ipAddress IP Address of host
887 * @return VLAN ID
888 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900889 private VlanId getVlanId(IpAddress ipAddress) {
890 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
891 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
892 return host.vlan();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900893 }
894 return VlanId.vlanId();
895 }
896
897 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900898 * Gets Interface ID of Switch which is connected to a host.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900899 *
900 * @param ipAddress IP Address of host
901 * @return Interface ID of Switch
902 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900903 private int getInterfaceId(IpAddress ipAddress) {
904 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
905 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
906 return (int) host.location().port().toLong();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900907 }
908 return -1;
909 }
910
911 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900912 * Gets MAC Address of host.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900913 *
914 * @param ipAddress IP Address of host
915 * @return MAC Address of host
916 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900917 private MacAddress getMacAddress(IpAddress ipAddress) {
918 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
919 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
920 return host.mac();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900921 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900922
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900923 return NO_HOST_MAC;
924 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900925
Jian Lif8b8c7f2018-08-27 18:49:04 +0900926 /**
927 * Gets IP address of the host which is attached to the given device and port.
928 *
929 * @param device device
930 * @param inPort IN port number
931 * @return IP address
932 */
933 private IpAddress getIpAddress(Device device, PortCriterion inPort) {
934
935 Host host = hostService.getConnectedHosts(device.id()).stream()
936 .filter(h -> h.location().port().equals(inPort.port()))
937 .findAny().orElse(null);
938
939 if (host != null) {
940 return host.ipAddresses().stream().findAny().get();
941 }
942
943 return NO_HOST_IP;
944 }
945
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900946 private void enqFlowInfo(FlowInfo flowInfo) {
947 String key = flowInfo.uniqueFlowInfoKey();
948 Queue<FlowInfo> queue = flowInfoMap.get(key);
949 if (queue == null) {
950 Queue<FlowInfo> newQueue = new LinkedList<FlowInfo>();
951 newQueue.offer(flowInfo);
952 flowInfoMap.put(key, newQueue);
953 return;
954 }
955 queue.offer(flowInfo);
956
957 while (queue.size() > DEFAULT_DATA_POINT_SIZE) {
958 queue.remove(); // Removes a garbage data in the queue.
959 }
960 }
961
Jian Lif8b8c7f2018-08-27 18:49:04 +0900962 /**
963 * Checks whether the given device is edge switch or not.
964 *
965 * @param id device identifier
966 * @return true if the given device is edge switch, false otherwise
967 */
968 private boolean isEdgeSwitch(DeviceId id) {
969
970 return !hostService.getConnectedHosts(id).isEmpty();
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900971 }
972
Jian Li753280e2018-07-03 02:24:34 +0900973 /**
974 * Extracts properties from the component configuration context.
975 *
976 * @param context the component context
977 */
978 private void readComponentConfiguration(ComponentContext context) {
979 Dictionary<?, ?> properties = context.getProperties();
980
981 Boolean reversePathStatsConfigured =
Ray Milkey8e406512018-10-24 15:56:50 -0700982 getBooleanProperty(properties, PROP_REVERSE_PATH_STATS);
Jian Li753280e2018-07-03 02:24:34 +0900983 if (reversePathStatsConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -0700984 reversePathStats = PROP_REVERSE_PATH_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900985 log.info("Reversed path stats flag is NOT " +
986 "configured, default value is {}", reversePathStats);
987 } else {
988 reversePathStats = reversePathStatsConfigured;
989 log.info("Configured. Reversed path stats flag is {}", reversePathStats);
990 }
991
Ray Milkey8e406512018-10-24 15:56:50 -0700992 Boolean egressStatsConfigured = getBooleanProperty(properties, PROP_EGRESS_STATS);
Jian Li753280e2018-07-03 02:24:34 +0900993 if (egressStatsConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -0700994 egressStats = PROP_EGRESS_STATS_DEFAULT;
Jian Li753280e2018-07-03 02:24:34 +0900995 log.info("Egress stats flag is NOT " +
996 "configured, default value is {}", egressStats);
997 } else {
998 egressStats = egressStatsConfigured;
999 log.info("Configured. Egress stats flag is {}", egressStats);
1000 }
Jian Lia4947682018-07-07 14:53:32 +09001001
Ray Milkey8e406512018-10-24 15:56:50 -07001002 Boolean portStatsConfigured = getBooleanProperty(properties, PROP_PORT_STATS);
Jian Lia4947682018-07-07 14:53:32 +09001003 if (portStatsConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -07001004 portStats = PROP_PORT_STATS_DEFAULT;
Jian Lia4947682018-07-07 14:53:32 +09001005 log.info("Port stats flag is NOT " +
1006 "configured, default value is {}", portStats);
1007 } else {
1008 portStats = portStatsConfigured;
1009 log.info("Configured. Port stats flag is {}", portStats);
1010 }
Jian Lif8b8c7f2018-08-27 18:49:04 +09001011
Ray Milkey8e406512018-10-24 15:56:50 -07001012 Boolean monitorOverlayConfigured = getBooleanProperty(properties, PROP_MONITOR_OVERLAY);
Jian Lif8b8c7f2018-08-27 18:49:04 +09001013 if (monitorOverlayConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -07001014 monitorOverlay = PROP_MONITOR_OVERLAY_DEFAULT;
Jian Lif8b8c7f2018-08-27 18:49:04 +09001015 log.info("Monitor overlay flag is NOT " +
1016 "configured, default value is {}", monitorOverlay);
1017 } else {
1018 monitorOverlay = monitorOverlayConfigured;
1019 log.info("Configured. Monitor overlay flag is {}", monitorOverlay);
1020 }
1021
Ray Milkey8e406512018-10-24 15:56:50 -07001022 Boolean monitorUnderlayConfigured = getBooleanProperty(properties, PROP_MONITOR_UNDERLAY);
Jian Lif8b8c7f2018-08-27 18:49:04 +09001023 if (monitorUnderlayConfigured == null) {
Ray Milkey8e406512018-10-24 15:56:50 -07001024 monitorUnderlay = PROP_MONITOR_UNDERLAY_DEFAULT;
Jian Lif8b8c7f2018-08-27 18:49:04 +09001025 log.info("Monitor underlay flag is NOT " +
1026 "configured, default value is {}", monitorUnderlay);
1027 } else {
1028 monitorUnderlay = monitorUnderlayConfigured;
1029 log.info("Configured. Monitor underlay flag is {}", monitorUnderlay);
1030 }
Jian Li753280e2018-07-03 02:24:34 +09001031 }
1032
Jian Lia4947682018-07-07 14:53:32 +09001033 private class TelemetryCollector implements Runnable {
Jian Li0bbbb1c2018-06-22 22:01:17 +09001034 @Override
1035 public void run() {
Jian Lif8b8c7f2018-08-27 18:49:04 +09001036 Set<FlowInfo> filteredOverlayFlowInfos = Sets.newConcurrentHashSet();
1037 Set<FlowInfo> filteredUnderlayFlowInfos = Sets.newConcurrentHashSet();
Jian Li85573f42018-06-27 22:29:14 +09001038
1039 // we only let the master controller of the device where the
Jian Lia4947682018-07-07 14:53:32 +09001040 // stats flow rules are installed send stats message
Jian Lif8b8c7f2018-08-27 18:49:04 +09001041 if (monitorOverlay) {
1042 getOverlayFlowInfos().forEach(f -> {
Jian Lia4947682018-07-07 14:53:32 +09001043 if (checkSrcDstLocalMaster(f)) {
Jian Lif8b8c7f2018-08-27 18:49:04 +09001044 filteredOverlayFlowInfos.add(f);
1045 }
1046 });
1047 }
1048 if (monitorUnderlay) {
1049 getUnderlayFlowInfos().forEach(f -> {
1050 if (checkSrcDstLocalMaster(f)) {
1051 filteredUnderlayFlowInfos.add(f);
Jian Lia4947682018-07-07 14:53:32 +09001052 }
1053 });
Jian Li0bbbb1c2018-06-22 22:01:17 +09001054 }
Jian Lia4947682018-07-07 14:53:32 +09001055
Jian Lif8b8c7f2018-08-27 18:49:04 +09001056 // we only let the master controller of the device where the port
1057 // is located to send stats message
1058 if (portStats) {
1059 if (monitorOverlay) {
1060 getOverlayDstPortBasedFlowInfos().forEach(f -> {
1061 if (checkSrcDstLocalMaster(f)) {
1062 filteredOverlayFlowInfos.add(f);
1063 }
1064 });
1065 }
Boyoung Jeong1cca5e82018-08-01 21:00:08 +09001066
Jian Lif8b8c7f2018-08-27 18:49:04 +09001067 if (monitorUnderlay) {
1068 getUnderlayDstPortBasedFlowInfos().forEach(f -> {
1069 if (checkSrcDstLocalMaster(f)) {
1070 filteredUnderlayFlowInfos.add(f);
1071 }
1072 });
1073 }
1074 }
1075
1076
1077 if (monitorOverlay) {
1078 telemetryService.publish(filteredOverlayFlowInfos);
1079
1080 // TODO: Refactor the following code to "TelemetryService" style.
1081 filteredOverlayFlowInfos.forEach(StatsFlowRuleManager.this::enqFlowInfo);
1082 }
1083
1084 if (monitorUnderlay) {
1085 telemetryService.publish(filteredUnderlayFlowInfos);
1086 }
Jian Lia4947682018-07-07 14:53:32 +09001087 }
1088
1089 private boolean checkSrcDstLocalMaster(FlowInfo info) {
1090 DeviceId srcDeviceId = getDeviceId(info.srcIp().address());
1091 DeviceId dstDeviceId = getDeviceId(info.dstIp().address());
1092
1093 boolean isSrcLocalMaster = srcDeviceId != null &&
1094 mastershipService.isLocalMaster(srcDeviceId);
1095 boolean isDstLocalMaster = dstDeviceId != null &&
1096 mastershipService.isLocalMaster(dstDeviceId);
1097
1098 return isSrcLocalMaster || isDstLocalMaster;
Jian Li0bbbb1c2018-06-22 22:01:17 +09001099 }
1100 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +09001101}