alshabib

adding igmp query polling to igmp application.

Change-Id: I995336417e11404d96f33cdae96b12202d454dd1

adding SafeRecurringTask

Change-Id: Ie560e61500f85339c296f03ed8684078737edcd1
...@@ -57,7 +57,6 @@ ...@@ -57,7 +57,6 @@
57 <version>${project.version}</version> 57 <version>${project.version}</version>
58 </dependency> 58 </dependency>
59 59
60 -
61 <dependency> 60 <dependency>
62 <groupId>org.onosproject</groupId> 61 <groupId>org.onosproject</groupId>
63 <artifactId>onlab-osgi</artifactId> 62 <artifactId>onlab-osgi</artifactId>
...@@ -84,36 +83,4 @@ ...@@ -84,36 +83,4 @@
84 83
85 </dependencies> 84 </dependencies>
86 85
87 - <build>
88 - <plugins>
89 - <plugin>
90 - <groupId>org.apache.felix</groupId>
91 - <artifactId>maven-bundle-plugin</artifactId>
92 - <extensions>true</extensions>
93 - <configuration>
94 - <instructions>
95 - <Bundle-SymbolicName>
96 - ${project.groupId}.${project.artifactId}
97 - </Bundle-SymbolicName>
98 - <Import-Package>
99 - org.slf4j,
100 - org.osgi.framework,
101 - com.google.common.*,
102 - org.onlab.packet.*,
103 - org.onosproject.*,
104 - </Import-Package>
105 - </instructions>
106 - </configuration>
107 - </plugin>
108 - <plugin>
109 - <groupId>org.apache.maven.plugins</groupId>
110 - <artifactId>maven-compiler-plugin</artifactId>
111 - <configuration>
112 - <source>1.8</source>
113 - <target>1.8</target>
114 - </configuration>
115 - </plugin>
116 - </plugins>
117 - </build>
118 -
119 </project> 86 </project>
......
...@@ -25,10 +25,12 @@ import org.onlab.packet.EthType; ...@@ -25,10 +25,12 @@ import org.onlab.packet.EthType;
25 import org.onlab.packet.Ethernet; 25 import org.onlab.packet.Ethernet;
26 import org.onlab.packet.IGMP; 26 import org.onlab.packet.IGMP;
27 import org.onlab.packet.IGMPMembership; 27 import org.onlab.packet.IGMPMembership;
28 +import org.onlab.packet.IGMPQuery;
28 import org.onlab.packet.IPv4; 29 import org.onlab.packet.IPv4;
29 import org.onlab.packet.Ip4Address; 30 import org.onlab.packet.Ip4Address;
30 import org.onlab.packet.IpAddress; 31 import org.onlab.packet.IpAddress;
31 import org.onlab.packet.IpPrefix; 32 import org.onlab.packet.IpPrefix;
33 +import org.onlab.util.SafeRecurringTask;
32 import org.onosproject.core.ApplicationId; 34 import org.onosproject.core.ApplicationId;
33 import org.onosproject.core.CoreService; 35 import org.onosproject.core.CoreService;
34 import org.onosproject.net.ConnectPoint; 36 import org.onosproject.net.ConnectPoint;
...@@ -44,6 +46,7 @@ import org.onosproject.net.device.DeviceEvent; ...@@ -44,6 +46,7 @@ import org.onosproject.net.device.DeviceEvent;
44 import org.onosproject.net.device.DeviceListener; 46 import org.onosproject.net.device.DeviceListener;
45 import org.onosproject.net.device.DeviceService; 47 import org.onosproject.net.device.DeviceService;
46 import org.onosproject.net.flow.DefaultTrafficTreatment; 48 import org.onosproject.net.flow.DefaultTrafficTreatment;
49 +import org.onosproject.net.flow.TrafficTreatment;
47 import org.onosproject.net.flow.criteria.Criteria; 50 import org.onosproject.net.flow.criteria.Criteria;
48 import org.onosproject.net.flowobjective.DefaultFilteringObjective; 51 import org.onosproject.net.flowobjective.DefaultFilteringObjective;
49 import org.onosproject.net.flowobjective.FilteringObjective; 52 import org.onosproject.net.flowobjective.FilteringObjective;
...@@ -53,6 +56,7 @@ import org.onosproject.net.flowobjective.ObjectiveContext; ...@@ -53,6 +56,7 @@ import org.onosproject.net.flowobjective.ObjectiveContext;
53 import org.onosproject.net.flowobjective.ObjectiveError; 56 import org.onosproject.net.flowobjective.ObjectiveError;
54 import org.onosproject.net.mcast.McastRoute; 57 import org.onosproject.net.mcast.McastRoute;
55 import org.onosproject.net.mcast.MulticastRouteService; 58 import org.onosproject.net.mcast.MulticastRouteService;
59 +import org.onosproject.net.packet.DefaultOutboundPacket;
56 import org.onosproject.net.packet.InboundPacket; 60 import org.onosproject.net.packet.InboundPacket;
57 import org.onosproject.net.packet.PacketContext; 61 import org.onosproject.net.packet.PacketContext;
58 import org.onosproject.net.packet.PacketProcessor; 62 import org.onosproject.net.packet.PacketProcessor;
...@@ -61,10 +65,16 @@ import org.onosproject.olt.AccessDeviceConfig; ...@@ -61,10 +65,16 @@ import org.onosproject.olt.AccessDeviceConfig;
61 import org.onosproject.olt.AccessDeviceData; 65 import org.onosproject.olt.AccessDeviceData;
62 import org.slf4j.Logger; 66 import org.slf4j.Logger;
63 67
68 +import java.nio.ByteBuffer;
64 import java.util.List; 69 import java.util.List;
65 import java.util.Map; 70 import java.util.Map;
66 import java.util.concurrent.ConcurrentHashMap; 71 import java.util.concurrent.ConcurrentHashMap;
72 +import java.util.concurrent.Executors;
73 +import java.util.concurrent.ScheduledExecutorService;
74 +import java.util.concurrent.ScheduledFuture;
75 +import java.util.concurrent.TimeUnit;
67 76
77 +import static org.onlab.util.Tools.groupedThreads;
68 import static org.slf4j.LoggerFactory.getLogger; 78 import static org.slf4j.LoggerFactory.getLogger;
69 79
70 /** 80 /**
...@@ -72,14 +82,29 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -72,14 +82,29 @@ import static org.slf4j.LoggerFactory.getLogger;
72 */ 82 */
73 @Component(immediate = true) 83 @Component(immediate = true)
74 public class IgmpSnoop { 84 public class IgmpSnoop {
85 +
86 +
75 private final Logger log = getLogger(getClass()); 87 private final Logger log = getLogger(getClass());
76 88
89 + 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;
77 private static final String DEFAULT_MCAST_ADDR = "224.0.0.0/4"; 94 private static final String DEFAULT_MCAST_ADDR = "224.0.0.0/4";
78 95
79 @Property(name = "multicastAddress", 96 @Property(name = "multicastAddress",
80 label = "Define the multicast base range to listen to") 97 label = "Define the multicast base range to listen to")
81 private String multicastAddress = DEFAULT_MCAST_ADDR; 98 private String multicastAddress = DEFAULT_MCAST_ADDR;
82 99
100 + @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 +
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected FlowObjectiveService flowObjectiveService; 109 protected FlowObjectiveService flowObjectiveService;
85 110
...@@ -98,6 +123,12 @@ public class IgmpSnoop { ...@@ -98,6 +123,12 @@ public class IgmpSnoop {
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected DeviceService deviceService; 124 protected DeviceService deviceService;
100 125
126 +
127 + private ScheduledFuture<?> queryTask;
128 + private final ScheduledExecutorService queryService =
129 + Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/igmp-query",
130 + "membership-query"));
131 +
101 private Map<DeviceId, AccessDeviceData> oltData = new ConcurrentHashMap<>(); 132 private Map<DeviceId, AccessDeviceData> oltData = new ConcurrentHashMap<>();
102 133
103 private DeviceListener deviceListener = new InternalDeviceListener(); 134 private DeviceListener deviceListener = new InternalDeviceListener();
...@@ -120,6 +151,9 @@ public class IgmpSnoop { ...@@ -120,6 +151,9 @@ public class IgmpSnoop {
120 }; 151 };
121 152
122 153
154 + private ByteBuffer queryPacket;
155 +
156 +
123 @Activate 157 @Activate
124 public void activate() { 158 public void activate() {
125 appId = coreService.registerApplication("org.onosproject.igmp"); 159 appId = coreService.registerApplication("org.onosproject.igmp");
...@@ -149,6 +183,14 @@ public class IgmpSnoop { ...@@ -149,6 +183,14 @@ public class IgmpSnoop {
149 183
150 deviceService.addListener(deviceListener); 184 deviceService.addListener(deviceListener);
151 185
186 + queryPacket = buildQueryPacket();
187 +
188 + queryTask = queryService.scheduleWithFixedDelay(
189 + SafeRecurringTask.wrap(this::querySubscribers),
190 + 0,
191 + queryPeriod,
192 + TimeUnit.SECONDS);
193 +
152 log.info("Started"); 194 log.info("Started");
153 } 195 }
154 196
...@@ -159,6 +201,8 @@ public class IgmpSnoop { ...@@ -159,6 +201,8 @@ public class IgmpSnoop {
159 deviceService.removeListener(deviceListener); 201 deviceService.removeListener(deviceListener);
160 networkConfig.removeListener(configListener); 202 networkConfig.removeListener(configListener);
161 networkConfig.unregisterConfigFactory(configFactory); 203 networkConfig.unregisterConfigFactory(configFactory);
204 + queryTask.cancel(true);
205 + queryService.shutdownNow();
162 log.info("Stopped"); 206 log.info("Stopped");
163 } 207 }
164 208
...@@ -194,19 +238,6 @@ public class IgmpSnoop { ...@@ -194,19 +238,6 @@ public class IgmpSnoop {
194 flowObjectiveService.filter(devId, igmp); 238 flowObjectiveService.filter(devId, igmp);
195 } 239 }
196 240
197 - private void processQuery(IGMP pkt, ConnectPoint location) {
198 - // TODO is this the right thing to do for a query?
199 - pkt.getGroups().forEach(group -> group.getSources().forEach(src -> {
200 -
201 - McastRoute route = new McastRoute(src,
202 - group.getGaddr(),
203 - McastRoute.Type.IGMP);
204 - multicastService.add(route);
205 - multicastService.addSink(route, location);
206 -
207 - }));
208 - }
209 -
210 private void processMembership(IGMP pkt, ConnectPoint location) { 241 private void processMembership(IGMP pkt, ConnectPoint location) {
211 pkt.getGroups().forEach(group -> { 242 pkt.getGroups().forEach(group -> {
212 243
...@@ -218,8 +249,8 @@ public class IgmpSnoop { ...@@ -218,8 +249,8 @@ public class IgmpSnoop {
218 IGMPMembership membership = (IGMPMembership) group; 249 IGMPMembership membership = (IGMPMembership) group;
219 250
220 McastRoute route = new McastRoute(IpAddress.valueOf("0.0.0.0"), 251 McastRoute route = new McastRoute(IpAddress.valueOf("0.0.0.0"),
221 - group.getGaddr(), 252 + group.getGaddr(),
222 - McastRoute.Type.IGMP); 253 + McastRoute.Type.IGMP);
223 254
224 if (membership.getRecordType() == IGMPMembership.MODE_IS_INCLUDE || 255 if (membership.getRecordType() == IGMPMembership.MODE_IS_INCLUDE ||
225 membership.getRecordType() == IGMPMembership.CHANGE_TO_INCLUDE_MODE) { 256 membership.getRecordType() == IGMPMembership.CHANGE_TO_INCLUDE_MODE) {
...@@ -237,6 +268,44 @@ public class IgmpSnoop { ...@@ -237,6 +268,44 @@ public class IgmpSnoop {
237 }); 268 });
238 } 269 }
239 270
271 + private ByteBuffer buildQueryPacket() {
272 + IGMP igmp = new IGMP();
273 + igmp.setIgmpType(IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY);
274 + igmp.setMaxRespCode(maxRespCode);
275 +
276 + IGMPQuery query = new IGMPQuery(IpAddress.valueOf("0.0.0.0"), 0);
277 + igmp.addGroup(query);
278 +
279 + IPv4 ip = new IPv4();
280 + ip.setDestinationAddress(DEST_IP);
281 + ip.setProtocol(IPv4.PROTOCOL_IGMP);
282 + ip.setSourceAddress("192.168.1.1");
283 + ip.setTtl((byte) 1);
284 + ip.setPayload(igmp);
285 +
286 + Ethernet eth = new Ethernet();
287 + eth.setDestinationMACAddress(DEST_MAC);
288 + eth.setSourceMACAddress("DE:AD:BE:EF:BA:11");
289 + eth.setEtherType(Ethernet.TYPE_IPV4);
290 +
291 + eth.setPayload(ip);
292 +
293 + return ByteBuffer.wrap(eth.serialize());
294 + }
295 +
296 + private void querySubscribers() {
297 + oltData.keySet().stream()
298 + .flatMap(did -> deviceService.getPorts(did).stream())
299 + .filter(p -> !oltData.get(p.element().id()).uplink().equals(p.number()))
300 + .filter(p -> p.isEnabled())
301 + .forEach(p -> {
302 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
303 + .setOutput(p.number()).build();
304 + packetService.emit(new DefaultOutboundPacket((DeviceId) p.element().id(),
305 + treatment, queryPacket));
306 + });
307 + }
308 +
240 /** 309 /**
241 * Packet processor responsible for handling IGMP packets. 310 * Packet processor responsible for handling IGMP packets.
242 */ 311 */
...@@ -295,14 +364,15 @@ public class IgmpSnoop { ...@@ -295,14 +364,15 @@ public class IgmpSnoop {
295 break; 364 break;
296 365
297 case IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY: 366 case IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY:
298 - processQuery(igmp, pkt.receivedFrom()); 367 + log.debug("Received a membership query {} from {}",
368 + igmp, pkt.receivedFrom());
299 break; 369 break;
300 370
301 case IGMP.TYPE_IGMPV1_MEMBERSHIP_REPORT: 371 case IGMP.TYPE_IGMPV1_MEMBERSHIP_REPORT:
302 case IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT: 372 case IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT:
303 case IGMP.TYPE_IGMPV2_LEAVE_GROUP: 373 case IGMP.TYPE_IGMPV2_LEAVE_GROUP:
304 log.debug("IGMP version 1 & 2 message types are not currently supported. Message type: {}", 374 log.debug("IGMP version 1 & 2 message types are not currently supported. Message type: {}",
305 - igmp.getIgmpType()); 375 + igmp.getIgmpType());
306 break; 376 break;
307 default: 377 default:
308 log.debug("Unknown IGMP message type: {}", igmp.getIgmpType()); 378 log.debug("Unknown IGMP message type: {}", igmp.getIgmpType());
......