blob: 60851d64a3b7649da1ca74f76e6806b4c19df21a [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
alshabibeff00542015-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;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
alshabibeff00542015-09-23 13:22:33 -070023import org.onlab.packet.Ethernet;
alshabibeff00542015-09-23 13:22:33 -070024import org.onlab.packet.IPv4;
Thomas Vachuska61ab5e02016-01-11 13:55:15 -080025import org.onlab.packet.Ip4Address;
26import org.onlab.packet.IpAddress;
27import org.onlab.packet.IpPrefix;
alshabibeff00542015-09-23 13:22:33 -070028import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
30import org.onosproject.net.ConnectPoint;
31import org.onosproject.net.flow.DefaultTrafficSelector;
32import org.onosproject.net.flow.DefaultTrafficTreatment;
33import org.onosproject.net.flow.TrafficSelector;
34import org.onosproject.net.flow.TrafficTreatment;
Julian Lawrencefa790f62016-01-07 17:18:30 -080035import org.onosproject.net.mcast.McastRoute;
Thomas Vachuska61ab5e02016-01-11 13:55:15 -080036import org.onosproject.net.mcast.MulticastRouteService;
alshabibeff00542015-09-23 13:22:33 -070037import org.onosproject.net.packet.DefaultOutboundPacket;
38import org.onosproject.net.packet.InboundPacket;
39import org.onosproject.net.packet.OutboundPacket;
40import org.onosproject.net.packet.PacketContext;
41import org.onosproject.net.packet.PacketPriority;
42import org.onosproject.net.packet.PacketProcessor;
43import org.onosproject.net.packet.PacketService;
44import org.slf4j.Logger;
45
Julian Lawrencefa790f62016-01-07 17:18:30 -080046import java.util.ArrayList;
47
Thomas Vachuska61ab5e02016-01-11 13:55:15 -080048import static com.google.common.base.Preconditions.checkNotNull;
49import static org.slf4j.LoggerFactory.getLogger;
50
alshabibeff00542015-09-23 13:22:33 -070051/**
Julian Lawrencefa790f62016-01-07 17:18:30 -080052 * The multicast forwarding component. This component is responsible for
53 * handling live multicast traffic by modifying multicast state and forwarding
54 * packets that do not yet have state installed.
alshabibeff00542015-09-23 13:22:33 -070055 */
56@Component(immediate = true)
57public class McastForwarding {
58
59 private final Logger log = getLogger(getClass());
60 private final IpPrefix mcast = IpPrefix.valueOf("224.0.0.0/4");
61
62 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 protected PacketService packetService;
64
65 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 protected CoreService coreService;
67
Julian Lawrencefa790f62016-01-07 17:18:30 -080068 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 protected MulticastRouteService mcastRouteManager;
70
71
72
alshabibeff00542015-09-23 13:22:33 -070073 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
alshabibeff00542015-09-23 13:22:33 -070074 private static ApplicationId appId;
75
76 /**
77 * Active MulticastForwardingIntent.
78 */
79 @Activate
80 public void activate() {
81 appId = coreService.registerApplication("org.onosproject.mfwd");
82
83 packetService.addProcessor(processor, PacketProcessor.director(2));
84
85 // Build a traffic selector for all multicast traffic
86 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
87 selector.matchEthType(Ethernet.TYPE_IPV4);
88 selector.matchIPDst(mcast);
Julian Lawrencefa790f62016-01-07 17:18:30 -080089
alshabibeff00542015-09-23 13:22:33 -070090 packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);
91
alshabibeff00542015-09-23 13:22:33 -070092 log.info("Started");
93 }
94
95 /**
96 * Deactivate Multicast Forwarding Intent.
97 */
98 @Deactivate
99 public void deactivate() {
100 packetService.removeProcessor(processor);
101 processor = null;
102 log.info("Stopped");
103 }
104
105 /**
106 * Get the application ID, used by the McastIntentManager.
107 *
108 * @return the application ID
109 */
110 public static ApplicationId getAppId() {
111 return appId;
112 }
113
114 /**
115 * Packet processor responsible for forwarding packets along their paths.
116 */
117 private class ReactivePacketProcessor implements PacketProcessor {
118
119 /**
120 * Process incoming packets.
121 *
122 * @param context packet processing context
123 */
124 @Override
125 public void process(PacketContext context) {
126 // Stop processing if the packet has been handled, since we
127 // can't do any more to it.
128 if (context.isHandled()) {
129 return;
130 }
131
132 InboundPacket pkt = context.inPacket();
133 Ethernet ethPkt = pkt.parsed();
134
135 if (ethPkt == null) {
136 return;
137 }
138
139 if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4 &&
140 ethPkt.getEtherType() != Ethernet.TYPE_IPV6) {
141 return;
142 }
143
144 if (ethPkt.getEtherType() == Ethernet.TYPE_IPV6) {
145 // Ignore ipv6 at the moment.
146 return;
147 }
148
149 IPv4 ip = (IPv4) ethPkt.getPayload();
alshabibeff00542015-09-23 13:22:33 -0700150 IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress());
Julian Lawrencefa790f62016-01-07 17:18:30 -0800151 IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());
alshabibeff00542015-09-23 13:22:33 -0700152
153 log.debug("Packet ({}, {}) has been punted\n" +
154 "\tingress port: {}\n",
155 saddr.toString(),
156 gaddr.toString(),
157 context.inPacket().receivedFrom().toString());
158
Julian Lawrencefa790f62016-01-07 17:18:30 -0800159 // Don't allow PIM/IGMP packets to be handled here.
160 byte proto = ip.getProtocol();
161 if (proto == IPv4.PROTOCOL_PIM || proto == IPv4.PROTOCOL_IGMP) {
alshabibeff00542015-09-23 13:22:33 -0700162 return;
163 }
164
165 IpPrefix spfx = IpPrefix.valueOf(saddr, 32);
166 IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32);
167
Julian Lawrencefa790f62016-01-07 17:18:30 -0800168 // TODO do we want to add a type for Mcast?
Thomas Vachuska61ab5e02016-01-11 13:55:15 -0800169 McastRoute mRoute = new McastRoute(saddr, gaddr, McastRoute.Type.STATIC);
alshabibeff00542015-09-23 13:22:33 -0700170
Julian Lawrencefa790f62016-01-07 17:18:30 -0800171 ConnectPoint ingress = mcastRouteManager.fetchSource(mRoute);
172
173 // An ingress port already exists. Log error.
174 if (ingress != null) {
175 log.error(McastForwarding.class.getSimpleName() + " received packet which already has a route.");
176 return;
177 } else {
178 //add ingress port
179 mcastRouteManager.addSource(mRoute, pkt.receivedFrom());
alshabibeff00542015-09-23 13:22:33 -0700180 }
181
Julian Lawrencefa790f62016-01-07 17:18:30 -0800182 ArrayList<ConnectPoint> egressList = (ArrayList<ConnectPoint>) mcastRouteManager.fetchSinks(mRoute);
183 //If there are no egress ports set return, otherwise forward the packets to their expected port.
184 if (egressList.size() == 0) {
alshabibeff00542015-09-23 13:22:33 -0700185 return;
186 }
187
alshabibeff00542015-09-23 13:22:33 -0700188 // Send the pack out each of the egress devices & port
Julian Lawrencefa790f62016-01-07 17:18:30 -0800189 forwardPacketToDst(context, egressList);
alshabibeff00542015-09-23 13:22:33 -0700190 }
191 }
192
193 /**
194 * Forward the packet to it's multicast destinations.
195 *
196 * @param context The packet context
Julian Lawrencefa790f62016-01-07 17:18:30 -0800197 * @param egressList The list of egress ports which the multicast packet is intended for.
alshabibeff00542015-09-23 13:22:33 -0700198 */
Julian Lawrencefa790f62016-01-07 17:18:30 -0800199 private void forwardPacketToDst(PacketContext context, ArrayList<ConnectPoint> egressList) {
alshabibeff00542015-09-23 13:22:33 -0700200
201 // Send the pack out each of the respective egress ports
Julian Lawrencefa790f62016-01-07 17:18:30 -0800202 for (ConnectPoint egress : egressList) {
alshabibeff00542015-09-23 13:22:33 -0700203 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
204 .setOutput(egress.port()).build();
205
206 OutboundPacket packet = new DefaultOutboundPacket(
207 egress.deviceId(),
208 treatment,
209 context.inPacket().unparsed());
210
211 packetService.emit(packet);
212 }
213 }
Julian Lawrencefa790f62016-01-07 17:18:30 -0800214
215 public static McastRoute createStaticRoute(String source, String group) {
216 checkNotNull(source, "Must provide a source");
217 checkNotNull(group, "Must provide a group");
Thomas Vachuska61ab5e02016-01-11 13:55:15 -0800218 IpAddress ipSource = IpAddress.valueOf(source);
219 IpAddress ipGroup = IpAddress.valueOf(group);
Julian Lawrencefa790f62016-01-07 17:18:30 -0800220 return createStaticcreateRoute(ipSource, ipGroup);
221 }
222
Thomas Vachuska61ab5e02016-01-11 13:55:15 -0800223 public static McastRoute createStaticcreateRoute(IpAddress source, IpAddress group) {
Julian Lawrencefa790f62016-01-07 17:18:30 -0800224 checkNotNull(source, "Must provide a source");
225 checkNotNull(group, "Must provide a group");
226 McastRoute.Type type = McastRoute.Type.STATIC;
227 return new McastRoute(source, group, type);
228 }
alshabibeff00542015-09-23 13:22:33 -0700229}