/*
* Copyright (c) 2017 Cisco Systems. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.groupbasedpolicy.renderer.vpp.lisp;
import com.google.common.base.Preconditions;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.lisp.AbstractLispCommand;
import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.lisp.LispCommandWrapper;
import org.opendaylight.groupbasedpolicy.renderer.vpp.config.ConfigUtil;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.exception.LispConfigCommandFailedException;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.exception.LispNotFoundException;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.NeutronTenantToVniMapper;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.ConfigManagerHelper;
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.Lisp;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.dp.subtable.grouping.local.mappings.LocalMapping;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.dp.subtable.grouping.local.mappings.local.mapping.Eid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.eid.table.grouping.eid.table.VniTable;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.lisp.feature.data.grouping.LispFeatureData;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.locator.sets.grouping.locator.sets.LocatorSet;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.map.register.grouping.MapRegister;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.map.resolvers.grouping.map.resolvers.MapResolver;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.map.servers.grouping.map.servers.MapServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
/**
* Created by Shakib Ahmed on 3/29/17.
*/
public class LispStateManager {
private static final Logger LOG = LoggerFactory.getLogger(LispStateManager.class);
private HashMap<String, LispState> lispStateMapper;
private MountedDataBrokerProvider mountedDataBrokerProvider;
private ConfigManagerHelper lispStateHelper;
private NeutronTenantToVniMapper neutronTenantToVniMapper;
private static final short DEFAULT_PRIORITY = 1;
private static final short DEFAULT_WEIGHT = 1;
public static final String DEFAULT_XTR_KEY = "admin";
public static final String DEFAULT_LOCATOR_SET_NAME_PREFIX = "LS";
public static final String DEFAULT_MAPPINGRECORD_NAME_PREFIX = "MR";
public LispStateManager(@Nonnull MountedDataBrokerProvider mountedDataBrokerProvider) {
Preconditions.checkNotNull(mountedDataBrokerProvider,
"MountedDataBrokerProvider found to be null!");
lispStateMapper = new HashMap<>();
this.mountedDataBrokerProvider= mountedDataBrokerProvider;
this.lispStateHelper = new ConfigManagerHelper(this.mountedDataBrokerProvider);
neutronTenantToVniMapper = NeutronTenantToVniMapper.getInstance();
}
public synchronized void configureEndPoint(AddressEndpointWithLocation addressEp) {
try {
DataBroker dataBroker = lispStateHelper.getPotentialExternalDataBroker(addressEp).get();
String hostName = lispStateHelper.getHostName(addressEp).get();
LispState lispStateOfNode = configureHostIfNeeded(hostName, dataBroker);
long vni = getVni(addressEp.getTenant().getValue());
long vrf = vni;
addVniToVrfMappingIfNeeded(dataBroker, lispStateOfNode, vni, vrf);
Eid eid = lispStateHelper.getEid(addressEp, vni);
if(!lispStateOfNode.eidSetContains(eid)) {
addEidInEidTable(dataBroker, lispStateOfNode, eid);
}
} catch (LispConfigCommandFailedException e) {
LOG.warn("Lisp endpoint configuration failed for address endpoint: {}", addressEp);
}
}
public synchronized LispState configureHostIfNeeded(String hostName, DataBroker vppDataBroker) throws LispConfigCommandFailedException {
LispState lispStateOfNode = lispStateMapper.get(hostName);
if (lispStateOfNode == null) {
lispStateOfNode = new LispState(hostName);
try {
enableLispForNode(vppDataBroker, lispStateOfNode);
addLocatorSet(vppDataBroker, lispStateOfNode);
addMapResolver(vppDataBroker, lispStateOfNode);
if (ConfigUtil.getInstance().isLispMapRegisterEnabled()) {
enableMapRegister(vppDataBroker, lispStateOfNode);
addMapServer(vppDataBroker, lispStateOfNode);
}
lispStateMapper.put(hostName, lispStateOfNode);
} catch (LispNotFoundException e) {
LOG.warn("Lisp host configuration failed: ", e.getMessage());
throw new LispConfigCommandFailedException("Failed LISP configuration!");
}
}
return lispStateOfNode;
}
public synchronized void deleteLispConfigurationForEndpoint(AddressEndpointWithLocation addressEp) {
try {
DataBroker vppDataBroker = lispStateHelper.getPotentialExternalDataBroker(addressEp).get();
String hostName = lispStateHelper.getHostName(addressEp).get();
LispState lispState = lispStateMapper.get(hostName);
if (lispState == null) {
LOG.debug("Endpoint not configured for LISP. EndPoint: {}", addressEp);
} else {
long vni = getVni(addressEp.getTenant().getValue());
Eid eid = lispStateHelper.getEid(addressEp, vni);
if (lispState.eidSetContains(eid)) {
deleteEidFromEidTable(vppDataBroker, lispState, eid);
}
if (lispState.eidCount() == 0) {
deleteLispStatesInEndPoints(vppDataBroker, lispState);
}
}
} catch (LispConfigCommandFailedException e) {
LOG.warn("Lisp command execution failed: {}", e.getMessage());
}
}
private void enableLispForNode(DataBroker vppDataBroker, LispState lispState) throws LispConfigCommandFailedException {
AbstractLispCommand<Lisp>
lispEnableCommand = LispCommandWrapper.enableLisp();
if (LispStateCommandExecutor.executePutCommand(vppDataBroker, lispEnableCommand)) {
lispState.setLispEnabled(true);
} else {
throw new LispConfigCommandFailedException("Lisp Enable Command failed execution!");
}
}
private void addLocatorSet(DataBroker vppDataBroker, LispState lispState) throws LispNotFoundException, LispConfigCommandFailedException {
try {
String locatorSetName = lispStateHelper.constructLocatorSetName(lispState.getLocatorCount());
String interfaceName = lispStateHelper.readRlocInterface(lispState.getHostName(), vppDataBroker).get();
AbstractLispCommand<LocatorSet> addLocatorSetCommand = LispCommandWrapper.addLocatorSet(locatorSetName,
interfaceName, DEFAULT_PRIORITY, DEFAULT_WEIGHT);
if (LispStateCommandExecutor.executePutCommand(vppDataBroker, addLocatorSetCommand)) {
lispState.setLocIntfToLocSetNameMapping(interfaceName, locatorSetName);
} else {
throw new LispConfigCommandFailedException("Lisp add locator set failed for host "
+ lispState.getHostName() + " and locator interface " + interfaceName);
}
} catch (InterruptedException | ExecutionException e) {
throw new LispNotFoundException("No interface with Ip Address found!");
}
}
private void addMapResolver(DataBroker vppDataBroker, LispState lispState) throws LispConfigCommandFailedException {
IpAddress mapResolverIpAddress = ConfigUtil.getInstance().getOdlTenantIp();
Preconditions.checkNotNull(mapResolverIpAddress, "Map Resolver ip not properly configured!");
AbstractLispCommand<MapResolver> addMapResolverCommand = LispCommandWrapper.
addMapResolver(mapResolverIpAddress);
if (LispStateCommandExecutor.executePutCommand(vppDataBroker, addMapResolverCommand)) {
lispState.addInMapResolverSet(mapResolverIpAddress);
} else {
throw new LispConfigCommandFailedException("Lisp add map resolver for host " + lispState.getHostName()
+ " failed for ODL ip " + mapResolverIpAddress);
}
}
private void addMapServer(DataBroker vppDataBroker, LispState lispState) throws LispConfigCommandFailedException {
IpAddress mapServerIpAddress = ConfigUtil.getInstance().getOdlTenantIp();
Preconditions.checkNotNull(mapServerIpAddress, "Mapserver ip not properly configured!");
AbstractLispCommand<MapServer> addMapServerCommand = LispCommandWrapper.addMapServer(mapServerIpAddress);
if (LispStateCommandExecutor.executePutCommand(vppDataBroker, addMapServerCommand)) {
lispState.addInMapServerSet(mapServerIpAddress);
} else {
throw new LispConfigCommandFailedException("Lisp add map server for host " + lispState.getHostName()
+ " failed for ODL ip " + mapServerIpAddress);
}
}
private void enableMapRegister(DataBroker vppDataBroker, LispState lispState) throws LispConfigCommandFailedException {
AbstractLispCommand<MapRegister> enableMapRegisterCommand = LispCommandWrapper.enableMapRegister();
if (LispStateCommandExecutor.executePutCommand(vppDataBroker, enableMapRegisterCommand)) {
lispState.setMapRegisteredEnabled(true);
} else {
throw new LispConfigCommandFailedException("Lisp enable mapregistration for host "
+ lispState.getHostName() + " failed!");
}
}
private void addVniToVrfMappingIfNeeded(DataBroker vppDataBroker,
LispState lispState,
long vni, long vrf) throws LispConfigCommandFailedException {
if (!lispState.vniSetContains(vni)) {
AbstractLispCommand<VniTable> addVniToVrfMapping = LispCommandWrapper.mapVniToVrf(vni, vrf);
addVniToVrfMapping.setOptions(General.Operations.PUT);
if (LispStateCommandExecutor.executePutCommand(vppDataBroker, addVniToVrfMapping)) {
lispState.addInVniSet(vni);
} else {
throw new LispConfigCommandFailedException("Lisp add vrf " + vrf +" for vni " +vni
+ " command failed!");
}
}
}
private void addEidInEidTable(DataBroker vppDataBroker,
LispState lispState,
Eid eid) throws LispConfigCommandFailedException {
String mappingId = lispStateHelper.constructMappingName(lispState.eidCount());
AbstractLispCommand<LocalMapping> addLocalMappingInEidTableCommand = LispCommandWrapper
.addLocalMappingInEidTable(mappingId,
eid,
lispStateHelper.getFirstLocatorSetName(lispState),
lispStateHelper.getDefaultHmacKey());
if (LispStateCommandExecutor.executePutCommand(vppDataBroker, addLocalMappingInEidTableCommand)) {
lispState.addInEidSet(eid, mappingId);
} else {
throw new LispConfigCommandFailedException("Lisp add local mapping for eid " + eid + "failed!");
}
}
private void deleteLispStatesInEndPoints(DataBroker vppDataBroker,
LispState lispState) throws LispConfigCommandFailedException {
AbstractLispCommand<LispFeatureData> deleteLispFeatureData = LispCommandWrapper.deleteLispFeatureData();
if (LispStateCommandExecutor.executeDeleteCommand(vppDataBroker, deleteLispFeatureData)) {
String computeNode = lispState.getHostName();
lispStateMapper.remove(computeNode);
} else {
throw new LispConfigCommandFailedException("Lisp delete feature data command failed!");
}
}
private void deleteEidFromEidTable(DataBroker vppDataBroker,
LispState lispState,
Eid eid) throws LispConfigCommandFailedException {
String mappingId = lispState.getEidMapping(eid);
long value = eid.getVirtualNetworkId().getValue();
AbstractLispCommand<LocalMapping> deleteLocalMappingCommand = LispCommandWrapper
.deleteLocalMappingFromEidTable(mappingId, value);
if (LispStateCommandExecutor.executeDeleteCommand(vppDataBroker, deleteLocalMappingCommand)) {
lispState.deleteEid(eid);
} else {
throw new LispConfigCommandFailedException("Lisp delete local mapping command failed!");
}
}
private long getVni(String tenantUuid) {
return neutronTenantToVniMapper.getVni(tenantUuid);
}
}