Integrated VBD to VPP renderer for VXLAN 22/40222/6
authorMartin Sunal <msunal@cisco.com>
Mon, 13 Jun 2016 09:12:17 +0000 (11:12 +0200)
committerMartin Sunal <msunal@cisco.com>
Tue, 14 Jun 2016 15:05:10 +0000 (17:05 +0200)
VBD with VXLAN tunnels is created when endpoint location
contains external-node-mount-point but there is no such VPP node
in VBD topology(L2FD from network-containment)

Change-Id: Ic557558f9ff4236f0d801b9a63b44dcadb077b26
Signed-off-by: Martin Sunal <msunal@cisco.com>
renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/VppRenderer.java
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/VppEndpointLocationProvider.java
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/ForwardingManager.java [new file with mode: 0644]
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/VppRendererPolicyManager.java
renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/VppRendererPolicyManagerTest.java

index c88149b33db8482218081094164ea32e8a549066..cf90406a2971cf72bf9ff25035f4db9ea62944de 100644 (file)
@@ -23,7 +23,9 @@ import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.RendererPolicyListener;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.VppEndpointListener;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.VppNodeListener;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.BridgeDomainManagerImpl;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.VppNodeManager;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.ForwardingManager;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.VppRendererPolicyManager;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.sf.AllowAction;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.sf.EtherTypeClassifier;
@@ -107,14 +109,16 @@ public class VppRenderer implements AutoCloseable, BindingAwareProvider {
     public void onSessionInitiated(BindingAwareBroker.ProviderContext providerContext) {
         LOG.info("starting vpp renderer");
 
-        MountPointService mountService = Preconditions.checkNotNull(providerContext.getSALService(MountPointService.class));
+        MountPointService mountService =
+                Preconditions.checkNotNull(providerContext.getSALService(MountPointService.class));
         MountedDataBrokerProvider mountDataProvider = new MountedDataBrokerProvider(mountService);
         vppNodeManager = new VppNodeManager(dataBroker, providerContext);
 
         EventBus dtoEventBus = new EventBus("DTO events");
         interfaceManager = new InterfaceManager(mountDataProvider, dataBroker, NETCONF_WORKER);
         dtoEventBus.register(interfaceManager);
-        vppRendererPolicyManager = new VppRendererPolicyManager(interfaceManager, dataBroker);
+        ForwardingManager fwManager = new ForwardingManager(interfaceManager, new BridgeDomainManagerImpl(dataBroker));
+        vppRendererPolicyManager = new VppRendererPolicyManager(fwManager, dataBroker);
         dtoEventBus.register(vppRendererPolicyManager);
 
         vppNodeListener = new VppNodeListener(dataBroker, vppNodeManager, dtoEventBus);
@@ -151,10 +155,10 @@ public class VppRenderer implements AutoCloseable, BindingAwareProvider {
         });
     }
 
