blob: 760fd8630a93ee9561607a14bbb9c3f0ba414c19 [file] [log] [blame]
Boyoung Jeong9e8faec2018-06-17 21:19:23 +09001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacktelemetry.impl;
17
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090018import com.google.common.collect.Maps;
Jian Li0bbbb1c2018-06-22 22:01:17 +090019import com.google.common.collect.Sets;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
Jian Li753280e2018-07-03 02:24:34 +090023import org.apache.felix.scr.annotations.Modified;
24import org.apache.felix.scr.annotations.Property;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090025import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.apache.felix.scr.annotations.Service;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090028import org.onlab.packet.IpAddress;
Jian Li753280e2018-07-03 02:24:34 +090029import org.onlab.packet.IpPrefix;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090030import org.onlab.packet.MacAddress;
31import org.onlab.packet.VlanId;
Jian Lia4947682018-07-07 14:53:32 +090032import org.onlab.util.SharedScheduledExecutors;
Jian Lie6110b72018-07-06 19:06:36 +090033import org.onosproject.cfg.ComponentConfigService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090034import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
Jian Li85573f42018-06-27 22:29:14 +090036import org.onosproject.mastership.MastershipService;
Jian Lif8b8c7f2018-08-27 18:49:04 +090037import org.onosproject.net.ConnectPoint;
38import org.onosproject.net.Device;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090039import org.onosproject.net.DeviceId;
40import org.onosproject.net.Host;
Jian Lia4947682018-07-07 14:53:32 +090041import org.onosproject.net.PortNumber;
42import org.onosproject.net.device.DeviceService;
43import org.onosproject.net.device.PortStatistics;
Jian Lif8b8c7f2018-08-27 18:49:04 +090044import org.onosproject.net.driver.Driver;
45import org.onosproject.net.driver.DriverService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090046import org.onosproject.net.flow.DefaultFlowRule;
47import org.onosproject.net.flow.DefaultTrafficSelector;
48import org.onosproject.net.flow.DefaultTrafficTreatment;
49import org.onosproject.net.flow.FlowEntry;
50import org.onosproject.net.flow.FlowRule;
51import org.onosproject.net.flow.FlowRuleOperations;
52import org.onosproject.net.flow.FlowRuleOperationsContext;
53import org.onosproject.net.flow.FlowRuleService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090054import org.onosproject.net.flow.TrafficSelector;
55import org.onosproject.net.flow.TrafficTreatment;
Jian Lif8b8c7f2018-08-27 18:49:04 +090056import org.onosproject.net.flow.criteria.Criterion;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090057import org.onosproject.net.flow.criteria.IPCriterion;
58import org.onosproject.net.flow.criteria.IPProtocolCriterion;
Jian Lif8b8c7f2018-08-27 18:49:04 +090059import org.onosproject.net.flow.criteria.PortCriterion;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090060import org.onosproject.net.flow.criteria.TcpPortCriterion;
61import org.onosproject.net.flow.criteria.UdpPortCriterion;
62import org.onosproject.net.host.HostService;
Jian Lia4947682018-07-07 14:53:32 +090063import org.onosproject.openstacknetworking.api.InstancePort;
64import org.onosproject.openstacknetworking.api.InstancePortService;
Jian Li753280e2018-07-03 02:24:34 +090065import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lia4947682018-07-07 14:53:32 +090066import org.onosproject.openstacknode.api.OpenstackNode;
67import org.onosproject.openstacknode.api.OpenstackNodeService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090068import org.onosproject.openstacktelemetry.api.FlowInfo;
Jian Li0bbbb1c2018-06-22 22:01:17 +090069import org.onosproject.openstacktelemetry.api.OpenstackTelemetryService;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090070import org.onosproject.openstacktelemetry.api.StatsFlowRule;
71import org.onosproject.openstacktelemetry.api.StatsFlowRuleAdminService;
72import org.onosproject.openstacktelemetry.api.StatsInfo;
Jian Li753280e2018-07-03 02:24:34 +090073import org.osgi.service.component.ComponentContext;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090074import org.slf4j.Logger;
75import org.slf4j.LoggerFactory;
76
Jian Lif8b8c7f2018-08-27 18:49:04 +090077import java.util.ArrayList;
Jian Li753280e2018-07-03 02:24:34 +090078import java.util.Dictionary;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090079import java.util.LinkedList;
Jian Lia4947682018-07-07 14:53:32 +090080import java.util.List;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090081import java.util.Map;
Jian Li85573f42018-06-27 22:29:14 +090082import java.util.Optional;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090083import java.util.Queue;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090084import java.util.Set;
Jian Lia4947682018-07-07 14:53:32 +090085import java.util.concurrent.ScheduledFuture;
86import java.util.concurrent.TimeUnit;
87import java.util.stream.Collectors;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +090088
Jian Li0bbbb1c2018-06-22 22:01:17 +090089import static org.onlab.packet.Ethernet.TYPE_IPV4;
90import static org.onlab.packet.IPv4.PROTOCOL_TCP;
91import static org.onlab.packet.IPv4.PROTOCOL_UDP;
Jian Lif8b8c7f2018-08-27 18:49:04 +090092import static org.onosproject.net.Device.Type.SWITCH;
Jian Li0bbbb1c2018-06-22 22:01:17 +090093import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
94import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC;
95import static org.onosproject.net.flow.criteria.Criterion.Type.IP_PROTO;
96import static org.onosproject.net.flow.criteria.Criterion.Type.TCP_DST;
97import static org.onosproject.net.flow.criteria.Criterion.Type.TCP_SRC;
98import static org.onosproject.net.flow.criteria.Criterion.Type.UDP_DST;
99import static org.onosproject.net.flow.criteria.Criterion.Type.UDP_SRC;
Jian Li753280e2018-07-03 02:24:34 +0900100import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900101import static org.onosproject.openstacknetworking.api.Constants.STAT_INBOUND_TABLE;
102import static org.onosproject.openstacknetworking.api.Constants.STAT_OUTBOUND_TABLE;
Jian Li753280e2018-07-03 02:24:34 +0900103import static org.onosproject.openstacknetworking.api.Constants.VTAP_FLAT_OUTBOUND_TABLE;
Jian Li87ded822018-07-02 18:31:22 +0900104import static org.onosproject.openstacknetworking.api.Constants.VTAP_INBOUND_TABLE;
105import static org.onosproject.openstacknetworking.api.Constants.VTAP_OUTBOUND_TABLE;
Jian Lia4947682018-07-07 14:53:32 +0900106import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Jian Lif8b8c7f2018-08-27 18:49:04 +0900107import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900108import static org.onosproject.openstacktelemetry.api.Constants.DEFAULT_DATA_POINT_SIZE;
Jian Lie6110b72018-07-06 19:06:36 +0900109import static org.onosproject.openstacktelemetry.api.Constants.FLAT;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900110import static org.onosproject.openstacktelemetry.api.Constants.OPENSTACK_TELEMETRY_APP_ID;
Jian Lie6110b72018-07-06 19:06:36 +0900111import static org.onosproject.openstacktelemetry.api.Constants.VLAN;
112import static org.onosproject.openstacktelemetry.api.Constants.VXLAN;
Jian Li753280e2018-07-03 02:24:34 +0900113import static org.onosproject.openstacktelemetry.util.OpenstackTelemetryUtil.getBooleanProperty;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900114
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900115/**
116 * Flow rule manager for network statistics of a VM.
117 */
118@Component(immediate = true)
119@Service
120public class StatsFlowRuleManager implements StatsFlowRuleAdminService {
121
122 private final Logger log = LoggerFactory.getLogger(getClass());
123
124 private static final byte FLOW_TYPE_SONA = 1; // VLAN
125
Ray Milkeybcc53d32018-07-02 10:22:57 -0700126 private static final long MILLISECONDS = 1000L;
Jian Lia4947682018-07-07 14:53:32 +0900127 private static final long INITIAL_DELAY = 5L;
Ray Milkeybcc53d32018-07-02 10:22:57 -0700128 private static final long REFRESH_INTERVAL = 5L;
Jian Lia4947682018-07-07 14:53:32 +0900129 private static final TimeUnit TIME_UNIT_SECOND = TimeUnit.SECONDS;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900130
Jian Li753280e2018-07-03 02:24:34 +0900131 private static final String REVERSE_PATH_STATS = "reversePathStats";
132 private static final String EGRESS_STATS = "egressStats";
Jian Lia4947682018-07-07 14:53:32 +0900133 private static final String PORT_STATS = "portStats";
Jian Li753280e2018-07-03 02:24:34 +0900134
Jian Lif8b8c7f2018-08-27 18:49:04 +0900135 private static final String MONITOR_OVERLAY = "monitorOverlay";
136 private static final String MONITOR_UNDERLAY = "monitorUnderlay";
137
138 private static final String OVS_DRIVER_NAME = "ovs";
139
Jian Li753280e2018-07-03 02:24:34 +0900140 private static final boolean DEFAULT_REVERSE_PATH_STATS = false;
141 private static final boolean DEFAULT_EGRESS_STATS = false;
Jian Lia4947682018-07-07 14:53:32 +0900142 private static final boolean DEFAULT_PORT_STATS = true;
Jian Li753280e2018-07-03 02:24:34 +0900143
Jian Lif8b8c7f2018-08-27 18:49:04 +0900144 private static final boolean DEFAULT_MONITOR_OVERLAY = true;
145 private static final boolean DEFAULT_MONITOR_UNDERLAY = true;
146
Jian Lia4947682018-07-07 14:53:32 +0900147 private static final String ARBITRARY_IP = "0.0.0.0/32";
148 private static final int ARBITRARY_LENGTH = 32;
149 private static final String ARBITRARY_MAC = "00:00:00:00:00:00";
Jian Lif8b8c7f2018-08-27 18:49:04 +0900150 private static final IpAddress NO_HOST_IP = IpAddress.valueOf("255.255.255.255");
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900151 private static final MacAddress NO_HOST_MAC = MacAddress.valueOf(ARBITRARY_MAC);
Jian Lia4947682018-07-07 14:53:32 +0900152 private static final int ARBITRARY_IN_INTF = 0;
153 private static final int ARBITRARY_OUT_INTF = 0;
154
155 private static final boolean RECOVER_FROM_FAILURE = true;
156
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900157 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
158 protected CoreService coreService;
159
160 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
161 protected FlowRuleService flowRuleService;
162
163 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
164 protected HostService hostService;
165
Jian Li0bbbb1c2018-06-22 22:01:17 +0900166 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lia4947682018-07-07 14:53:32 +0900167 protected DeviceService deviceService;
168
169 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900170 protected DriverService driverService;
171
172 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lie6110b72018-07-06 19:06:36 +0900173 protected ComponentConfigService componentConfigService;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900174
175 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li85573f42018-06-27 22:29:14 +0900176 protected MastershipService mastershipService;
177
178 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li753280e2018-07-03 02:24:34 +0900179 protected OpenstackNetworkService osNetworkService;
180
181 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lia4947682018-07-07 14:53:32 +0900182 protected InstancePortService instPortService;
183
184 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
185 protected OpenstackNodeService osNodeService;
186
187 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li0bbbb1c2018-06-22 22:01:17 +0900188 protected OpenstackTelemetryService telemetryService;
189
Jian Li753280e2018-07-03 02:24:34 +0900190 @Property(name = REVERSE_PATH_STATS, boolValue = DEFAULT_REVERSE_PATH_STATS,
191 label = "A flag which indicates whether to install the rules for " +
192 "collecting the flow-based stats for reversed path.")
193 private boolean reversePathStats = DEFAULT_REVERSE_PATH_STATS;
194
195 @Property(name = EGRESS_STATS, boolValue = DEFAULT_EGRESS_STATS,
196 label = "A flag which indicates whether to install the rules for " +
197 "collecting the flow-based stats for egress port.")
198 private boolean egressStats = DEFAULT_EGRESS_STATS;
199
Jian Lia4947682018-07-07 14:53:32 +0900200 @Property(name = PORT_STATS, boolValue = DEFAULT_PORT_STATS,
201 label = "A flag which indicates whether to collect port TX & RX stats.")
202 private boolean portStats = DEFAULT_PORT_STATS;
203
Jian Lif8b8c7f2018-08-27 18:49:04 +0900204 @Property(name = MONITOR_OVERLAY, boolValue = DEFAULT_MONITOR_OVERLAY,
205 label = "A flag which indicates whether to monitor overlay network port stats.")
206 private boolean monitorOverlay = DEFAULT_MONITOR_OVERLAY;
207
208 @Property(name = MONITOR_UNDERLAY, boolValue = DEFAULT_MONITOR_UNDERLAY,
209 label = "A flag which indicates whether to monitor underlay network port stats.")
210 private boolean monitorUnderlay = DEFAULT_MONITOR_UNDERLAY;
211
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
269 public void createStatFlowRule(StatsFlowRule statsFlowRule) {
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900270
Jian Li0bbbb1c2018-06-22 22:01:17 +0900271 setStatFlowRule(statsFlowRule, true);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900272 }
273
274 @Override
275 public void deleteStatFlowRule(StatsFlowRule statsFlowRule) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900276
277 setStatFlowRule(statsFlowRule, false);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900278 }
279
Jian Lif8b8c7f2018-08-27 18:49:04 +0900280
Jian Lia4947682018-07-07 14:53:32 +0900281 @Override
Jian Lif8b8c7f2018-08-27 18:49:04 +0900282 public Map<String, Queue<FlowInfo>> getFlowInfoMap() {
283 return flowInfoMap;
284 }
285
286
287 @Override
288 public Set<FlowInfo> getUnderlayFlowInfos() {
289
290 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
291
292 for (Device device : getUnderlayDevices()) {
293
294 if (!isEdgeSwitch(device.id())) {
295 continue;
296 }
297
298 for (FlowEntry entry : flowRuleService.getFlowEntries(device.id())) {
299 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
300 TrafficSelector selector = entry.selector();
301 Criterion inPort = selector.getCriterion(Criterion.Type.IN_PORT);
302 Criterion dstIpCriterion = selector.getCriterion(Criterion.Type.IPV4_DST);
303 if (inPort != null && dstIpCriterion != null) {
304 IpAddress srcIp = getIpAddress(device, (PortCriterion) inPort);
305 IpAddress dstIp = ((IPCriterion) dstIpCriterion).ip().address();
306
307 if (srcIp == null) {
308 continue;
309 }
310
311 fBuilder.withFlowType(FLOW_TYPE_SONA)
312 .withSrcIp(IpPrefix.valueOf(srcIp, ARBITRARY_LENGTH))
313 .withDstIp(IpPrefix.valueOf(dstIp, ARBITRARY_LENGTH))
314 .withSrcMac(getMacAddress(srcIp))
315 .withDstMac(getMacAddress(dstIp))
316 .withInputInterfaceId(getInterfaceId(srcIp))
317 .withOutputInterfaceId(getInterfaceId(dstIp))
318 .withDeviceId(entry.deviceId());
319
320 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
321
322 sBuilder.withStartupTime(System.currentTimeMillis())
323 .withFstPktArrTime(System.currentTimeMillis())
324 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
325 .withCurrAccPkts((int) entry.packets())
326 .withCurrAccBytes(entry.bytes())
327 .withErrorPkts((short) 0)
328 .withDropPkts((short) 0);
329
330 fBuilder.withStatsInfo(sBuilder.build());
331
332 FlowInfo flowInfo = mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
333
334 flowInfos.add(flowInfo);
335 }
336 }
337 }
338
339 return flowInfos;
340 }
341
342 @Override
343 public Set<FlowInfo> getOverlayFlowInfos() {
344
Jian Lia4947682018-07-07 14:53:32 +0900345 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
346
347 // obtain all flow rule entries installed by telemetry app
Jian Lif8b8c7f2018-08-27 18:49:04 +0900348 for (FlowEntry entry : flowRuleService.getFlowEntriesById(telemetryAppId)) {
Jian Lia4947682018-07-07 14:53:32 +0900349 FlowInfo.Builder fBuilder = new DefaultFlowInfo.DefaultBuilder();
350 TrafficSelector selector = entry.selector();
Jian Lia4947682018-07-07 14:53:32 +0900351 IPCriterion srcIp = (IPCriterion) selector.getCriterion(IPV4_SRC);
352 IPCriterion dstIp = (IPCriterion) selector.getCriterion(IPV4_DST);
353 IPProtocolCriterion ipProtocol =
354 (IPProtocolCriterion) selector.getCriterion(IP_PROTO);
355
Jian Lia4947682018-07-07 14:53:32 +0900356 fBuilder.withFlowType(FLOW_TYPE_SONA)
357 .withSrcIp(srcIp.ip())
358 .withDstIp(dstIp.ip());
359
360 if (ipProtocol != null) {
361 fBuilder.withProtocol((byte) ipProtocol.protocol());
362
363 if (ipProtocol.protocol() == PROTOCOL_TCP) {
364 TcpPortCriterion tcpSrc =
365 (TcpPortCriterion) selector.getCriterion(TCP_SRC);
366 TcpPortCriterion tcpDst =
367 (TcpPortCriterion) selector.getCriterion(TCP_DST);
Jian Lia4947682018-07-07 14:53:32 +0900368 fBuilder.withSrcPort(tcpSrc.tcpPort());
369 fBuilder.withDstPort(tcpDst.tcpPort());
Jian Lia4947682018-07-07 14:53:32 +0900370 } else if (ipProtocol.protocol() == PROTOCOL_UDP) {
Jian Lia4947682018-07-07 14:53:32 +0900371 UdpPortCriterion udpSrc =
372 (UdpPortCriterion) selector.getCriterion(UDP_SRC);
373 UdpPortCriterion udpDst =
374 (UdpPortCriterion) selector.getCriterion(UDP_DST);
Jian Lia4947682018-07-07 14:53:32 +0900375 fBuilder.withSrcPort(udpSrc.udpPort());
376 fBuilder.withDstPort(udpDst.udpPort());
377 } else {
378 log.debug("Other protocol: {}", ipProtocol.protocol());
379 }
380 }
381
382 fBuilder.withSrcMac(getMacAddress(srcIp.ip().address()))
383 .withDstMac(getMacAddress(dstIp.ip().address()))
384 .withInputInterfaceId(getInterfaceId(srcIp.ip().address()))
385 .withOutputInterfaceId(getInterfaceId(dstIp.ip().address()))
386 .withVlanId(getVlanId(srcIp.ip().address()))
387 .withDeviceId(entry.deviceId());
388
389 StatsInfo.Builder sBuilder = new DefaultStatsInfo.DefaultBuilder();
390
Jian Lia4947682018-07-07 14:53:32 +0900391 sBuilder.withStartupTime(System.currentTimeMillis())
392 .withFstPktArrTime(System.currentTimeMillis())
393 .withLstPktOffset((int) (REFRESH_INTERVAL * MILLISECONDS))
394 .withCurrAccPkts((int) entry.packets())
395 .withCurrAccBytes(entry.bytes())
396 .withErrorPkts((short) 0)
397 .withDropPkts((short) 0);
398
399 fBuilder.withStatsInfo(sBuilder.build());
400
401 FlowInfo flowInfo = mergeFlowInfo(fBuilder.build(), fBuilder, sBuilder);
402
403 flowInfos.add(flowInfo);
404
405 log.debug("FlowInfo: \n{}", flowInfo.toString());
406 }
407
408 return flowInfos;
409 }
410
411 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900412 * Gets a set of flow infos by referring to overlay destination VM port.
Jian Lia4947682018-07-07 14:53:32 +0900413 *
414 * @return flow infos
415 */
Jian Lif8b8c7f2018-08-27 18:49:04 +0900416 private Set<FlowInfo> getOverlayDstPortBasedFlowInfos() {
Jian Lia4947682018-07-07 14:53:32 +0900417 Set<FlowInfo> flowInfos = Sets.newConcurrentHashSet();
418 Set<PortNumber> instPortNums = instPortService.instancePorts()
419 .stream()
420 .map(InstancePort::portNumber)
421 .collect(Collectors.toSet());
422 Set<DeviceId> deviceIds = osNodeService.completeNodes(COMPUTE)
423 .stream()
424 .map(OpenstackNode::intgBridge)
425 .collect(Collectors.toSet());
426
427 deviceIds.forEach(d -> {
428 List<PortStatistics> stats =
429 deviceService.getPortStatistics(d)
430 .stream()
431 .filter(s -> instPortNums.contains(s.portNumber()))
432 .collect(Collectors.toList());
433
434 stats.forEach(s -> {
435 InstancePort instPort = getInstancePort(d, s.portNumber());
Jian Lif8b8c7f2018-08-27 18:49:04 +0900436 flowInfos.add(buildTxFlowInfoFromInstancePort(instPort, s));
437 flowInfos.add(buildRxFlowInfoFromInstancePort(instPort, s));
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 Lia4947682018-07-07 14:53:32 +0900590 .withInputInterfaceId(ARBITRARY_IN_INTF)
591 .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 Li0bbbb1c2018-06-22 22:01:17 +0900699 } else {
700 log.warn("Unsupported protocol {}", statsFlowRule.ipProtocol());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900701 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900702
703 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
704
705 treatmentBuilder.transition(toTable);
706
707 FlowRule flowRule = DefaultFlowRule.builder()
Jian Li753280e2018-07-03 02:24:34 +0900708 .forDevice(deviceId)
709 .withSelector(selectorBuilder.build())
710 .withTreatment(treatmentBuilder.build())
711 .withPriority(prefixLength)
Jian Lif8b8c7f2018-08-27 18:49:04 +0900712 .fromApp(telemetryAppId)
Jian Li753280e2018-07-03 02:24:34 +0900713 .makePermanent()
714 .forTable(fromTable)
715 .build();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900716
717 applyRule(flowRule, install);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900718 }
719
720 /**
Jian Li0bbbb1c2018-06-22 22:01:17 +0900721 * Installs stats related flow rule to switch.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900722 *
Jian Li0bbbb1c2018-06-22 22:01:17 +0900723 * @param flowRule flow rule
724 * @param install flag to install or not
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900725 */
726 private void applyRule(FlowRule flowRule, boolean install) {
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900727 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
Jian Li0bbbb1c2018-06-22 22:01:17 +0900728 flowOpsBuilder = install ?
729 flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900730
731 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
732 @Override
733 public void onSuccess(FlowRuleOperations ops) {
Jian Lia4947682018-07-07 14:53:32 +0900734 log.debug("Install rules for telemetry stats: \n {}",
735 ops.toString());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900736 }
737
738 @Override
739 public void onError(FlowRuleOperations ops) {
Jian Lia4947682018-07-07 14:53:32 +0900740 log.debug("Failed to install rules for telemetry stats: \n {}",
741 ops.toString());
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900742 }
743 }));
744 }
745
746 /**
Jian Li0bbbb1c2018-06-22 22:01:17 +0900747 * Merges old FlowInfo.StatsInfo and current FlowInfo.StatsInfo.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900748 *
749 * @param flowInfo current FlowInfo object
750 * @param fBuilder Builder for FlowInfo
751 * @param sBuilder Builder for StatsInfo
752 * @return Merged FlowInfo object
753 */
754 private FlowInfo mergeFlowInfo(FlowInfo flowInfo,
755 FlowInfo.Builder fBuilder,
756 StatsInfo.Builder sBuilder) {
Jian Li0bbbb1c2018-06-22 22:01:17 +0900757 for (FlowInfo gFlowInfo : gFlowInfoSet) {
758 log.debug("Old FlowInfo:\n{}", gFlowInfo.toString());
759 if (gFlowInfo.roughEquals(flowInfo)) {
760
761 // Get old StatsInfo object and merge the value to current object.
762 StatsInfo oldStatsInfo = gFlowInfo.statsInfo();
763 sBuilder.withPrevAccPkts(oldStatsInfo.currAccPkts());
764 sBuilder.withPrevAccBytes(oldStatsInfo.currAccBytes());
765 FlowInfo newFlowInfo = fBuilder.withStatsInfo(sBuilder.build())
766 .build();
767
768 gFlowInfoSet.remove(gFlowInfo);
769 gFlowInfoSet.add(newFlowInfo);
Jian Li85573f42018-06-27 22:29:14 +0900770 log.debug("Old FlowInfo found, Merge this {}", newFlowInfo.toString());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900771 return newFlowInfo;
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900772 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900773 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900774
775 // No such record, then build the FlowInfo object and return this object.
Jian Li85573f42018-06-27 22:29:14 +0900776 log.debug("No FlowInfo found, add new FlowInfo {}", flowInfo.toString());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900777 FlowInfo newFlowInfo = fBuilder.withStatsInfo(sBuilder.build()).build();
778 gFlowInfoSet.add(newFlowInfo);
779 return newFlowInfo;
780 }
781
Jian Li753280e2018-07-03 02:24:34 +0900782 /**
783 * Installs flow rules for collecting both normal and reverse path flow stats.
784 *
785 * @param statsFlowRule flow rule used for collecting stats
786 * @param install flow rule installation flag
787 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900788 private void setStatFlowRule(StatsFlowRule statsFlowRule, boolean install) {
Jian Li753280e2018-07-03 02:24:34 +0900789 setStatFlowRuleBase(statsFlowRule, install);
Jian Li0bbbb1c2018-06-22 22:01:17 +0900790
Jian Li753280e2018-07-03 02:24:34 +0900791 // if reverse path stats is enabled, we will install flow rules for
792 // collecting reverse path vFlow stats
793 if (reversePathStats) {
794 StatsFlowRule reverseFlowRule = DefaultStatsFlowRule.builder()
795 .srcIpPrefix(statsFlowRule.dstIpPrefix())
796 .dstIpPrefix(statsFlowRule.srcIpPrefix())
797 .ipProtocol(statsFlowRule.ipProtocol())
798 .srcTpPort(statsFlowRule.dstTpPort())
799 .dstTpPort(statsFlowRule.srcTpPort())
800 .build();
801 setStatFlowRuleBase(reverseFlowRule, install);
802 }
803 }
804
805 /**
806 * A base method which is for installing flow rules for collecting stats.
807 *
808 * @param statsFlowRule flow rule used for collecting stats
809 * @param install flow rule installation flag
810 */
811 private void setStatFlowRuleBase(StatsFlowRule statsFlowRule, boolean install) {
Jian Lie6110b72018-07-06 19:06:36 +0900812
813 IpPrefix srcIp = statsFlowRule.srcIpPrefix();
814 IpPrefix dstIp = statsFlowRule.dstIpPrefix();
815 DeviceId srcDeviceId = getDeviceId(srcIp.address());
816 DeviceId dstDeviceId = getDeviceId(dstIp.address());
Jian Li0bbbb1c2018-06-22 22:01:17 +0900817
Jian Li998ec7b2018-06-29 15:15:49 +0900818 if (srcDeviceId == null && dstDeviceId == null) {
Jian Li85573f42018-06-27 22:29:14 +0900819 return;
820 }
821
Jian Li998ec7b2018-06-29 15:15:49 +0900822 if (srcDeviceId != null) {
Jian Li87ded822018-07-02 18:31:22 +0900823 connectTables(srcDeviceId, STAT_INBOUND_TABLE, VTAP_INBOUND_TABLE,
Jian Li998ec7b2018-06-29 15:15:49 +0900824 statsFlowRule, METRIC_PRIORITY_SOURCE, install);
Jian Li998ec7b2018-06-29 15:15:49 +0900825
Jian Lie6110b72018-07-06 19:06:36 +0900826 if (install) {
827 log.info("Install ingress stat flow rule for SrcIp:{} DstIp:{}",
828 srcIp.toString(), dstIp.toString());
829 } else {
830 log.info("Remove ingress stat flow rule for SrcIp:{} DstIp:{}",
831 srcIp.toString(), dstIp.toString());
Jian Li753280e2018-07-03 02:24:34 +0900832 }
Jian Li998ec7b2018-06-29 15:15:49 +0900833 }
Jian Li85573f42018-06-27 22:29:14 +0900834
Jian Lie6110b72018-07-06 19:06:36 +0900835 Set<IpPrefix> vxlanIps = osNetworkService.getFixedIpsByNetworkType(VXLAN);
836 Set<IpPrefix> vlanIps = osNetworkService.getFixedIpsByNetworkType(VLAN);
837 Set<IpPrefix> flatIps = osNetworkService.getFixedIpsByNetworkType(FLAT);
Jian Li753280e2018-07-03 02:24:34 +0900838
Jian Lie6110b72018-07-06 19:06:36 +0900839 int fromTable, toTable;
Jian Li753280e2018-07-03 02:24:34 +0900840
Jian Lie6110b72018-07-06 19:06:36 +0900841 if (dstDeviceId != null && egressStats) {
842
843 IpPrefix dstIpPrefix = statsFlowRule.dstIpPrefix();
844
845 if (vxlanIps.contains(dstIpPrefix) || vlanIps.contains(dstIpPrefix)) {
846 fromTable = STAT_OUTBOUND_TABLE;
847 toTable = VTAP_OUTBOUND_TABLE;
848 } else if (flatIps.contains(dstIpPrefix)) {
849 fromTable = STAT_FLAT_OUTBOUND_TABLE;
850 toTable = VTAP_FLAT_OUTBOUND_TABLE;
851 } else {
852 return;
853 }
854
855 connectTables(dstDeviceId, fromTable, toTable,
856 statsFlowRule, METRIC_PRIORITY_TARGET, install);
857
858 if (install) {
859 log.info("Install egress stat flow rule for SrcIp:{} DstIp:{}",
860 srcIp.toString(), dstIp.toString());
861 } else {
862 log.info("Remove egress stat flow rule for SrcIp:{} DstIp:{}",
863 srcIp.toString(), dstIp.toString());
864 }
Jian Li753280e2018-07-03 02:24:34 +0900865 }
Jian Li753280e2018-07-03 02:24:34 +0900866 }
867
868 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900869 * Gets Device ID which the VM is located.
Jian Li85573f42018-06-27 22:29:14 +0900870 *
871 * @param ipAddress IP Address of host
872 * @return Device ID
873 */
874 private DeviceId getDeviceId(IpAddress ipAddress) {
875 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
876 Optional<Host> host = hostService.getHostsByIp(ipAddress).stream().findAny();
877 return host.map(host1 -> host1.location().deviceId()).orElse(null);
878 } else {
Jian Lia4947682018-07-07 14:53:32 +0900879 log.debug("No DeviceID is associated to {}", ipAddress.toString());
Jian Li85573f42018-06-27 22:29:14 +0900880 return null;
Jian Li0bbbb1c2018-06-22 22:01:17 +0900881 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900882 }
883
884 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900885 * Gets VLAN ID with respect to IP Address.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900886 *
887 * @param ipAddress IP Address of host
888 * @return VLAN ID
889 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900890 private VlanId getVlanId(IpAddress ipAddress) {
891 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
892 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
893 return host.vlan();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900894 }
895 return VlanId.vlanId();
896 }
897
898 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900899 * Gets Interface ID of Switch which is connected to a host.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900900 *
901 * @param ipAddress IP Address of host
902 * @return Interface ID of Switch
903 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900904 private int getInterfaceId(IpAddress ipAddress) {
905 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
906 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
907 return (int) host.location().port().toLong();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900908 }
909 return -1;
910 }
911
912 /**
Jian Lif8b8c7f2018-08-27 18:49:04 +0900913 * Gets MAC Address of host.
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900914 *
915 * @param ipAddress IP Address of host
916 * @return MAC Address of host
917 */
Jian Li0bbbb1c2018-06-22 22:01:17 +0900918 private MacAddress getMacAddress(IpAddress ipAddress) {
919 if (!hostService.getHostsByIp(ipAddress).isEmpty()) {
920 Host host = hostService.getHostsByIp(ipAddress).stream().findAny().get();
921 return host.mac();
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900922 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900923
Boyoung Jeong9e8faec2018-06-17 21:19:23 +0900924 return NO_HOST_MAC;
925 }
Jian Li0bbbb1c2018-06-22 22:01:17 +0900926
Jian Lif8b8c7f2018-08-27 18:49:04 +0900927 /**
928 * Gets IP address of the host which is attached to the given device and port.
929 *
930 * @param device device
931 * @param inPort IN port number
932 * @return IP address
933 */
934 private IpAddress getIpAddress(Device device, PortCriterion inPort) {
935
936 Host host = hostService.getConnectedHosts(device.id()).stream()
937 .filter(h -> h.location().port().equals(inPort.port()))
938 .findAny().orElse(null);
939
940 if (host != null) {
941 return host.ipAddresses().stream().findAny().get();
942 }
943
944 return NO_HOST_IP;
945 }
946
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900947 private void enqFlowInfo(FlowInfo flowInfo) {
948 String key = flowInfo.uniqueFlowInfoKey();
949 Queue<FlowInfo> queue = flowInfoMap.get(key);
950 if (queue == null) {
951 Queue<FlowInfo> newQueue = new LinkedList<FlowInfo>();
952 newQueue.offer(flowInfo);
953 flowInfoMap.put(key, newQueue);
954 return;
955 }
956 queue.offer(flowInfo);
957
958 while (queue.size() > DEFAULT_DATA_POINT_SIZE) {
959 queue.remove(); // Removes a garbage data in the queue.
960 }
961 }
962
Jian Lif8b8c7f2018-08-27 18:49:04 +0900963 /**
964 * Checks whether the given device is edge switch or not.
965 *
966 * @param id device identifier
967 * @return true if the given device is edge switch, false otherwise
968 */
969 private boolean isEdgeSwitch(DeviceId id) {
970
971 return !hostService.getConnectedHosts(id).isEmpty();
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900972 }
973
Jian Li753280e2018-07-03 02:24:34 +0900974 /**
975 * Extracts properties from the component configuration context.
976 *
977 * @param context the component context
978 */
979 private void readComponentConfiguration(ComponentContext context) {
980 Dictionary<?, ?> properties = context.getProperties();
981
982 Boolean reversePathStatsConfigured =
983 getBooleanProperty(properties, REVERSE_PATH_STATS);
984 if (reversePathStatsConfigured == null) {
985 reversePathStats = DEFAULT_REVERSE_PATH_STATS;
986 log.info("Reversed path stats flag is NOT " +
987 "configured, default value is {}", reversePathStats);
988 } else {
989 reversePathStats = reversePathStatsConfigured;
990 log.info("Configured. Reversed path stats flag is {}", reversePathStats);
991 }
992
993 Boolean egressStatsConfigured = getBooleanProperty(properties, EGRESS_STATS);
994 if (egressStatsConfigured == null) {
995 egressStats = DEFAULT_EGRESS_STATS;
996 log.info("Egress stats flag is NOT " +
997 "configured, default value is {}", egressStats);
998 } else {
999 egressStats = egressStatsConfigured;
1000 log.info("Configured. Egress stats flag is {}", egressStats);
1001 }
Jian Lia4947682018-07-07 14:53:32 +09001002
1003 Boolean portStatsConfigured = getBooleanProperty(properties, PORT_STATS);
1004 if (portStatsConfigured == null) {
1005 portStats = DEFAULT_PORT_STATS;
1006 log.info("Port stats flag is NOT " +
1007 "configured, default value is {}", portStats);
1008 } else {
1009 portStats = portStatsConfigured;
1010 log.info("Configured. Port stats flag is {}", portStats);
1011 }
Jian Lif8b8c7f2018-08-27 18:49:04 +09001012
1013 Boolean monitorOverlayConfigured = getBooleanProperty(properties, MONITOR_OVERLAY);
1014 if (monitorOverlayConfigured == null) {
1015 monitorOverlay = DEFAULT_MONITOR_OVERLAY;
1016 log.info("Monitor overlay flag is NOT " +
1017 "configured, default value is {}", monitorOverlay);
1018 } else {
1019 monitorOverlay = monitorOverlayConfigured;
1020 log.info("Configured. Monitor overlay flag is {}", monitorOverlay);
1021 }
1022
1023 Boolean monitorUnderlayConfigured = getBooleanProperty(properties, MONITOR_UNDERLAY);
1024 if (monitorUnderlayConfigured == null) {
1025 monitorUnderlay = DEFAULT_MONITOR_UNDERLAY;
1026 log.info("Monitor underlay flag is NOT " +
1027 "configured, default value is {}", monitorUnderlay);
1028 } else {
1029 monitorUnderlay = monitorUnderlayConfigured;
1030 log.info("Configured. Monitor underlay flag is {}", monitorUnderlay);
1031 }
Jian Li753280e2018-07-03 02:24:34 +09001032 }
1033
Jian Lia4947682018-07-07 14:53:32 +09001034 private class TelemetryCollector implements Runnable {
Jian Li0bbbb1c2018-06-22 22:01:17 +09001035 @Override
1036 public void run() {
Jian Lif8b8c7f2018-08-27 18:49:04 +09001037 Set<FlowInfo> filteredOverlayFlowInfos = Sets.newConcurrentHashSet();
1038 Set<FlowInfo> filteredUnderlayFlowInfos = Sets.newConcurrentHashSet();
Jian Li85573f42018-06-27 22:29:14 +09001039
1040 // we only let the master controller of the device where the
Jian Lia4947682018-07-07 14:53:32 +09001041 // stats flow rules are installed send stats message
Jian Lif8b8c7f2018-08-27 18:49:04 +09001042 if (monitorOverlay) {
1043 getOverlayFlowInfos().forEach(f -> {
Jian Lia4947682018-07-07 14:53:32 +09001044 if (checkSrcDstLocalMaster(f)) {
Jian Lif8b8c7f2018-08-27 18:49:04 +09001045 filteredOverlayFlowInfos.add(f);
1046 }
1047 });
1048 }
1049 if (monitorUnderlay) {
1050 getUnderlayFlowInfos().forEach(f -> {
1051 if (checkSrcDstLocalMaster(f)) {
1052 filteredUnderlayFlowInfos.add(f);
Jian Lia4947682018-07-07 14:53:32 +09001053 }
1054 });
Jian Li0bbbb1c2018-06-22 22:01:17 +09001055 }
Jian Lia4947682018-07-07 14:53:32 +09001056
Jian Lif8b8c7f2018-08-27 18:49:04 +09001057 // we only let the master controller of the device where the port
1058 // is located to send stats message
1059 if (portStats) {
1060 if (monitorOverlay) {
1061 getOverlayDstPortBasedFlowInfos().forEach(f -> {
1062 if (checkSrcDstLocalMaster(f)) {
1063 filteredOverlayFlowInfos.add(f);
1064 }
1065 });
1066 }
Boyoung Jeong1cca5e82018-08-01 21:00:08 +09001067
Jian Lif8b8c7f2018-08-27 18:49:04 +09001068 if (monitorUnderlay) {
1069 getUnderlayDstPortBasedFlowInfos().forEach(f -> {
1070 if (checkSrcDstLocalMaster(f)) {
1071 filteredUnderlayFlowInfos.add(f);
1072 }
1073 });
1074 }
1075 }
1076
1077
1078 if (monitorOverlay) {
1079 telemetryService.publish(filteredOverlayFlowInfos);
1080
1081 // TODO: Refactor the following code to "TelemetryService" style.
1082 filteredOverlayFlowInfos.forEach(StatsFlowRuleManager.this::enqFlowInfo);
1083 }
1084
1085 if (monitorUnderlay) {
1086 telemetryService.publish(filteredUnderlayFlowInfos);
1087 }
Jian Lia4947682018-07-07 14:53:32 +09001088 }
1089
1090 private boolean checkSrcDstLocalMaster(FlowInfo info) {
1091 DeviceId srcDeviceId = getDeviceId(info.srcIp().address());
1092 DeviceId dstDeviceId = getDeviceId(info.dstIp().address());
1093
1094 boolean isSrcLocalMaster = srcDeviceId != null &&
1095 mastershipService.isLocalMaster(srcDeviceId);
1096 boolean isDstLocalMaster = dstDeviceId != null &&
1097 mastershipService.isLocalMaster(dstDeviceId);
1098
1099 return isSrcLocalMaster || isDstLocalMaster;
Jian Li0bbbb1c2018-06-22 22:01:17 +09001100 }
1101 }
Boyoung Jeong9e8faec2018-06-17 21:19:23 +09001102}