blob: a2867267fc3fc979f06abe0723e18408ae1586d9 [file] [log] [blame]
Rusty Eddy4ae5aa82015-12-15 12:58:27 -08001/*
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.pim.impl;
17
18import 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;
23import org.onlab.packet.Ethernet;
24import org.onlab.packet.IPv4;
25import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
27import org.onosproject.incubator.net.config.basics.ConfigException;
28import org.onosproject.incubator.net.config.basics.InterfaceConfig;
29import org.onosproject.incubator.net.intf.Interface;
30import org.onosproject.incubator.net.intf.InterfaceService;
31import org.onosproject.net.ConnectPoint;
32import org.onosproject.net.config.NetworkConfigEvent;
33import org.onosproject.net.config.NetworkConfigListener;
34import org.onosproject.net.config.NetworkConfigService;
35import org.onosproject.net.flow.DefaultTrafficSelector;
36import org.onosproject.net.flow.TrafficSelector;
37import org.onosproject.net.mcast.MulticastRouteService;
38import org.onosproject.net.packet.InboundPacket;
39import org.onosproject.net.packet.PacketContext;
40import org.onosproject.net.packet.PacketProcessor;
41import org.onosproject.net.packet.PacketService;
42import org.slf4j.Logger;
43
44import java.util.Set;
45
46import static org.slf4j.LoggerFactory.getLogger;
47
48/**
49 * The main PIM controller class.
50 */
51@Component(immediate = true)
52public class PIMApplication {
53 private final Logger log = getLogger(getClass());
54
55 // Used to get the appId
56 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
57 protected CoreService coreService;
58
59 // Our application ID
60 private static ApplicationId appId;
61
62 // Register to receive PIM packets, used to send packets as well
63 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 protected PacketService packetService;
65
66 // Use the MulticastRouteService to manage incoming PIM Join/Prune state as well as
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected MulticastRouteService ms;
69
70 // Create an instance of the PIM packet handler
71 protected PIMPacketHandler pimPacketHandler;
72
73 // Get the network configuration updates
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected NetworkConfigService configService;
76
77 // Access defined network (IP) interfaces
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected InterfaceService interfaceService;
80
81 // Internal class used to listen for network configuration changes
82 private InternalConfigListener configListener = new InternalConfigListener();
83
84 // Provide interfaces to the pimInterface manager as a result of Netconfig updates.
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected PIMInterfaceService pimInterfaceManager;
87
88 /**
89 * Activate the PIM component.
90 */
91 @Activate
92 public void activate() {
93
94 // Get our application ID
95 appId = coreService.registerApplication("org.onosproject.pim");
96
97 // Build the traffic selector for PIM packets
98 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
99 selector.matchEthType(Ethernet.TYPE_IPV4);
100 selector.matchIPProtocol(IPv4.PROTOCOL_PIM);
101
102 // Use the traffic selector to tell the packet service which packets we want.
103 // PIMPacketService is an inner class defined below
104 PIMPacketProcessor processor = new PIMPacketProcessor();
105 packetService.addProcessor(processor, PacketProcessor.director(5));
106
107 // Register for notifications from the Network config & Interface services.
108 // We'll use these services to represent "PIMInterfaces"
109
110 // Get a copy of the PIM Packet Handler
111 pimPacketHandler = new PIMPacketHandler();
112
113 // Listen for network configuration changes
114 configService.addListener(configListener);
115
116 log.info("Started");
117 }
118
119 /**
120 * Deactivate the PIM component.
121 */
122 @Deactivate
123 public void deactivate() {
124 log.info("Stopped");
125 }
126
127 /**
128 * The class that will receive PIM packets, sanitize them, determine the PIMInterface
129 * they arrived on, then forward them on to be processed by the appropriate entity.
130 */
131 public class PIMPacketProcessor implements PacketProcessor {
132 private final Logger log = getLogger(getClass());
133
134 @Override
135 public void process(PacketContext context) {
136
137 // return if this packet has already been handled
138 if (context.isHandled()) {
139 return;
140 }
141
142 // get the inbound packet
143 InboundPacket pkt = context.inPacket();
144 if (pkt == null) {
145 // problem getting the inbound pkt. Log it debug to avoid spamming log file
146 log.debug("Could not retrieve packet from context");
147 return;
148 }
149
150 // Get the ethernet header
151 Ethernet eth = pkt.parsed();
152 if (eth == null) {
153 // problem getting the ethernet pkt. Log it debug to avoid spamming log file
154 log.debug("Could not retrieve ethnernet packet from the parsed packet");
155 return;
156 }
157
158 // Get the PIM Interface the packet was received on.
159 PIMInterface pimi = pimInterfaceManager.getPIMInterface(pkt.receivedFrom());
160 if (pimi == null) {
161 log.debug("We received PIM packet from a non PIM interface: " + pkt.receivedFrom().toString());
162 return;
163 }
164
165 /*
166 * Pass the packet processing off to the PIMInterface for processing.
167 *
168 * TODO: Is it possible that PIM interface processing should move to the
169 * PIMInterfaceManager directly?
170 */
171 PIMPacketHandler ph = new PIMPacketHandler();
172 ph.processPacket(eth, pimi);
173 }
174 }
175
176 /*
177 * This class receives all events from the network config services, then hands the
178 * event off to the PIMInterfaceManager for proper handling.
179 *
180 * TODO: should this move to PIMInterfaceManager?
181 */
182 private class InternalConfigListener implements NetworkConfigListener {
183
184 @Override
185 public void event(NetworkConfigEvent event) {
186
187 log.debug(event.toString());
188 switch (event.type()) {
189 case CONFIG_ADDED:
190 case CONFIG_UPDATED:
191
192 if (event.configClass() == InterfaceConfig.class) {
193 InterfaceConfig config = configService.getConfig(
194 (ConnectPoint) event.subject(),
195 InterfaceConfig.class);
196
197 log.debug("Got a network configuration event");
198
199 // Walk the interfaces and feed them to the PIMInterfaceManager
200 Set<Interface> intfs;
201 try {
202 intfs = config.getInterfaces();
203 for (Interface intf : intfs) {
204 pimInterfaceManager.updateInterface(intf);
205 }
206 } catch (ConfigException e) {
207 log.error(e.toString());
208 return;
209 }
210 }
211 break;
212
213 case CONFIG_REMOVED:
214 if (event.configClass() == InterfaceConfig.class) {
215 ConnectPoint cp = (ConnectPoint) event.subject();
216 //assertNotNull(cp);
217 pimInterfaceManager.deleteInterface(cp);
218 }
219 break;
220
221 case CONFIG_REGISTERED:
222 case CONFIG_UNREGISTERED:
223 default:
224 log.debug("\tWe are not handling this event type");
225 break;
226 }
227 }
228 }
229}