-
     private void unregisterFromRendererManager() {
         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
-        writeTransaction.delete(LogicalDatastoreType.OPERATIONAL, VppIidFactory.getRendererIID(new RendererKey(VppRenderer.NAME)));
+        writeTransaction.delete(LogicalDatastoreType.OPERATIONAL,
+                VppIidFactory.getRendererIID(new RendererKey(VppRenderer.NAME)));
 
         CheckedFuture<Void, TransactionCommitFailedException> future = writeTransaction.submit();
         Futures.addCallback(future, new FutureCallback<Void>() {
index d2abc84bfdf0d1e00956c6bba2d96828fdbc8238..52accca62f54dbbee42e5867aa384b2b6f01a242 100644 (file)
@@ -56,7 +56,7 @@ public class VppEndpointLocationProvider implements AutoCloseable {
 
             @Override
             public void onSuccess(Void result) {
-                LOG.trace("{} was created", VPP_ENDPOINT_LOCATION_PROVIDER.getValue());
+                LOG.debug("{} was created", VPP_ENDPOINT_LOCATION_PROVIDER.getValue());
             }
 
             @Override
@@ -79,7 +79,7 @@ public class VppEndpointLocationProvider implements AutoCloseable {
 
             @Override
             public void onSuccess(Void result) {
-                LOG.trace("{} provides location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(),
+                LOG.debug("{} provides location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(),
                         providerAddressEndpointLocation);
             }
 
@@ -113,7 +113,7 @@ public class VppEndpointLocationProvider implements AutoCloseable {
 
             @Override
             public void onSuccess(Void result) {
-                LOG.trace("{} removes location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(), provAddrEpLocKey);
+                LOG.debug("{} removes location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(), provAddrEpLocKey);
             }
 
             @Override
@@ -149,7 +149,7 @@ public class VppEndpointLocationProvider implements AutoCloseable {
 
             @Override
             public void onSuccess(Void result) {
-                LOG.trace("{} merges location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(),
+                LOG.debug("{} merges location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(),
                         providerAddressEndpointLocation);
             }
 
diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/ForwardingManager.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/ForwardingManager.java
new file mode 100644 (file)
index 0000000..6c5ba8f
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. 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.policy;
+
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainment;
+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.ForwardingContextContainment;
+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.L2FloodDomain;
+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.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.SetMultimap;
+
+public class ForwardingManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ForwardingManager.class);
+
+    private final InterfaceManager ifaceManager;
+    private final BridgeDomainManager bdManager;
+
+    public ForwardingManager(@Nonnull InterfaceManager ifaceManager, @Nonnull BridgeDomainManager bdManager) {
+        this.ifaceManager = Preconditions.checkNotNull(ifaceManager);
+        this.bdManager = Preconditions.checkNotNull(bdManager);
+    }
+
+    public void createVxlanBridgeDomainsOnNodes(SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
+        for (String bd : vppNodesByBridgeDomain.keySet()) {
+            Set<NodeId> vppNodes = vppNodesByBridgeDomain.get(bd);
+            for (NodeId vppNode : vppNodes) {
+                try {
+                    bdManager.createVxlanBridgeDomainOnVppNode(bd, null, vppNode).get();
+                } catch (InterruptedException | ExecutionException e) {
+                    LOG.warn("Bridge domain {} was not created on node {}", bd, vppNode.getValue(), e);
+                }
+            }
+        }
+    }
+
+    public void removeVxlanBridgeDomainsOnNodes(SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
+        for (String bd : vppNodesByBridgeDomain.keySet()) {
+            Set<NodeId> vppNodes = vppNodesByBridgeDomain.get(bd);
+            for (NodeId vppNode : vppNodes) {
+                try {
+                    bdManager.removeBridgeDomainFromVppNode(bd, vppNode).get();
+                } catch (InterruptedException | ExecutionException e) {
+                    LOG.warn("Bridge domain {} was not removed from node {}", bd, vppNode.getValue(), e);
+                }
+            }
+        }
+    }
+
+    public void createForwardingForEndpoint(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
+        AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
+        ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
+        if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
+            // TODO add it to the status for renderer manager
+            LOG.info("Rednerer endpoint does not have external-node-connector therefore it is ignored {}", rEp);
+            return;
+        }
+
+        if (Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
+            Optional<String> optL2FloodDomain = resolveL2FloodDomain(rEp.getNetworkContainment());
+            if (!optL2FloodDomain.isPresent()) {
+                // TODO add it to the status for renderer manager
+                LOG.info("Rednerer endpoint does not have l2FloodDomain as network containment {}", rEp);
+                return;
+            }
+            String l2FloodDomain = optL2FloodDomain.get();
+            try {
+                ifaceManager.addBridgeDomainToInterface(l2FloodDomain, rEp).get();
+                LOG.debug("Interface added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp);
+            } catch (InterruptedException | ExecutionException e) {
+                // TODO add it to the status for renderer manager
+                LOG.warn("Interface was not added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp, e);
+            }
+        }
+    }
+
+    public void removeForwardingForEndpoint(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
+        AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
+        ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
+        if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
+            // nothing was created for endpoint therefore nothing is removed
+            return;
+        }
+
+        if (!Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
+            try {
+                ifaceManager.deleteBridgeDomainFromInterface(rEp).get();
+                LOG.debug("bridge-domain was deleted from interface for endpoint {}", rEp);
+            } catch (InterruptedException | ExecutionException e) {
+                // TODO add it to the status for renderer manager
+                LOG.warn("bridge-domain was not deleted from interface for endpoint {}", rEp, e);
+            }
+        }
+    }
+
+    public static ExternalLocationCase resolveAndValidateLocation(AddressEndpointWithLocation addrEpWithLoc) {
+        LocationType locationType = addrEpWithLoc.getAbsoluteLocation().getLocationType();
+        if (!(locationType instanceof ExternalLocationCase)) {
+            throw new IllegalStateException("Endpoint does not have external location " + addrEpWithLoc);
+        }
+        ExternalLocationCase result = (ExternalLocationCase) locationType;
+        if (result.getExternalNodeMountPoint() == null) {
+            throw new IllegalStateException("Endpoint does not have external-node-mount-point " + addrEpWithLoc);
+        }
+        return result;
+    }
+
+    public static Optional<String> resolveL2FloodDomain(@Nullable NetworkContainment netCont) {
+        if (netCont == null) {
+            return Optional.absent();
+        }
+        Containment containment = netCont.getContainment();
+        if (containment instanceof ForwardingContextContainment) {
+            ForwardingContextContainment fwCtxCont = (ForwardingContextContainment) containment;
+            if (fwCtxCont.getContextType().isAssignableFrom(L2FloodDomain.class)) {
+                return fwCtxCont.getContextId() == null ? null : Optional.of(fwCtxCont.getContextId().getValue());
+            }
+        }
+        if (containment instanceof NetworkDomainContainment) {
+            // TODO address missing impl
+            LOG.info("Network domain containment in endpoint is not supported yet. {}", netCont);
+            return Optional.absent();
+        }
+        return Optional.absent();
+    }
+
+}
index 303f83a2d436d109d28da5bc548f57a67af57774..3d21b6224d31ca2cde306c6c4360faae970c801a 100644 (file)
@@ -8,6 +8,13 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.vpp.policy;
 
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 import javax.annotation.Nonnull;
 
 import org.opendaylight.controller.config.yang.config.vpp_provider.impl.VppRenderer;
@@ -16,56 +23,57 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.event.NodeOperEvent;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.event.RendererPolicyConfEvent;
-import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
 import org.opendaylight.groupbasedpolicy.util.IidFactory;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainment;
-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.ForwardingContextContainment;
-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.L2FloodDomain;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicy;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicyBuilder;
-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.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointKey;
+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.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
+import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.MapDifference;
+import com.google.common.collect.MapDifference.ValueDifference;
+import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
 import com.google.common.collect.Sets;
 import com.google.common.collect.Sets.SetView;
 import com.google.common.eventbus.Subscribe;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
 
 public class VppRendererPolicyManager {
 
     private static final Logger LOG = LoggerFactory.getLogger(VppRendererPolicyManager.class);
-    private final InterfaceManager ifaceManager;
     private final DataBroker dataProvider;
+    private ForwardingManager fwManager;
 
-    public VppRendererPolicyManager(@Nonnull InterfaceManager ifaceManager, @Nonnull DataBroker dataProvider) {
-        this.ifaceManager = Preconditions.checkNotNull(ifaceManager);
+    public VppRendererPolicyManager(@Nonnull ForwardingManager fwManager, @Nonnull DataBroker dataProvider) {
+        this.fwManager = Preconditions.checkNotNull(fwManager);
         this.dataProvider = Preconditions.checkNotNull(dataProvider);
     }
 
     @Subscribe
     public void rendererPolicyChanged(RendererPolicyConfEvent event) {
-        RendererPolicyBuilder responseBulder = new RendererPolicyBuilder();
+        RendererPolicyBuilder responseBuilder = new RendererPolicyBuilder();
         switch (event.getDtoModificationType()) {
             case CREATED:
-                responseBulder.setVersion(event.getAfter().get().getVersion());
+                LOG.trace("CREATED : {}", event);
+                responseBuilder.setVersion(event.getAfter().get().getVersion());
                 rendererPolicyCreated(event.getAfter().get());
                 break;
             case UPDATED:
+                LOG.trace("UPDATED: {}", event);
                 RendererPolicy rPolicyBefore = event.getBefore().get();
                 RendererPolicy rPolicyAfter = event.getAfter().get();
-                responseBulder.setVersion(rPolicyAfter.getVersion());
+                responseBuilder.setVersion(rPolicyAfter.getVersion());
                 if (!isConfigurationChanged(rPolicyBefore, rPolicyAfter)) {
                     LOG.debug("Configuration is not changed only updating config version from {} to {}",
                             rPolicyBefore.getVersion(), rPolicyAfter.getVersion());
@@ -75,12 +83,13 @@ public class VppRendererPolicyManager {
                 }
                 break;
             case DELETED:
-                responseBulder.setVersion(event.getBefore().get().getVersion());
+                LOG.trace("DELETED: {}", event);
+                responseBuilder.setVersion(event.getBefore().get().getVersion());
                 rendererPolicyDeleted(event.getBefore().get());
                 break;
         }
         WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
-        RendererPolicy response = responseBulder.build();
+        RendererPolicy response = responseBuilder.build();
         wTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.rendererIid(VppRenderer.NAME).child(RendererPolicy.class),
                 response, true);
         Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
@@ -107,130 +116,109 @@ public class VppRendererPolicyManager {
     private void rendererPolicyUpdated(RendererPolicy rPolicyBefore, RendererPolicy rPolicyAfter) {
         PolicyContext policyCtxBefore = new PolicyContext(rPolicyBefore);
         PolicyContext policyCtxAfter = new PolicyContext(rPolicyAfter);
+
+        MapDifference<String, Collection<NodeId>> vppNodesByL2FlDiff =
+                createDiffForVppNodesByL2Fd(policyCtxBefore, policyCtxAfter);
+        SetMultimap<String, NodeId> removedVppNodesByL2Fd = HashMultimap.create();
+        SetMultimap<String, NodeId> createdVppNodesByL2Fd = HashMultimap.create();
+        for (Entry<String, ValueDifference<Collection<NodeId>>> entry : vppNodesByL2FlDiff.entriesDiffering()
+            .entrySet()) {
+            String bridgeDomain = entry.getKey();
+            Collection<NodeId> beforeNodes = entry.getValue().leftValue();
+            Collection<NodeId> afterNodes = entry.getValue().rightValue();
+            if (beforeNodes != null && afterNodes != null) {
+                SetView<NodeId> removedNodes = Sets.difference(new HashSet<>(beforeNodes), new HashSet<>(afterNodes));
+                removedVppNodesByL2Fd.putAll(bridgeDomain, removedNodes);
+                SetView<NodeId> createdNodes = Sets.difference(new HashSet<>(afterNodes), new HashSet<>(beforeNodes));
+                createdVppNodesByL2Fd.putAll(bridgeDomain, createdNodes);
+            } else if (beforeNodes != null) {
+                removedVppNodesByL2Fd.putAll(bridgeDomain, beforeNodes);
+            } else if (afterNodes != null) {
+                createdVppNodesByL2Fd.putAll(bridgeDomain, afterNodes);
+            }
+        }
+        Map<String, Collection<NodeId>> removedL2Fds = vppNodesByL2FlDiff.entriesOnlyOnLeft();
+        for (Entry<String, Collection<NodeId>> entry : removedL2Fds.entrySet()) {
+            String bridgeDomain = entry.getKey();
+            Collection<NodeId> removedNodes = entry.getValue();
+            if (removedNodes != null) {
+                removedVppNodesByL2Fd.putAll(bridgeDomain, removedNodes);
+            }
+        }
+        Map<String, Collection<NodeId>> createdL2Fds = vppNodesByL2FlDiff.entriesOnlyOnRight();
+        for (Entry<String, Collection<NodeId>> entry : createdL2Fds.entrySet()) {
+            String bridgeDomain = entry.getKey();
+            Collection<NodeId> createdNodes = entry.getValue();
+            if (createdNodes != null) {
+                createdVppNodesByL2Fd.putAll(bridgeDomain, createdNodes);
+            }
+        }
+
         ImmutableSet<RendererEndpointKey> rendEpsBefore = policyCtxBefore.getPolicyTable().rowKeySet();
         ImmutableSet<RendererEndpointKey> rendEpsAfter = policyCtxAfter.getPolicyTable().rowKeySet();
 
         SetView<RendererEndpointKey> removedRendEps = Sets.difference(rendEpsBefore, rendEpsAfter);
-        removedRendEps.forEach(rEpKey -> rendererEndpointDeleted(rEpKey, policyCtxBefore));
+        removedRendEps.forEach(rEpKey -> fwManager.removeForwardingForEndpoint(rEpKey, policyCtxBefore));
+
+        fwManager.removeVxlanBridgeDomainsOnNodes(removedVppNodesByL2Fd);
+        fwManager.createVxlanBridgeDomainsOnNodes(createdVppNodesByL2Fd);
 
         SetView<RendererEndpointKey> createdRendEps = Sets.difference(rendEpsAfter, rendEpsBefore);
-        createdRendEps.forEach(rEpKey -> rendererEndpointCreated(rEpKey, policyCtxAfter));
+        createdRendEps.forEach(rEpKey -> fwManager.createForwardingForEndpoint(rEpKey, policyCtxAfter));
 
         SetView<RendererEndpointKey> updatedRendEps = Sets.intersection(rendEpsBefore, rendEpsAfter);
         // TODO think about all cases, but keep it simple for now
-        updatedRendEps.forEach(rEpKey -> rendererEndpointDeleted(rEpKey, policyCtxBefore));
-        updatedRendEps.forEach(rEpKey -> rendererEndpointCreated(rEpKey, policyCtxAfter));
+        updatedRendEps.forEach(rEpKey -> fwManager.removeForwardingForEndpoint(rEpKey, policyCtxBefore));
+        updatedRendEps.forEach(rEpKey -> fwManager.createForwardingForEndpoint(rEpKey, policyCtxAfter));
+    }
+
+    private static MapDifference<String, Collection<NodeId>> createDiffForVppNodesByL2Fd(PolicyContext policyCtxBefore,
+            PolicyContext policyCtxAfter) {
+        ImmutableSet<RendererEndpointKey> rendEpsBefore = policyCtxBefore.getPolicyTable().rowKeySet();
+        ImmutableSet<RendererEndpointKey> rendEpsAfter = policyCtxAfter.getPolicyTable().rowKeySet();
+        SetMultimap<String, NodeId> vppNodesByL2FdBefore = resolveVppNodesByL2Fd(rendEpsBefore, policyCtxBefore);
+        SetMultimap<String, NodeId> vppNodesByL2FdAfter = resolveVppNodesByL2Fd(rendEpsAfter, policyCtxBefore);
+        return Maps.difference(vppNodesByL2FdBefore.asMap(), vppNodesByL2FdAfter.asMap());
     }
 
     private void rendererPolicyCreated(RendererPolicy rPolicy) {
         PolicyContext policyCtx = new PolicyContext(rPolicy);
+        ImmutableSet<RendererEndpointKey> rEpKeys = policyCtx.getPolicyTable().rowKeySet();
 
-        // TODO create topology for each L2FloodDomain in RendererForwarding
+        SetMultimap<String, NodeId> vppNodesByL2Fd = resolveVppNodesByL2Fd(rEpKeys, policyCtx);
+        fwManager.createVxlanBridgeDomainsOnNodes(vppNodesByL2Fd);
 
-        policyCtx.getPolicyTable().rowKeySet().forEach(rEpKey -> rendererEndpointCreated(rEpKey, policyCtx));
-    }
-
-    private void rendererEndpointCreated(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
-        AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
-        ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
-        if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
-            // TODO add it to the status for renderer manager
-            LOG.info("Rednerer endpoint does not have external-node-connector therefore it is ignored {}", rEp);
-            return;
-        }
-
-        // TODO add rEpLoc.getExternalNodeMountPoint() to VBD as node
-
-        if (Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
-            String l2FloodDomain = resolveL2FloodDomain(rEp.getNetworkContainment());
-            if (Strings.isNullOrEmpty(l2FloodDomain)) {
-                // TODO add it to the status for renderer manager
-                LOG.info("Rednerer endpoint does not have l2FloodDomain as network containment {}", rEp);
-                return;
-            }
-            ListenableFuture<Void> futureAddBridgeDomainToInterface =
-                    ifaceManager.addBridgeDomainToInterface(l2FloodDomain, rEp);
-            Futures.addCallback(futureAddBridgeDomainToInterface, new FutureCallback<Void>() {
-
-                @Override
-                public void onSuccess(Void result) {
-                    LOG.debug("Interface added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp);
-                }
-
-                @Override
-                public void onFailure(Throwable t) {
-                    // TODO add it to the status for renderer manager
-                    LOG.warn("Interface was not added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp, t);
-                }
-            });
-        }
+        rEpKeys.forEach(rEpKey -> fwManager.createForwardingForEndpoint(rEpKey, policyCtx));
     }
 
     private void rendererPolicyDeleted(RendererPolicy rendererPolicy) {
         PolicyContext policyCtx = new PolicyContext(rendererPolicy);
+        ImmutableSet<RendererEndpointKey> rEpKeys = policyCtx.getPolicyTable().rowKeySet();
 
-        // TODO delete topology for each L2FloodDomain in RendererForwarding
+        rEpKeys.forEach(rEpKey -> fwManager.removeForwardingForEndpoint(rEpKey, policyCtx));
 
-        policyCtx.getPolicyTable().rowKeySet().forEach(rEpKey -> rendererEndpointDeleted(rEpKey, policyCtx));
+        SetMultimap<String, NodeId> vppNodesByL2Fd = resolveVppNodesByL2Fd(rEpKeys, policyCtx);
+        fwManager.removeVxlanBridgeDomainsOnNodes(vppNodesByL2Fd);
     }
 
-    private void rendererEndpointDeleted(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
-        AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
-        ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
-        if (Strings.isNullOrEmpty(rEpLoc.getExternalNodeConnector())) {
-            // nothing was created for endpoint therefore nothing is removed
-            return;
-        }
-
-        // TODO remove rEpLoc.getExternalNodeMountPoint() to VBD as node
-
-        if (!Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
-            ListenableFuture<Void> futureAddBridgeDomainToInterface = ifaceManager.deleteBridgeDomainFromInterface(rEp);
-            Futures.addCallback(futureAddBridgeDomainToInterface, new FutureCallback<Void>() {
-
-                @Override
-                public void onSuccess(Void result) {
-                    LOG.debug("bridge-domain was deleted from interface for endpoint {}", rEp);
-                }
-
-                @Override
-                public void onFailure(Throwable t) {
-                    // TODO add it to the status for renderer manager
-                    LOG.warn("bridge-domain was not deleted from interface for endpoint {}", rEp, t);
+    private static SetMultimap<String, NodeId> resolveVppNodesByL2Fd(Set<RendererEndpointKey> rEpKeys,
+            PolicyContext policyCtx) {
+        SetMultimap<String, NodeId> vppNodesByL2Fd = HashMultimap.create();
+        rEpKeys.stream()
+            .map(rEpKey -> KeyFactory.addressEndpointKey(rEpKey))
+            .map(addrEpKey -> policyCtx.getAddrEpByKey().get(addrEpKey))
+            .collect(Collectors.toSet())
+            .forEach(addrEpWithLoc -> {
+                Optional<String> optL2Fd =
+                        ForwardingManager.resolveL2FloodDomain(addrEpWithLoc.getNetworkContainment());
+                if (optL2Fd.isPresent()) {
+                    ExternalLocationCase rEpLoc = ForwardingManager.resolveAndValidateLocation(addrEpWithLoc);
+                    InstanceIdentifier<?> externalNodeMountPoint = rEpLoc.getExternalNodeMountPoint();
+                    NodeId vppNode = externalNodeMountPoint.firstKeyOf(Node.class).getNodeId();
+                    vppNodesByL2Fd.put(optL2Fd.get(), vppNode);
                 }
             });
-        }
-    }
-
-    private static String resolveL2FloodDomain(NetworkContainment netCont) {
-        if (netCont == null) {
-            return null;
-        }
-        Containment containment = netCont.getContainment();
-        if (containment instanceof ForwardingContextContainment) {
-            ForwardingContextContainment fwCtxCont = (ForwardingContextContainment) containment;
-            if (fwCtxCont.getContextType().isAssignableFrom(L2FloodDomain.class)) {
-                return fwCtxCont.getContextId() == null ? null : fwCtxCont.getContextId().getValue();
-            }
-        }
-        if (containment instanceof NetworkDomainContainment) {
-            // TODO address missing impl
-            LOG.info("Network domain containment in endpoint is not supported yet. {}", netCont);
-            return null;
-        }
-        return null;
-    }
-
-    private static ExternalLocationCase resolveAndValidateLocation(AddressEndpointWithLocation addrEpWithLoc) {
-        LocationType locationType = addrEpWithLoc.getAbsoluteLocation().getLocationType();
-        if (!(locationType instanceof ExternalLocationCase)) {
-            throw new IllegalStateException("Endpoint does not have external location " + addrEpWithLoc);
-        }
-        ExternalLocationCase result = (ExternalLocationCase) locationType;
-        if (result.getExternalNodeMountPoint() == null) {
-            throw new IllegalStateException("Endpoint does not have external-node-mount-point " + addrEpWithLoc);
-        }
-        return result;
+        return vppNodesByL2Fd;
     }
 
     @Subscribe
index 25132e5b1842607f9107792a3aae53b1e8ec30a8..9e79c52baa9430fcf7185e0b38f34142fd529925 100644 (file)
@@ -22,11 +22,13 @@ import org.opendaylight.controller.config.yang.config.vpp_provider.impl.VppRende
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.event.RendererPolicyConfEvent;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.event.VppEndpointConfEvent;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.VppEndpointLocationProvider;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.VppPathMapper;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.BridgeDomainManagerImpl;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
 import org.opendaylight.groupbasedpolicy.test.CustomDataBrokerTest;
@@ -77,9 +79,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_render
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.VhostUserCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBased;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev160429.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 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.TopologyId;
@@ -147,13 +152,16 @@ public class VppRendererPolicyManagerTest extends CustomDataBrokerTest {
     private DataBroker mountPointDataBroker;
     private DataBroker dataBroker;
 
+    private BridgeDomainManager bdManager;
     private InterfaceManager ifaceManager;
+    private ForwardingManager fwManager;
     private VppRendererPolicyManager vppRendererPolicyManager;
 
     @Override
     public Collection<Class<?>> getClassesFromModules() {
         return Arrays.asList(Node.class, VppEndpoint.class, Interfaces.class, BridgeDomains.class,
-                LocationProviders.class, L2FloodDomain.class);
+                LocationProviders.class, L2FloodDomain.class, VxlanVni.class, TopologyVbridgeAugment.class,
+                TunnelTypeVxlan.class);
     }
 
     @Before
@@ -165,7 +173,9 @@ public class VppRendererPolicyManagerTest extends CustomDataBrokerTest {
         Mockito.when(mountedDataProviderMock.getDataBrokerForMountPoint(Mockito.any(InstanceIdentifier.class)))
             .thenReturn(Optional.of(mountPointDataBroker));
         ifaceManager = new InterfaceManager(mountedDataProviderMock, dataBroker, MoreExecutors.newDirectExecutorService());
-        vppRendererPolicyManager = new VppRendererPolicyManager(ifaceManager, dataBroker);
+        bdManager = new BridgeDomainManagerImpl(mountPointDataBroker);
+        fwManager = new ForwardingManager(ifaceManager, bdManager);
+        vppRendererPolicyManager = new VppRendererPolicyManager(fwManager, dataBroker);
     }
 
     @Test