blob: cf5f8a0c37b20b4083a72ce189adc68754739262 [file] [log] [blame]
alshabibeff00542015-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 */
alshabib79e52872015-12-07 16:01:01 -080016package org.onosproject.igmp;
alshabibeff00542015-09-23 13:22:33 -070017
18import static org.slf4j.LoggerFactory.getLogger;
19
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
alshabib79e52872015-12-07 16:01:01 -080023import org.apache.felix.scr.annotations.Property;
alshabibeff00542015-09-23 13:22:33 -070024import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.onlab.packet.Ethernet;
27import org.onlab.packet.IPv4;
28import org.onlab.packet.Ip4Address;
29import org.onlab.packet.IpAddress;
30import org.onlab.packet.IpPrefix;
31import org.onlab.packet.IGMP;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
alshabib79e52872015-12-07 16:01:01 -080034import org.onosproject.net.ConnectPoint;
35import org.onosproject.net.DeviceId;
36import org.onosproject.net.config.NetworkConfigRegistry;
alshabibeff00542015-09-23 13:22:33 -070037import org.onosproject.net.flow.DefaultTrafficSelector;
38import org.onosproject.net.flow.TrafficSelector;
alshabib79e52872015-12-07 16:01:01 -080039import org.onosproject.net.mcast.McastRoute;
40import org.onosproject.net.mcast.MulticastRouteService;
alshabibeff00542015-09-23 13:22:33 -070041import org.onosproject.net.packet.InboundPacket;
42import org.onosproject.net.packet.PacketContext;
43import org.onosproject.net.packet.PacketPriority;
44import org.onosproject.net.packet.PacketProcessor;
45import org.onosproject.net.packet.PacketService;
46import org.slf4j.Logger;
47
alshabib79e52872015-12-07 16:01:01 -080048import java.util.Optional;
49
alshabibeff00542015-09-23 13:22:33 -070050/**
51 * Internet Group Management Protocol.
52 */
53@Component(immediate = true)
alshabib79e52872015-12-07 16:01:01 -080054public class IgmpSnoop {
alshabibeff00542015-09-23 13:22:33 -070055 private final Logger log = getLogger(getClass());
56
alshabib79e52872015-12-07 16:01:01 -080057 private static final String DEFAULT_MCAST_ADDR = "224.0.0.0/4";
58
59 @Property(name = "multicastAddress",
60 label = "Define the multicast base raneg to listen to")
61 private String multicastAddress = DEFAULT_MCAST_ADDR;
62
alshabibeff00542015-09-23 13:22:33 -070063 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 protected PacketService packetService;
65
66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 protected CoreService coreService;
68
alshabib79e52872015-12-07 16:01:01 -080069 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 protected NetworkConfigRegistry networkConfig;
71
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected MulticastRouteService multicastService;
74
75 private IgmpPacketProcessor processor = new IgmpPacketProcessor();
alshabibeff00542015-09-23 13:22:33 -070076 private static ApplicationId appId;
77
78 @Activate
79 public void activate() {
80 appId = coreService.registerApplication("org.onosproject.igmp");
81
82 packetService.addProcessor(processor, PacketProcessor.director(1));
83
alshabib79e52872015-12-07 16:01:01 -080084 networkConfig.getSubjects(DeviceId.class, IgmpDeviceConfig.class).forEach(
85 subject -> {
86 IgmpDeviceConfig config = networkConfig.getConfig(subject,
87 IgmpDeviceConfig.class);
88 if (config != null) {
89 IgmpDeviceData data = config.getDevice();
90 submitPacketRequests(data.deviceId());
91 }
92 }
93 );
alshabibeff00542015-09-23 13:22:33 -070094
95 log.info("Started");
96 }
97
98 @Deactivate
99 public void deactivate() {
100 packetService.removeProcessor(processor);
101 processor = null;
102 log.info("Stopped");
103 }
104
alshabib79e52872015-12-07 16:01:01 -0800105 private void submitPacketRequests(DeviceId deviceId) {
106 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
107 selector.matchEthType(Ethernet.TYPE_IPV4);
108 selector.matchIPProtocol(IPv4.PROTOCOL_IGMP);
109 packetService.requestPackets(selector.build(),
110 PacketPriority.REACTIVE,
111 appId,
112 Optional.of(deviceId));
113
114 }
115
alshabibeff00542015-09-23 13:22:33 -0700116 /**
117 * Packet processor responsible for handling IGMP packets.
118 */
alshabib79e52872015-12-07 16:01:01 -0800119 private class IgmpPacketProcessor implements PacketProcessor {
alshabibeff00542015-09-23 13:22:33 -0700120
121 @Override
122 public void process(PacketContext context) {
123 // Stop processing if the packet has been handled, since we
124 // can't do any more to it.
125 if (context.isHandled()) {
126 return;
127 }
128
129 InboundPacket pkt = context.inPacket();
130 Ethernet ethPkt = pkt.parsed();
131 if (ethPkt == null) {
132 return;
133 }
134
135 /*
136 * IPv6 MLD packets are handled by ICMP6. We'll only deal
137 * with IPv4.
138 */
139 if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) {
140 return;
141 }
142
143 IPv4 ip = (IPv4) ethPkt.getPayload();
144 IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());
145 IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress());
alshabib79e52872015-12-07 16:01:01 -0800146 log.debug("Packet ({}, {}) -> ingress port: {}", saddr, gaddr,
147 context.inPacket().receivedFrom());
148
alshabibeff00542015-09-23 13:22:33 -0700149
150 if (ip.getProtocol() != IPv4.PROTOCOL_IGMP) {
Rusty Eddy158d5d82015-10-12 16:59:04 -0700151 log.debug("IGMP Picked up a non IGMP packet.");
alshabibeff00542015-09-23 13:22:33 -0700152 return;
153 }
154
alshabib79e52872015-12-07 16:01:01 -0800155 IpPrefix mcast = IpPrefix.valueOf(DEFAULT_MCAST_ADDR);
alshabibeff00542015-09-23 13:22:33 -0700156 if (!mcast.contains(gaddr)) {
Rusty Eddy158d5d82015-10-12 16:59:04 -0700157 log.debug("IGMP Picked up a non multicast packet.");
alshabibeff00542015-09-23 13:22:33 -0700158 return;
159 }
160
161 if (mcast.contains(saddr)) {
Rusty Eddy158d5d82015-10-12 16:59:04 -0700162 log.debug("IGMP Picked up a packet with a multicast source address.");
alshabibeff00542015-09-23 13:22:33 -0700163 return;
164 }
alshabibeff00542015-09-23 13:22:33 -0700165
166 IGMP igmp = (IGMP) ip.getPayload();
167 switch (igmp.getIgmpType()) {
168
169 case IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT:
170 IGMPProcessMembership.processMembership(igmp, pkt.receivedFrom());
171 break;
172
173 case IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY:
alshabib79e52872015-12-07 16:01:01 -0800174 processQuery(igmp, pkt.receivedFrom());
alshabibeff00542015-09-23 13:22:33 -0700175 break;
176
177 case IGMP.TYPE_IGMPV1_MEMBERSHIP_REPORT:
178 case IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT:
179 case IGMP.TYPE_IGMPV2_LEAVE_GROUP:
180 log.debug("IGMP version 1 & 2 message types are not currently supported. Message type: " +
alshabib79e52872015-12-07 16:01:01 -0800181 igmp.getIgmpType());
alshabibeff00542015-09-23 13:22:33 -0700182 break;
183
184 default:
185 log.debug("Unkown IGMP message type: " + igmp.getIgmpType());
186 break;
187 }
188 }
189 }
alshabib79e52872015-12-07 16:01:01 -0800190
191 private void processQuery(IGMP pkt, ConnectPoint location) {
192 pkt.getGroups().forEach(group -> group.getSources().forEach(src -> {
193
194 McastRoute route = new McastRoute(src,
195 group.getGaddr(),
196 McastRoute.Type.IGMP);
197 multicastService.add(route);
198 multicastService.addSink(route, location);
199
200 }));
201 }
alshabibeff00542015-09-23 13:22:33 -0700202}