blob: 573db1b7702069dbdc28274a1d0e4bacc6d87a78 [file] [log] [blame]
Jian Li6322a362016-10-31 00:57:19 +09001/*
2 * Copyright 2016-present 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 */
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.apache.felix.scr.annotations.Activate;
Jian Li6322a362016-10-31 00:57:19 +090020import org.apache.felix.scr.annotations.Component;
Jian Li712ec052016-11-22 03:23:54 +090021import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Modified;
23import org.apache.felix.scr.annotations.Property;
Jian Li6322a362016-10-31 00:57:19 +090024import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
Jian Li712ec052016-11-22 03:23:54 +090027import org.onlab.util.Tools;
28import org.onosproject.cfg.ComponentConfigService;
Jian Li6322a362016-10-31 00:57:19 +090029import org.onosproject.core.CoreService;
Jian Li5e505c62016-12-05 02:44:24 +090030import org.onosproject.lisp.ctl.LispController;
Jian Li7ccc3a82016-12-09 01:30:56 +090031import org.onosproject.lisp.ctl.LispMessageListener;
32import org.onosproject.lisp.ctl.LispRouter;
Jian Li834ff722016-12-13 19:43:02 +090033import org.onosproject.lisp.ctl.LispRouterAgent;
Jian Lib1a8fd02016-12-27 03:55:32 +090034import org.onosproject.lisp.ctl.LispRouterFactory;
Jian Li7ccc3a82016-12-09 01:30:56 +090035import org.onosproject.lisp.ctl.LispRouterId;
36import org.onosproject.lisp.ctl.LispRouterListener;
Jian Li712ec052016-11-22 03:23:54 +090037import org.onosproject.lisp.msg.authentication.LispAuthenticationConfig;
Jian Li834ff722016-12-13 19:43:02 +090038import org.onosproject.lisp.msg.protocols.LispInfoReply;
39import org.onosproject.lisp.msg.protocols.LispInfoRequest;
40import org.onosproject.lisp.msg.protocols.LispMessage;
Jian Li712ec052016-11-22 03:23:54 +090041import org.osgi.service.component.ComponentContext;
Jian Li6322a362016-10-31 00:57:19 +090042import org.slf4j.Logger;
Jian Li6322a362016-10-31 00:57:19 +090043
Jian Li712ec052016-11-22 03:23:54 +090044import java.util.Dictionary;
Jian Li834ff722016-12-13 19:43:02 +090045import java.util.Map;
46import java.util.Set;
47import java.util.concurrent.ConcurrentMap;
48import java.util.concurrent.CopyOnWriteArraySet;
49import java.util.concurrent.ExecutorService;
Jian Li712ec052016-11-22 03:23:54 +090050
Jian Li834ff722016-12-13 19:43:02 +090051import static java.util.concurrent.Executors.newFixedThreadPool;
52import static java.util.stream.Collectors.toConcurrentMap;
Jian Li712ec052016-11-22 03:23:54 +090053import static org.onlab.util.Tools.get;
54import static org.onlab.util.Tools.getIntegerProperty;
Jian Li834ff722016-12-13 19:43:02 +090055import static org.onlab.util.Tools.groupedThreads;
56import static org.slf4j.LoggerFactory.getLogger;
Jian Li712ec052016-11-22 03:23:54 +090057
Jian Li6322a362016-10-31 00:57:19 +090058/**
59 * LISP controller initiation class.
60 */
61@Component(immediate = true)
62@Service
63public class LispControllerImpl implements LispController {
64
65 private static final String APP_ID = "org.onosproject.lisp-base";
66
Jian Li834ff722016-12-13 19:43:02 +090067 private static final Logger log = getLogger(LispControllerImpl.class);
Jian Li6322a362016-10-31 00:57:19 +090068
Jian Li712ec052016-11-22 03:23:54 +090069 private static final String DEFAULT_LISP_AUTH_KEY = "onos";
70 private static final short DEFAULT_LISP_AUTH_KEY_ID = 1;
71
Jian Li6322a362016-10-31 00:57:19 +090072 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected CoreService coreService;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li712ec052016-11-22 03:23:54 +090076 protected ComponentConfigService cfgService;
77
78 @Property(name = "lispAuthKey", value = DEFAULT_LISP_AUTH_KEY,
79 label = "Authentication key which is used to calculate authentication " +
80 "data for LISP control message; default value is onos")
Jian Li834ff722016-12-13 19:43:02 +090081 private String lispAuthKey = DEFAULT_LISP_AUTH_KEY;
Jian Li712ec052016-11-22 03:23:54 +090082
83 @Property(name = "lispAuthKeyId", intValue = DEFAULT_LISP_AUTH_KEY_ID,
84 label = "Authentication key id which denotes the authentication method " +
85 "that ONOS uses to calculate the authentication data; " +
86 "1 denotes HMAC SHA1 encryption, 2 denotes HMAC SHA256 encryption; " +
87 "default value is 1")
Jian Li834ff722016-12-13 19:43:02 +090088 private int lispAuthKeyId = DEFAULT_LISP_AUTH_KEY_ID;
89
Jian Lib86d8ad2017-05-03 02:53:44 +090090 @Property(name = "enableSmr", boolValue = false,
91 label = "Enable to send SMR(Solicit Map Request) by map server; " +
92 "By default SMR is not activated")
93 private boolean enableSmr = false;
94
Jian Li834ff722016-12-13 19:43:02 +090095 ExecutorService executorMessages =
96 newFixedThreadPool(4, groupedThreads("onos/lisp", "event-stats-%d", log));
97
98 protected LispRouterAgent agent = new DefaultLispRouterAgent();
99
100 ConcurrentMap<LispRouterId, LispRouter> connectedRouters = Maps.newConcurrentMap();
101
Jian Li0dab5962016-12-15 03:44:28 +0900102 final LispAuthenticationConfig authConfig = LispAuthenticationConfig.getInstance();
103 LispControllerBootstrap bootstrap = new LispControllerBootstrap();
104
Jian Li834ff722016-12-13 19:43:02 +0900105 private Set<LispRouterListener> lispRouterListeners = new CopyOnWriteArraySet<>();
106 private Set<LispMessageListener> lispMessageListeners = new CopyOnWriteArraySet<>();
Jian Li712ec052016-11-22 03:23:54 +0900107
Jian Lib1a8fd02016-12-27 03:55:32 +0900108 private LispRouterFactory routerFactory = LispRouterFactory.getInstance();
109
Jian Li6322a362016-10-31 00:57:19 +0900110 @Activate
Jian Li712ec052016-11-22 03:23:54 +0900111 public void activate(ComponentContext context) {
Jian Li834ff722016-12-13 19:43:02 +0900112 coreService.registerApplication(APP_ID, this::cleanup);
Jian Li712ec052016-11-22 03:23:54 +0900113 cfgService.registerProperties(getClass());
Jian Li712ec052016-11-22 03:23:54 +0900114 initAuthConfig(context.getProperties());
Jian Lib1a8fd02016-12-27 03:55:32 +0900115 routerFactory.setAgent(agent);
Jian Li6322a362016-10-31 00:57:19 +0900116 bootstrap.start();
117 log.info("Started");
118 }
119
Jian Li834ff722016-12-13 19:43:02 +0900120 /**
121 * Shutdowns all listening channel and all LISP channels.
122 * Clean information about routers before deactivating.
123 */
124 private void cleanup() {
125 bootstrap.stop();
Jian Lib1a8fd02016-12-27 03:55:32 +0900126 routerFactory.cleanAgent();
Jian Li834ff722016-12-13 19:43:02 +0900127 connectedRouters.values().forEach(LispRouter::disconnectRouter);
128 connectedRouters.clear();
129 }
130
Jian Li6322a362016-10-31 00:57:19 +0900131 @Deactivate
132 public void deactivate() {
Jian Li834ff722016-12-13 19:43:02 +0900133 cleanup();
Jian Li712ec052016-11-22 03:23:54 +0900134 cfgService.unregisterProperties(getClass(), false);
Jian Li6322a362016-10-31 00:57:19 +0900135 log.info("Stopped");
136 }
Jian Li712ec052016-11-22 03:23:54 +0900137
138 @Modified
139 public void modified(ComponentContext context) {
140 readComponentConfiguration(context);
Jian Li834ff722016-12-13 19:43:02 +0900141 bootstrap.stop();
142 bootstrap.start();
Jian Li712ec052016-11-22 03:23:54 +0900143 }
144
145 /**
146 * Initializes authentication key and authentication method.
147 *
148 * @param properties a set of properties that contained in component context
149 */
150 private void initAuthConfig(Dictionary<?, ?> properties) {
151 authConfig.updateLispAuthKey(get(properties, "lispAuthKey"));
152 authConfig.updateLispAuthKeyId(getIntegerProperty(properties, "lispAuthKeyId"));
153 }
154
155 /**
156 * Extracts properties from the component configuration context.
157 *
158 * @param context the component context
159 */
160 private void readComponentConfiguration(ComponentContext context) {
161 Dictionary<?, ?> properties = context.getProperties();
162
163 String lispAuthKeyStr = Tools.get(properties, "lispAuthKey");
164 lispAuthKey = lispAuthKeyStr != null ? lispAuthKeyStr : DEFAULT_LISP_AUTH_KEY;
165 authConfig.updateLispAuthKey(lispAuthKey);
166 log.info("Configured. LISP authentication key is {}", lispAuthKey);
167
168 Integer lispAuthMethodInt = Tools.getIntegerProperty(properties, "lispAuthKeyId");
169 if (lispAuthMethodInt == null) {
170 lispAuthKeyId = DEFAULT_LISP_AUTH_KEY_ID;
171 log.info("LISP authentication method is not configured, default value is {}", lispAuthKeyId);
172 } else {
173 lispAuthKeyId = lispAuthMethodInt;
174 log.info("Configured. LISP authentication method is configured to {}", lispAuthKeyId);
175 }
176 authConfig.updateLispAuthKeyId(lispAuthKeyId);
Jian Lib86d8ad2017-05-03 02:53:44 +0900177
178 Boolean enableSmr = Tools.isPropertyEnabled(properties, "enableSmr");
179 if (enableSmr == null) {
180 log.info("Enable SMR is not configured, " +
181 "using current value of {}", this.enableSmr);
182 } else {
183 this.enableSmr = enableSmr;
184 log.info("Configured. Sending SMR through map server is {}",
185 this.enableSmr ? "enabled" : "disabled");
186 }
Jian Li712ec052016-11-22 03:23:54 +0900187 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900188
189 @Override
190 public Iterable<LispRouter> getRouters() {
Jian Li834ff722016-12-13 19:43:02 +0900191 return connectedRouters.values();
192 }
193
194 @Override
195 public Iterable<LispRouter> getSubscribedRouters() {
196 return connectedRouters.entrySet()
197 .stream()
198 .filter(e -> e.getValue().isSubscribed())
199 .collect(toConcurrentMap(Map.Entry::getKey,
200 Map.Entry::getValue)).values();
Jian Li7ccc3a82016-12-09 01:30:56 +0900201 }
202
203 @Override
Jian Li9b1a45b2017-01-19 13:34:31 -0800204 public LispRouter connectRouter(LispRouterId routerId) {
205 if (connectedRouters.containsKey(routerId)) {
206 log.debug("LISP router {} is already existing", routerId);
207 return connectedRouters.get(routerId);
208 } else {
209 // TODO: currently we do not consider to add LISP router from netcfg
210 log.warn("Adding router from netcfg is not supported currently");
211 return null;
212 }
213 }
214
215 @Override
216 public void disconnectRouter(LispRouterId routerId, boolean remove) {
217 if (!connectedRouters.containsKey(routerId)) {
218 log.warn("LISP router {} is not existing", routerId);
219 } else {
220 connectedRouters.get(routerId).disconnectRouter();
221 if (remove) {
222 agent.removeConnectedRouter(routerId);
223 }
224 }
225 }
226
227 @Override
Jian Li7ccc3a82016-12-09 01:30:56 +0900228 public LispRouter getRouter(LispRouterId routerId) {
Jian Li834ff722016-12-13 19:43:02 +0900229 return connectedRouters.get(routerId);
Jian Li7ccc3a82016-12-09 01:30:56 +0900230 }
231
232 @Override
233 public void addRouterListener(LispRouterListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900234 if (!lispRouterListeners.contains(listener)) {
235 lispRouterListeners.add(listener);
236 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900237 }
238
239 @Override
240 public void removeRouterListener(LispRouterListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900241 lispRouterListeners.remove(listener);
Jian Li7ccc3a82016-12-09 01:30:56 +0900242 }
243
244 @Override
245 public void addMessageListener(LispMessageListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900246 if (!lispMessageListeners.contains(listener)) {
247 lispMessageListeners.add(listener);
248 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900249 }
250
251 @Override
252 public void removeMessageListener(LispMessageListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900253 lispMessageListeners.remove(listener);
254 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900255
Jian Li834ff722016-12-13 19:43:02 +0900256 /**
257 * Implementation of a LISP agent which is responsible for keeping track of
258 * connected LISP routers and the state in which they are in.
259 */
260 public final class DefaultLispRouterAgent implements LispRouterAgent {
261
262 private final Logger log = getLogger(DefaultLispRouterAgent.class);
263
264 /**
265 * Prevents object instantiation from external class.
266 */
267 private DefaultLispRouterAgent() {
268 }
269
270 @Override
271 public boolean addConnectedRouter(LispRouterId routerId, LispRouter router) {
272
273 if (connectedRouters.get(routerId) != null) {
Jian Li07b90202017-04-14 12:03:24 +0900274 log.warn("Trying to add connectedRouter but found a previous " +
Jian Li834ff722016-12-13 19:43:02 +0900275 "value for routerId: {}", routerId);
276 return false;
277 } else {
278 log.info("Added router {}", routerId);
279 connectedRouters.put(routerId, router);
280 for (LispRouterListener listener : lispRouterListeners) {
281 listener.routerAdded(routerId);
282 }
283 return true;
284 }
285 }
286
287 @Override
288 public void removeConnectedRouter(LispRouterId routerId) {
289
290 if (connectedRouters.get(routerId) == null) {
291 log.error("Trying to remove router {} from connectedRouter " +
292 "list but no element was found", routerId);
293 } else {
294 log.info("Removed router {}", routerId);
295 connectedRouters.remove(routerId);
296 for (LispRouterListener listener : lispRouterListeners) {
297 listener.routerRemoved(routerId);
298 }
299 }
300 }
301
302 @Override
303 public void processUpstreamMessage(LispRouterId routerId, LispMessage message) {
304
305 switch (message.getType()) {
306 case LISP_MAP_REGISTER:
307 case LISP_MAP_REQUEST:
308 executorMessages.execute(
309 new LispIncomingMessageHandler(routerId, message));
310 break;
311 case LISP_INFO:
312 if (message instanceof LispInfoRequest) {
313 executorMessages.execute(
314 new LispIncomingMessageHandler(routerId, message));
315 } else {
316 log.warn("Not incoming LISP control message");
317 }
318 break;
319 default:
320 log.warn("Not incoming LISP control message");
321 break;
322 }
323 }
324
325 @Override
326 public void processDownstreamMessage(LispRouterId routerId, LispMessage message) {
327
328 switch (message.getType()) {
329 case LISP_MAP_NOTIFY:
330 case LISP_MAP_REPLY:
331 executorMessages.execute(
332 new LispOutgoingMessageHandler(routerId, message));
333 break;
334 case LISP_INFO:
335 if (message instanceof LispInfoReply) {
336 executorMessages.execute(
337 new LispOutgoingMessageHandler(routerId, message));
338 } else {
339 log.warn("Not outgoing LISP control message");
340 }
341 break;
342 default:
343 log.warn("Not outgoing LISP control message");
344 break;
345 }
346 }
347 }
348
349 /**
350 * LISP message handler.
351 */
352 protected class LispMessageHandler implements Runnable {
353
354 private final LispRouterId routerId;
355 private final LispMessage message;
356 private final boolean isIncoming;
357
358 LispMessageHandler(LispRouterId routerId,
359 LispMessage message, boolean isIncoming) {
360 this.routerId = routerId;
361 this.message = message;
362 this.isIncoming = isIncoming;
363 }
364
365 @Override
366 public void run() {
367 for (LispMessageListener listener : lispMessageListeners) {
368 if (isIncoming) {
369 listener.handleIncomingMessage(routerId, message);
370 } else {
371 listener.handleOutgoingMessage(routerId, message);
372 }
373 }
374 }
375 }
376
377 /**
378 * LISP incoming message handler.
379 */
380 protected final class LispIncomingMessageHandler
381 extends LispMessageHandler implements Runnable {
382
383 LispIncomingMessageHandler(LispRouterId routerId,
384 LispMessage message) {
385 super(routerId, message, true);
386 }
387 }
388
389 /**
390 * LISP outgoing message handler.
391 */
392 protected final class LispOutgoingMessageHandler
393 extends LispMessageHandler implements Runnable {
394
395 LispOutgoingMessageHandler(LispRouterId routerId,
396 LispMessage message) {
397 super(routerId, message, false);
398 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900399 }
Jian Li6322a362016-10-31 00:57:19 +0900400}