blob: 5d82527069d07ca1f82b0e01552adcd4ef0d1302 [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 Li7ccc3a82016-12-09 01:30:56 +090034import org.onosproject.lisp.ctl.LispRouterId;
35import org.onosproject.lisp.ctl.LispRouterListener;
Jian Li712ec052016-11-22 03:23:54 +090036import org.onosproject.lisp.msg.authentication.LispAuthenticationConfig;
Jian Li834ff722016-12-13 19:43:02 +090037import org.onosproject.lisp.msg.protocols.LispInfoReply;
38import org.onosproject.lisp.msg.protocols.LispInfoRequest;
39import org.onosproject.lisp.msg.protocols.LispMessage;
Jian Li712ec052016-11-22 03:23:54 +090040import org.osgi.service.component.ComponentContext;
Jian Li6322a362016-10-31 00:57:19 +090041import org.slf4j.Logger;
Jian Li6322a362016-10-31 00:57:19 +090042
Jian Li712ec052016-11-22 03:23:54 +090043import java.util.Dictionary;
Jian Li834ff722016-12-13 19:43:02 +090044import java.util.Map;
45import java.util.Set;
46import java.util.concurrent.ConcurrentMap;
47import java.util.concurrent.CopyOnWriteArraySet;
48import java.util.concurrent.ExecutorService;
Jian Li712ec052016-11-22 03:23:54 +090049
Jian Li834ff722016-12-13 19:43:02 +090050import static java.util.concurrent.Executors.newFixedThreadPool;
51import static java.util.stream.Collectors.toConcurrentMap;
Jian Li712ec052016-11-22 03:23:54 +090052import static org.onlab.util.Tools.get;
53import static org.onlab.util.Tools.getIntegerProperty;
Jian Li834ff722016-12-13 19:43:02 +090054import static org.onlab.util.Tools.groupedThreads;
55import 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 */
60@Component(immediate = true)
61@Service
62public class LispControllerImpl implements LispController {
63
64 private static final String APP_ID = "org.onosproject.lisp-base";
65
Jian Li834ff722016-12-13 19:43:02 +090066 private static final Logger log = getLogger(LispControllerImpl.class);
Jian Li6322a362016-10-31 00:57:19 +090067
Jian Li712ec052016-11-22 03:23:54 +090068 private static final String DEFAULT_LISP_AUTH_KEY = "onos";
69 private static final short DEFAULT_LISP_AUTH_KEY_ID = 1;
70
Jian Li6322a362016-10-31 00:57:19 +090071 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected CoreService coreService;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li712ec052016-11-22 03:23:54 +090075 protected ComponentConfigService cfgService;
76
77 @Property(name = "lispAuthKey", value = DEFAULT_LISP_AUTH_KEY,
78 label = "Authentication key which is used to calculate authentication " +
79 "data for LISP control message; default value is onos")
Jian Li834ff722016-12-13 19:43:02 +090080 private String lispAuthKey = DEFAULT_LISP_AUTH_KEY;
Jian Li712ec052016-11-22 03:23:54 +090081
82 @Property(name = "lispAuthKeyId", intValue = DEFAULT_LISP_AUTH_KEY_ID,
83 label = "Authentication key id which denotes the authentication method " +
84 "that ONOS uses to calculate the authentication data; " +
85 "1 denotes HMAC SHA1 encryption, 2 denotes HMAC SHA256 encryption; " +
86 "default value is 1")
Jian Li834ff722016-12-13 19:43:02 +090087 private int lispAuthKeyId = DEFAULT_LISP_AUTH_KEY_ID;
88
89 ExecutorService executorMessages =
90 newFixedThreadPool(4, groupedThreads("onos/lisp", "event-stats-%d", log));
91
92 protected LispRouterAgent agent = new DefaultLispRouterAgent();
93
94 ConcurrentMap<LispRouterId, LispRouter> connectedRouters = Maps.newConcurrentMap();
95
96 private Set<LispRouterListener> lispRouterListeners = new CopyOnWriteArraySet<>();
97 private Set<LispMessageListener> lispMessageListeners = new CopyOnWriteArraySet<>();
Jian Li712ec052016-11-22 03:23:54 +090098
Jian Li6322a362016-10-31 00:57:19 +090099 private final LispControllerBootstrap bootstrap = new LispControllerBootstrap();
Jian Li712ec052016-11-22 03:23:54 +0900100 private final LispAuthenticationConfig authConfig = LispAuthenticationConfig.getInstance();
Jian Li6322a362016-10-31 00:57:19 +0900101
102 @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 Li6322a362016-10-31 00:57:19 +0900107 bootstrap.start();
108 log.info("Started");
109 }
110
Jian Li834ff722016-12-13 19:43:02 +0900111 /**
112 * Shutdowns all listening channel and all LISP channels.
113 * Clean information about routers before deactivating.
114 */
115 private void cleanup() {
116 bootstrap.stop();
117 connectedRouters.values().forEach(LispRouter::disconnectRouter);
118 connectedRouters.clear();
119 }
120
Jian Li6322a362016-10-31 00:57:19 +0900121 @Deactivate
122 public void deactivate() {
Jian Li834ff722016-12-13 19:43:02 +0900123 cleanup();
Jian Li712ec052016-11-22 03:23:54 +0900124 cfgService.unregisterProperties(getClass(), false);
Jian Li6322a362016-10-31 00:57:19 +0900125 log.info("Stopped");
126 }
Jian Li712ec052016-11-22 03:23:54 +0900127
128 @Modified
129 public void modified(ComponentContext context) {
130 readComponentConfiguration(context);
Jian Li834ff722016-12-13 19:43:02 +0900131 bootstrap.stop();
132 bootstrap.start();
Jian Li712ec052016-11-22 03:23:54 +0900133 }
134
135 /**
136 * Initializes authentication key and authentication method.
137 *
138 * @param properties a set of properties that contained in component context
139 */
140 private void initAuthConfig(Dictionary<?, ?> properties) {
141 authConfig.updateLispAuthKey(get(properties, "lispAuthKey"));
142 authConfig.updateLispAuthKeyId(getIntegerProperty(properties, "lispAuthKeyId"));
143 }
144
145 /**
146 * Extracts properties from the component configuration context.
147 *
148 * @param context the component context
149 */
150 private void readComponentConfiguration(ComponentContext context) {
151 Dictionary<?, ?> properties = context.getProperties();
152
153 String lispAuthKeyStr = Tools.get(properties, "lispAuthKey");
154 lispAuthKey = lispAuthKeyStr != null ? lispAuthKeyStr : DEFAULT_LISP_AUTH_KEY;
155 authConfig.updateLispAuthKey(lispAuthKey);
156 log.info("Configured. LISP authentication key is {}", lispAuthKey);
157
158 Integer lispAuthMethodInt = Tools.getIntegerProperty(properties, "lispAuthKeyId");
159 if (lispAuthMethodInt == null) {
160 lispAuthKeyId = DEFAULT_LISP_AUTH_KEY_ID;
161 log.info("LISP authentication method is not configured, default value is {}", lispAuthKeyId);
162 } else {
163 lispAuthKeyId = lispAuthMethodInt;
164 log.info("Configured. LISP authentication method is configured to {}", lispAuthKeyId);
165 }
166 authConfig.updateLispAuthKeyId(lispAuthKeyId);
167 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900168
169 @Override
170 public Iterable<LispRouter> getRouters() {
Jian Li834ff722016-12-13 19:43:02 +0900171 return connectedRouters.values();
172 }
173
174 @Override
175 public Iterable<LispRouter> getSubscribedRouters() {
176 return connectedRouters.entrySet()
177 .stream()
178 .filter(e -> e.getValue().isSubscribed())
179 .collect(toConcurrentMap(Map.Entry::getKey,
180 Map.Entry::getValue)).values();
Jian Li7ccc3a82016-12-09 01:30:56 +0900181 }
182
183 @Override
184 public LispRouter getRouter(LispRouterId routerId) {
Jian Li834ff722016-12-13 19:43:02 +0900185 return connectedRouters.get(routerId);
Jian Li7ccc3a82016-12-09 01:30:56 +0900186 }
187
188 @Override
189 public void addRouterListener(LispRouterListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900190 if (!lispRouterListeners.contains(listener)) {
191 lispRouterListeners.add(listener);
192 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900193 }
194
195 @Override
196 public void removeRouterListener(LispRouterListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900197 lispRouterListeners.remove(listener);
Jian Li7ccc3a82016-12-09 01:30:56 +0900198 }
199
200 @Override
201 public void addMessageListener(LispMessageListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900202 if (!lispMessageListeners.contains(listener)) {
203 lispMessageListeners.add(listener);
204 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900205 }
206
207 @Override
208 public void removeMessageListener(LispMessageListener listener) {
Jian Li834ff722016-12-13 19:43:02 +0900209 lispMessageListeners.remove(listener);
210 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900211
Jian Li834ff722016-12-13 19:43:02 +0900212 /**
213 * Implementation of a LISP agent which is responsible for keeping track of
214 * connected LISP routers and the state in which they are in.
215 */
216 public final class DefaultLispRouterAgent implements LispRouterAgent {
217
218 private final Logger log = getLogger(DefaultLispRouterAgent.class);
219
220 /**
221 * Prevents object instantiation from external class.
222 */
223 private DefaultLispRouterAgent() {
224 }
225
226 @Override
227 public boolean addConnectedRouter(LispRouterId routerId, LispRouter router) {
228
229 if (connectedRouters.get(routerId) != null) {
230 log.error("Trying to add connectedRouter but found a previous " +
231 "value for routerId: {}", routerId);
232 return false;
233 } else {
234 log.info("Added router {}", routerId);
235 connectedRouters.put(routerId, router);
236 for (LispRouterListener listener : lispRouterListeners) {
237 listener.routerAdded(routerId);
238 }
239 return true;
240 }
241 }
242
243 @Override
244 public void removeConnectedRouter(LispRouterId routerId) {
245
246 if (connectedRouters.get(routerId) == null) {
247 log.error("Trying to remove router {} from connectedRouter " +
248 "list but no element was found", routerId);
249 } else {
250 log.info("Removed router {}", routerId);
251 connectedRouters.remove(routerId);
252 for (LispRouterListener listener : lispRouterListeners) {
253 listener.routerRemoved(routerId);
254 }
255 }
256 }
257
258 @Override
259 public void processUpstreamMessage(LispRouterId routerId, LispMessage message) {
260
261 switch (message.getType()) {
262 case LISP_MAP_REGISTER:
263 case LISP_MAP_REQUEST:
264 executorMessages.execute(
265 new LispIncomingMessageHandler(routerId, message));
266 break;
267 case LISP_INFO:
268 if (message instanceof LispInfoRequest) {
269 executorMessages.execute(
270 new LispIncomingMessageHandler(routerId, message));
271 } else {
272 log.warn("Not incoming LISP control message");
273 }
274 break;
275 default:
276 log.warn("Not incoming LISP control message");
277 break;
278 }
279 }
280
281 @Override
282 public void processDownstreamMessage(LispRouterId routerId, LispMessage message) {
283
284 switch (message.getType()) {
285 case LISP_MAP_NOTIFY:
286 case LISP_MAP_REPLY:
287 executorMessages.execute(
288 new LispOutgoingMessageHandler(routerId, message));
289 break;
290 case LISP_INFO:
291 if (message instanceof LispInfoReply) {
292 executorMessages.execute(
293 new LispOutgoingMessageHandler(routerId, message));
294 } else {
295 log.warn("Not outgoing LISP control message");
296 }
297 break;
298 default:
299 log.warn("Not outgoing LISP control message");
300 break;
301 }
302 }
303 }
304
305 /**
306 * LISP message handler.
307 */
308 protected class LispMessageHandler implements Runnable {
309
310 private final LispRouterId routerId;
311 private final LispMessage message;
312 private final boolean isIncoming;
313
314 LispMessageHandler(LispRouterId routerId,
315 LispMessage message, boolean isIncoming) {
316 this.routerId = routerId;
317 this.message = message;
318 this.isIncoming = isIncoming;
319 }
320
321 @Override
322 public void run() {
323 for (LispMessageListener listener : lispMessageListeners) {
324 if (isIncoming) {
325 listener.handleIncomingMessage(routerId, message);
326 } else {
327 listener.handleOutgoingMessage(routerId, message);
328 }
329 }
330 }
331 }
332
333 /**
334 * LISP incoming message handler.
335 */
336 protected final class LispIncomingMessageHandler
337 extends LispMessageHandler implements Runnable {
338
339 LispIncomingMessageHandler(LispRouterId routerId,
340 LispMessage message) {
341 super(routerId, message, true);
342 }
343 }
344
345 /**
346 * LISP outgoing message handler.
347 */
348 protected final class LispOutgoingMessageHandler
349 extends LispMessageHandler implements Runnable {
350
351 LispOutgoingMessageHandler(LispRouterId routerId,
352 LispMessage message) {
353 super(routerId, message, false);
354 }
Jian Li7ccc3a82016-12-09 01:30:56 +0900355 }
Jian Li6322a362016-10-31 00:57:19 +0900356}