blob: f46d77b5ab6ac4934ebd3910671c1d22e5875ba4 [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 */
16package org.onosproject.mfwd.impl;
17
Julian Lawrencefa790f62016-01-07 17:18:30 -080018import static com.google.common.base.Preconditions.checkNotNull;
alshabibeff00542015-09-23 13:22:33 -070019import static org.slf4j.LoggerFactory.getLogger;
20
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26
27import org.onlab.packet.Ethernet;
28import org.onlab.packet.IpPrefix;
29import org.onlab.packet.IpAddress;
30import org.onlab.packet.Ip4Address;
31import org.onlab.packet.IPv4;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.net.ConnectPoint;
35import org.onosproject.net.flow.DefaultTrafficSelector;
36import org.onosproject.net.flow.DefaultTrafficTreatment;
37import org.onosproject.net.flow.TrafficSelector;
38import org.onosproject.net.flow.TrafficTreatment;
Julian Lawrencefa790f62016-01-07 17:18:30 -080039import org.onosproject.net.mcast.MulticastRouteService;
40import org.onosproject.net.mcast.McastRoute;
alshabibeff00542015-09-23 13:22:33 -070041import org.onosproject.net.packet.DefaultOutboundPacket;
42import org.onosproject.net.packet.InboundPacket;
43import org.onosproject.net.packet.OutboundPacket;
44import org.onosproject.net.packet.PacketContext;
45import org.onosproject.net.packet.PacketPriority;
46import org.onosproject.net.packet.PacketProcessor;
47import org.onosproject.net.packet.PacketService;
48import org.slf4j.Logger;
49
Julian Lawrencefa790f62016-01-07 17:18:30 -080050import java.util.ArrayList;
51
alshabibeff00542015-09-23 13:22:33 -070052/**
Julian Lawrencefa790f62016-01-07 17:18:30 -080053 * The multicast forwarding component. This component is responsible for
54 * handling live multicast traffic by modifying multicast state and forwarding
55 * packets that do not yet have state installed.
alshabibeff00542015-09-23 13:22:33 -070056 */
57@Component(immediate = true)
58public class McastForwarding {
59
60 private final Logger log = getLogger(getClass());
61 private final IpPrefix mcast = IpPrefix.valueOf("224.0.0.0/4");
62
63 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 protected PacketService packetService;
65
66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 protected CoreService coreService;
68
Julian Lawrencefa790f62016-01-07 17:18:30 -080069 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 protected MulticastRouteService mcastRouteManager;
71
72
73
alshabibeff00542015-09-23 13:22:33 -070074 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
alshabibeff00542015-09-23 13:22:33 -070075 private static ApplicationId appId;
76
77 /**
78 * Active MulticastForwardingIntent.
79 */
80 @Activate
81 public void activate() {
82 appId = coreService.registerApplication("org.onosproject.mfwd");
83
84 packetService.addProcessor(processor, PacketProcessor.director(2));
85
86 // Build a traffic selector for all multicast traffic
87 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
88 selector.matchEthType(Ethernet.TYPE_IPV4);
89 selector.matchIPDst(mcast);
Julian Lawrencefa790f62016-01-07 17:18:30 -080090
alshabibeff00542015-09-23 13:22:33 -070091 packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);
92
alshabibeff00542015-09-23 13:22:33 -070093 log.info("Started");
94 }
95
96 /**
97 * Deactivate Multicast Forwarding Intent.
98 */
99 @Deactivate
100 public void deactivate() {
101 packetService.removeProcessor(processor);
102 processor = null;
103 log.info("Stopped");
104 }
105
106 /**
107 * Get the application ID, used by the McastIntentManager.
108 *
109 * @return the application ID
110 */
111 public static ApplicationId getAppId() {
112 return appId;
113 }
114
115 /**
116 * Packet processor responsible for forwarding packets along their paths.
117 */
118 private class ReactivePacketProcessor implements PacketProcessor {
119
120 /**
121 * Process incoming packets.
122 *
123 * @param context packet processing context
124 */
125 @Override
126 public void process(PacketContext context) {
127 // Stop processing if the packet has been handled, since we
128 // can't do any more to it.
129 if (context.isHandled()) {
130 return;
131 }
132
133 InboundPacket pkt = context.inPacket();
134 Ethernet ethPkt = pkt.parsed();
135
136 if (ethPkt == null) {
137 return;
138 }
139
140 if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4 &&
141 ethPkt.getEtherType() != Ethernet.TYPE_IPV6) {
142 return;
143 }
144
145 if (ethPkt.getEtherType() == Ethernet.TYPE_IPV6) {
146 // Ignore ipv6 at the moment.
147 return;
148 }
149
150 IPv4 ip = (IPv4) ethPkt.getPayload();
alshabibeff00542015-09-23 13:22:33 -0700151 IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress());
Julian Lawrencefa790f62016-01-07 17:18:30 -0800152 IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());
alshabibeff00542015-09-23 13:22:33 -0700153
154 log.debug("Packet ({}, {}) has been punted\n" +
155 "\tingress port: {}\n",
156 saddr.toString(),
157 gaddr.toString(),
158 context.inPacket().receivedFrom().toString());
159
Julian Lawrencefa790f62016-01-07 17:18:30 -0800160 // Don't allow PIM/IGMP packets to be handled here.
161 byte proto = ip.getProtocol();
162 if (proto == IPv4.PROTOCOL_PIM || proto == IPv4.PROTOCOL_IGMP) {
alshabibeff00542015-09-23 13:22:33 -0700163 return;
164 }
165
166 IpPrefix spfx = IpPrefix.valueOf(saddr, 32);
167 IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32);
168
Julian Lawrencefa790f62016-01-07 17:18:30 -0800169 // TODO do we want to add a type for Mcast?
170 McastRoute mRoute = new McastRoute(spfx, gpfx, McastRoute.Type.STATIC);
alshabibeff00542015-09-23 13:22:33 -0700171
Julian Lawrencefa790f62016-01-07 17:18:30 -0800172 ConnectPoint ingress = mcastRouteManager.fetchSource(mRoute);
173
174 // An ingress port already exists. Log error.
175 if (ingress != null) {
176 log.error(McastForwarding.class.getSimpleName() + " received packet which already has a route.");
177 return;
178 } else {
179 //add ingress port
180 mcastRouteManager.addSource(mRoute, pkt.receivedFrom());
alshabibeff00542015-09-23 13:22:33 -0700181 }
182
Julian Lawrencefa790f62016-01-07 17:18:30 -0800183 ArrayList<ConnectPoint> egressList = (ArrayList<ConnectPoint>) mcastRouteManager.fetchSinks(mRoute);
184 //If there are no egress ports set return, otherwise forward the packets to their expected port.
185 if (egressList.size() == 0) {
alshabibeff00542015-09-23 13:22:33 -0700186 return;
187 }
188
alshabibeff00542015-09-23 13:22:33 -0700189 // Send the pack out each of the egress devices & port
Julian Lawrencefa790f62016-01-07 17:18:30 -0800190 forwardPacketToDst(context, egressList);
alshabibeff00542015-09-23 13:22:33 -0700191 }
192 }
193
194 /**
195 * Forward the packet to it's multicast destinations.
196 *
197 * @param context The packet context
Julian Lawrencefa790f62016-01-07 17:18:30 -0800198 * @param egressList The list of egress ports which the multicast packet is intended for.
alshabibeff00542015-09-23 13:22:33 -0700199 */
Julian Lawrencefa790f62016-01-07 17:18:30 -0800200 private void forwardPacketToDst(PacketContext context, ArrayList<ConnectPoint> egressList) {
alshabibeff00542015-09-23 13:22:33 -0700201
202 // Send the pack out each of the respective egress ports
Julian Lawrencefa790f62016-01-07 17:18:30 -0800203 for (ConnectPoint egress : egressList) {
alshabibeff00542015-09-23 13:22:33 -0700204 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
205 .setOutput(egress.port()).build();
206
207 OutboundPacket packet = new DefaultOutboundPacket(
208 egress.deviceId(),
209 treatment,
210 context.inPacket().unparsed());
211
212 packetService.emit(packet);
213 }
214 }
Julian Lawrencefa790f62016-01-07 17:18:30 -0800215
216 public static McastRoute createStaticRoute(String source, String group) {
217 checkNotNull(source, "Must provide a source");
218 checkNotNull(group, "Must provide a group");
219 IpPrefix ipSource = IpPrefix.valueOf(source);
220 IpPrefix ipGroup = IpPrefix.valueOf(group);
221 return createStaticcreateRoute(ipSource, ipGroup);
222 }
223
224 public static McastRoute createStaticcreateRoute(IpPrefix source, IpPrefix group) {
225 checkNotNull(source, "Must provide a source");
226 checkNotNull(group, "Must provide a group");
227 McastRoute.Type type = McastRoute.Type.STATIC;
228 return new McastRoute(source, group, type);
229 }
alshabibeff00542015-09-23 13:22:33 -0700230}