Fixed bug in update forwarding
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / policy / ForwardingManager.java
index 6c5ba8fccc8ba508e18f89fb85e621303f44c370..d42e47d130da3b8b8634112dca6091a5ee42a5f2 100644 (file)
@@ -8,15 +8,23 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.vpp.policy;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+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.iface.InterfaceManager;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
+import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
 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;
@@ -26,48 +34,112 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpo
 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.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.VlanNetwork;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.BridgeDomainKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.annotations.VisibleForTesting;
 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 {
+public final class ForwardingManager {
 
     private static final Logger LOG = LoggerFactory.getLogger(ForwardingManager.class);
-
+    @VisibleForTesting
+    static long WAIT_FOR_BD_CREATION = 10; // seconds
+    private long lastVxlanVni = 1L;
+    private final Map<String, VxlanVni> vxlanVniByBridgeDomain = new HashMap<>();
     private final InterfaceManager ifaceManager;
     private final BridgeDomainManager bdManager;
-
-    public ForwardingManager(@Nonnull InterfaceManager ifaceManager, @Nonnull BridgeDomainManager bdManager) {
+    private final DataBroker dataBroker;
+    public ForwardingManager(@Nonnull InterfaceManager ifaceManager, @Nonnull BridgeDomainManager bdManager, @Nonnull DataBroker dataBroker) {
         this.ifaceManager = Preconditions.checkNotNull(ifaceManager);
         this.bdManager = Preconditions.checkNotNull(bdManager);
+        this.dataBroker = Preconditions.checkNotNull(dataBroker);
     }
 
-    public void createVxlanBridgeDomainsOnNodes(SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
+    public Optional<BridgeDomain> readBridgeDomainConfig(String name) {
+        InstanceIdentifier<BridgeDomain> bdIid = InstanceIdentifier.builder(Config.class)
+            .child(BridgeDomain.class, new BridgeDomainKey(name))
+            .build();
+        ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
+        return DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, bdIid, rTx);
+    }
+
+    public void createBridgeDomainOnNodes(SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
         for (String bd : vppNodesByBridgeDomain.keySet()) {
+            Optional<BridgeDomain> bdConfig = readBridgeDomainConfig(bd);
             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);
+            if (bdConfig.isPresent()) {
+                if (bdConfig.get().getType().equals(VlanNetwork.class)) {
+                    createVlanBridgeDomains(bd, bdConfig.get().getVlan(), vppNodes);
+                }
+            } else {
+                VxlanVni vxlanVni = vxlanVniByBridgeDomain.get(bd);
+                if (vxlanVni == null) {
+                    vxlanVni = new VxlanVni(lastVxlanVni++);
+                    vxlanVniByBridgeDomain.put(bd, vxlanVni);
                 }
+                createVxlanBridgeDomains(bd, vxlanVni, vppNodes);
+            }
+        }
+    }
+
+    private void createVxlanBridgeDomains(String bd, VxlanVni vni, Set<NodeId> vppNodes) {
+        for (NodeId vppNode : vppNodes) {
+            try {
+                LOG.trace("Creating VXLAN bridge-domain {} on node {} with VNI {}", bd, vppNode.getValue(),
+                        vni);
+                // TODO think about propagating ListenableFuture - timeout set as workaround
+                bdManager.createVxlanBridgeDomainOnVppNode(bd, vni, vppNode).get(WAIT_FOR_BD_CREATION,
+                        TimeUnit.SECONDS);
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.warn("VXLAN Bridge domain {} was not created on node {}", bd, vppNode.getValue(), e);
+            } catch (TimeoutException e) {
+                LOG.warn("Probably, VXLAN Bridge domain {} was not created on node {} because BridgeDomainManager "
+                        + "did not respond by {} seconds.", bd, vppNode.getValue(), WAIT_FOR_BD_CREATION, e);
+            }
+        }
+    }
+
+    private void createVlanBridgeDomains(String bd, VlanId vlanId, Set<NodeId> vppNodes) {
+        for (NodeId vppNode : vppNodes) {
+            try {
+                LOG.trace("Creating VLAN bridge-domain {} on node {} with VLAN ID {}", bd, vppNode.getValue(),
+                        vlanId.getValue());
+                // TODO think about propagating ListenableFuture - timeout set as workaround
+                bdManager.createVlanBridgeDomainOnVppNode(bd, vlanId, vppNode).get(WAIT_FOR_BD_CREATION,
+                        TimeUnit.SECONDS);
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.warn("VLAN Bridge domain {} was not created on node {}", bd, vppNode.getValue(), e);
+            } catch (TimeoutException e) {
+                LOG.warn("Probably, VLAN Bridge domain {} was not created on node {} because BridgeDomainManager "
+                        + "did not respond by {} seconds.", bd, vppNode.getValue(), WAIT_FOR_BD_CREATION, e);
             }
         }
     }
 
-    public void removeVxlanBridgeDomainsOnNodes(SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
+    public void removeBridgeDomainOnNodes(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();
+                    bdManager.removeBridgeDomainFromVppNode(bd, vppNode).get(WAIT_FOR_BD_CREATION,
+                            TimeUnit.SECONDS);
                 } catch (InterruptedException | ExecutionException e) {
                     LOG.warn("Bridge domain {} was not removed from node {}", bd, vppNode.getValue(), e);
+                } catch (TimeoutException e) {
+                    LOG.warn("Probably, bridge domain {} was not removed from node {} because BridgeDomainManager "
+                            + "did not respond by {} seconds.", bd, vppNode.getValue(), WAIT_FOR_BD_CREATION, e);
                 }
             }
         }
@@ -97,6 +169,10 @@ public class ForwardingManager {
                 // TODO add it to the status for renderer manager
                 LOG.warn("Interface was not added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp, e);
             }
+        } else {
+            LOG.debug("Forwarding is not created - Location of renderer endpoint contains "
+                    + "external-node therefore VPP renderer assumes that interface for endpoint is "
+                    + "already assigned in bridge-domain representing external-node. {}", rEp);
         }
     }
 
@@ -116,6 +192,10 @@ public class ForwardingManager {
                 // TODO add it to the status for renderer manager
                 LOG.warn("bridge-domain was not deleted from interface for endpoint {}", rEp, e);
             }
+        } else {
+            LOG.debug("Forwarding is not removed - Location of renderer endpoint does not contain "
+                    + "external-node therefore VPP renderer assumes that interface for endpoint is not "
+                    + "assigned to bridge-domain representing external-node. {}", rEp);
         }
     }