blob: 7fa1e982528abb67b21875a1a540bbd7abe9704d [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
90 ExecutorService executorMessages =
91 newFixedThreadPool(4, groupedThreads("onos/lisp", "event-stats-%d", log));
92
93 protected LispRouterAgent agent = new DefaultLispRouterAgent();
94
95 ConcurrentMap<LispRouterId, LispRouter> connectedRouters = Maps.newConcurrentMap();
96
Jian Li0dab5962016-12-15 03:44:28 +090097 final LispAuthenticationConfig authConfig = LispAuthenticationConfig.getInstance();
98 LispControllerBootstrap bootstrap = new LispControllerBootstrap();
99
Jian Li834ff722016-12-13 19:43:02 +0900100 private Set<LispRouterListener> lispRouterListeners = new CopyOnWriteArraySet<>();
101 private Set<LispMessageListener> lispMessageListeners = new CopyOnWriteArraySet<>();
Jian Li712ec052016-11-22 03:23:54 +0900102
Jian Lib1a8fd02016-12-27 03:55:32 +0900103 private LispRouterFactory routerFactory = LispRouterFactory.getInstance();
104
Jian Li6322a362016-10-31 00:57:19 +0900105 @Activate
Jian Li712ec052016-11-22 03:23:54 +0900106 public void activate(ComponentContext context) {
Jian Li834ff722016-12-13 19:43:02 +0900107 coreService.registerApplication(APP_ID, this::cleanup);
Jian Li712ec052016-11-22 03:23:54 +0900108 cfgService.registerProperties(getClass());
Jian Li712ec052016-11-22 03:23:54 +0900109 initAuthConfig(context.getProperties());
Jian Lib1a8fd02016-12-27 03:55:32 +0900110 routerFactory.setAgent(agent);
Jian Li6322a362016-10-31 00:57:19 +0900111 bootstrap.start();
112 log.info("Started");
113 }
114
Jian Li834ff722016-12-13 19:43:02 +0900115 /**
116 * Shutdowns all listening channel and all LISP channels.
117 * Clean information about routers before deactivating.
118 */
119 private void cleanup() {
120 bootstrap.stop();
Jian Lib1a8fd02016-12-27 03:55:32 +0900121 routerFactory.cleanAgent();
Jian Li834ff722016-12-13 19:43:02 +0900122 connectedRouters.values().forEach(LispRouter::disconnectRouter);
123 connectedRouters.clear();
124 }
125
Jian Li6322a362016-10-31 00:57:19 +0900126 @Deactivate
127 public void deactivate() {
Jian Li834ff722016-12-13 19:43:02 +0900128 cleanup();
Jian Li712ec052016-11-22 03:23:54 +0900129 cfgService.unregisterProperties(getClass(), false);
Jian Li6322a362016-10-31 00:57:19 +0900130 log.info("Stopped");
131 }
Jian Li712ec052016-11-22 03:23:54 +0900132
133 @Modified
134 public void modified(ComponentContext context) {
135 readComponentConfiguration(context);
Jian Li834ff722016-12-13 19:43:02 +0900136 bootstrap.stop();
137 bootstrap.start();
Jian Li712ec052016-11-22 03:23:54 +0900138 }
139
140 /**
141 * Initializes authentication key and authentication method.
142 *
143 * @param properties a set of properties that contained in component context
144 */
145 private void initAuthConfig(Dictionary<?, ?> properties) {
146 authConfig.updateLispAuthKey(get(properties, "lispAuthKey"));
147 authConfig.updateLispAuthKeyId(getIntegerProperty(properties, "lispAuthKeyId"));
148 }
149
150 /**
151 * Extracts properties from the component configuration context.
152 *
153 * @param context the component context
154 */
155 private void readComponentConfiguration(ComponentContext context) {
156 Dictionary<?, ?> properties = context.getProperties();
157
158 String lispAuthKeyStr = Tools.get(properties, "lispAuthKey");
159 lispAuthKey = lispAuthKeyStr != null ? lispAuthKeyStr : DEFAULT_LISP_AUTH_KEY;
160 authConfig.updateLispAuthKey(lispAuthKey);
161 log.info("Configured. LISP authentication key is {}", lispAuthKey);
162
163 Integer lispAuthMethodInt = Tools.getIntegerProperty(properties, "lispAuthKeyId");
164 if (lispAuthMethodInt == null) {
165 lispAuthKeyId = DEFAULT_LISP_AUTH_KEY_ID;
166 log.info("LISP authentication method is not configured, default value is {}", lispAuthKeyId);
167 } else {
168 lispAuthKeyId = lispAuthMethodInt;
169 log.info("Configured. LISP authentication method is configured to {}", lispAuthKeyId);
170 }
171 authConfig.updateLispAuthKeyId(lispAuthKeyId);
172 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900173
174 @Override
175 public Iterable<LispRouter> getRouters() {
Jian Li834ff722016-12-13 19:43:02 +0900176 return connectedRouters.values();
177 }
178
179 @Override
180 public Iterable<LispRouter> getSubscribedRouters() {
181 return connectedRouters.entrySet()
182 .stream()
183 .filter(e -> e.getValue().isSubscribed())
184 .collect(toConcurrentMap(Map.Entry::getKey,
185 Map.Entry::getValue)).values();
Jian Li7ccc3a82016-12-09 01:30:56 +0900186 }
187
188 @Override
189 public LispRouter getRouter(LispRouterId routerId) {
Jian Li834ff722016-12-13 19:43:02 +0900190 return connectedRouters.get(routerId);
Jian Li7ccc3a82016-12-09 01:30:56 +0900191 }
192
193 @Override
194 public void addRouterListener(LispRouterListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900195 if (!lispRouterListeners.contains(listener)) {
196 lispRouterListeners.add(listener);
197 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900198 }
199
200 @Override
201 public void removeRouterListener(LispRouterListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900202 lispRouterListeners.remove(listener);
Jian Li7ccc3a82016-12-09 01:30:56 +0900203 }
204
205 @Override
206 public void addMessageListener(LispMessageListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900207 if (!lispMessageListeners.contains(listener)) {
208 lispMessageListeners.add(listener);
209 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900210 }
211
212 @Override
213 public void removeMessageListener(LispMessageListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900214 lispMessageListeners.remove(listener);
215 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900216
Jian Li834ff722016-12-13 19:43:02 +0900217 /**
218 * Implementation of a LISP agent which is responsible for keeping track of
219 * connected LISP routers and the state in which they are in.
220 */
221 public final class DefaultLispRouterAgent implements LispRouterAgent {
222
223 private final Logger log = getLogger(DefaultLispRouterAgent.class);
224
225 /**
226 * Prevents object instantiation from external class.
227 */
228 private DefaultLispRouterAgent() {
229 }
230
231 @Override
232 public boolean addConnectedRouter(LispRouterId routerId, LispRouter router) {
233
234 if (connectedRouters.get(routerId) != null) {
235 log.error("Trying to add connectedRouter but found a previous " +
236 "value for routerId: {}", routerId);
237 return false;
238 } else {
239 log.info("Added router {}", routerId);
240 connectedRouters.put(routerId, router);
241 for (LispRouterListener listener : lispRouterListeners) {
242 listener.routerAdded(routerId);
243 }
244 return true;
245 }
246 }
247
248 @Override
249 public void removeConnectedRouter(LispRouterId routerId) {
250
251 if (connectedRouters.get(routerId) == null) {
252 log.error("Trying to remove router {} from connectedRouter " +
253 "list but no element was found", routerId);
254 } else {
255 log.info("Removed router {}", routerId);
256 connectedRouters.remove(routerId);
257 for (LispRouterListener listener : lispRouterListeners) {
258 listener.routerRemoved(routerId);
259 }
260 }
261 }
262
263 @Override
264 public void processUpstreamMessage(LispRouterId routerId, LispMessage message) {
265
266 switch (message.getType()) {
267 case LISP_MAP_REGISTER:
268 case LISP_MAP_REQUEST:
269 executorMessages.execute(
270 new LispIncomingMessageHandler(routerId, message));
271 break;
272 case LISP_INFO:
273 if (message instanceof LispInfoRequest) {
274 executorMessages.execute(
275 new LispIncomingMessageHandler(routerId, message));
276 } else {
277 log.warn("Not incoming LISP control message");
278 }
279 break;
280 default:
281 log.warn("Not incoming LISP control message");
282 break;
283 }
284 }
285
286 @Override
287 public void processDownstreamMessage(LispRouterId routerId, LispMessage message) {
288
289 switch (message.getType()) {
290 case LISP_MAP_NOTIFY:
291 case LISP_MAP_REPLY:
292 executorMessages.execute(
293 new LispOutgoingMessageHandler(routerId, message));
294 break;
295 case LISP_INFO:
296 if (message instanceof LispInfoReply) {
297 executorMessages.execute(
298 new LispOutgoingMessageHandler(routerId, message));
299 } else {
300 log.warn("Not outgoing LISP control message");
301 }
302 break;
303 default:
304 log.warn("Not outgoing LISP control message");
305 break;
306 }
307 }
308 }
309
310 /**
311 * LISP message handler.
312 */
313 protected class LispMessageHandler implements Runnable {
314
315 private final LispRouterId routerId;
316 private final LispMessage message;
317 private final boolean isIncoming;
318
319 LispMessageHandler(LispRouterId routerId,
320 LispMessage message, boolean isIncoming) {
321 this.routerId = routerId;
322 this.message = message;
323 this.isIncoming = isIncoming;
324 }
325
326 @Override
327 public void run() {
328 for (LispMessageListener listener : lispMessageListeners) {
329 if (isIncoming) {
330 listener.handleIncomingMessage(routerId, message);
331 } else {
332 listener.handleOutgoingMessage(routerId, message);
333 }
334 }
335 }
336 }
337
338 /**
339 * LISP incoming message handler.
340 */
341 protected final class LispIncomingMessageHandler
342 extends LispMessageHandler implements Runnable {
343
344 LispIncomingMessageHandler(LispRouterId routerId,
345 LispMessage message) {
346 super(routerId, message, true);
347 }
348 }
349
350 /**
351 * LISP outgoing message handler.
352 */
353 protected final class LispOutgoingMessageHandler
354 extends LispMessageHandler implements Runnable {
355
356 LispOutgoingMessageHandler(LispRouterId routerId,
357 LispMessage message) {
358 super(routerId, message, false);
359 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900360 }
Jian Li6322a362016-10-31 00:57:19 +0900361}