blob: bcaeb2c27fd7353ec4b1afbac91dd79947ec925b [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
Jonathan Hart5af5f142016-01-28 18:45:27 -080018import com.google.common.collect.ImmutableSet;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080019import com.google.common.collect.Maps;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
26import org.onosproject.incubator.net.intf.Interface;
Jonathan Hart5af5f142016-01-28 18:45:27 -080027import org.onosproject.incubator.net.intf.InterfaceEvent;
28import org.onosproject.incubator.net.intf.InterfaceListener;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080029import org.onosproject.incubator.net.intf.InterfaceService;
30import org.onosproject.net.ConnectPoint;
Jonathan Hart5af5f142016-01-28 18:45:27 -080031import org.onosproject.net.config.ConfigFactory;
32import org.onosproject.net.config.NetworkConfigEvent;
33import org.onosproject.net.config.NetworkConfigListener;
34import org.onosproject.net.config.NetworkConfigRegistry;
35import org.onosproject.net.config.basics.SubjectFactories;
Jonathan Hart36fd31e2016-01-28 15:55:31 -080036import org.onosproject.net.packet.PacketService;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080037import org.slf4j.Logger;
Jonathan Hart5af5f142016-01-28 18:45:27 -080038
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080039import java.util.Map;
Jonathan Hart5af5f142016-01-28 18:45:27 -080040import java.util.Set;
Rusty Eddy4d5a92f2016-01-25 17:12:14 -080041import java.util.concurrent.Executors;
42import java.util.concurrent.ScheduledExecutorService;
43import java.util.concurrent.TimeUnit;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080044
45import static org.slf4j.LoggerFactory.getLogger;
46
47/**
48 * Manages PIMInterfaces.
49 *
50 * TODO: Do we need to add a ServiceListener?
51 */
52@Component(immediate = true)
53@Service
54public class PIMInterfaceManager implements PIMInterfaceService {
55
56 private final Logger log = getLogger(getClass());
57
Jonathan Hart5af5f142016-01-28 18:45:27 -080058 private static final Class<PimInterfaceConfig> PIM_INTERFACE_CONFIG_CLASS = PimInterfaceConfig.class;
59 private static final String PIM_INTERFACE_CONFIG_KEY = "pimInterface";
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080060
Rusty Eddy4d5a92f2016-01-25 17:12:14 -080061 // Create a Scheduled Executor service to send PIM hellos
62 private final ScheduledExecutorService helloScheduler =
63 Executors.newScheduledThreadPool(1);
64
65 // Wait for a bout 3 seconds before sending the initial hello messages.
66 // TODO: make this tunnable.
Jonathan Hart5af5f142016-01-28 18:45:27 -080067 private final long initialHelloDelay = 3;
Rusty Eddy4d5a92f2016-01-25 17:12:14 -080068
69 // Send PIM hello packets: 30 seconds.
Jonathan Hart5af5f142016-01-28 18:45:27 -080070 private final long pimHelloPeriod = 30;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080071
Jonathan Hart36fd31e2016-01-28 15:55:31 -080072 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected PacketService packetService;
74
Jonathan Hart5af5f142016-01-28 18:45:27 -080075 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected NetworkConfigRegistry networkConfig;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected InterfaceService interfaceService;
80
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080081 // Store PIM Interfaces in a map key'd by ConnectPoint
82 private final Map<ConnectPoint, PIMInterface> pimInterfaces = Maps.newConcurrentMap();
83
Jonathan Hart5af5f142016-01-28 18:45:27 -080084 private final InternalNetworkConfigListener configListener =
85 new InternalNetworkConfigListener();
86 private final InternalInterfaceListener interfaceListener =
87 new InternalInterfaceListener();
88
89 private final ConfigFactory<ConnectPoint, PimInterfaceConfig> pimConfigFactory
90 = new ConfigFactory<ConnectPoint, PimInterfaceConfig>(
91 SubjectFactories.CONNECT_POINT_SUBJECT_FACTORY, PIM_INTERFACE_CONFIG_CLASS,
92 PIM_INTERFACE_CONFIG_KEY) {
93
94 @Override
95 public PimInterfaceConfig createConfig() {
96 return new PimInterfaceConfig();
97 }
98 };
99
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800100 @Activate
101 public void activate() {
Jonathan Hart5af5f142016-01-28 18:45:27 -0800102 networkConfig.registerConfigFactory(pimConfigFactory);
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800103
Jonathan Hart5af5f142016-01-28 18:45:27 -0800104 // Create PIM Interfaces for each of the existing configured interfaces.
105 Set<ConnectPoint> subjects = networkConfig.getSubjects(
106 ConnectPoint.class, PIM_INTERFACE_CONFIG_CLASS);
107 for (ConnectPoint cp : subjects) {
108 PimInterfaceConfig config = networkConfig.getConfig(cp, PIM_INTERFACE_CONFIG_CLASS);
109 updateInterface(config);
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800110 }
Rusty Eddy4d5a92f2016-01-25 17:12:14 -0800111
Jonathan Hart5af5f142016-01-28 18:45:27 -0800112 networkConfig.addListener(configListener);
113 interfaceService.addListener(interfaceListener);
114
Rusty Eddy4d5a92f2016-01-25 17:12:14 -0800115 // Schedule the periodic hello sender.
116 helloScheduler.scheduleAtFixedRate(new Runnable() {
117 @Override
118 public void run() {
Jonathan Hart5af5f142016-01-28 18:45:27 -0800119 try {
120 for (PIMInterface pif : pimInterfaces.values()) {
121 pif.sendHello();
122 }
123 } catch (Exception e) {
124 log.warn("exception", e);
Rusty Eddy4d5a92f2016-01-25 17:12:14 -0800125 }
126 }
127 }, initialHelloDelay, pimHelloPeriod, TimeUnit.SECONDS);
Jonathan Hart5af5f142016-01-28 18:45:27 -0800128
129 log.info("Started");
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800130 }
131
132 @Deactivate
133 public void deactivate() {
Jonathan Hart5af5f142016-01-28 18:45:27 -0800134 interfaceService.removeListener(interfaceListener);
135 networkConfig.removeListener(configListener);
136 networkConfig.unregisterConfigFactory(pimConfigFactory);
Rusty Eddy4d5a92f2016-01-25 17:12:14 -0800137
138 // Shutdown the periodic hello task.
139 helloScheduler.shutdown();
140
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800141 log.info("Stopped");
142 }
143
144 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800145 * Return the PIMInterface that corresponds to the given ConnectPoint.
146 *
147 * @param cp The ConnectPoint we want to get the PIMInterface for
148 * @return The PIMInterface if it exists, NULL if it does not exist.
149 */
150 @Override
151 public PIMInterface getPIMInterface(ConnectPoint cp) {
152 PIMInterface pi = pimInterfaces.getOrDefault(cp, null);
153 if (pi == null) {
154 log.warn("We have been asked for an Interface we don't have: " + cp.toString());
155 }
156 return pi;
157 }
Jonathan Hart5af5f142016-01-28 18:45:27 -0800158
159 @Override
160 public Set<PIMInterface> getPimInterfaces() {
161 return ImmutableSet.copyOf(pimInterfaces.values());
162 }
163
164 private void updateInterface(PimInterfaceConfig config) {
165 ConnectPoint cp = config.subject();
166
167 if (!config.isEnabled()) {
168 removeInterface(cp);
169 return;
170 }
171
172 String intfName = config.getInterfaceName();
173 Interface intf = interfaceService.getInterfaceByName(cp, intfName);
174
175 if (intf == null) {
176 log.debug("Interface configuration missing: {}", config.getInterfaceName());
177 return;
178 }
179
180
181 log.debug("Updating Interface for " + intf.connectPoint().toString());
182 pimInterfaces.computeIfAbsent(cp, k -> buildPimInterface(config, intf));
183 }
184
185 private void removeInterface(ConnectPoint cp) {
186 pimInterfaces.remove(cp);
187 }
188
189 private PIMInterface buildPimInterface(PimInterfaceConfig config, Interface intf) {
190 PIMInterface.Builder builder = PIMInterface.builder()
191 .withPacketService(packetService)
192 .withInterface(intf);
193
194 if (config.getHoldTime().isPresent()) {
195 builder.withHoldTime(config.getHoldTime().get());
196 }
197 if (config.getPriority().isPresent()) {
198 builder.withPriority(config.getPriority().get());
199 }
200 if (config.getPropagationDelay().isPresent()) {
201 builder.withPropagationDelay(config.getPropagationDelay().get());
202 }
203 if (config.getOverrideInterval().isPresent()) {
204 builder.withOverrideInterval(config.getOverrideInterval().get());
205 }
206
207 return builder.build();
208 }
209
210 /**
211 * Listener for network config events.
212 */
213 private class InternalNetworkConfigListener implements NetworkConfigListener {
214
215 @Override
216 public void event(NetworkConfigEvent event) {
217 if (event.configClass() != PIM_INTERFACE_CONFIG_CLASS) {
218 return;
219 }
220
221 switch (event.type()) {
222 case CONFIG_REGISTERED:
223 case CONFIG_UNREGISTERED:
224 break;
225 case CONFIG_ADDED:
226 case CONFIG_UPDATED:
227 ConnectPoint cp = (ConnectPoint) event.subject();
228 PimInterfaceConfig config = networkConfig.getConfig(
229 cp, PIM_INTERFACE_CONFIG_CLASS);
230
231 updateInterface(config);
232 break;
233 case CONFIG_REMOVED:
234 removeInterface((ConnectPoint) event.subject());
235 break;
236 default:
237 break;
238 }
239 }
240 }
241
242 /**
243 * Listener for interface events.
244 */
245 private class InternalInterfaceListener implements InterfaceListener {
246
247 @Override
248 public void event(InterfaceEvent event) {
249 switch (event.type()) {
250 case INTERFACE_ADDED:
251 PimInterfaceConfig config = networkConfig.getConfig(
252 event.subject().connectPoint(), PIM_INTERFACE_CONFIG_CLASS);
253
254 if (config != null) {
255 updateInterface(config);
256 }
257 break;
258 case INTERFACE_UPDATED:
259 break;
260 case INTERFACE_REMOVED:
261 removeInterface(event.subject().connectPoint());
262 break;
263 default:
264 break;
265
266 }
267 }
268 }
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800269}