blob: 95535ad7a7f28ee7595da19200cd6522a5453376 [file] [log] [blame]
Jian Li6322a362016-10-31 00:57:19 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Jian Li6322a362016-10-31 00:57:19 +09003 *
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 */
Jian Li5e505c62016-12-05 02:44:24 +090016package org.onosproject.lisp.ctl.impl;
Jian Li6322a362016-10-31 00:57:19 +090017
Jian Li834ff722016-12-13 19:43:02 +090018import com.google.common.collect.Maps;
Jian Li712ec052016-11-22 03:23:54 +090019import org.onlab.util.Tools;
20import org.onosproject.cfg.ComponentConfigService;
Jian Li6322a362016-10-31 00:57:19 +090021import org.onosproject.core.CoreService;
Jian Li5e505c62016-12-05 02:44:24 +090022import org.onosproject.lisp.ctl.LispController;
Jian Li7ccc3a82016-12-09 01:30:56 +090023import org.onosproject.lisp.ctl.LispMessageListener;
24import org.onosproject.lisp.ctl.LispRouter;
Jian Li834ff722016-12-13 19:43:02 +090025import org.onosproject.lisp.ctl.LispRouterAgent;
Jian Lib1a8fd02016-12-27 03:55:32 +090026import org.onosproject.lisp.ctl.LispRouterFactory;
Jian Li7ccc3a82016-12-09 01:30:56 +090027import org.onosproject.lisp.ctl.LispRouterId;
28import org.onosproject.lisp.ctl.LispRouterListener;
Jian Li712ec052016-11-22 03:23:54 +090029import org.onosproject.lisp.msg.authentication.LispAuthenticationConfig;
Jian Li834ff722016-12-13 19:43:02 +090030import org.onosproject.lisp.msg.protocols.LispInfoReply;
31import org.onosproject.lisp.msg.protocols.LispInfoRequest;
32import org.onosproject.lisp.msg.protocols.LispMessage;
Jian Li712ec052016-11-22 03:23:54 +090033import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070034import org.osgi.service.component.annotations.Activate;
35import org.osgi.service.component.annotations.Component;
36import org.osgi.service.component.annotations.Deactivate;
37import org.osgi.service.component.annotations.Modified;
38import org.osgi.service.component.annotations.Reference;
39import org.osgi.service.component.annotations.ReferenceCardinality;
Jian Li6322a362016-10-31 00:57:19 +090040import org.slf4j.Logger;
Jian Li6322a362016-10-31 00:57:19 +090041
Jian Li712ec052016-11-22 03:23:54 +090042import java.util.Dictionary;
Jian Li834ff722016-12-13 19:43:02 +090043import java.util.Map;
44import java.util.Set;
45import java.util.concurrent.ConcurrentMap;
46import java.util.concurrent.CopyOnWriteArraySet;
47import java.util.concurrent.ExecutorService;
Jian Li712ec052016-11-22 03:23:54 +090048
Jian Li834ff722016-12-13 19:43:02 +090049import static java.util.concurrent.Executors.newFixedThreadPool;
50import static java.util.stream.Collectors.toConcurrentMap;
Jian Li712ec052016-11-22 03:23:54 +090051import static org.onlab.util.Tools.get;
52import static org.onlab.util.Tools.getIntegerProperty;
Jian Li834ff722016-12-13 19:43:02 +090053import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -070054import static org.onosproject.lisp.ctl.impl.OsgiPropertyConstants.*;
Jian Li834ff722016-12-13 19:43:02 +090055import static org.slf4j.LoggerFactory.getLogger;
Jian Li712ec052016-11-22 03:23:54 +090056
Jian Li6322a362016-10-31 00:57:19 +090057/**
58 * LISP controller initiation class.
59 */
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -070060@Component(immediate = true, service = LispController.class,
61 property = {
62 LISP_AUTH_KEY + "=" + LISP_AUTH_KEY_DEFAULT,
63 LISP_AUTH_KEY_ID + ":Integer=" + LISP_AUTH_KEY_ID_DEFAULT,
64 ENABLE_SMR + ":Boolean=" + ENABLE_SMR_DEFAULT,
65 })
Jian Li6322a362016-10-31 00:57:19 +090066public class LispControllerImpl implements LispController {
67
68 private static final String APP_ID = "org.onosproject.lisp-base";
69
Jian Li834ff722016-12-13 19:43:02 +090070 private static final Logger log = getLogger(LispControllerImpl.class);
Jian Li6322a362016-10-31 00:57:19 +090071
Ray Milkeyd84f89b2018-08-17 14:54:17 -070072 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6322a362016-10-31 00:57:19 +090073 protected CoreService coreService;
74
Ray Milkeyd84f89b2018-08-17 14:54:17 -070075 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li712ec052016-11-22 03:23:54 +090076 protected ComponentConfigService cfgService;
77
Ray Milkey11ce9302019-02-07 14:41:17 -080078 /** Authentication key which is used to calculate authentication data. */
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -070079 private String lispAuthKey = LISP_AUTH_KEY_DEFAULT;
Jian Li712ec052016-11-22 03:23:54 +090080
Ray Milkey11ce9302019-02-07 14:41:17 -080081 /** Authentication key id which denotes the authentication method used to calculate the authentication data. */
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -070082 private int lispAuthKeyId = LISP_AUTH_KEY_ID_DEFAULT;
Jian Li834ff722016-12-13 19:43:02 +090083
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -070084 /** Enable to send SMR(Solicit Map Request) by map server; by default SMR is not activated. */
Jian Lib86d8ad2017-05-03 02:53:44 +090085 private boolean enableSmr = false;
86
Jian Li834ff722016-12-13 19:43:02 +090087 ExecutorService executorMessages =
88 newFixedThreadPool(4, groupedThreads("onos/lisp", "event-stats-%d", log));
89
90 protected LispRouterAgent agent = new DefaultLispRouterAgent();
91
92 ConcurrentMap<LispRouterId, LispRouter> connectedRouters = Maps.newConcurrentMap();
93
Jian Li0dab5962016-12-15 03:44:28 +090094 final LispAuthenticationConfig authConfig = LispAuthenticationConfig.getInstance();
95 LispControllerBootstrap bootstrap = new LispControllerBootstrap();
96
Jian Li834ff722016-12-13 19:43:02 +090097 private Set<LispRouterListener> lispRouterListeners = new CopyOnWriteArraySet<>();
98 private Set<LispMessageListener> lispMessageListeners = new CopyOnWriteArraySet<>();
Jian Li712ec052016-11-22 03:23:54 +090099
Jian Lib1a8fd02016-12-27 03:55:32 +0900100 private LispRouterFactory routerFactory = LispRouterFactory.getInstance();
101
Jian Li6322a362016-10-31 00:57:19 +0900102 @Activate
Jian Li712ec052016-11-22 03:23:54 +0900103 public void activate(ComponentContext context) {
Jian Li834ff722016-12-13 19:43:02 +0900104 coreService.registerApplication(APP_ID, this::cleanup);
Jian Li712ec052016-11-22 03:23:54 +0900105 cfgService.registerProperties(getClass());
Jian Li712ec052016-11-22 03:23:54 +0900106 initAuthConfig(context.getProperties());
Jian Lib1a8fd02016-12-27 03:55:32 +0900107 routerFactory.setAgent(agent);
Jian Li6322a362016-10-31 00:57:19 +0900108 bootstrap.start();
109 log.info("Started");
110 }
111
Jian Li834ff722016-12-13 19:43:02 +0900112 /**
113 * Shutdowns all listening channel and all LISP channels.
114 * Clean information about routers before deactivating.
115 */
116 private void cleanup() {
117 bootstrap.stop();
Jian Lib1a8fd02016-12-27 03:55:32 +0900118 routerFactory.cleanAgent();
Jian Li834ff722016-12-13 19:43:02 +0900119 connectedRouters.values().forEach(LispRouter::disconnectRouter);
120 connectedRouters.clear();
121 }
122
Jian Li6322a362016-10-31 00:57:19 +0900123 @Deactivate
124 public void deactivate() {
Jian Li834ff722016-12-13 19:43:02 +0900125 cleanup();
Jian Li712ec052016-11-22 03:23:54 +0900126 cfgService.unregisterProperties(getClass(), false);
Jian Li6322a362016-10-31 00:57:19 +0900127 log.info("Stopped");
128 }
Jian Li712ec052016-11-22 03:23:54 +0900129
130 @Modified
131 public void modified(ComponentContext context) {
132 readComponentConfiguration(context);
Jian Li834ff722016-12-13 19:43:02 +0900133 bootstrap.stop();
134 bootstrap.start();
Jian Li712ec052016-11-22 03:23:54 +0900135 }
136
137 /**
138 * Initializes authentication key and authentication method.
139 *
140 * @param properties a set of properties that contained in component context
141 */
142 private void initAuthConfig(Dictionary<?, ?> properties) {
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700143 authConfig.updateLispAuthKey(get(properties, LISP_AUTH_KEY));
144 authConfig.updateLispAuthKeyId(getIntegerProperty(properties, LISP_AUTH_KEY_ID));
Jian Li712ec052016-11-22 03:23:54 +0900145 }
146
147 /**
148 * Extracts properties from the component configuration context.
149 *
150 * @param context the component context
151 */
152 private void readComponentConfiguration(ComponentContext context) {
153 Dictionary<?, ?> properties = context.getProperties();
154
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700155 String lispAuthKeyStr = Tools.get(properties, LISP_AUTH_KEY);
156 lispAuthKey = lispAuthKeyStr != null ? lispAuthKeyStr : LISP_AUTH_KEY_DEFAULT;
Jian Li712ec052016-11-22 03:23:54 +0900157 authConfig.updateLispAuthKey(lispAuthKey);
158 log.info("Configured. LISP authentication key is {}", lispAuthKey);
159
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700160 Integer lispAuthMethodInt = Tools.getIntegerProperty(properties, LISP_AUTH_KEY_ID);
Jian Li712ec052016-11-22 03:23:54 +0900161 if (lispAuthMethodInt == null) {
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700162 lispAuthKeyId = LISP_AUTH_KEY_ID_DEFAULT;
Jian Li712ec052016-11-22 03:23:54 +0900163 log.info("LISP authentication method is not configured, default value is {}", lispAuthKeyId);
164 } else {
165 lispAuthKeyId = lispAuthMethodInt;
166 log.info("Configured. LISP authentication method is configured to {}", lispAuthKeyId);
167 }
168 authConfig.updateLispAuthKeyId(lispAuthKeyId);
Jian Lib86d8ad2017-05-03 02:53:44 +0900169
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700170 Boolean enableSmr = Tools.isPropertyEnabled(properties, ENABLE_SMR);
Jian Lib86d8ad2017-05-03 02:53:44 +0900171 if (enableSmr == null) {
172 log.info("Enable SMR is not configured, " +
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700173 "using current value of {}", this.enableSmr);
Jian Lib86d8ad2017-05-03 02:53:44 +0900174 } else {
175 this.enableSmr = enableSmr;
176 log.info("Configured. Sending SMR through map server is {}",
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700177 this.enableSmr ? "enabled" : "disabled");
Jian Lib86d8ad2017-05-03 02:53:44 +0900178 }
Jian Li712ec052016-11-22 03:23:54 +0900179 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900180
181 @Override
182 public Iterable<LispRouter> getRouters() {
Jian Li834ff722016-12-13 19:43:02 +0900183 return connectedRouters.values();
184 }
185
186 @Override
187 public Iterable<LispRouter> getSubscribedRouters() {
188 return connectedRouters.entrySet()
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700189 .stream()
190 .filter(e -> e.getValue().isSubscribed())
191 .collect(toConcurrentMap(Map.Entry::getKey,
Jian Li834ff722016-12-13 19:43:02 +0900192 Map.Entry::getValue)).values();
Jian Li7ccc3a82016-12-09 01:30:56 +0900193 }
194
195 @Override
Jian Li9b1a45b2017-01-19 13:34:31 -0800196 public LispRouter connectRouter(LispRouterId routerId) {
197 if (connectedRouters.containsKey(routerId)) {
198 log.debug("LISP router {} is already existing", routerId);
199 return connectedRouters.get(routerId);
200 } else {
201 // TODO: currently we do not consider to add LISP router from netcfg
202 log.warn("Adding router from netcfg is not supported currently");
203 return null;
204 }
205 }
206
207 @Override
208 public void disconnectRouter(LispRouterId routerId, boolean remove) {
209 if (!connectedRouters.containsKey(routerId)) {
210 log.warn("LISP router {} is not existing", routerId);
211 } else {
212 connectedRouters.get(routerId).disconnectRouter();
213 if (remove) {
214 agent.removeConnectedRouter(routerId);
215 }
216 }
217 }
218
219 @Override
Jian Li7ccc3a82016-12-09 01:30:56 +0900220 public LispRouter getRouter(LispRouterId routerId) {
Jian Li834ff722016-12-13 19:43:02 +0900221 return connectedRouters.get(routerId);
Jian Li7ccc3a82016-12-09 01:30:56 +0900222 }
223
224 @Override
225 public void addRouterListener(LispRouterListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900226 if (!lispRouterListeners.contains(listener)) {
227 lispRouterListeners.add(listener);
228 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900229 }
230
231 @Override
232 public void removeRouterListener(LispRouterListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900233 lispRouterListeners.remove(listener);
Jian Li7ccc3a82016-12-09 01:30:56 +0900234 }
235
236 @Override
237 public void addMessageListener(LispMessageListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900238 if (!lispMessageListeners.contains(listener)) {
239 lispMessageListeners.add(listener);
240 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900241 }
242
243 @Override
244 public void removeMessageListener(LispMessageListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900245 lispMessageListeners.remove(listener);
246 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900247
Jian Li834ff722016-12-13 19:43:02 +0900248 /**
249 * Implementation of a LISP agent which is responsible for keeping track of
250 * connected LISP routers and the state in which they are in.
251 */
252 public final class DefaultLispRouterAgent implements LispRouterAgent {
253
254 private final Logger log = getLogger(DefaultLispRouterAgent.class);
255
256 /**
257 * Prevents object instantiation from external class.
258 */
259 private DefaultLispRouterAgent() {
260 }
261
262 @Override
263 public boolean addConnectedRouter(LispRouterId routerId, LispRouter router) {
264
265 if (connectedRouters.get(routerId) != null) {
Jian Li07b90202017-04-14 12:03:24 +0900266 log.warn("Trying to add connectedRouter but found a previous " +
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700267 "value for routerId: {}", routerId);
Jian Li834ff722016-12-13 19:43:02 +0900268 return false;
269 } else {
270 log.info("Added router {}", routerId);
271 connectedRouters.put(routerId, router);
272 for (LispRouterListener listener : lispRouterListeners) {
273 listener.routerAdded(routerId);
274 }
275 return true;
276 }
277 }
278
279 @Override
280 public void removeConnectedRouter(LispRouterId routerId) {
281
282 if (connectedRouters.get(routerId) == null) {
283 log.error("Trying to remove router {} from connectedRouter " +
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700284 "list but no element was found", routerId);
Jian Li834ff722016-12-13 19:43:02 +0900285 } else {
286 log.info("Removed router {}", routerId);
287 connectedRouters.remove(routerId);
288 for (LispRouterListener listener : lispRouterListeners) {
289 listener.routerRemoved(routerId);
290 }
291 }
292 }
293
294 @Override
295 public void processUpstreamMessage(LispRouterId routerId, LispMessage message) {
296
297 switch (message.getType()) {
298 case LISP_MAP_REGISTER:
299 case LISP_MAP_REQUEST:
300 executorMessages.execute(
301 new LispIncomingMessageHandler(routerId, message));
302 break;
303 case LISP_INFO:
304 if (message instanceof LispInfoRequest) {
305 executorMessages.execute(
306 new LispIncomingMessageHandler(routerId, message));
307 } else {
308 log.warn("Not incoming LISP control message");
309 }
310 break;
311 default:
312 log.warn("Not incoming LISP control message");
313 break;
314 }
315 }
316
317 @Override
318 public void processDownstreamMessage(LispRouterId routerId, LispMessage message) {
319
320 switch (message.getType()) {
321 case LISP_MAP_NOTIFY:
322 case LISP_MAP_REPLY:
323 executorMessages.execute(
324 new LispOutgoingMessageHandler(routerId, message));
325 break;
326 case LISP_INFO:
327 if (message instanceof LispInfoReply) {
328 executorMessages.execute(
329 new LispOutgoingMessageHandler(routerId, message));
330 } else {
331 log.warn("Not outgoing LISP control message");
332 }
333 break;
334 default:
335 log.warn("Not outgoing LISP control message");
336 break;
337 }
338 }
339 }
340
341 /**
342 * LISP message handler.
343 */
344 protected class LispMessageHandler implements Runnable {
345
346 private final LispRouterId routerId;
347 private final LispMessage message;
348 private final boolean isIncoming;
349
350 LispMessageHandler(LispRouterId routerId,
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700351 LispMessage message, boolean isIncoming) {
Jian Li834ff722016-12-13 19:43:02 +0900352 this.routerId = routerId;
353 this.message = message;
354 this.isIncoming = isIncoming;
355 }
356
357 @Override
358 public void run() {
359 for (LispMessageListener listener : lispMessageListeners) {
360 if (isIncoming) {
361 listener.handleIncomingMessage(routerId, message);
362 } else {
363 listener.handleOutgoingMessage(routerId, message);
364 }
365 }
366 }
367 }
368
369 /**
370 * LISP incoming message handler.
371 */
372 protected final class LispIncomingMessageHandler
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700373 extends LispMessageHandler implements Runnable {
Jian Li834ff722016-12-13 19:43:02 +0900374
375 LispIncomingMessageHandler(LispRouterId routerId,
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700376 LispMessage message) {
Jian Li834ff722016-12-13 19:43:02 +0900377 super(routerId, message, true);
378 }
379 }
380
381 /**
382 * LISP outgoing message handler.
383 */
384 protected final class LispOutgoingMessageHandler
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700385 extends LispMessageHandler implements Runnable {
Jian Li834ff722016-12-13 19:43:02 +0900386
387 LispOutgoingMessageHandler(LispRouterId routerId,
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700388 LispMessage message) {
Jian Li834ff722016-12-13 19:43:02 +0900389 super(routerId, message, false);
390 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900391 }
Jian Li6322a362016-10-31 00:57:19 +0900392}