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