introducing loopback port for VPP
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / policy / ForwardingManager.java
index 6e7ed5a1717898c33c32bcf13679597d77b72b1e..5823d5bc4ef4b6aa8e74fdcce04517590cbd11c3 100644 (file)
@@ -43,10 +43,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererNetworkDomainKey;
 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.groupbasedpolicy.vpp_renderer.rev160425.config.GbpBridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpBridgeDomainKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
+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.InterfaceTypeChoice;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.LoopbackCase;
 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.opendaylight.params.xml.ns.yang.v3po.rev161214.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;
@@ -63,7 +67,7 @@ public final class ForwardingManager {
 
     private static final Logger LOG = LoggerFactory.getLogger(ForwardingManager.class);
     @VisibleForTesting
-    static long WAIT_FOR_BD_CREATION = 10; // seconds
+    private byte WAIT_FOR_BD_PROCESSING = 60; // seconds
     private long lastVxlanVni = 1L;
     private final Map<String, VxlanVni> vxlanVniByBridgeDomain = new HashMap<>();
     private final InterfaceManager ifaceManager;
@@ -75,9 +79,9 @@ public final class ForwardingManager {
         this.dataBroker = Preconditions.checkNotNull(dataBroker);
     }
 
-    public Optional<BridgeDomain> readBridgeDomainConfig(String name) {
-        InstanceIdentifier<BridgeDomain> bdIid = InstanceIdentifier.builder(Config.class)
-            .child(BridgeDomain.class, new BridgeDomainKey(name))
+    public Optional<GbpBridgeDomain> readGbpBridgeDomainConfig(String name) {
+        InstanceIdentifier<GbpBridgeDomain> bdIid = InstanceIdentifier.builder(Config.class)
+            .child(GbpBridgeDomain.class, new GbpBridgeDomainKey(name))
             .build();
         ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
         return DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, bdIid, rTx);
@@ -85,7 +89,7 @@ public final class ForwardingManager {
 
     public void createBridgeDomainOnNodes(SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
         for (String bd : vppNodesByBridgeDomain.keySet()) {
-            Optional<BridgeDomain> bdConfig = readBridgeDomainConfig(bd);
+            Optional<GbpBridgeDomain> bdConfig = readGbpBridgeDomainConfig(bd);
             Set<NodeId> vppNodes = vppNodesByBridgeDomain.get(bd);
             if (bdConfig.isPresent()) {
                 if (bdConfig.get().getType().equals(VlanNetwork.class)) {
@@ -102,52 +106,53 @@ public final class ForwardingManager {
         }
     }
 
-    private void createVxlanBridgeDomains(String bd, VxlanVni vni, Set<NodeId> vppNodes) {
+    private void createVxlanBridgeDomains(final String bd, final VxlanVni vni, final Set<NodeId> vppNodes) {
         for (NodeId vppNode : vppNodes) {
             try {
                 LOG.debug("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,
+                bdManager.createVxlanBridgeDomainOnVppNode(bd, vni, vppNode).get(WAIT_FOR_BD_PROCESSING,
                         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);
+                        + "did not respond by {} seconds. Check VBD log for more details",
+                        bd, vppNode.getValue(), WAIT_FOR_BD_PROCESSING, e);
             }
         }
     }
 
-    private void createVlanBridgeDomains(String bd, VlanId vlanId, Set<NodeId> vppNodes) {
+    private void createVlanBridgeDomains(final String bd, final VlanId vlanId, final Set<NodeId> vppNodes) {
         for (NodeId vppNode : vppNodes) {
             try {
                 LOG.debug("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,
+                bdManager.createVlanBridgeDomainOnVppNode(bd, vlanId, vppNode).get(WAIT_FOR_BD_PROCESSING,
                         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);
+                        + "did not respond by {} seconds. Check VBD log for more details",
+                        bd, vppNode.getValue(), WAIT_FOR_BD_PROCESSING, e);
             }
         }
     }
 
-    public void removeBridgeDomainOnNodes(SetMultimap<String, NodeId> vppNodesByBridgeDomain) {
+    public void removeBridgeDomainOnNodes(final 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(WAIT_FOR_BD_CREATION,
+                    bdManager.removeBridgeDomainFromVppNode(bd, vppNode).get(WAIT_FOR_BD_PROCESSING,
                             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);
+                            + "did not respond by {} seconds. Check VBD log for more details",
+                            bd, vppNode.getValue(), WAIT_FOR_BD_PROCESSING, e);
                 }
             }
         }
@@ -158,7 +163,7 @@ public final class ForwardingManager {
         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);
+            LOG.info("Renderer endpoint does not have external-node-connector therefore it is ignored {}", rEp);
             return;
         }
 
@@ -166,24 +171,43 @@ public final class ForwardingManager {
             java.util.Optional<String> optL2FloodDomain = resolveL2FloodDomain(rEp, policyCtx);
             if (!optL2FloodDomain.isPresent()) {
                 // TODO add it to the status for renderer manager
-                LOG.info("Rednerer endpoint does not have l2FloodDomain as network containment {}", rEp);
+                LOG.info("Renderer endpoint does not have l2FloodDomain as network containment {}", rEp);
                 return;
             }
             String l2FloodDomain = optL2FloodDomain.get();
             try {
-                ifaceManager.addBridgeDomainToInterface(l2FloodDomain, rEp).get();
+                ifaceManager.addBridgeDomainToInterface(l2FloodDomain, rEp, isBviForEndpoint(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);
             }
         } else {
-            LOG.debug("Forwarding is not created - Location of renderer endpoint contains "
+            LOG.warn("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);
         }
     }
 
+    private boolean isBviForEndpoint(AddressEndpointWithLocation rEp) {
+        VppEndpointKey vppEndpointKey =
+            new VppEndpointKey(rEp.getAddress(), rEp.getAddressType(), rEp.getContextId(), rEp.getContextType());
+        ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
+        Optional<VppEndpoint> vppEndpointOptional =
+            DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEndpointKey).build(), rTx);
+        if (vppEndpointOptional.isPresent()) {
+            InterfaceTypeChoice interfaceTypeChoice = vppEndpointOptional.get().getInterfaceTypeChoice();
+            if (interfaceTypeChoice instanceof LoopbackCase) {
+                LOG.trace("Vpp renderer endpoint {} IS a BVI interface.", rEp.getKey());
+                return ((LoopbackCase) interfaceTypeChoice).isBvi();
+            }
+        }
+        rTx.close();
+        LOG.trace("Vpp renderer endpoint {} IS NOT a BVI interface.", rEp.getKey());
+        return false;
+    }
+
     public void removeForwardingForEndpoint(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
         AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
         ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp);
@@ -191,7 +215,6 @@ public final class ForwardingManager {
             // nothing was created for endpoint therefore nothing is removed
             return;
         }
-
         if (!Strings.isNullOrEmpty(rEpLoc.getExternalNode())) {
             try {
                 ifaceManager.deleteBridgeDomainFromInterface(rEp).get();
@@ -201,7 +224,7 @@ public final class ForwardingManager {
                 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 "
+            LOG.warn("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);
         }
@@ -244,7 +267,7 @@ public final class ForwardingManager {
                         .map(RendererForwardingContext::getContextId)
                         .map(ContextId::getValue);
             if (!optL2Fd.isPresent()) {
-                LOG.info("network-domain-containment in endpoint does not have L2-flood-domain as parent. "
+                LOG.warn("network-domain-containment in endpoint does not have L2-flood-domain as parent. "
                         + "This case is not supported in VPP renderer. {}", ep);
             }
             return optL2Fd;
@@ -252,7 +275,7 @@ public final class ForwardingManager {
         return java.util.Optional.empty();
     }
 
-    public static @Nonnull java.util.Optional<RendererForwardingContext> getForwardingCtxForParent(
+    private static @Nonnull java.util.Optional<RendererForwardingContext> getForwardingCtxForParent(
             @Nullable TenantId tenant, @Nullable Parent parent,
             Table<TenantId, RendererForwardingContextKey, RendererForwardingContext> forwardingCtxTable) {
         if (tenant == null || parent == null) {
@@ -265,4 +288,8 @@ public final class ForwardingManager {
         return java.util.Optional.empty();
     }
 
+    @VisibleForTesting
+    void setTimer(byte time) {
+        WAIT_FOR_BD_PROCESSING = time;
+    }
 }