blob: 03f561b07529fda26935d366e379529433bf5934 [file] [log] [blame]
alshabib69297fd2015-09-23 13:22:33 -07001/*
2 * Copyright 2015 Open Networking Laboratory
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 */
alshabibad1e3b22015-12-07 16:01:01 -080016package org.onosproject.igmp;
alshabib69297fd2015-09-23 13:22:33 -070017
alshabib69297fd2015-09-23 13:22:33 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
alshabibad1e3b22015-12-07 16:01:01 -080021import org.apache.felix.scr.annotations.Property;
alshabib69297fd2015-09-23 13:22:33 -070022import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
alshabibe9a108d2016-02-01 17:25:00 -080024import org.onlab.packet.EthType;
alshabib69297fd2015-09-23 13:22:33 -070025import org.onlab.packet.Ethernet;
alshabibe9a108d2016-02-01 17:25:00 -080026import org.onlab.packet.IGMP;
Jonathan Hartcb286ac2016-02-12 19:26:02 -080027import org.onlab.packet.IGMPMembership;
alshabib9bb0e182016-02-14 19:53:42 -080028import org.onlab.packet.IGMPQuery;
alshabib69297fd2015-09-23 13:22:33 -070029import org.onlab.packet.IPv4;
30import org.onlab.packet.Ip4Address;
31import org.onlab.packet.IpAddress;
32import org.onlab.packet.IpPrefix;
alshabib9bb0e182016-02-14 19:53:42 -080033import org.onlab.util.SafeRecurringTask;
alshabib69297fd2015-09-23 13:22:33 -070034import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
alshabibad1e3b22015-12-07 16:01:01 -080036import org.onosproject.net.ConnectPoint;
37import org.onosproject.net.DeviceId;
alshabibe9a108d2016-02-01 17:25:00 -080038import org.onosproject.net.Port;
39import org.onosproject.net.PortNumber;
alshabib36e043f2016-02-11 17:31:36 -080040import org.onosproject.net.config.ConfigFactory;
41import org.onosproject.net.config.NetworkConfigEvent;
42import org.onosproject.net.config.NetworkConfigListener;
alshabibad1e3b22015-12-07 16:01:01 -080043import org.onosproject.net.config.NetworkConfigRegistry;
alshabib36e043f2016-02-11 17:31:36 -080044import org.onosproject.net.config.basics.SubjectFactories;
alshabibe9a108d2016-02-01 17:25:00 -080045import org.onosproject.net.device.DeviceEvent;
46import org.onosproject.net.device.DeviceListener;
47import org.onosproject.net.device.DeviceService;
48import org.onosproject.net.flow.DefaultTrafficTreatment;
alshabib9bb0e182016-02-14 19:53:42 -080049import org.onosproject.net.flow.TrafficTreatment;
alshabibe9a108d2016-02-01 17:25:00 -080050import org.onosproject.net.flow.criteria.Criteria;
51import org.onosproject.net.flowobjective.DefaultFilteringObjective;
52import org.onosproject.net.flowobjective.FilteringObjective;
53import org.onosproject.net.flowobjective.FlowObjectiveService;
54import org.onosproject.net.flowobjective.Objective;
55import org.onosproject.net.flowobjective.ObjectiveContext;
56import org.onosproject.net.flowobjective.ObjectiveError;
alshabibad1e3b22015-12-07 16:01:01 -080057import org.onosproject.net.mcast.McastRoute;
58import org.onosproject.net.mcast.MulticastRouteService;
alshabib9bb0e182016-02-14 19:53:42 -080059import org.onosproject.net.packet.DefaultOutboundPacket;
alshabib69297fd2015-09-23 13:22:33 -070060import org.onosproject.net.packet.InboundPacket;
61import org.onosproject.net.packet.PacketContext;
alshabib69297fd2015-09-23 13:22:33 -070062import org.onosproject.net.packet.PacketProcessor;
63import org.onosproject.net.packet.PacketService;
alshabibe9a108d2016-02-01 17:25:00 -080064import org.onosproject.olt.AccessDeviceConfig;
65import org.onosproject.olt.AccessDeviceData;
alshabib69297fd2015-09-23 13:22:33 -070066import org.slf4j.Logger;
67
alshabib9bb0e182016-02-14 19:53:42 -080068import java.nio.ByteBuffer;
Jonathan Hart16e1fa22016-02-16 13:06:26 -080069import java.util.Collection;
alshabib36e043f2016-02-11 17:31:36 -080070import java.util.List;
alshabibe9a108d2016-02-01 17:25:00 -080071import java.util.Map;
72import java.util.concurrent.ConcurrentHashMap;
alshabib9bb0e182016-02-14 19:53:42 -080073import java.util.concurrent.Executors;
74import java.util.concurrent.ScheduledExecutorService;
75import java.util.concurrent.ScheduledFuture;
76import java.util.concurrent.TimeUnit;
alshabibe9a108d2016-02-01 17:25:00 -080077
alshabib9bb0e182016-02-14 19:53:42 -080078import static org.onlab.util.Tools.groupedThreads;
alshabibe9a108d2016-02-01 17:25:00 -080079import static org.slf4j.LoggerFactory.getLogger;
alshabibad1e3b22015-12-07 16:01:01 -080080
alshabib69297fd2015-09-23 13:22:33 -070081/**
82 * Internet Group Management Protocol.
83 */
84@Component(immediate = true)
alshabibad1e3b22015-12-07 16:01:01 -080085public class IgmpSnoop {
alshabib9bb0e182016-02-14 19:53:42 -080086
alshabib69297fd2015-09-23 13:22:33 -070087 private final Logger log = getLogger(getClass());
88
alshabib9bb0e182016-02-14 19:53:42 -080089 private static final String DEST_MAC = "01:00:5E:00:00:01";
90 private static final String DEST_IP = "224.0.0.1";
91
92 private static final int DEFAULT_QUERY_PERIOD_SECS = 60;
93 private static final byte DEFAULT_IGMP_RESP_CODE = 0;
alshabibad1e3b22015-12-07 16:01:01 -080094 private static final String DEFAULT_MCAST_ADDR = "224.0.0.0/4";
95
96 @Property(name = "multicastAddress",
Jonathan Hartcb286ac2016-02-12 19:26:02 -080097 label = "Define the multicast base range to listen to")
alshabibad1e3b22015-12-07 16:01:01 -080098 private String multicastAddress = DEFAULT_MCAST_ADDR;
99
alshabib9bb0e182016-02-14 19:53:42 -0800100 @Property(name = "queryPeriod", intValue = DEFAULT_QUERY_PERIOD_SECS,
101 label = "Delay in seconds between successive query runs")
102 private int queryPeriod = DEFAULT_QUERY_PERIOD_SECS;
103
104 @Property(name = "maxRespCode", byteValue = DEFAULT_IGMP_RESP_CODE,
105 label = "Maximum time allowed before sending a responding report")
106 private byte maxRespCode = DEFAULT_IGMP_RESP_CODE;
107
alshabib69297fd2015-09-23 13:22:33 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibe9a108d2016-02-01 17:25:00 -0800109 protected FlowObjectiveService flowObjectiveService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib69297fd2015-09-23 13:22:33 -0700112 protected PacketService packetService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected CoreService coreService;
116
alshabibad1e3b22015-12-07 16:01:01 -0800117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected NetworkConfigRegistry networkConfig;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected MulticastRouteService multicastService;
122
alshabibe9a108d2016-02-01 17:25:00 -0800123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected DeviceService deviceService;
125
alshabib9bb0e182016-02-14 19:53:42 -0800126
127 private ScheduledFuture<?> queryTask;
128 private final ScheduledExecutorService queryService =
129 Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/igmp-query",
130 "membership-query"));
131
alshabibe9a108d2016-02-01 17:25:00 -0800132 private Map<DeviceId, AccessDeviceData> oltData = new ConcurrentHashMap<>();
133
Jonathan Hart16e1fa22016-02-16 13:06:26 -0800134 private Map<IpAddress, IpAddress> ssmTranslateTable = new ConcurrentHashMap<>();
135
alshabibe9a108d2016-02-01 17:25:00 -0800136 private DeviceListener deviceListener = new InternalDeviceListener();
alshabibad1e3b22015-12-07 16:01:01 -0800137 private IgmpPacketProcessor processor = new IgmpPacketProcessor();
alshabib69297fd2015-09-23 13:22:33 -0700138 private static ApplicationId appId;
139
alshabib36e043f2016-02-11 17:31:36 -0800140 private InternalNetworkConfigListener configListener =
141 new InternalNetworkConfigListener();
142
143 private static final Class<AccessDeviceConfig> CONFIG_CLASS =
144 AccessDeviceConfig.class;
145
Jonathan Hart965b9f92016-02-16 13:06:26 -0800146 private static final Class<IgmpSsmTranslateConfig> SSM_TRANSLATE_CONFIG_CLASS =
147 IgmpSsmTranslateConfig.class;
148
alshabib36e043f2016-02-11 17:31:36 -0800149 private ConfigFactory<DeviceId, AccessDeviceConfig> configFactory =
150 new ConfigFactory<DeviceId, AccessDeviceConfig>(
151 SubjectFactories.DEVICE_SUBJECT_FACTORY, CONFIG_CLASS, "accessDevice") {
152 @Override
153 public AccessDeviceConfig createConfig() {
154 return new AccessDeviceConfig();
155 }
156 };
157
Jonathan Hart16e1fa22016-02-16 13:06:26 -0800158 private ConfigFactory<ApplicationId, IgmpSsmTranslateConfig> ssmTranslateConfigFactory =
159 new ConfigFactory<ApplicationId, IgmpSsmTranslateConfig>(
Jonathan Hart965b9f92016-02-16 13:06:26 -0800160 SubjectFactories.APP_SUBJECT_FACTORY, SSM_TRANSLATE_CONFIG_CLASS, "ssmTranslate", true) {
Jonathan Hart16e1fa22016-02-16 13:06:26 -0800161 @Override
162 public IgmpSsmTranslateConfig createConfig() {
163 return new IgmpSsmTranslateConfig();
164 }
165 };
166
alshabib36e043f2016-02-11 17:31:36 -0800167
alshabib9bb0e182016-02-14 19:53:42 -0800168 private ByteBuffer queryPacket;
169
170
alshabib69297fd2015-09-23 13:22:33 -0700171 @Activate
172 public void activate() {
173 appId = coreService.registerApplication("org.onosproject.igmp");
174
175 packetService.addProcessor(processor, PacketProcessor.director(1));
176
alshabib36e043f2016-02-11 17:31:36 -0800177 networkConfig.registerConfigFactory(configFactory);
Jonathan Hart16e1fa22016-02-16 13:06:26 -0800178 networkConfig.registerConfigFactory(ssmTranslateConfigFactory);
alshabib36e043f2016-02-11 17:31:36 -0800179 networkConfig.addListener(configListener);
180
alshabibe9a108d2016-02-01 17:25:00 -0800181 networkConfig.getSubjects(DeviceId.class, AccessDeviceConfig.class).forEach(
alshabibad1e3b22015-12-07 16:01:01 -0800182 subject -> {
alshabibe9a108d2016-02-01 17:25:00 -0800183 AccessDeviceConfig config = networkConfig.getConfig(subject,
184 AccessDeviceConfig.class);
alshabibad1e3b22015-12-07 16:01:01 -0800185 if (config != null) {
alshabibe9a108d2016-02-01 17:25:00 -0800186 AccessDeviceData data = config.getOlt();
187 oltData.put(data.deviceId(), data);
alshabib36e043f2016-02-11 17:31:36 -0800188
alshabibad1e3b22015-12-07 16:01:01 -0800189 }
190 }
191 );
alshabib69297fd2015-09-23 13:22:33 -0700192
Jonathan Hart16e1fa22016-02-16 13:06:26 -0800193 IgmpSsmTranslateConfig ssmTranslateConfig =
194 networkConfig.getConfig(appId, IgmpSsmTranslateConfig.class);
195
196 if (ssmTranslateConfig != null) {
197 Collection<McastRoute> translations = ssmTranslateConfig.getSsmTranslations();
198 for (McastRoute route : translations) {
199 ssmTranslateTable.put(route.group(), route.source());
200 }
201 }
202
alshabib36e043f2016-02-11 17:31:36 -0800203 oltData.keySet().stream()
204 .flatMap(did -> deviceService.getPorts(did).stream())
205 .filter(p -> !oltData.get(p.element().id()).uplink().equals(p.number()))
206 .filter(p -> p.isEnabled())
207 .forEach(p -> processFilterObjective((DeviceId) p.element().id(), p, false));
208
alshabibe9a108d2016-02-01 17:25:00 -0800209 deviceService.addListener(deviceListener);
210
alshabib9bb0e182016-02-14 19:53:42 -0800211 queryPacket = buildQueryPacket();
212
213 queryTask = queryService.scheduleWithFixedDelay(
214 SafeRecurringTask.wrap(this::querySubscribers),
215 0,
216 queryPeriod,
217 TimeUnit.SECONDS);
218
alshabib69297fd2015-09-23 13:22:33 -0700219 log.info("Started");
220 }
221
222 @Deactivate
223 public void deactivate() {
224 packetService.removeProcessor(processor);
225 processor = null;
alshabibe9a108d2016-02-01 17:25:00 -0800226 deviceService.removeListener(deviceListener);
alshabib36e043f2016-02-11 17:31:36 -0800227 networkConfig.removeListener(configListener);
228 networkConfig.unregisterConfigFactory(configFactory);
Jonathan Hart16e1fa22016-02-16 13:06:26 -0800229 networkConfig.unregisterConfigFactory(ssmTranslateConfigFactory);
alshabib9bb0e182016-02-14 19:53:42 -0800230 queryTask.cancel(true);
231 queryService.shutdownNow();
alshabib69297fd2015-09-23 13:22:33 -0700232 log.info("Stopped");
233 }
234
alshabibe9a108d2016-02-01 17:25:00 -0800235 private void processFilterObjective(DeviceId devId, Port port, boolean remove) {
alshabibad1e3b22015-12-07 16:01:01 -0800236
alshabibe9a108d2016-02-01 17:25:00 -0800237 //TODO migrate to packet requests when packet service uses filtering objectives
238 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
239
240 builder = remove ? builder.deny() : builder.permit();
241
242 FilteringObjective igmp = builder
243 .withKey(Criteria.matchInPort(port.number()))
244 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
245 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
246 .withMeta(DefaultTrafficTreatment.builder()
247 .setOutput(PortNumber.CONTROLLER).build())
248 .fromApp(appId)
alshabib72f43dc2016-02-17 15:37:56 -0800249 .withPriority(10000)
alshabibe9a108d2016-02-01 17:25:00 -0800250 .add(new ObjectiveContext() {
251 @Override
252 public void onSuccess(Objective objective) {
253 log.info("Igmp filter for {} on {} installed.",
254 devId, port);
255 }
256
257 @Override
258 public void onError(Objective objective, ObjectiveError error) {
259 log.info("Igmp filter for {} on {} failed because {}.",
260 devId, port, error);
261 }
262 });
263
264 flowObjectiveService.filter(devId, igmp);
265 }
266
Jonathan Hartcb286ac2016-02-12 19:26:02 -0800267 private void processMembership(IGMP pkt, ConnectPoint location) {
268 pkt.getGroups().forEach(group -> {
269
270 if (!(group instanceof IGMPMembership)) {
271 log.warn("Wrong group type in IGMP membership");
272 return;
273 }
274
275 IGMPMembership membership = (IGMPMembership) group;
276
Jonathan Hart16e1fa22016-02-16 13:06:26 -0800277 // TODO allow pulling source from IGMP packet
Jonathan Hart04857782016-02-18 15:56:22 -0800278 IpAddress source = ssmTranslateTable.get(group.getGaddr());
279 if (source == null) {
280 log.warn("No source found in SSM translate table for {}", group.getGaddr());
281 return;
Jonathan Hart16e1fa22016-02-16 13:06:26 -0800282 }
283
284 McastRoute route = new McastRoute(source,
285 group.getGaddr(),
286 McastRoute.Type.IGMP);
Jonathan Hartcb286ac2016-02-12 19:26:02 -0800287
288 if (membership.getRecordType() == IGMPMembership.MODE_IS_INCLUDE ||
289 membership.getRecordType() == IGMPMembership.CHANGE_TO_INCLUDE_MODE) {
290
Jonathan Hart04857782016-02-18 15:56:22 -0800291 multicastService.removeSink(route, location);
292 // TODO remove route if all sinks are gone
293 } else if (membership.getRecordType() == IGMPMembership.MODE_IS_EXCLUDE ||
294 membership.getRecordType() == IGMPMembership.CHANGE_TO_EXCLUDE_MODE) {
Jonathan Hartcb286ac2016-02-12 19:26:02 -0800295
296 multicastService.add(route);
297 multicastService.addSink(route, location);
Jonathan Hartcb286ac2016-02-12 19:26:02 -0800298 }
299
300 });
301 }
302
alshabib9bb0e182016-02-14 19:53:42 -0800303 private ByteBuffer buildQueryPacket() {
304 IGMP igmp = new IGMP();
305 igmp.setIgmpType(IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY);
306 igmp.setMaxRespCode(maxRespCode);
307
308 IGMPQuery query = new IGMPQuery(IpAddress.valueOf("0.0.0.0"), 0);
309 igmp.addGroup(query);
310
311 IPv4 ip = new IPv4();
312 ip.setDestinationAddress(DEST_IP);
313 ip.setProtocol(IPv4.PROTOCOL_IGMP);
314 ip.setSourceAddress("192.168.1.1");
315 ip.setTtl((byte) 1);
316 ip.setPayload(igmp);
317
318 Ethernet eth = new Ethernet();
319 eth.setDestinationMACAddress(DEST_MAC);
320 eth.setSourceMACAddress("DE:AD:BE:EF:BA:11");
321 eth.setEtherType(Ethernet.TYPE_IPV4);
322
323 eth.setPayload(ip);
324
325 return ByteBuffer.wrap(eth.serialize());
326 }
327
328 private void querySubscribers() {
329 oltData.keySet().stream()
330 .flatMap(did -> deviceService.getPorts(did).stream())
331 .filter(p -> !oltData.get(p.element().id()).uplink().equals(p.number()))
332 .filter(p -> p.isEnabled())
333 .forEach(p -> {
334 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
335 .setOutput(p.number()).build();
336 packetService.emit(new DefaultOutboundPacket((DeviceId) p.element().id(),
337 treatment, queryPacket));
338 });
339 }
340
alshabib69297fd2015-09-23 13:22:33 -0700341 /**
342 * Packet processor responsible for handling IGMP packets.
343 */
alshabibad1e3b22015-12-07 16:01:01 -0800344 private class IgmpPacketProcessor implements PacketProcessor {
alshabib69297fd2015-09-23 13:22:33 -0700345
346 @Override
347 public void process(PacketContext context) {
348 // Stop processing if the packet has been handled, since we
349 // can't do any more to it.
350 if (context.isHandled()) {
351 return;
352 }
353
354 InboundPacket pkt = context.inPacket();
355 Ethernet ethPkt = pkt.parsed();
356 if (ethPkt == null) {
357 return;
358 }
359
360 /*
361 * IPv6 MLD packets are handled by ICMP6. We'll only deal
362 * with IPv4.
363 */
364 if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) {
365 return;
366 }
367
368 IPv4 ip = (IPv4) ethPkt.getPayload();
369 IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());
370 IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress());
alshabibad1e3b22015-12-07 16:01:01 -0800371 log.debug("Packet ({}, {}) -> ingress port: {}", saddr, gaddr,
372 context.inPacket().receivedFrom());
373
alshabib69297fd2015-09-23 13:22:33 -0700374
375 if (ip.getProtocol() != IPv4.PROTOCOL_IGMP) {
Rusty Eddy05f1b642015-10-12 16:59:04 -0700376 log.debug("IGMP Picked up a non IGMP packet.");
alshabib69297fd2015-09-23 13:22:33 -0700377 return;
378 }
379
alshabibad1e3b22015-12-07 16:01:01 -0800380 IpPrefix mcast = IpPrefix.valueOf(DEFAULT_MCAST_ADDR);
alshabib69297fd2015-09-23 13:22:33 -0700381 if (!mcast.contains(gaddr)) {
Rusty Eddy05f1b642015-10-12 16:59:04 -0700382 log.debug("IGMP Picked up a non multicast packet.");
alshabib69297fd2015-09-23 13:22:33 -0700383 return;
384 }
385
386 if (mcast.contains(saddr)) {
Rusty Eddy05f1b642015-10-12 16:59:04 -0700387 log.debug("IGMP Picked up a packet with a multicast source address.");
alshabib69297fd2015-09-23 13:22:33 -0700388 return;
389 }
alshabib69297fd2015-09-23 13:22:33 -0700390
391 IGMP igmp = (IGMP) ip.getPayload();
392 switch (igmp.getIgmpType()) {
393
394 case IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT:
Jonathan Hartcb286ac2016-02-12 19:26:02 -0800395 processMembership(igmp, pkt.receivedFrom());
alshabib69297fd2015-09-23 13:22:33 -0700396 break;
397
398 case IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY:
alshabib9bb0e182016-02-14 19:53:42 -0800399 log.debug("Received a membership query {} from {}",
400 igmp, pkt.receivedFrom());
alshabib69297fd2015-09-23 13:22:33 -0700401 break;
402
403 case IGMP.TYPE_IGMPV1_MEMBERSHIP_REPORT:
404 case IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT:
405 case IGMP.TYPE_IGMPV2_LEAVE_GROUP:
Jonathan Hartcb286ac2016-02-12 19:26:02 -0800406 log.debug("IGMP version 1 & 2 message types are not currently supported. Message type: {}",
alshabib9bb0e182016-02-14 19:53:42 -0800407 igmp.getIgmpType());
alshabib69297fd2015-09-23 13:22:33 -0700408 break;
alshabib69297fd2015-09-23 13:22:33 -0700409 default:
Jonathan Hartcb286ac2016-02-12 19:26:02 -0800410 log.debug("Unknown IGMP message type: {}", igmp.getIgmpType());
alshabib69297fd2015-09-23 13:22:33 -0700411 break;
412 }
413 }
414 }
alshabibad1e3b22015-12-07 16:01:01 -0800415
alshabibad1e3b22015-12-07 16:01:01 -0800416
alshabibe9a108d2016-02-01 17:25:00 -0800417 private class InternalDeviceListener implements DeviceListener {
418 @Override
419 public void event(DeviceEvent event) {
alshabib72f43dc2016-02-17 15:37:56 -0800420 DeviceId devId = event.subject().id();
alshabibe9a108d2016-02-01 17:25:00 -0800421 switch (event.type()) {
422
423 case DEVICE_ADDED:
424 case DEVICE_UPDATED:
425 case DEVICE_REMOVED:
426 case DEVICE_SUSPENDED:
427 case DEVICE_AVAILABILITY_CHANGED:
428 case PORT_STATS_UPDATED:
429 break;
430 case PORT_ADDED:
alshabib72f43dc2016-02-17 15:37:56 -0800431 if (!oltData.get(devId).uplink().equals(event.port().number()) &&
432 event.port().isEnabled()) {
alshabibe9a108d2016-02-01 17:25:00 -0800433 processFilterObjective(event.subject().id(), event.port(), false);
434 }
435 break;
436 case PORT_UPDATED:
alshabib72f43dc2016-02-17 15:37:56 -0800437 if (oltData.get(devId).uplink().equals(event.port().number())) {
438 break;
439 }
alshabibe9a108d2016-02-01 17:25:00 -0800440 if (event.port().isEnabled()) {
441 processFilterObjective(event.subject().id(), event.port(), false);
442 } else {
443 processFilterObjective(event.subject().id(), event.port(), true);
444 }
445 break;
446 case PORT_REMOVED:
alshabib36e043f2016-02-11 17:31:36 -0800447 processFilterObjective(event.subject().id(), event.port(), true);
alshabibe9a108d2016-02-01 17:25:00 -0800448 break;
449 default:
450 log.warn("Unknown device event {}", event.type());
451 break;
452 }
alshabibe9a108d2016-02-01 17:25:00 -0800453 }
454
455 @Override
456 public boolean isRelevant(DeviceEvent event) {
457 return oltData.containsKey(event.subject().id());
458 }
alshabibad1e3b22015-12-07 16:01:01 -0800459 }
alshabib36e043f2016-02-11 17:31:36 -0800460
461 private class InternalNetworkConfigListener implements NetworkConfigListener {
462 @Override
463 public void event(NetworkConfigEvent event) {
464 switch (event.type()) {
465
466 case CONFIG_ADDED:
467 case CONFIG_UPDATED:
468 if (event.configClass().equals(CONFIG_CLASS)) {
469 AccessDeviceConfig config =
470 networkConfig.getConfig((DeviceId) event.subject(), CONFIG_CLASS);
471 if (config != null) {
472 oltData.put(config.getOlt().deviceId(), config.getOlt());
473 provisionDefaultFlows((DeviceId) event.subject());
474 }
475 }
Jonathan Hart965b9f92016-02-16 13:06:26 -0800476 if (event.configClass().equals(SSM_TRANSLATE_CONFIG_CLASS)) {
477 IgmpSsmTranslateConfig config =
478 networkConfig.getConfig((ApplicationId) event.subject(),
479 SSM_TRANSLATE_CONFIG_CLASS);
480
481 if (config != null) {
482 ssmTranslateTable.clear();
483 config.getSsmTranslations().forEach(
484 route -> ssmTranslateTable.put(route.group(), route.source()));
485 }
486 }
alshabib36e043f2016-02-11 17:31:36 -0800487 break;
Jonathan Hart965b9f92016-02-16 13:06:26 -0800488 case CONFIG_REGISTERED:
alshabib36e043f2016-02-11 17:31:36 -0800489 case CONFIG_UNREGISTERED:
Jonathan Hart965b9f92016-02-16 13:06:26 -0800490 break;
alshabib36e043f2016-02-11 17:31:36 -0800491 case CONFIG_REMOVED:
Jonathan Hart965b9f92016-02-16 13:06:26 -0800492 if (event.configClass().equals(SSM_TRANSLATE_CONFIG_CLASS)) {
493 ssmTranslateTable.clear();
494 }
alshabib36e043f2016-02-11 17:31:36 -0800495 default:
496 break;
497 }
498 }
499 }
500
501 private void provisionDefaultFlows(DeviceId deviceId) {
502 List<Port> ports = deviceService.getPorts(deviceId);
503
504 ports.stream()
505 .filter(p -> !oltData.get(p.element().id()).uplink().equals(p.number()))
506 .filter(p -> p.isEnabled())
507 .forEach(p -> processFilterObjective((DeviceId) p.element().id(), p, false));
508
509 }
alshabib69297fd2015-09-23 13:22:33 -0700510}