From: Faseela K Date: Fri, 1 Feb 2019 10:20:51 +0000 (+0530) Subject: L3 handling for COE services. X-Git-Tag: release/sodium~71 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=751dc031275bc2e375ceb04421ba691657e6870c;p=netvirt.git L3 handling for COE services. Current implementation of services is handled via ELAN pipeline, which is not an efficient solution. The proposal here makes each service IP an extraroute on the service-gateway port. Change-Id: I3f8d022124e118cf08eb13ccac19185f81a6736e Signed-off-by: Faseela K --- diff --git a/coe/api/src/main/yang/service-meta.yang b/coe/api/src/main/yang/service-meta.yang new file mode 100644 index 0000000000..83537b9443 --- /dev/null +++ b/coe/api/src/main/yang/service-meta.yang @@ -0,0 +1,34 @@ +module service-meta { + namespace "urn:opendaylight:netvirt:coe:service-meta"; + prefix "coe-service-meta"; + + import ietf-yang-types { + prefix yang; + revision-date "2013-07-15"; + } + + revision "2019-01-23" { + description "Coe Service Meta Information"; + } + + container service-gateway-info { + description "Contains the list of services to poduuid mapping"; + + list service-gateway { + key gateway-pod-name; + leaf gateway-pod-name { + type string; + } + + leaf gateway-pod-ip-address { + type string; + description "ip address of the service gateway"; + } + + leaf gateway-pod-mac-address { + type string; + description "MAC address of the associated port."; + } + } + } +} \ No newline at end of file diff --git a/coe/impl/src/main/java/org/opendaylight/netvirt/coe/listeners/ServiceListener.java b/coe/impl/src/main/java/org/opendaylight/netvirt/coe/listeners/ServiceListener.java index 7f81e93c8f..e9c34d6f87 100644 --- a/coe/impl/src/main/java/org/opendaylight/netvirt/coe/listeners/ServiceListener.java +++ b/coe/impl/src/main/java/org/opendaylight/netvirt/coe/listeners/ServiceListener.java @@ -8,6 +8,8 @@ package org.opendaylight.netvirt.coe.listeners; +import static org.opendaylight.genius.infra.Datastore.CONFIGURATION; + import java.util.Collection; import javax.annotation.Nonnull; import javax.annotation.PreDestroy; @@ -20,6 +22,9 @@ import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.genius.infra.ManagedNewTransactionRunner; +import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl; +import org.opendaylight.netvirt.coe.utils.CoeUtils; import org.opendaylight.yang.gen.v1.urn.opendaylight.coe.northbound.service.rev170611.ServiceInformation; import org.opendaylight.yang.gen.v1.urn.opendaylight.coe.northbound.service.rev170611.service.information.Services; import org.opendaylight.yangtools.concepts.ListenerRegistration; @@ -31,11 +36,17 @@ import org.slf4j.LoggerFactory; public class ServiceListener implements DataTreeChangeListener { private static final Logger LOG = LoggerFactory.getLogger(ServiceListener.class); + + private final CoeUtils coeUtils; + private final ManagedNewTransactionRunner txRunner; + private ListenerRegistration listenerRegistration; @Inject - public ServiceListener(@Reference final DataBroker dataBroker) { + public ServiceListener(@Reference final DataBroker dataBroker, final CoeUtils coeUtils) { registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker); + this.coeUtils = coeUtils; + this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker); } protected InstanceIdentifier getWildCardPath() { @@ -69,6 +80,7 @@ public class ServiceListener implements DataTreeChangeListener { break; case SUBTREE_MODIFIED: LOG.info("Service updated old : {}, new : {}", mod.getDataBefore(), mod.getDataAfter()); + add(mod.getDataAfter()); break; case WRITE: if (mod.getDataBefore() == null) { @@ -76,6 +88,7 @@ public class ServiceListener implements DataTreeChangeListener { } else { LOG.info("Service updated old : {}, new : {}", mod.getDataBefore(), mod.getDataAfter()); } + add(mod.getDataAfter()); break; default: // FIXME: May be not a good idea to throw. @@ -83,4 +96,9 @@ public class ServiceListener implements DataTreeChangeListener { } } } + + void add(Services services) { + txRunner.callWithNewReadWriteTransactionAndSubmit( + CONFIGURATION, tx -> coeUtils.updateVpnInterfaceWithExtraRouteAdjacency(tx, services)); + } } diff --git a/coe/impl/src/main/java/org/opendaylight/netvirt/coe/listeners/TerminationPointStateListener.java b/coe/impl/src/main/java/org/opendaylight/netvirt/coe/listeners/TerminationPointStateListener.java index 3195634516..f48629d95b 100644 --- a/coe/impl/src/main/java/org/opendaylight/netvirt/coe/listeners/TerminationPointStateListener.java +++ b/coe/impl/src/main/java/org/opendaylight/netvirt/coe/listeners/TerminationPointStateListener.java @@ -109,11 +109,15 @@ public class TerminationPointStateListener extends pods.getHostIpAddress().stringValue(), clusterId); coeUtils.updateElanInterfaceWithStaticMac(macAddress, podIpAddress, interfaceName, elanInstanceName, tx); - if (!isServiceGateway) { - coeUtils.createVpnInterface(clusterId, pods, interfaceName, - macAddress,false, tx); - LOG.debug("Bind Kube Proxy Service for {}", interfaceName); - bindKubeProxyService(tx, interfaceName); + coeUtils.createVpnInterface(pods.getClusterId().getValue(), pods, interfaceName, + macAddress,false, tx); + LOG.debug("Bind Kube Proxy Service for {}", interfaceName); + bindKubeProxyService(tx, interfaceName); + if (isServiceGateway) { + String ipValue = podIpAddress.getIpv4Address() != null + ? podIpAddress.getIpv4Address().getValue() : + podIpAddress.getIpv6Address().getValue(); + coeUtils.updateServiceGatewayList(tx, interfaceName, ipValue, macAddress); } } }), LOG, "Error handling pod configuration for termination-point"); diff --git a/coe/impl/src/main/java/org/opendaylight/netvirt/coe/utils/CoeUtils.java b/coe/impl/src/main/java/org/opendaylight/netvirt/coe/utils/CoeUtils.java index 6304cb8163..e00898e395 100644 --- a/coe/impl/src/main/java/org/opendaylight/netvirt/coe/utils/CoeUtils.java +++ b/coe/impl/src/main/java/org/opendaylight/netvirt/coe/utils/CoeUtils.java @@ -8,11 +8,13 @@ package org.opendaylight.netvirt.coe.utils; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableBiMap; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -60,6 +62,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types. import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid; import org.opendaylight.yang.gen.v1.urn.opendaylight.coe.northbound.pod.rev170611.NetworkAttributes; import org.opendaylight.yang.gen.v1.urn.opendaylight.coe.northbound.pod.rev170611.coe.Pods; +import org.opendaylight.yang.gen.v1.urn.opendaylight.coe.northbound.service.rev170611.service.information.Services; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlanBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings; @@ -72,6 +75,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.coe.meta.rev180118. import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.coe.meta.rev180118.podidentifier.info.PodIdentifier; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.coe.meta.rev180118.podidentifier.info.PodIdentifierBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.coe.meta.rev180118.podidentifier.info.PodIdentifierKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.coe.service.meta.rev190123.ServiceGatewayInfo; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.coe.service.meta.rev190123.service.gateway.info.ServiceGateway; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.coe.service.meta.rev190123.service.gateway.info.ServiceGatewayBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.coe.service.meta.rev190123.service.gateway.info.ServiceGatewayKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeBase; @@ -462,21 +469,63 @@ public final class CoeUtils { if (!adjList.contains(vmAdj)) { adjList.add(vmAdj); } - - //if (isRouterInterface) { - // TODO - // create extraroute Adjacence for each ipValue, - // because router can have IPv4 and IPv6 subnet ports, or can have - // more that one IPv4 subnet port or more than one IPv6 subnet port - //List erAdjList = getAdjacencyforExtraRoute(vpnId, routeList, ipValue); - //if (!erAdjList.isEmpty()) { - // adjList.addAll(erAdjList); - //} - //} return new AdjacenciesBuilder().setAdjacency(adjList).build(); } public void unbindKubeProxyService(String interfaceName, TypedWriteTransaction tx) { tx.delete(buildKubeProxyServicesIId(interfaceName)); } + + public void updateServiceGatewayList(TypedWriteTransaction tx, String serviceGatewayPod, + String serviceGatewayIp, String serviceGatewayMac) { + InstanceIdentifier serviceGatewayInstanceIdentifier = + InstanceIdentifier.builder(ServiceGatewayInfo.class).child( + ServiceGateway.class, new ServiceGatewayKey(serviceGatewayPod)).build(); + ServiceGateway serviceGateway = new ServiceGatewayBuilder().setGatewayPodName(serviceGatewayPod) + .setGatewayPodIpAddress(serviceGatewayIp).setGatewayPodMacAddress(serviceGatewayMac).build(); + tx.put(serviceGatewayInstanceIdentifier, serviceGateway); + } + + private InstanceIdentifier buildServiceGatewayInstanceIndentifier() { + return InstanceIdentifier.builder(ServiceGatewayInfo.class).build(); + } + + public void updateVpnInterfaceWithExtraRouteAdjacency(TypedReadWriteTransaction tx, + Services services) throws ExecutionException, + InterruptedException { + if (services.getClusterIpAddress() == null) { + LOG.error("Incorrect input received for extra route. {}", services.getName()); + } else { + LOG.info("update vpn-interface with extra route adjacencies for {}", services.getName()); + Optional serviceGatewayList = tx.read(buildServiceGatewayInstanceIndentifier()).get(); + if (serviceGatewayList.isPresent() && serviceGatewayList.get() != null) { + for (ServiceGateway serviceGateway : serviceGatewayList.get().nonnullServiceGateway()) { + String nextHop = serviceGateway.getGatewayPodIpAddress(); + IpAddress destination = services.getClusterIpAddress(); + String destinationIpValue = destination.getIpv4Address() != null + ? destination.getIpv4Address().getValue() : + destination.getIpv6Address().getValue(); + String destinationIpPrefix = destination.getIpv4Address() != null ? destinationIpValue + "/32" + : destinationIpValue + "/128"; + String infName = serviceGateway.getGatewayPodName(); + if (infName != null) { + LOG.info("Updating extra route for destination {} onto vpn {} with nexthop {} and infName {}", + destination, services.getClusterId(), nextHop, infName); + InstanceIdentifier path = InstanceIdentifier.builder(VpnInterfaces.class) + .child(VpnInterface.class, new VpnInterfaceKey(infName)).build() + .augmentation(Adjacencies.class).child(Adjacency.class, + new AdjacencyKey(destinationIpPrefix)); + Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destinationIpPrefix) + .setNextHopIpList(Collections.singletonList(nextHop)) + .setAdjacencyType(Adjacency.AdjacencyType.ExtraRoute).build(); + tx.put(path, erAdj); + + } else { + LOG.error("Unable to find VPN NextHop interface to apply extra-route destination {} on VPN {} " + + "with nexthop {}", destination, services.getClusterId(), nextHop); + } + } + } + } + } }