2 * Copyright (c) 2014 Contextream, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.lispflowmapping.implementation;
11 import java.util.List;
13 import org.apache.commons.lang3.tuple.MutablePair;
14 import org.apache.commons.lang3.tuple.Pair;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
17 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
18 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
19 import org.opendaylight.controller.sal.binding.api.NotificationListener;
20 import org.opendaylight.controller.sal.binding.api.NotificationService;
21 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
22 import org.opendaylight.lispflowmapping.implementation.config.ConfigIni;
23 import org.opendaylight.lispflowmapping.implementation.lisp.MapResolver;
24 import org.opendaylight.lispflowmapping.implementation.lisp.MapServer;
25 import org.opendaylight.lispflowmapping.implementation.mdsal.AuthenticationKeyDataListener;
26 import org.opendaylight.lispflowmapping.implementation.mdsal.DataStoreBackEnd;
27 import org.opendaylight.lispflowmapping.implementation.mdsal.MappingDataListener;
28 import org.opendaylight.lispflowmapping.implementation.util.LispNotificationHelper;
29 import org.opendaylight.lispflowmapping.lisp.type.LispMessage;
30 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
31 import org.opendaylight.lispflowmapping.interfaces.dao.IRowVisitor;
32 import org.opendaylight.lispflowmapping.interfaces.dao.SubKeys;
33 import org.opendaylight.lispflowmapping.interfaces.lisp.IFlowMapping;
34 import org.opendaylight.lispflowmapping.interfaces.lisp.IFlowMappingShell;
35 import org.opendaylight.lispflowmapping.interfaces.lisp.IMapNotifyHandler;
36 import org.opendaylight.lispflowmapping.interfaces.lisp.IMapRequestResultHandler;
37 import org.opendaylight.lispflowmapping.interfaces.lisp.IMapResolverAsync;
38 import org.opendaylight.lispflowmapping.interfaces.lisp.IMapServerAsync;
39 import org.opendaylight.lispflowmapping.lisp.util.LispAFIConvertor;
40 import org.opendaylight.lispflowmapping.lisp.util.LispAddressStringifier;
41 import org.opendaylight.lispflowmapping.lisp.util.MapServerMapResolverUtil;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.LispProtoService;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.AddMapping;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.MapNotify;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.MapRegister;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.MapReply;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.MapRequest;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.RequestMapping;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.SendMapNotifyInputBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.SendMapReplyInputBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.SendMapRequestInputBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.lispaddress.LispAddressContainer;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.lispaddress.lispaddresscontainer.address.ipv4.Ipv4AddressBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.mapnotifymessage.MapNotifyBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.mapreplymessage.MapReplyBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.maprequestmessage.MapRequestBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.transportaddress.TransportAddress;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.transportaddress.TransportAddressBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150820.MappingserviceService;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150820.MappingOrigin;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150820.db.instance.AuthenticationKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150820.db.instance.Mapping;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
64 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
65 import org.opendaylight.yangtools.yang.binding.Notification;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
69 public class LispMappingService implements IFlowMapping, IFlowMappingShell, BindingAwareProvider,
70 IMapRequestResultHandler, IMapNotifyHandler, AutoCloseable {
71 protected static final Logger LOG = LoggerFactory.getLogger(LispMappingService.class);
73 private static final ConfigIni configIni = new ConfigIni();
74 private AuthenticationKeyDataListener keyListener;
75 private MappingDataListener mappingListener;
76 private ILispDAO lispDao = null;
77 private IMapResolverAsync mapResolver;
78 private IMapServerAsync mapServer;
79 private volatile boolean shouldIterateMask;
80 private volatile boolean shouldAuthenticate;
81 private volatile boolean smr = configIni.smrIsSet();
82 private ThreadLocal<MapReply> tlsMapReply = new ThreadLocal<MapReply>();
83 private ThreadLocal<MapNotify> tlsMapNotify = new ThreadLocal<MapNotify>();
84 private ThreadLocal<Pair<MapRequest, TransportAddress>> tlsMapRequest = new ThreadLocal<Pair<MapRequest, TransportAddress>>();
86 private LispProtoService lispSB = null;
87 private ProviderContext session;
89 private DataStoreBackEnd dsbe;
90 private NotificationService notificationService;
91 private static LispMappingService lfmService = null;
92 private BindingAwareBroker.RpcRegistration<MappingserviceService> lfmDbRpc;
93 private DataBroker dataBrokerService;
94 private RpcProviderRegistry rpcRegistry;
95 private BindingAwareBroker broker;
97 public LispMappingService() {
98 LOG.debug("LispMappingService Module starting!");
102 public void setDataBrokerService(DataBroker dataBrokerService) {
103 this.dataBrokerService = dataBrokerService;
106 public void setRpcProviderRegistry(RpcProviderRegistry rpcRegistry) {
107 this.rpcRegistry = rpcRegistry;
110 public void setBindingAwareBroker(BindingAwareBroker broker) {
111 this.broker = broker;
114 public void initialize() {
115 broker.registerProvider(this);
117 LfmMappingDatabaseRpc mappingDbProviderRpc = new LfmMappingDatabaseRpc(dataBrokerService);
118 lfmDbRpc = rpcRegistry.addRpcImplementation(MappingserviceService.class, mappingDbProviderRpc);
119 dsbe = new DataStoreBackEnd(dataBrokerService);
120 restoreDaoFromDatastore();
124 public void onSessionInitiated(ProviderContext session) {
125 LOG.info("Lisp Consumer session initialized!");
126 notificationService = session.getSALService(NotificationService.class);
127 registerNotificationListener(AddMapping.class, new MapRegisterNotificationHandler());
128 registerNotificationListener(RequestMapping.class, new MapRequestNotificationHandler());
129 registerDataListeners(session.getSALService(DataBroker.class));
130 this.session = session;
131 LOG.info("LISP (RFC6830) Mapping Service init finished");
134 public static LispMappingService getLispMappingService() {
138 public void basicInit(ILispDAO dao) {
140 mapResolver = new MapResolver(dao);
141 mapServer = new MapServer(dao);
144 public void setLispDao(ILispDAO dao) {
145 LOG.trace("LispDAO set in LispMappingService");
149 void unsetLispDao(ILispDAO dao) {
150 LOG.trace("LispDAO was unset in LispMappingService");
156 private void restoreDaoFromDatastore() {
157 List<Mapping> mappings = dsbe.getAllMappings();
158 List<AuthenticationKey> authKeys = dsbe.getAllAuthenticationKeys();
160 LOG.info("Restoring {} mappings and {} keys from datastore into DAO", mappings.size(), authKeys.size());
162 // restore southbound registered entries first ...
163 for (Mapping mapping : mappings) {
164 if (mapping.getOrigin() == MappingOrigin.Southbound) {
165 MapRegister register = MapServerMapResolverUtil.getMapRegister(mapping);
166 handleMapRegister(register, false);
170 // because northbound registrations have priority
171 for (Mapping mapping : mappings) {
172 if (mapping.getOrigin() == MappingOrigin.Northbound) {
173 MapRegister register = MapServerMapResolverUtil.getMapRegister(mapping);
174 handleMapRegister(register, false);
178 for (AuthenticationKey authKey : authKeys) {
179 addAuthenticationKey(authKey.getLispAddressContainer(), authKey.getAuthkey());
183 public void destroy() {
184 LOG.info("LISP (RFC6830) Mapping Service is destroyed!");
187 closeDataListeners();
190 public String printMappings() {
191 final StringBuffer sb = new StringBuffer();
192 sb.append("EID\tRLOCs\n");
193 final IRowVisitor innerVisitor = (new IRowVisitor() {
196 public void visitRow(Object keyId, String valueKey, Object value) {
197 String key = keyId.getClass().getSimpleName() + "#" + keyId;
198 if (!lastKey.equals(key)) {
199 sb.append(key + "\t");
201 if (!(valueKey.equals(SubKeys.LCAF_SRCDST))) {
202 sb.append(valueKey + "=" + value + "\t");
207 lispDao.getAll(new IRowVisitor() {
210 public void visitRow(Object keyId, String valueKey, Object value) {
211 String key = keyId.getClass().getSimpleName() + "#" + keyId;
212 if (!lastKey.equals(key)) {
213 sb.append("\n" + key + "\t");
215 if (valueKey.equals(SubKeys.LCAF_SRCDST)) {
216 sb.append(valueKey + "= { ");
217 ((ILispDAO)value).getAll(innerVisitor);
220 sb.append(valueKey + "=" + value + "\t");
226 return sb.toString();
229 public void addDefaultKeyIPv4() {
230 LispAddressContainer address = LispAFIConvertor.toContainer(
231 new Ipv4AddressBuilder().setIpv4Address(new Ipv4Address("0.0.0.0")).setMask((short)0).build());
232 addAuthenticationKey(address, "password");
235 public MapReply handleMapRequest(MapRequest request) {
236 return handleMapRequest(request, smr);
239 public MapReply handleMapRequest(MapRequest request, boolean smr) {
240 LOG.debug("DAO: Retrieving mapping for {}",
241 LispAddressStringifier.getString(request.getEidRecord().get(0).getLispAddressContainer()));
243 tlsMapReply.set(null);
244 tlsMapRequest.set(null);
245 mapResolver.handleMapRequest(request, smr, this);
246 // After this invocation we assume that the thread local is filled with the reply
247 if (tlsMapRequest.get() != null) {
248 SendMapRequestInputBuilder smrib = new SendMapRequestInputBuilder();
249 new MapRequestBuilder(tlsMapRequest.get().getLeft());
250 smrib.setMapRequest(new MapRequestBuilder(tlsMapRequest.get().getLeft()).build());
251 smrib.setTransportAddress(tlsMapRequest.get().getRight());
252 getLispSB().sendMapRequest(smrib.build());
255 return tlsMapReply.get();
260 public MapNotify handleMapRegister(MapRegister mapRegister) {
261 return handleMapRegister(mapRegister, smr);
264 public MapNotify handleMapRegister(MapRegister mapRegister, boolean smr) {
265 LOG.debug("DAO: Adding mapping for {}",
266 LispAddressStringifier.getString(mapRegister.getEidToLocatorRecord().get(0).getLispAddressContainer()));
268 tlsMapNotify.set(null);
269 mapServer.handleMapRegister(mapRegister, smr, this);
270 // After this invocation we assume that the thread local is filled with the reply
271 return tlsMapNotify.get();
274 public String getAuthenticationKey(LispAddressContainer address) {
275 LOG.debug("DAO: Retrieving authentication key for {}", LispAddressStringifier.getString(address));
276 return mapServer.getAuthenticationKey(address);
279 public void removeAuthenticationKey(LispAddressContainer address) {
280 LOG.debug("DAO: Removing authentication key for {}", LispAddressStringifier.getString(address));
281 mapServer.removeAuthenticationKey(address);
284 public void addAuthenticationKey(LispAddressContainer address, String key) {
285 LOG.debug("DAO: Adding authentication key '{}' for {}", key,
286 LispAddressStringifier.getString(address));
287 mapServer.addAuthenticationKey(address, key);
290 public void removeMapping(LispAddressContainer address) {
291 LOG.debug("DAO: Removing mapping for {}", LispAddressStringifier.getString(address));
292 mapServer.removeMapping(address, smr, this);
295 public boolean shouldIterateMask() {
296 return this.shouldIterateMask;
299 public boolean shouldUseSmr() {
303 public void setShouldUseSmr(boolean smr) {
307 public void setShouldIterateMask(boolean shouldIterateMask) {
308 this.shouldIterateMask = shouldIterateMask;
309 this.mapResolver.setShouldIterateMask(shouldIterateMask);
310 this.mapServer.setShouldIterateMask(shouldIterateMask);
313 public void setShouldAuthenticate(boolean shouldAuthenticate) {
314 this.shouldAuthenticate = shouldAuthenticate;
315 this.mapResolver.setShouldAuthenticate(shouldAuthenticate);
316 this.mapServer.setShouldAuthenticate(shouldAuthenticate);
319 public boolean shouldAuthenticate() {
320 return shouldAuthenticate;
323 private void registerDataListeners(DataBroker broker) {
324 keyListener = new AuthenticationKeyDataListener(broker, this);
325 mappingListener = new MappingDataListener(broker, this);
328 private void closeDataListeners() {
329 keyListener.closeDataChangeListener();
330 mappingListener.closeDataChangeListener();
333 public <T extends Notification> void registerNotificationListener(Class<T> notificationType, NotificationListener<T> listener) {
334 notificationService.registerNotificationListener(notificationType, listener);
337 private class MapRegisterNotificationHandler implements NotificationListener<AddMapping> {
340 public void onNotification(AddMapping mapRegisterNotification) {
341 MapNotify mapNotify = handleMapRegister(mapRegisterNotification.getMapRegister(), smr);
342 if (mapNotify != null) {
343 // store mappings in md-sal datastore only if we have a MapNotify
344 // XXX: this assumes that null MapNotifys are equivalent to authentication/registration errors
345 // however notifies may be disabled with a flag (by the registering router). This should
346 // be solved by moving southbound authentication of registrations out of handleMapRegister().
347 List<Mapping> mappings = LispNotificationHelper.getMapping(mapRegisterNotification);
348 for (Mapping mapping : mappings) {
349 dsbe.updateMapping(mapping);
352 TransportAddressBuilder tab = new TransportAddressBuilder();
353 tab.setIpAddress(mapRegisterNotification.getTransportAddress().getIpAddress());
354 tab.setPort(new PortNumber(LispMessage.PORT_NUM));
355 SendMapNotifyInputBuilder smnib = new SendMapNotifyInputBuilder();
356 smnib.setMapNotify(new MapNotifyBuilder(mapNotify).build());
357 smnib.setTransportAddress(tab.build());
358 getLispSB().sendMapNotify(smnib.build());
360 LOG.warn("got null map notify");
366 private class MapRequestNotificationHandler implements NotificationListener<RequestMapping> {
369 public void onNotification(RequestMapping mapRequestNotification) {
370 MapReply mapReply = handleMapRequest(mapRequestNotification.getMapRequest());
371 if (mapReply != null) {
372 SendMapReplyInputBuilder smrib = new SendMapReplyInputBuilder();
373 smrib.setMapReply((new MapReplyBuilder(mapReply).build()));
374 smrib.setTransportAddress(mapRequestNotification.getTransportAddress());
375 getLispSB().sendMapReply(smrib.build());
377 LOG.warn("got null map reply");
382 private LispProtoService getLispSB() {
383 if (lispSB == null) {
384 lispSB = session.getRpcService(LispProtoService.class);
389 public void handleMapReply(MapReply reply) {
390 tlsMapReply.set(reply);
393 public void handleMapNotify(MapNotify notify) {
394 tlsMapNotify.set(notify);
397 public void handleSMR(MapRequest smr, LispAddressContainer subscriber) {
398 LOG.debug("Sending SMR to {} with Source-EID {} and EID Record {}",
399 LispAddressStringifier.getString(subscriber),
400 LispAddressStringifier.getString(smr.getSourceEid().getLispAddressContainer()),
401 LispAddressStringifier.getString(smr.getEidRecord().get(0).getLispAddressContainer()));
402 SendMapRequestInputBuilder smrib = new SendMapRequestInputBuilder();
403 smrib.setMapRequest(new MapRequestBuilder(smr).build());
404 smrib.setTransportAddress(LispNotificationHelper.getTransportAddressFromContainer(subscriber));
405 getLispSB().sendMapRequest(smrib.build());
410 public void handleNonProxyMapRequest(MapRequest mapRequest, TransportAddress transportAddress) {
411 tlsMapRequest.set(new MutablePair<MapRequest, TransportAddress>(mapRequest, transportAddress));
415 public void clean() {
420 public boolean shouldOverwrite() {
421 return mapServer.shouldOverwrite();
425 public void setOverwrite(boolean overwrite) {
426 mapServer.setOverwrite(overwrite);
430 public void close() throws Exception {