blob: 7fa1e982528abb67b21875a1a540bbd7abe9704d [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.lisp.ctl.impl;
import com.google.common.collect.Maps;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.util.Tools;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.core.CoreService;
import org.onosproject.lisp.ctl.LispController;
import org.onosproject.lisp.ctl.LispMessageListener;
import org.onosproject.lisp.ctl.LispRouter;
import org.onosproject.lisp.ctl.LispRouterAgent;
import org.onosproject.lisp.ctl.LispRouterFactory;
import org.onosproject.lisp.ctl.LispRouterId;
import org.onosproject.lisp.ctl.LispRouterListener;
import org.onosproject.lisp.msg.authentication.LispAuthenticationConfig;
import org.onosproject.lisp.msg.protocols.LispInfoReply;
import org.onosproject.lisp.msg.protocols.LispInfoRequest;
import org.onosproject.lisp.msg.protocols.LispMessage;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import java.util.Dictionary;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import static java.util.concurrent.Executors.newFixedThreadPool;
import static java.util.stream.Collectors.toConcurrentMap;
import static org.onlab.util.Tools.get;
import static org.onlab.util.Tools.getIntegerProperty;
import static org.onlab.util.Tools.groupedThreads;
import static org.slf4j.LoggerFactory.getLogger;
/**
* LISP controller initiation class.
*/
@Component(immediate = true)
@Service
public class LispControllerImpl implements LispController {
private static final String APP_ID = "org.onosproject.lisp-base";
private static final Logger log = getLogger(LispControllerImpl.class);
private static final String DEFAULT_LISP_AUTH_KEY = "onos";
private static final short DEFAULT_LISP_AUTH_KEY_ID = 1;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ComponentConfigService cfgService;
@Property(name = "lispAuthKey", value = DEFAULT_LISP_AUTH_KEY,
label = "Authentication key which is used to calculate authentication " +
"data for LISP control message; default value is onos")
private String lispAuthKey = DEFAULT_LISP_AUTH_KEY;
@Property(name = "lispAuthKeyId", intValue = DEFAULT_LISP_AUTH_KEY_ID,
label = "Authentication key id which denotes the authentication method " +
"that ONOS uses to calculate the authentication data; " +
"1 denotes HMAC SHA1 encryption, 2 denotes HMAC SHA256 encryption; " +
"default value is 1")
private int lispAuthKeyId = DEFAULT_LISP_AUTH_KEY_ID;
ExecutorService executorMessages =
newFixedThreadPool(4, groupedThreads("onos/lisp", "event-stats-%d", log));
protected LispRouterAgent agent = new DefaultLispRouterAgent();
ConcurrentMap<LispRouterId, LispRouter> connectedRouters = Maps.newConcurrentMap();
final LispAuthenticationConfig authConfig = LispAuthenticationConfig.getInstance();
LispControllerBootstrap bootstrap = new LispControllerBootstrap();
private Set<LispRouterListener> lispRouterListeners = new CopyOnWriteArraySet<>();
private Set<LispMessageListener> lispMessageListeners = new CopyOnWriteArraySet<>();
private LispRouterFactory routerFactory = LispRouterFactory.getInstance();
@Activate
public void activate(ComponentContext context) {
coreService.registerApplication(APP_ID, this::cleanup);
cfgService.registerProperties(getClass());
initAuthConfig(context.getProperties());
routerFactory.setAgent(agent);
bootstrap.start();
log.info("Started");
}
/**
* Shutdowns all listening channel and all LISP channels.
* Clean information about routers before deactivating.
*/
private void cleanup() {
bootstrap.stop();
routerFactory.cleanAgent();
connectedRouters.values().forEach(LispRouter::disconnectRouter);
connectedRouters.clear();
}
@Deactivate
public void deactivate() {
cleanup();
cfgService.unregisterProperties(getClass(), false);
log.info("Stopped");
}
@Modified
public void modified(ComponentContext context) {
readComponentConfiguration(context);
bootstrap.stop();
bootstrap.start();
}
/**
* Initializes authentication key and authentication method.
*
* @param properties a set of properties that contained in component context
*/
private void initAuthConfig(Dictionary<?, ?> properties) {
authConfig.updateLispAuthKey(get(properties, "lispAuthKey"));
authConfig.updateLispAuthKeyId(getIntegerProperty(properties, "lispAuthKeyId"));
}
/**
* Extracts properties from the component configuration context.
*
* @param context the component context
*/
private void readComponentConfiguration(ComponentContext context) {
Dictionary<?, ?> properties = context.getProperties();
String lispAuthKeyStr = Tools.get(properties, "lispAuthKey");
lispAuthKey = lispAuthKeyStr != null ? lispAuthKeyStr : DEFAULT_LISP_AUTH_KEY;
authConfig.updateLispAuthKey(lispAuthKey);
log.info("Configured. LISP authentication key is {}", lispAuthKey);
Integer lispAuthMethodInt = Tools.getIntegerProperty(properties, "lispAuthKeyId");
if (lispAuthMethodInt == null) {
lispAuthKeyId = DEFAULT_LISP_AUTH_KEY_ID;
log.info("LISP authentication method is not configured, default value is {}", lispAuthKeyId);
} else {
lispAuthKeyId = lispAuthMethodInt;
log.info("Configured. LISP authentication method is configured to {}", lispAuthKeyId);
}
authConfig.updateLispAuthKeyId(lispAuthKeyId);
}
@Override
public Iterable<LispRouter> getRouters() {
return connectedRouters.values();
}
@Override
public Iterable<LispRouter> getSubscribedRouters() {
return connectedRouters.entrySet()
.stream()
.filter(e -> e.getValue().isSubscribed())
.collect(toConcurrentMap(Map.Entry::getKey,
Map.Entry::getValue)).values();
}
@Override
public LispRouter getRouter(LispRouterId routerId) {
return connectedRouters.get(routerId);
}
@Override
public void addRouterListener(LispRouterListener listener) {
if (!lispRouterListeners.contains(listener)) {
lispRouterListeners.add(listener);
}
}
@Override
public void removeRouterListener(LispRouterListener listener) {
lispRouterListeners.remove(listener);
}
@Override
public void addMessageListener(LispMessageListener listener) {
if (!lispMessageListeners.contains(listener)) {
lispMessageListeners.add(listener);
}
}
@Override
public void removeMessageListener(LispMessageListener listener) {
lispMessageListeners.remove(listener);
}
/**
* Implementation of a LISP agent which is responsible for keeping track of
* connected LISP routers and the state in which they are in.
*/
public final class DefaultLispRouterAgent implements LispRouterAgent {
private final Logger log = getLogger(DefaultLispRouterAgent.class);
/**
* Prevents object instantiation from external class.
*/
private DefaultLispRouterAgent() {
}
@Override
public boolean addConnectedRouter(LispRouterId routerId, LispRouter router) {
if (connectedRouters.get(routerId) != null) {
log.error("Trying to add connectedRouter but found a previous " +
"value for routerId: {}", routerId);
return false;
} else {
log.info("Added router {}", routerId);
connectedRouters.put(routerId, router);
for (LispRouterListener listener : lispRouterListeners) {
listener.routerAdded(routerId);
}
return true;
}
}
@Override
public void removeConnectedRouter(LispRouterId routerId) {
if (connectedRouters.get(routerId) == null) {
log.error("Trying to remove router {} from connectedRouter " +
"list but no element was found", routerId);
} else {
log.info("Removed router {}", routerId);
connectedRouters.remove(routerId);
for (LispRouterListener listener : lispRouterListeners) {
listener.routerRemoved(routerId);
}
}
}
@Override
public void processUpstreamMessage(LispRouterId routerId, LispMessage message) {
switch (message.getType()) {
case LISP_MAP_REGISTER:
case LISP_MAP_REQUEST:
executorMessages.execute(
new LispIncomingMessageHandler(routerId, message));
break;
case LISP_INFO:
if (message instanceof LispInfoRequest) {
executorMessages.execute(
new LispIncomingMessageHandler(routerId, message));
} else {
log.warn("Not incoming LISP control message");
}
break;
default:
log.warn("Not incoming LISP control message");
break;
}
}
@Override
public void processDownstreamMessage(LispRouterId routerId, LispMessage message) {
switch (message.getType()) {
case LISP_MAP_NOTIFY:
case LISP_MAP_REPLY:
executorMessages.execute(
new LispOutgoingMessageHandler(routerId, message));
break;
case LISP_INFO:
if (message instanceof LispInfoReply) {
executorMessages.execute(
new LispOutgoingMessageHandler(routerId, message));
} else {
log.warn("Not outgoing LISP control message");
}
break;
default:
log.warn("Not outgoing LISP control message");
break;
}
}
}
/**
* LISP message handler.
*/
protected class LispMessageHandler implements Runnable {
private final LispRouterId routerId;
private final LispMessage message;
private final boolean isIncoming;
LispMessageHandler(LispRouterId routerId,
LispMessage message, boolean isIncoming) {
this.routerId = routerId;
this.message = message;
this.isIncoming = isIncoming;
}
@Override
public void run() {
for (LispMessageListener listener : lispMessageListeners) {
if (isIncoming) {
listener.handleIncomingMessage(routerId, message);
} else {
listener.handleOutgoingMessage(routerId, message);
}
}
}
}
/**
* LISP incoming message handler.
*/
protected final class LispIncomingMessageHandler
extends LispMessageHandler implements Runnable {
LispIncomingMessageHandler(LispRouterId routerId,
LispMessage message) {
super(routerId, message, true);
}
}
/**
* LISP outgoing message handler.
*/
protected final class LispOutgoingMessageHandler
extends LispMessageHandler implements Runnable {
LispOutgoingMessageHandler(LispRouterId routerId,
LispMessage message) {
super(routerId, message, false);
}
}
}