blob: 1cdb55b359256a2df598959e261fba18285cdfb0 [file] [log] [blame]
David K. Bainbridged77028f2017-08-01 12:47:55 -07001/*
Brian O'Connor4d084702017-08-03 22:45:58 -07002 * Copyright 2017-present Open Networking Foundation
David K. Bainbridged77028f2017-08-01 12:47:55 -07003 *
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 */
ke han81a38b92017-03-10 18:41:44 +080016package org.opencord.igmpproxy;
17
18import com.google.common.collect.Maps;
Esin Karamaneff10392019-06-27 18:09:13 +000019import com.google.common.collect.Sets;
Matteo Scandolo7482bbe2020-02-12 14:37:09 -080020import org.onosproject.net.Device;
21import org.opencord.sadis.BaseInformationService;
22import org.opencord.sadis.SadisService;
23import org.opencord.sadis.SubscriberAndDeviceInformation;
Carmelo Casconebef302e2019-11-14 19:58:20 -080024import org.osgi.service.component.annotations.Activate;
25import org.osgi.service.component.annotations.Component;
26import org.osgi.service.component.annotations.Deactivate;
27import org.osgi.service.component.annotations.Reference;
28import org.osgi.service.component.annotations.ReferenceCardinality;
ke han81a38b92017-03-10 18:41:44 +080029import org.onlab.packet.EthType;
30import org.onlab.packet.Ethernet;
31import org.onlab.packet.IGMP;
32import org.onlab.packet.IGMPGroup;
33import org.onlab.packet.IGMPMembership;
34import org.onlab.packet.IGMPQuery;
35import org.onlab.packet.IPv4;
36import org.onlab.packet.Ip4Address;
37import org.onlab.packet.IpAddress;
38import org.onlab.packet.VlanId;
39import org.onosproject.core.ApplicationId;
40import org.onosproject.core.CoreService;
ke han81a38b92017-03-10 18:41:44 +080041import org.onosproject.mastership.MastershipService;
42import org.onosproject.net.AnnotationKeys;
43import org.onosproject.net.ConnectPoint;
44import org.onosproject.net.DeviceId;
45import org.onosproject.net.Port;
46import org.onosproject.net.PortNumber;
47import org.onosproject.net.config.ConfigFactory;
48import org.onosproject.net.config.NetworkConfigEvent;
49import org.onosproject.net.config.NetworkConfigListener;
50import org.onosproject.net.config.NetworkConfigRegistry;
Jonathan Hart488e1142018-05-02 17:30:05 -070051import org.onosproject.net.config.basics.McastConfig;
ke han81a38b92017-03-10 18:41:44 +080052import org.onosproject.net.config.basics.SubjectFactories;
53import org.onosproject.net.device.DeviceEvent;
54import org.onosproject.net.device.DeviceListener;
55import org.onosproject.net.device.DeviceService;
56import org.onosproject.net.flow.DefaultTrafficTreatment;
57import org.onosproject.net.flow.FlowRuleService;
58import org.onosproject.net.flow.criteria.Criteria;
59import org.onosproject.net.flowobjective.DefaultFilteringObjective;
60import org.onosproject.net.flowobjective.FilteringObjective;
61import org.onosproject.net.flowobjective.FlowObjectiveService;
62import org.onosproject.net.flowobjective.Objective;
63import org.onosproject.net.flowobjective.ObjectiveContext;
64import org.onosproject.net.flowobjective.ObjectiveError;
Esin Karamaneff10392019-06-27 18:09:13 +000065import org.onosproject.mcast.api.McastRoute;
66import org.onosproject.mcast.api.MulticastRouteService;
ke han81a38b92017-03-10 18:41:44 +080067import org.onosproject.net.packet.InboundPacket;
68import org.onosproject.net.packet.PacketContext;
69import org.onosproject.net.packet.PacketProcessor;
70import org.onosproject.net.packet.PacketService;
ke han81a38b92017-03-10 18:41:44 +080071import org.slf4j.Logger;
72import org.slf4j.LoggerFactory;
73
74import java.util.ArrayList;
75import java.util.Collection;
Esin Karamaneff10392019-06-27 18:09:13 +000076import java.util.HashSet;
ke han81a38b92017-03-10 18:41:44 +080077import java.util.Iterator;
78import java.util.List;
79import java.util.Map;
Esin Karamaneff10392019-06-27 18:09:13 +000080import java.util.Optional;
ke han81a38b92017-03-10 18:41:44 +080081import java.util.Set;
82import java.util.TimerTask;
83import java.util.concurrent.ConcurrentHashMap;
Esin Karamanb38700c2019-09-17 13:01:25 +000084import java.util.concurrent.ExecutorService;
ke han81a38b92017-03-10 18:41:44 +080085import java.util.concurrent.Executors;
86import java.util.concurrent.ScheduledExecutorService;
87import java.util.concurrent.TimeUnit;
88
Esin Karamanb38700c2019-09-17 13:01:25 +000089import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
90import static org.onlab.util.Tools.groupedThreads;
91
ke han81a38b92017-03-10 18:41:44 +080092/**
93 * Igmp process application, use proxy mode, support first join/ last leave , fast leave
94 * period query and keep alive, packet out igmp message to uplink port features.
95 */
96@Component(immediate = true)
97public class IgmpManager {
98
Matteo Scandolo7482bbe2020-02-12 14:37:09 -080099 private static final String APP_NAME = "org.opencord.igmpproxy";
100
ke han81a38b92017-03-10 18:41:44 +0800101 private static final Class<IgmpproxyConfig> IGMPPROXY_CONFIG_CLASS =
102 IgmpproxyConfig.class;
103 private static final Class<IgmpproxySsmTranslateConfig> IGMPPROXY_SSM_CONFIG_CLASS =
104 IgmpproxySsmTranslateConfig.class;
105 private static final Class<McastConfig> MCAST_CONFIG_CLASS =
106 McastConfig.class;
Esin Karamaneff10392019-06-27 18:09:13 +0000107
ke han81a38b92017-03-10 18:41:44 +0800108 public static Map<String, GroupMember> groupMemberMap = Maps.newConcurrentMap();
109 private static ApplicationId appId;
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800110
ke han81a38b92017-03-10 18:41:44 +0800111 private static int unSolicitedTimeout = 3; // unit is 1 sec
112 private static int keepAliveCount = 3;
113 private static int lastQueryInterval = 2; //unit is 1 sec
114 private static int lastQueryCount = 2;
115 private static boolean fastLeave = true;
116 private static boolean withRAUplink = true;
117 private static boolean withRADownlink = false;
118 private static boolean periodicQuery = true;
119 private static short mvlan = 4000;
120 private static byte igmpCos = 7;
121 public static boolean connectPointMode = true;
122 public static ConnectPoint connectPoint = null;
Esin Karamaneff10392019-06-27 18:09:13 +0000123 private static ConnectPoint sourceDeviceAndPort = null;
124 private static boolean enableIgmpProvisioning = false;
Esin Karamanb38700c2019-09-17 13:01:25 +0000125 private static boolean igmpOnPodBasis = false;
Esin Karamaneff10392019-06-27 18:09:13 +0000126
127 private static final Integer MAX_PRIORITY = 10000;
128 private static final String INSTALLED = "installed";
129 private static final String REMOVED = "removed";
130 private static final String INSTALLATION = "installation";
131 private static final String REMOVAL = "removal";
Esin Karaman00e16b72020-02-21 10:32:39 +0000132 private static final String NNI_PREFIX = "nni";
ke han81a38b92017-03-10 18:41:44 +0800133
ke han29af27b2017-09-08 10:29:12 +0800134 private static boolean pimSSmInterworking = false;
135 private static final String DEFAULT_PIMSSM_HOST = "127.0.0.1";
ke han81a38b92017-03-10 18:41:44 +0800136 private final ScheduledExecutorService scheduledExecutorService =
137 Executors.newScheduledThreadPool(1);
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800138
Carmelo Casconebef302e2019-11-14 19:58:20 -0800139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
ke han81a38b92017-03-10 18:41:44 +0800140 protected CoreService coreService;
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800141
Carmelo Casconebef302e2019-11-14 19:58:20 -0800142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
ke han81a38b92017-03-10 18:41:44 +0800143 protected PacketService packetService;
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800144
Carmelo Casconebef302e2019-11-14 19:58:20 -0800145 @Reference(cardinality = ReferenceCardinality.MANDATORY)
ke han81a38b92017-03-10 18:41:44 +0800146 protected MastershipService mastershipService;
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800147
Carmelo Casconebef302e2019-11-14 19:58:20 -0800148 @Reference(cardinality = ReferenceCardinality.MANDATORY)
ke han81a38b92017-03-10 18:41:44 +0800149 protected FlowRuleService flowRuleService;
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800150
Carmelo Casconebef302e2019-11-14 19:58:20 -0800151 @Reference(cardinality = ReferenceCardinality.MANDATORY)
ke han81a38b92017-03-10 18:41:44 +0800152 protected DeviceService deviceService;
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800153
Carmelo Casconebef302e2019-11-14 19:58:20 -0800154 @Reference(cardinality = ReferenceCardinality.MANDATORY)
ke han81a38b92017-03-10 18:41:44 +0800155 protected FlowObjectiveService flowObjectiveService;
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800156
Carmelo Casconebef302e2019-11-14 19:58:20 -0800157 @Reference(cardinality = ReferenceCardinality.MANDATORY)
ke han81a38b92017-03-10 18:41:44 +0800158 protected NetworkConfigRegistry networkConfig;
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800159
Carmelo Casconebef302e2019-11-14 19:58:20 -0800160 @Reference(cardinality = ReferenceCardinality.MANDATORY)
ke han81a38b92017-03-10 18:41:44 +0800161 protected MulticastRouteService multicastService;
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800162
163 @Reference(cardinality = ReferenceCardinality.MANDATORY)
164 protected SadisService sadisService;
165
ke han81a38b92017-03-10 18:41:44 +0800166 private IgmpPacketProcessor processor = new IgmpPacketProcessor();
167 private Logger log = LoggerFactory.getLogger(getClass());
168 private ApplicationId coreAppId;
169 private Map<Ip4Address, Ip4Address> ssmTranslateTable = new ConcurrentHashMap<>();
Esin Karamaneff10392019-06-27 18:09:13 +0000170
ke han81a38b92017-03-10 18:41:44 +0800171 private InternalNetworkConfigListener configListener =
172 new InternalNetworkConfigListener();
173 private DeviceListener deviceListener = new InternalDeviceListener();
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800174
ke han81a38b92017-03-10 18:41:44 +0800175 private ConfigFactory<ApplicationId, IgmpproxyConfig> igmpproxyConfigFactory =
176 new ConfigFactory<ApplicationId, IgmpproxyConfig>(
177 SubjectFactories.APP_SUBJECT_FACTORY, IGMPPROXY_CONFIG_CLASS, "igmpproxy") {
178 @Override
179 public IgmpproxyConfig createConfig() {
180 return new IgmpproxyConfig();
181 }
182 };
183 private ConfigFactory<ApplicationId, IgmpproxySsmTranslateConfig> igmpproxySsmConfigFactory =
184 new ConfigFactory<ApplicationId, IgmpproxySsmTranslateConfig>(
185 SubjectFactories.APP_SUBJECT_FACTORY, IGMPPROXY_SSM_CONFIG_CLASS, "ssmTranslate", true) {
186 @Override
187 public IgmpproxySsmTranslateConfig createConfig() {
188 return new IgmpproxySsmTranslateConfig();
189 }
190 };
Esin Karamaneff10392019-06-27 18:09:13 +0000191
ke han81a38b92017-03-10 18:41:44 +0800192 private int maxResp = 10; //unit is 1 sec
193 private int keepAliveInterval = 120; //unit is 1 sec
194
Esin Karamanb38700c2019-09-17 13:01:25 +0000195 private ExecutorService eventExecutor;
196
ke han81a38b92017-03-10 18:41:44 +0800197 public static int getUnsolicitedTimeout() {
198 return unSolicitedTimeout;
199 }
200
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800201 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800202
ke han81a38b92017-03-10 18:41:44 +0800203 @Activate
204 protected void activate() {
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800205 appId = coreService.registerApplication(APP_NAME);
ke han81a38b92017-03-10 18:41:44 +0800206 coreAppId = coreService.registerApplication(CoreService.CORE_APP_NAME);
207 packetService.addProcessor(processor, PacketProcessor.director(4));
208 IgmpSender.init(packetService, mastershipService);
209
ke han81a38b92017-03-10 18:41:44 +0800210 networkConfig.registerConfigFactory(igmpproxySsmConfigFactory);
211 networkConfig.registerConfigFactory(igmpproxyConfigFactory);
212 networkConfig.addListener(configListener);
213
214 configListener.reconfigureNetwork(networkConfig.getConfig(appId, IGMPPROXY_CONFIG_CLASS));
215 configListener.reconfigureSsmTable(networkConfig.getConfig(appId, IGMPPROXY_SSM_CONFIG_CLASS));
216
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800217 subsService = sadisService.getSubscriberInfoService();
ke han81a38b92017-03-10 18:41:44 +0800218
ke han81a38b92017-03-10 18:41:44 +0800219 if (connectPointMode) {
220 provisionConnectPointFlows();
221 } else {
222 provisionUplinkFlows();
223 }
224
225 McastConfig config = networkConfig.getConfig(coreAppId, MCAST_CONFIG_CLASS);
226 if (config != null) {
227 mvlan = config.egressVlan().toShort();
Deepa Vaddireddy88134a42017-07-05 12:16:03 +0530228 IgmpSender.getInstance().setMvlan(mvlan);
ke han81a38b92017-03-10 18:41:44 +0800229 }
230 deviceService.addListener(deviceListener);
Sonal Kasliwalddc3ff22019-11-18 11:52:49 +0000231 scheduledExecutorService.scheduleAtFixedRate(new IgmpProxyTimerTask(), 1000, 1000, TimeUnit.MILLISECONDS);
Esin Karamanb38700c2019-09-17 13:01:25 +0000232 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("cord/igmpproxy",
233 "events-igmp-%d", log));
ke han81a38b92017-03-10 18:41:44 +0800234
235 log.info("Started");
236 }
237
238 @Deactivate
239 protected void deactivate() {
240 scheduledExecutorService.shutdown();
Esin Karamanb38700c2019-09-17 13:01:25 +0000241 eventExecutor.shutdown();
ke han81a38b92017-03-10 18:41:44 +0800242
243 // de-register and null our handler
244 networkConfig.removeListener(configListener);
ke han81a38b92017-03-10 18:41:44 +0800245 networkConfig.unregisterConfigFactory(igmpproxyConfigFactory);
246 networkConfig.unregisterConfigFactory(igmpproxySsmConfigFactory);
247 deviceService.removeListener(deviceListener);
248 packetService.removeProcessor(processor);
249 flowRuleService.removeFlowRulesById(appId);
250
251 log.info("Stopped");
252 }
253
254 protected Ip4Address getDeviceIp(DeviceId ofDeviceId) {
255 try {
256 String[] mgmtAddress = deviceService.getDevice(ofDeviceId)
257 .annotations().value(AnnotationKeys.MANAGEMENT_ADDRESS).split(":");
258 return Ip4Address.valueOf(mgmtAddress[0]);
259 } catch (Exception ex) {
260 log.info("No valid Ipaddress for " + ofDeviceId.toString());
261 return null;
262 }
263 }
264
265 private void processIgmpQuery(IGMPQuery igmpQuery, ConnectPoint cp, int maxResp) {
266
267 DeviceId deviceId = cp.deviceId();
268 Ip4Address gAddr = igmpQuery.getGaddr().getIp4Address();
Deepa Vaddireddybcd52352017-09-21 05:04:48 +0000269 maxResp = calculateMaxResp(maxResp);
270 if (gAddr != null && !gAddr.isZero()) {
271 StateMachine.specialQuery(deviceId, gAddr, maxResp);
272 } else {
273 StateMachine.generalQuery(deviceId, maxResp);
274 }
275 }
ke han81a38b92017-03-10 18:41:44 +0800276
Deepa Vaddireddybcd52352017-09-21 05:04:48 +0000277 private void processIgmpConnectPointQuery(IGMPQuery igmpQuery, ConnectPoint cp, int maxResp) {
278
Deepa Vaddireddybcd52352017-09-21 05:04:48 +0000279 Ip4Address gAddr = igmpQuery.getGaddr().getIp4Address();
Esin Karaman00e16b72020-02-21 10:32:39 +0000280 final int maxResponseTime = calculateMaxResp(maxResp);
Deepa Vaddireddybcd52352017-09-21 05:04:48 +0000281 //The query is received on the ConnectPoint
282 // send query accordingly to the registered OLT devices.
283 if (gAddr != null && !gAddr.isZero()) {
Esin Karaman00e16b72020-02-21 10:32:39 +0000284 deviceService.getAvailableDevices().forEach(device -> {
285 Optional<SubscriberAndDeviceInformation> accessDevice = getSubscriberAndDeviceInformation(device.id());
286 if (accessDevice.isPresent()) {
287 StateMachine.specialQuery(device.id(), gAddr, maxResponseTime);
288 }
289 });
Deepa Vaddireddybcd52352017-09-21 05:04:48 +0000290 } else {
291 //Don't know which group is targeted by the query
292 //So query all the members(in all the OLTs) and proxy their reports
Esin Karaman00e16b72020-02-21 10:32:39 +0000293 StateMachine.generalQuery(maxResponseTime);
Deepa Vaddireddybcd52352017-09-21 05:04:48 +0000294 }
295 }
296
297
298 private int calculateMaxResp(int maxResp) {
ke han81a38b92017-03-10 18:41:44 +0800299 if (maxResp >= 128) {
300 int mant = maxResp & 0xf;
301 int exp = (maxResp >> 4) & 0x7;
302 maxResp = (mant | 0x10) << (exp + 3);
303 }
304
Deepa Vaddireddybcd52352017-09-21 05:04:48 +0000305 return (maxResp + 5) / 10;
ke han81a38b92017-03-10 18:41:44 +0800306 }
307
308 private Ip4Address ssmTranslateRoute(IpAddress group) {
309 return ssmTranslateTable.get(group);
310 }
311
312 private void processIgmpReport(IGMPMembership igmpGroup, VlanId vlan, ConnectPoint cp, byte igmpType) {
313 DeviceId deviceId = cp.deviceId();
314 PortNumber portNumber = cp.port();
315
316 Ip4Address groupIp = igmpGroup.getGaddr().getIp4Address();
317 if (!groupIp.isMulticast()) {
318 log.info(groupIp.toString() + " is not a valid group address");
319 return;
320 }
321 Ip4Address srcIp = getDeviceIp(deviceId);
322
323 byte recordType = igmpGroup.getRecordType();
324 boolean join = false;
325
326 ArrayList<Ip4Address> sourceList = new ArrayList<>();
327
328 if (igmpGroup.getSources().size() > 0) {
329 igmpGroup.getSources().forEach(source -> sourceList.add(source.getIp4Address()));
330 if (recordType == IGMPMembership.CHANGE_TO_EXCLUDE_MODE ||
331 recordType == IGMPMembership.MODE_IS_EXCLUDE ||
332 recordType == IGMPMembership.BLOCK_OLD_SOURCES) {
333 join = false;
334 } else if (recordType == IGMPMembership.CHANGE_TO_INCLUDE_MODE ||
335 recordType == IGMPMembership.MODE_IS_INCLUDE ||
336 recordType == IGMPMembership.ALLOW_NEW_SOURCES) {
337 join = true;
338 }
339 } else {
ke han29af27b2017-09-08 10:29:12 +0800340 IpAddress src = null;
341 if (pimSSmInterworking) {
342 src = ssmTranslateRoute(groupIp);
343 if (src == null) {
344 log.info("no ssm translate for group " + groupIp.toString());
345 return;
346 }
347 } else {
348 src = IpAddress.valueOf(DEFAULT_PIMSSM_HOST);
ke han81a38b92017-03-10 18:41:44 +0800349 }
350 sourceList.add(src.getIp4Address());
351 if (recordType == IGMPMembership.CHANGE_TO_EXCLUDE_MODE ||
352 recordType == IGMPMembership.MODE_IS_EXCLUDE ||
353 recordType == IGMPMembership.BLOCK_OLD_SOURCES) {
354 join = true;
355 } else if (recordType == IGMPMembership.CHANGE_TO_INCLUDE_MODE ||
356 recordType == IGMPMembership.MODE_IS_INCLUDE ||
357 recordType == IGMPMembership.ALLOW_NEW_SOURCES) {
358 join = false;
359 }
360 }
361 String groupMemberKey = GroupMember.getkey(groupIp, deviceId, portNumber);
362 GroupMember groupMember = groupMemberMap.get(groupMemberKey);
363
364 if (join) {
365 if (groupMember == null) {
Esin Karamaneff10392019-06-27 18:09:13 +0000366 Optional<ConnectPoint> sourceConfigured = getSource();
367 if (!sourceConfigured.isPresent()) {
368 log.warn("Unable to process IGMP Join from {} since no source " +
369 "configuration is found.", deviceId);
370 return;
371 }
Esin Karaman00e16b72020-02-21 10:32:39 +0000372
373 Optional<PortNumber> deviceUplink = getDeviceUplink(deviceId);
374 if (deviceUplink.isEmpty()) {
375 log.warn("Unable to process IGMP Join since uplink port " +
376 "of the device {} is not found.", deviceId);
377 return;
378 }
379
380 if (igmpType == IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT) {
381 groupMember = new GroupMember(groupIp, vlan, deviceId, portNumber, true);
382 } else {
383 groupMember = new GroupMember(groupIp, vlan, deviceId, portNumber, false);
384 }
385
Esin Karamaneff10392019-06-27 18:09:13 +0000386 HashSet<ConnectPoint> sourceConnectPoints = Sets.newHashSet(sourceConfigured.get());
387
Esin Karaman00e16b72020-02-21 10:32:39 +0000388 StateMachine.join(deviceId, groupIp, srcIp, deviceUplink.get());
ke han81a38b92017-03-10 18:41:44 +0800389 groupMemberMap.put(groupMemberKey, groupMember);
390 groupMember.updateList(recordType, sourceList);
Esin Karamaneff10392019-06-27 18:09:13 +0000391 groupMember.getSourceList().forEach(source -> {
392 McastRoute route = new McastRoute(source, groupIp, McastRoute.Type.IGMP);
393 //add route
394 multicastService.add(route);
395 //add source to the route
396 multicastService.addSources(route, Sets.newHashSet(sourceConnectPoints));
397 //add sink to the route
398 multicastService.addSinks(route, Sets.newHashSet(cp));
399 });
400
ke han81a38b92017-03-10 18:41:44 +0800401 }
402 groupMember.resetAllTimers();
403 groupMember.updateList(recordType, sourceList);
404 groupMember.setLeave(false);
405 } else {
406 if (groupMember == null) {
407 log.info("receive leave but no instance, group " + groupIp.toString() +
408 " device:" + deviceId.toString() + " port:" + portNumber.toString());
409 return;
410 } else {
411 groupMember.setLeave(true);
412 if (fastLeave) {
413 leaveAction(groupMember);
414 } else {
415 sendQuery(groupMember);
416 }
417 }
418 }
419 }
420
421 private void leaveAction(GroupMember groupMember) {
422 ConnectPoint cp = new ConnectPoint(groupMember.getDeviceId(), groupMember.getPortNumber());
423 StateMachine.leave(groupMember.getDeviceId(), groupMember.getGroupIp());
Esin Karamaneff10392019-06-27 18:09:13 +0000424 groupMember.getSourceList().forEach(source -> multicastService.removeSinks(
ke han81a38b92017-03-10 18:41:44 +0800425 new McastRoute(source, groupMember.getGroupIp(),
Esin Karamaneff10392019-06-27 18:09:13 +0000426 McastRoute.Type.IGMP), Sets.newHashSet(cp)));
ke han81a38b92017-03-10 18:41:44 +0800427 groupMemberMap.remove(groupMember.getId());
428 }
429
430 private void sendQuery(GroupMember groupMember) {
431 Ethernet ethpkt;
432 Ip4Address srcIp = getDeviceIp(groupMember.getDeviceId());
433 if (groupMember.getv2()) {
434 ethpkt = IgmpSender.getInstance().buildIgmpV2Query(groupMember.getGroupIp(), srcIp);
435 } else {
436 ethpkt = IgmpSender.getInstance().buildIgmpV3Query(groupMember.getGroupIp(), srcIp);
437 }
438 IgmpSender.getInstance().sendIgmpPacket(ethpkt, groupMember.getDeviceId(), groupMember.getPortNumber());
439 }
440
Esin Karamaneff10392019-06-27 18:09:13 +0000441 /**
442 * @return connect point of the source if configured; and empty Optional otherwise.
443 */
444 public static Optional<ConnectPoint> getSource() {
445 return sourceDeviceAndPort == null ? Optional.empty() :
446 Optional.of(sourceDeviceAndPort);
ke han81a38b92017-03-10 18:41:44 +0800447 }
448
449 /**
450 * Packet processor responsible for forwarding packets along their paths.
451 */
452 private class IgmpPacketProcessor implements PacketProcessor {
453 @Override
454 public void process(PacketContext context) {
Esin Karamanb38700c2019-09-17 13:01:25 +0000455 eventExecutor.execute(() -> {
456 try {
457 InboundPacket pkt = context.inPacket();
458 Ethernet ethPkt = pkt.parsed();
459 if (ethPkt == null) {
460 return;
461 }
ke han81a38b92017-03-10 18:41:44 +0800462
Esin Karamanb38700c2019-09-17 13:01:25 +0000463 if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) {
464 return;
465 }
ke han81a38b92017-03-10 18:41:44 +0800466
Esin Karamanb38700c2019-09-17 13:01:25 +0000467 IPv4 ipv4Pkt = (IPv4) ethPkt.getPayload();
ke han81a38b92017-03-10 18:41:44 +0800468
Esin Karamanb38700c2019-09-17 13:01:25 +0000469 if (ipv4Pkt.getProtocol() != IPv4.PROTOCOL_IGMP) {
470 return;
471 }
ke han81a38b92017-03-10 18:41:44 +0800472
Esin Karamanb38700c2019-09-17 13:01:25 +0000473 short vlan = ethPkt.getVlanID();
474 DeviceId deviceId = pkt.receivedFrom().deviceId();
ke han81a38b92017-03-10 18:41:44 +0800475
Esin Karaman00e16b72020-02-21 10:32:39 +0000476 if (!isConnectPoint(deviceId, pkt.receivedFrom().port()) &&
477 !getSubscriberAndDeviceInformation(deviceId).isPresent()) {
Esin Karamanb38700c2019-09-17 13:01:25 +0000478 log.error("Device not registered in netcfg :" + deviceId.toString());
479 return;
480 }
ke han81a38b92017-03-10 18:41:44 +0800481
Esin Karamanb38700c2019-09-17 13:01:25 +0000482 IGMP igmp = (IGMP) ipv4Pkt.getPayload();
483 switch (igmp.getIgmpType()) {
484 case IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY:
485 //Discard Query from OLT’s non-uplink port’s
486 if (!pkt.receivedFrom().port().equals(getDeviceUplink(deviceId))) {
487 if (isConnectPoint(deviceId, pkt.receivedFrom().port())) {
488 log.info("IGMP Picked up query from connectPoint");
489 //OK to process packet
490 processIgmpConnectPointQuery((IGMPQuery) igmp.getGroups().get(0),
491 pkt.receivedFrom(),
492 0xff & igmp.getMaxRespField());
493 break;
494 } else {
495 //Not OK to process packet
496 log.warn("IGMP Picked up query from non-uplink port");
497 return;
498 }
499 }
ke han81a38b92017-03-10 18:41:44 +0800500
Esin Karamanb38700c2019-09-17 13:01:25 +0000501 processIgmpQuery((IGMPQuery) igmp.getGroups().get(0), pkt.receivedFrom(),
502 0xff & igmp.getMaxRespField());
503 break;
504 case IGMP.TYPE_IGMPV1_MEMBERSHIP_REPORT:
505 log.debug("IGMP version 1 message types are not currently supported.");
506 break;
507 case IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT:
508 case IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT:
509 case IGMP.TYPE_IGMPV2_LEAVE_GROUP:
510 //Discard join/leave from OLT’s uplink port’s
511 if (pkt.receivedFrom().port().equals(getDeviceUplink(deviceId)) ||
512 isConnectPoint(deviceId, pkt.receivedFrom().port())) {
513 log.info("IGMP Picked up join/leave from uplink/connectPoint port");
Deepa Vaddireddybcd52352017-09-21 05:04:48 +0000514 return;
515 }
ke han81a38b92017-03-10 18:41:44 +0800516
Esin Karamanb38700c2019-09-17 13:01:25 +0000517 Iterator<IGMPGroup> itr = igmp.getGroups().iterator();
518 while (itr.hasNext()) {
519 IGMPGroup group = itr.next();
520 if (group instanceof IGMPMembership) {
521 processIgmpReport((IGMPMembership) group, VlanId.vlanId(vlan),
522 pkt.receivedFrom(), igmp.getIgmpType());
523 } else if (group instanceof IGMPQuery) {
524 IGMPMembership mgroup;
525 mgroup = new IGMPMembership(group.getGaddr().getIp4Address());
526 mgroup.setRecordType(igmp.getIgmpType() == IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT ?
527 IGMPMembership.MODE_IS_EXCLUDE :
528 IGMPMembership.MODE_IS_INCLUDE);
529 processIgmpReport(mgroup, VlanId.vlanId(vlan),
530 pkt.receivedFrom(), igmp.getIgmpType());
531 }
ke han81a38b92017-03-10 18:41:44 +0800532 }
Esin Karamanb38700c2019-09-17 13:01:25 +0000533 break;
ke han81a38b92017-03-10 18:41:44 +0800534
Esin Karamanb38700c2019-09-17 13:01:25 +0000535 default:
536 log.info("wrong IGMP v3 type:" + igmp.getIgmpType());
537 break;
538 }
539
540 } catch (Exception ex) {
541 log.error("igmp process error : {} ", ex);
542 ex.printStackTrace();
ke han81a38b92017-03-10 18:41:44 +0800543 }
Esin Karamanb38700c2019-09-17 13:01:25 +0000544 });
ke han81a38b92017-03-10 18:41:44 +0800545 }
546 }
547
548 private class IgmpProxyTimerTask extends TimerTask {
549 public void run() {
550 try {
551 IgmpTimer.timeOut1s();
552 queryMembers();
553 } catch (Exception ex) {
554 log.warn("Igmp timer task error : {}", ex.getMessage());
555 }
556 }
557
558 private void queryMembers() {
559 GroupMember groupMember;
560 Set groupMemberSet = groupMemberMap.entrySet();
561 Iterator itr = groupMemberSet.iterator();
562 while (itr.hasNext()) {
563 Map.Entry entry = (Map.Entry) itr.next();
564 groupMember = (GroupMember) entry.getValue();
565 DeviceId did = groupMember.getDeviceId();
566 if (mastershipService.isLocalMaster(did)) {
567 if (groupMember.isLeave()) {
568 lastQuery(groupMember);
569 } else if (periodicQuery) {
570 periodicQuery(groupMember);
571 }
572 }
573 }
574 }
575
576 private void lastQuery(GroupMember groupMember) {
577 if (groupMember.getLastQueryInterval() < lastQueryInterval) {
578 groupMember.lastQueryInterval(true); // count times
579 } else if (groupMember.getLastQueryCount() < lastQueryCount - 1) {
580 sendQuery(groupMember);
581 groupMember.lastQueryInterval(false); // reset count number
582 groupMember.lastQueryCount(true); //count times
583 } else if (groupMember.getLastQueryCount() == lastQueryCount - 1) {
584 leaveAction(groupMember);
585 }
586 }
587
588 private void periodicQuery(GroupMember groupMember) {
589 if (groupMember.getKeepAliveQueryInterval() < keepAliveInterval) {
590 groupMember.keepAliveInterval(true);
591 } else if (groupMember.getKeepAliveQueryCount() < keepAliveCount) {
592 sendQuery(groupMember);
593 groupMember.keepAliveInterval(false);
594 groupMember.keepAliveQueryCount(true);
595 } else if (groupMember.getKeepAliveQueryCount() == keepAliveCount) {
596 leaveAction(groupMember);
597 }
598 }
599
600 }
601
Esin Karaman00e16b72020-02-21 10:32:39 +0000602 public Optional<PortNumber> getDeviceUplink(DeviceId devId) {
603 Device device = deviceService.getDevice(devId);
604 if (device == null || device.serialNumber() == null) {
605 return Optional.empty();
Deepa Vaddireddybcd52352017-09-21 05:04:48 +0000606 }
Esin Karaman00e16b72020-02-21 10:32:39 +0000607 Optional<SubscriberAndDeviceInformation> olt = getSubscriberAndDeviceInformation(device.serialNumber());
608 if (olt.isEmpty()) {
609 return Optional.empty();
610 }
611 PortNumber portNumber = PortNumber.portNumber(olt.get().uplinkPort());
612 return validateUpLinkPort(device.id(), portNumber) ?
613 Optional.of(portNumber) : Optional.empty();
614 }
615
616 /**
617 *
618 * @param deviceId device id
619 * @param portNumber port number
620 * @return true if the port name starts with NNI_PREFIX; false otherwise.
621 */
622 public boolean validateUpLinkPort(DeviceId deviceId, PortNumber portNumber) {
623 Port port = deviceService.getPort(deviceId, portNumber);
624 if (port == null) {
625 //port is not discovered by ONOS; so cannot validate it.
626 return false;
627 }
628 return port.annotations().value(AnnotationKeys.PORT_NAME) != null &&
629 port.annotations().value(AnnotationKeys.PORT_NAME).startsWith(NNI_PREFIX);
ke han81a38b92017-03-10 18:41:44 +0800630 }
631
Esin Karamanb38700c2019-09-17 13:01:25 +0000632 public static boolean isIgmpOnPodBasis() {
633 return igmpOnPodBasis;
634 }
635
ke han81a38b92017-03-10 18:41:44 +0800636 private void processFilterObjective(DeviceId devId, PortNumber port, boolean remove) {
Esin Karamaneff10392019-06-27 18:09:13 +0000637 if (!enableIgmpProvisioning) {
638 log.debug("IGMP trap rules won't be installed since enableIgmpProvisioning flag is not set");
639 return;
640 }
ke han81a38b92017-03-10 18:41:44 +0800641 //TODO migrate to packet requests when packet service uses filtering objectives
642 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
643
644 builder = remove ? builder.deny() : builder.permit();
645
646 FilteringObjective igmp = builder
647 .withKey(Criteria.matchInPort(port))
648 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
649 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
650 .withMeta(DefaultTrafficTreatment.builder().setOutput(PortNumber.CONTROLLER).build())
651 .fromApp(appId)
Esin Karamaneff10392019-06-27 18:09:13 +0000652 .withPriority(MAX_PRIORITY)
ke han81a38b92017-03-10 18:41:44 +0800653 .add(new ObjectiveContext() {
654 @Override
655 public void onSuccess(Objective objective) {
Esin Karamaneff10392019-06-27 18:09:13 +0000656 log.info("Igmp filter for {} on {} {}.",
657 devId, port, (remove) ? REMOVED : INSTALLED);
ke han81a38b92017-03-10 18:41:44 +0800658 }
659
660 @Override
661 public void onError(Objective objective, ObjectiveError error) {
Esin Karamaneff10392019-06-27 18:09:13 +0000662 log.info("Igmp filter {} for device {} on port {} failed because of {}",
663 (remove) ? INSTALLATION : REMOVAL, devId, port,
664 error);
ke han81a38b92017-03-10 18:41:44 +0800665 }
666 });
667
668 flowObjectiveService.filter(devId, igmp);
Esin Karamaneff10392019-06-27 18:09:13 +0000669
ke han81a38b92017-03-10 18:41:44 +0800670 }
671
672 private boolean isConnectPoint(DeviceId device, PortNumber port) {
Deepa Vaddireddy01f33b42017-07-02 13:26:53 +0530673 if (connectPoint != null) {
674 return (connectPointMode && connectPoint.deviceId().equals(device)
675 && connectPoint.port().equals(port));
676 } else {
677 log.info("connectPoint not configured for device {}", device);
678 return false;
679 }
ke han81a38b92017-03-10 18:41:44 +0800680 }
Deepa Vaddireddy01f33b42017-07-02 13:26:53 +0530681
ke han81a38b92017-03-10 18:41:44 +0800682 private boolean isUplink(DeviceId device, PortNumber port) {
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800683 return ((!connectPointMode) && getDeviceUplink(device).equals(port));
ke han81a38b92017-03-10 18:41:44 +0800684 }
685
Esin Karaman00e16b72020-02-21 10:32:39 +0000686 /**
687 * Fetches device information associated with the device serial number from SADIS.
688 *
689 * @param serialNumber serial number of a device
690 * @return device information; an empty Optional otherwise.
691 */
692 private Optional<SubscriberAndDeviceInformation> getSubscriberAndDeviceInformation(String serialNumber) {
693 long start = System.currentTimeMillis();
694 try {
695 return Optional.ofNullable(sadisService.getSubscriberInfoService().get(serialNumber));
696 } finally {
697 if (log.isDebugEnabled()) {
698 // SADIS can call remote systems to fetch device data and this calls can take a long time.
699 // This measurement is just for monitoring these kinds of situations.
700 log.debug("Device fetched from SADIS. Elapsed {} msec", System.currentTimeMillis() - start);
701 }
702
703 }
704 }
705
706 /**
707 * Fetches device information associated with the device serial number from SADIS.
708 *
709 * @param deviceId device id
710 * @return device information; an empty Optional otherwise.
711 */
712 private Optional<SubscriberAndDeviceInformation> getSubscriberAndDeviceInformation(DeviceId deviceId) {
713 Device device = deviceService.getDevice(deviceId);
714 if (device == null || device.serialNumber() == null) {
715 return Optional.empty();
716 }
717 return getSubscriberAndDeviceInformation(device.serialNumber());
718 }
719
ke han81a38b92017-03-10 18:41:44 +0800720 private class InternalDeviceListener implements DeviceListener {
721 @Override
722 public void event(DeviceEvent event) {
723 DeviceId devId = event.subject().id();
Deepa Vaddireddyca7b25d2017-09-28 13:47:18 +0000724 Port p = event.port();
Esin Karaman00e16b72020-02-21 10:32:39 +0000725 if (getSubscriberAndDeviceInformation(devId).isEmpty() &&
Deepa Vaddireddyca7b25d2017-09-28 13:47:18 +0000726 !(p != null && isConnectPoint(devId, p.number()))) {
ke han81a38b92017-03-10 18:41:44 +0800727 return;
728 }
Deepa Vaddireddyca7b25d2017-09-28 13:47:18 +0000729 PortNumber port;
730
ke han81a38b92017-03-10 18:41:44 +0800731 switch (event.type()) {
732
733 case DEVICE_ADDED:
734 case DEVICE_UPDATED:
735 case DEVICE_REMOVED:
736 case DEVICE_SUSPENDED:
737 case DEVICE_AVAILABILITY_CHANGED:
738 case PORT_STATS_UPDATED:
739 break;
740 case PORT_ADDED:
Deepa Vaddireddyca7b25d2017-09-28 13:47:18 +0000741 port = p.number();
Esin Karaman00e16b72020-02-21 10:32:39 +0000742 if (getSubscriberAndDeviceInformation(devId).isPresent() &&
743 !isUplink(devId, port) && !isConnectPoint(devId, port)) {
ke han81a38b92017-03-10 18:41:44 +0800744 processFilterObjective(devId, port, false);
745 } else if (isUplink(devId, port)) {
746 provisionUplinkFlows();
747 } else if (isConnectPoint(devId, port)) {
748 provisionConnectPointFlows();
749 }
750 break;
751 case PORT_UPDATED:
Deepa Vaddireddyca7b25d2017-09-28 13:47:18 +0000752 port = p.number();
Esin Karaman00e16b72020-02-21 10:32:39 +0000753 if (getSubscriberAndDeviceInformation(devId).isPresent() &&
754 !isUplink(devId, port) && !isConnectPoint(devId, port)) {
ke han81a38b92017-03-10 18:41:44 +0800755 if (event.port().isEnabled()) {
756 processFilterObjective(devId, port, false);
757 } else {
758 processFilterObjective(devId, port, true);
759 }
760 } else if (isUplink(devId, port)) {
761 if (event.port().isEnabled()) {
762 provisionUplinkFlows(devId);
763 } else {
764 processFilterObjective(devId, port, true);
765 }
766 } else if (isConnectPoint(devId, port)) {
767 if (event.port().isEnabled()) {
768 provisionConnectPointFlows();
769 } else {
770 unprovisionConnectPointFlows();
771 }
772 }
773 break;
774 case PORT_REMOVED:
Deepa Vaddireddyca7b25d2017-09-28 13:47:18 +0000775 port = p.number();
ke han81a38b92017-03-10 18:41:44 +0800776 processFilterObjective(devId, port, true);
777 break;
778 default:
779 log.info("Unknown device event {}", event.type());
780 break;
781 }
782 }
783
784 @Override
785 public boolean isRelevant(DeviceEvent event) {
786 return true;
787 }
788 }
789
790 private class InternalNetworkConfigListener implements NetworkConfigListener {
791
792 private void reconfigureNetwork(IgmpproxyConfig cfg) {
Esin Karamaneff10392019-06-27 18:09:13 +0000793 IgmpproxyConfig newCfg = cfg == null ? new IgmpproxyConfig() : cfg;
ke han81a38b92017-03-10 18:41:44 +0800794
795 unSolicitedTimeout = newCfg.unsolicitedTimeOut();
796 maxResp = newCfg.maxResp();
797 keepAliveInterval = newCfg.keepAliveInterval();
798 keepAliveCount = newCfg.keepAliveCount();
799 lastQueryInterval = newCfg.lastQueryInterval();
800 lastQueryCount = newCfg.lastQueryCount();
801 withRAUplink = newCfg.withRAUplink();
802 withRADownlink = newCfg.withRADownlink();
803 igmpCos = newCfg.igmpCos();
804 periodicQuery = newCfg.periodicQuery();
805 fastLeave = newCfg.fastLeave();
ke han29af27b2017-09-08 10:29:12 +0800806 pimSSmInterworking = newCfg.pimSsmInterworking();
Esin Karamaneff10392019-06-27 18:09:13 +0000807 enableIgmpProvisioning = newCfg.enableIgmpProvisioning();
Esin Karamanb38700c2019-09-17 13:01:25 +0000808 igmpOnPodBasis = newCfg.igmpOnPodBasis();
Deepa Vaddireddyca7b25d2017-09-28 13:47:18 +0000809
810 if (connectPointMode != newCfg.connectPointMode() ||
811 connectPoint != newCfg.connectPoint()) {
ke han81a38b92017-03-10 18:41:44 +0800812 connectPointMode = newCfg.connectPointMode();
Deepa Vaddireddyca7b25d2017-09-28 13:47:18 +0000813 connectPoint = newCfg.connectPoint();
ke han81a38b92017-03-10 18:41:44 +0800814 if (connectPointMode) {
815 unprovisionUplinkFlows();
816 provisionConnectPointFlows();
817 } else {
818 unprovisionConnectPointFlows();
819 provisionUplinkFlows();
820 }
821 }
822 if (connectPoint != null) {
Esin Karamaneff10392019-06-27 18:09:13 +0000823 log.info("connect point : {}", connectPoint);
ke han81a38b92017-03-10 18:41:44 +0800824 }
Esin Karamaneff10392019-06-27 18:09:13 +0000825 log.info("mode: {}", connectPointMode);
826
827 getSourceConnectPoint(newCfg);
ke han81a38b92017-03-10 18:41:44 +0800828
829 IgmpSender.getInstance().setIgmpCos(igmpCos);
830 IgmpSender.getInstance().setMaxResp(maxResp);
831 IgmpSender.getInstance().setMvlan(mvlan);
832 IgmpSender.getInstance().setWithRADownlink(withRADownlink);
833 IgmpSender.getInstance().setWithRAUplink(withRAUplink);
Esin Karamaneff10392019-06-27 18:09:13 +0000834 }
ke han81a38b92017-03-10 18:41:44 +0800835
Esin Karamaneff10392019-06-27 18:09:13 +0000836 void getSourceConnectPoint(IgmpproxyConfig cfg) {
837 sourceDeviceAndPort = cfg.getSourceDeviceAndPort();
838 if (sourceDeviceAndPort != null) {
839 log.debug("source parameter configured to {}", sourceDeviceAndPort);
840 }
ke han81a38b92017-03-10 18:41:44 +0800841 }
842
843 public void reconfigureSsmTable(IgmpproxySsmTranslateConfig cfg) {
844 if (cfg == null) {
845 return;
846 }
847 Collection<McastRoute> translations = cfg.getSsmTranslations();
848 for (McastRoute route : translations) {
Esin Karamaneff10392019-06-27 18:09:13 +0000849 ssmTranslateTable.put(route.group().getIp4Address(), route.source().get().getIp4Address());
ke han81a38b92017-03-10 18:41:44 +0800850 }
851 }
852
853 @Override
854 public void event(NetworkConfigEvent event) {
855 switch (event.type()) {
856 case CONFIG_ADDED:
857 case CONFIG_UPDATED:
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800858 // NOTE how to know if something has changed in sadis?
ke han81a38b92017-03-10 18:41:44 +0800859
860 if (event.configClass().equals(IGMPPROXY_CONFIG_CLASS)) {
861 IgmpproxyConfig config = networkConfig.getConfig(appId, IGMPPROXY_CONFIG_CLASS);
862 if (config != null) {
Esin Karamaneff10392019-06-27 18:09:13 +0000863 log.info("igmpproxy config received. {}", config);
ke han81a38b92017-03-10 18:41:44 +0800864 reconfigureNetwork(config);
865 }
866 }
867
868 if (event.configClass().equals(IGMPPROXY_SSM_CONFIG_CLASS)) {
869 IgmpproxySsmTranslateConfig config = networkConfig.getConfig(appId, IGMPPROXY_SSM_CONFIG_CLASS);
870 if (config != null) {
871 reconfigureSsmTable(config);
872 }
873 }
874
875 if (event.configClass().equals(MCAST_CONFIG_CLASS)) {
876 McastConfig config = networkConfig.getConfig(coreAppId, MCAST_CONFIG_CLASS);
877 if (config != null && mvlan != config.egressVlan().toShort()) {
878 mvlan = config.egressVlan().toShort();
Deepa Vaddireddy88134a42017-07-05 12:16:03 +0530879 IgmpSender.getInstance().setMvlan(mvlan);
ke han81a38b92017-03-10 18:41:44 +0800880 groupMemberMap.values().forEach(m -> leaveAction(m));
881 }
882 }
883
884 log.info("Reconfigured");
885 break;
886 case CONFIG_REGISTERED:
887 case CONFIG_UNREGISTERED:
888 break;
889 case CONFIG_REMOVED:
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800890 // NOTE how to know if something has changed in sadis?
ke han81a38b92017-03-10 18:41:44 +0800891 default:
892 break;
893 }
894 }
895 }
896
897 private void provisionDefaultFlows(DeviceId deviceId) {
898 List<Port> ports = deviceService.getPorts(deviceId);
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800899
ke han81a38b92017-03-10 18:41:44 +0800900 ports.stream()
Matteo Scandolo7482bbe2020-02-12 14:37:09 -0800901 .filter(p -> (!getDeviceUplink(((Device) p.element()).id()).equals(p.number()) && p.isEnabled()))
ke han81a38b92017-03-10 18:41:44 +0800902 .forEach(p -> processFilterObjective((DeviceId) p.element().id(), p.number(), false));
903 }
904
905 private void provisionUplinkFlows(DeviceId deviceId) {
906 if (connectPointMode) {
907 return;
908 }
909
Esin Karaman00e16b72020-02-21 10:32:39 +0000910 Optional<PortNumber> upLink = getDeviceUplink(deviceId);
911 if (upLink.isPresent()) {
912 processFilterObjective(deviceId, upLink.get(), false);
913 }
ke han81a38b92017-03-10 18:41:44 +0800914 }
915
916 private void provisionUplinkFlows() {
917 if (connectPointMode) {
918 return;
919 }
Esin Karaman00e16b72020-02-21 10:32:39 +0000920 deviceService.getAvailableDevices().forEach(device -> {
921 Optional<SubscriberAndDeviceInformation> accessDevice = getSubscriberAndDeviceInformation(device.id());
922 if (accessDevice.isPresent()) {
923 provisionUplinkFlows(device.id());
924 }
925 });
ke han81a38b92017-03-10 18:41:44 +0800926 }
Esin Karaman00e16b72020-02-21 10:32:39 +0000927
ke han81a38b92017-03-10 18:41:44 +0800928 private void unprovisionUplinkFlows() {
Esin Karaman00e16b72020-02-21 10:32:39 +0000929 deviceService.getAvailableDevices().forEach(device -> {
930 Optional<SubscriberAndDeviceInformation> accessDevices = getSubscriberAndDeviceInformation(device.id());
931 if (accessDevices.isPresent()) {
932 Optional<PortNumber> upLink = getDeviceUplink(device.id());
933 if (upLink.isPresent()) {
934 processFilterObjective(device.id(), upLink.get(), true);
935 }
936 }
937 });
ke han81a38b92017-03-10 18:41:44 +0800938 }
939
940 private void provisionConnectPointFlows() {
941 if ((!connectPointMode) || connectPoint == null) {
942 return;
943 }
944
945 processFilterObjective(connectPoint.deviceId(), connectPoint.port(), false);
946 }
947 private void unprovisionConnectPointFlows() {
948 if (connectPoint == null) {
949 return;
950 }
951 processFilterObjective(connectPoint.deviceId(), connectPoint.port(), true);
952 }
953}