/*
* 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.util;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.VppPathMapper;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.LispState;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.LispStateManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.exception.LispNotFoundException;
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.LispUtil;
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.Ipv4Afi;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.Containment;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.NetworkDomainContainment;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.LocationType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.IpPrefixType;
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.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.HmacKeyType;
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.hmac.key.grouping.HmacKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170315.interfaces._interface.Routing;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170315.interfaces._interface.RoutingBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Created by Shakib Ahmed on 3/31/17.
*/
public class ConfigManagerHelper {
private static final Logger LOG = LoggerFactory.getLogger(ConfigManagerHelper.class);
private static final String TENANT_INTERFACE = "tenant-interface";
private MountedDataBrokerProvider mountedDataBrokerProvider;
public ConfigManagerHelper(MountedDataBrokerProvider mountedDataBrokerProvider) {
this.mountedDataBrokerProvider = mountedDataBrokerProvider;
}
public Optional<DataBroker> getPotentialExternalDataBroker(AddressEndpointWithLocation addressEpWithLoc) {
ExternalLocationCase externalLocationCase = resolveAndValidateLocation(addressEpWithLoc);
InstanceIdentifier<?> vppNodeIid = externalLocationCase.getExternalNodeMountPoint();
String interfacePath = externalLocationCase.getExternalNodeConnector();
Optional<DataBroker> potentialVppDataProvider = mountedDataBrokerProvider.getDataBrokerForMountPoint(vppNodeIid);
Preconditions.checkArgument(potentialVppDataProvider.isPresent(),
"Cannot resolve data broker for interface path: {}", interfacePath);
return potentialVppDataProvider;
}
public Optional<DataBroker> getPotentialExternalDataBroker(VppEndpoint vppEp) {
InstanceIdentifier<Node> vppNodeIid = VppIidFactory.getNetconfNodeIid(vppEp.getVppNodeId());
Optional<DataBroker> potentialVppDataProvider =
mountedDataBrokerProvider.getDataBrokerForMountPoint(vppNodeIid);
Preconditions.checkArgument(potentialVppDataProvider.isPresent(),
"Cannot resolve data broker for Vpp Endpoint: {}", vppEp);
return potentialVppDataProvider;
}
public Optional<DataBroker> getPotentialExternalDataBroker(String hostId) {
InstanceIdentifier<Node> nodeIid = VppIidFactory.getNetconfNodeIid(new NodeId(hostId));
Optional<DataBroker> potentialVppDataProvider = mountedDataBrokerProvider.getDataBrokerForMountPoint(nodeIid);
Preconditions.checkArgument(potentialVppDataProvider.isPresent(),
"Data Broker not found for {}", hostId);
return potentialVppDataProvider;
}
public Optional<String> getHostName(AddressEndpointWithLocation addrEp) {
ExternalLocationCase locationCase = resolveAndValidateLocation(addrEp);
NodeKey nodeKey = locationCase.getExternalNodeMountPoint().firstKeyOf(Node.class);
String hostId = Preconditions.checkNotNull(nodeKey.getNodeId().getValue(),
"Host Id extraction failed from address endpoint: {}", addrEp);
return Optional.fromNullable(hostId);
}
public ExternalLocationCase resolveAndValidateLocation(AddressEndpointWithLocation addrEpWithLoc) {
LocationType locationType = addrEpWithLoc.getAbsoluteLocation().getLocationType();
if (!(locationType instanceof ExternalLocationCase)) {
throw new IllegalArgumentException("Endpoint does not have external location " + addrEpWithLoc);
}
ExternalLocationCase result = (ExternalLocationCase) locationType;
if (result.getExternalNodeMountPoint() == null || result.getExternalNodeConnector() == null) {
throw new IllegalArgumentException(
"Endpoint does not have external-node-mount-point or external-node-connector " + addrEpWithLoc);
}
return result;
}
//This is almost identical to VBD's equivalent method
public ListenableFuture<String> readRlocInterface(@Nonnull String hostName, @Nonnull DataBroker vppDataBroker) {
Preconditions.checkNotNull(hostName, "Hostname is null!");
Preconditions.checkNotNull(vppDataBroker, "Vpp DataBroker is null!");
final Optional<InterfacesState> opInterfaceState = GbpNetconfTransaction.read(vppDataBroker,
LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(InterfacesState.class),
GbpNetconfTransaction.RETRY_COUNT);
if (!opInterfaceState.isPresent()) {
LOG.debug("There appear to be no interfaces on node {}.", hostName);
return Futures.immediateFailedFuture(new LispNotFoundException("No interfaces found"));
}
String interfaceName = null;
for(Interface intf: opInterfaceState.get().getInterface()) {
if(!ipAddressPresent(intf)) {
continue;
}
interfaceName = intf.getName();
}
final Optional<Interfaces> opInterfaces =
GbpNetconfTransaction.read(vppDataBroker, LogicalDatastoreType.CONFIGURATION,
InstanceIdentifier.create(Interfaces.class), GbpNetconfTransaction.RETRY_COUNT);
if (opInterfaces.isPresent()) {
for (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.
interfaces.Interface intf : opInterfaces.get().getInterface()) {
if (TENANT_INTERFACE.equals(intf.getDescription())
&& ipAddressPresent(intf)
&& intf.getType().equals(EthernetCsmacd.class)) {
return Futures.immediateFuture(intf.getName());
}
}
}
if (interfaceName == null) {
LOG.warn("No interface with IP found for host {}", hostName);
return Futures.immediateFailedFuture(new LispNotFoundException("No interface with Ip address found!"));
}
return Futures.immediateFuture(interfaceName);
}
private boolean ipAddressPresent(Interface intf) {
Interface2 augIntf = intf.getAugmentation(Interface2.class);
if (augIntf == null) {
return false;
}
Ipv4 ipv4 = augIntf.getIpv4();
if (ipv4 == null) {
return false;
}
final List<Address> addresses = ipv4.getAddress();
if (addresses == null || addresses.isEmpty()) {
return false;
}
final Ipv4AddressNoZone ip = addresses.iterator().next().getIp();
if (ip == null) {
return false;
}
return true;
}
private boolean ipAddressPresent(final org.opendaylight.yang.gen.v1.urn.ietf.
params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface intf) {
final Interface1 augIntf = intf.getAugmentation(Interface1.class);
if (augIntf == null) {
LOG.debug("Cannot get Interface1 augmentation for intf {}", intf);
return false;
}
final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4 ipv4 =
augIntf.getIpv4();
if (ipv4 == null) {
return false;
}
final List<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address> addresses =
ipv4.getAddress();
if (addresses == null || addresses.isEmpty()) {
return false;
}
final Ipv4AddressNoZone ip = addresses.iterator().next().getIp();
if (ip == null) {
return false;
}
return true;
}
public String constructLocatorSetName(int locatorSetCount) {
return LispStateManager.DEFAULT_LOCATOR_SET_NAME_PREFIX + (locatorSetCount + 1);
}
public String constructMappingName(int presentMappingCount) {
return LispStateManager.DEFAULT_MAPPINGRECORD_NAME_PREFIX + (presentMappingCount + 1);
}
public String getSubnet(AddressEndpointWithLocation addressEp) {
String subnetUuid = null;
Containment containment = addressEp.getNetworkContainment().getContainment();
if (containment instanceof NetworkDomainContainment) {
NetworkDomainContainment networkDomainContainment = (NetworkDomainContainment) containment;
subnetUuid = networkDomainContainment.getNetworkDomainId().getValue();
}
return subnetUuid;
}
public Eid getEid(AddressEndpointWithLocation addressEp, long vni) {
String ipPrefix = getIpWithPrefixOfEndpoint(addressEp);
return LispUtil.toEid(LispUtil.toIpv4(ipPrefix), vni, Ipv4Afi.class);
}
public String getIpWithPrefixOfEndpoint(AddressEndpointWithLocation addressEp) {
String ipPrefix = null;
if (addressEp.getAddressType().equals(IpPrefixType.class)) {
ipPrefix = addressEp.getAddress();
}
return Preconditions.checkNotNull(ipPrefix,
"No IP address found for Address Endpoint: {}", addressEp);
}
public Ipv4Address getInterfaceIp(AddressEndpointWithLocation addressEp) {
String ipPrefix = getIpWithPrefixOfEndpoint(addressEp);
return LispUtil.toIpv4(ipPrefix).getIpv4();
}
public Ipv4Prefix getInterfaceIpAsPrefix(AddressEndpointWithLocation addressEp) {
return new Ipv4Prefix(getInterfaceIp(addressEp).getValue() + "/32");
}
public String getFirstLocatorSetName(LispState lispState) {
Set<Map.Entry<String, String >> locatorSet = lispState.getLocatorSetEntry();
Preconditions.checkNotNull(locatorSet, "No locator set found!");
if (!locatorSet.iterator().hasNext()) {
return null;
}
return locatorSet.iterator().next().getValue();
}
public HmacKey getDefaultHmacKey() {
return LispUtil.toHmacKey(HmacKeyType.Sha196Key, LispStateManager.DEFAULT_XTR_KEY);
}
public Routing getRouting(long vrf) {
return new RoutingBuilder().setIpv4VrfId(vrf).build();
}
}