HONEYCOMB-204 exclude deleted interfaces from operational data 53/2753/1
authorMaros Marsalek <mmarsale@cisco.com>
Fri, 9 Sep 2016 09:41:03 +0000 (11:41 +0200)
committerMaros Marsalek <mmarsale@cisco.com>
Fri, 9 Sep 2016 11:26:03 +0000 (13:26 +0200)
Change-Id: I187ac52095e15c8c9302871a0d7e7be792e6a0e2
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
13 files changed:
v3po/api/src/main/yang/v3po-context.yang [new file with mode: 0644]
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/DisabledInterfacesManager.java [new file with mode: 0644]
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/InterfacesStateReaderFactory.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/InterfacesWriterFactory.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/V3poModule.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizer.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/DisabledInterfacesManagerTest.java [new file with mode: 0644]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizerTest.java
vpp-common/naming-context-api/src/main/yang/naming-context.yang

diff --git a/v3po/api/src/main/yang/v3po-context.yang b/v3po/api/src/main/yang/v3po-context.yang
new file mode 100644 (file)
index 0000000..ae35be5
--- /dev/null
@@ -0,0 +1,29 @@
+module v3po-context {
+  yang-version 1;
+  namespace "urn:opendaylight:params:xml:ns:yang:v3po:context";
+  prefix "v3po-ctx";
+
+  revision "2016-09-09" {
+    description
+    "Initial revision of v3po specific context";
+  }
+
+  container disabled-interfaces {
+    config false;
+    // context data
+
+    description "Index list of disabled interfaces. VPP does not always delete an interface after deletion. It just
+                 disables it and keeps it there. Honeycomb can hide such interfaces from operational data, and this
+                 is the place to heep track of which interfaces were deleted, but are expected to show up in VPP";
+
+    list disabled-interface-index {
+
+        key "index";
+
+        leaf index {
+            type int32;
+        }
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/DisabledInterfacesManager.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/DisabledInterfacesManager.java
new file mode 100644 (file)
index 0000000..9772923
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.translate.v3po;
+
+import com.google.common.base.Optional;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.honeycomb.translate.util.read.BindingBrokerReader;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.DisabledInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.DisabledInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.disabled.interfaces.DisabledInterfaceIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.disabled.interfaces.DisabledInterfaceIndexBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.disabled.interfaces.DisabledInterfaceIndexKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+/**
+ * Facade on top of {@link MappingContext} making access to {@link DisabledInterfaces} easier.
+ */
+public class DisabledInterfacesManager {
+
+    private static final InstanceIdentifier<DisabledInterfaces>
+            DISABLED_IFCS_ROOT = InstanceIdentifier.create(DisabledInterfaces.class);
+
+    /**
+     * Read the list of currently disabled interfaces.
+     */
+    public List<Integer> getDisabledInterfaces(@Nonnull final MappingContext ctx) {
+        final Optional<DisabledInterfaces> read = ctx.read(DISABLED_IFCS_ROOT);
+        if (read.isPresent()) {
+            return read.get().getDisabledInterfaceIndex().stream()
+                    .map(DisabledInterfaceIndex::getIndex)
+                    .collect(Collectors.toList());
+        } else {
+            return Collections.emptyList();
+        }
+    }
+
+    /**
+     * Check whether a specific interface is disabled.
+     */
+    public boolean isInterfaceDisabled(final int index, @Nonnull final MappingContext ctx) {
+        return ctx.read(getKeyedId(index))
+                .isPresent();
+    }
+
+    /**
+     * Make a specific interface disabled.
+     */
+    public void disableInterface(final int index, @Nonnull final MappingContext ctx) {
+        ctx.put(getKeyedId(index), getDisabledInterfaceIndex(index));
+    }
+
+    /**
+     * Remove interface disability.
+     */
+    public void removeDisabledInterface(final int index, @Nonnull final MappingContext ctx) {
+        ctx.delete(getKeyedId(index));
+    }
+
+    private static DisabledInterfaceIndex getDisabledInterfaceIndex(final int index) {
+        return new DisabledInterfaceIndexBuilder().setIndex(index).build();
+    }
+
+    private static KeyedInstanceIdentifier<DisabledInterfaceIndex, DisabledInterfaceIndexKey> getKeyedId(final int id) {
+        return DISABLED_IFCS_ROOT.child(DisabledInterfaceIndex.class, new DisabledInterfaceIndexKey(id));
+    }
+
+    public static final class ContextsReaderFactory implements ReaderFactory {
+
+        @Inject
+        @Named("honeycomb-context")
+        private DataBroker contextBindingBrokerDependency;
+
+        @Override
+        public void init(final ModifiableReaderRegistryBuilder registry) {
+            registry.add(new BindingBrokerReader<>(DISABLED_IFCS_ROOT,
+                    contextBindingBrokerDependency,
+                    LogicalDatastoreType.OPERATIONAL, DisabledInterfacesBuilder.class));
+        }
+    }
+
+}
index 69ac8f9..ef020e9 100644 (file)
@@ -66,10 +66,11 @@ import org.openvpp.jvpp.core.future.FutureJVppCore;
 
 public final class InterfacesStateReaderFactory implements ReaderFactory {
 
-    private NamingContext ifcCtx;
-    private NamingContext bdCtx;
-    private NamingContext classifyCtx;
-    private FutureJVppCore jvpp;
+    private final NamingContext ifcNamingCtx;
+    private final NamingContext bdNamingCtx;
+    private final NamingContext classifyNamingCtx;
+    private final DisabledInterfacesManager ifcDisableContext;
+    private final FutureJVppCore jvpp;
 
     static final InstanceIdentifier<InterfacesState> IFC_STATE_ID =
             InstanceIdentifier.create(InterfacesState.class);
@@ -77,13 +78,15 @@ public final class InterfacesStateReaderFactory implements ReaderFactory {
 
     @Inject
     public InterfacesStateReaderFactory(final FutureJVppCore jvpp,
-                                        @Named("interface-context") final NamingContext ifcCtx,
-                                        @Named("bridge-domain-context") final NamingContext bdCtx,
-                                        @Named("classify-table-context") final NamingContext classifyCtx) {
+                                        @Named("interface-context") final NamingContext ifcNamingCtx,
+                                        @Named("bridge-domain-context") final NamingContext bdNamingCtx,
+                                        @Named("classify-table-context") final NamingContext classifyNamingCtx,
+                                        final DisabledInterfacesManager ifcDisableContext) {
         this.jvpp = jvpp;
-        this.ifcCtx = ifcCtx;
-        this.bdCtx = bdCtx;
-        this.classifyCtx = classifyCtx;
+        this.ifcNamingCtx = ifcNamingCtx;
+        this.bdNamingCtx = bdNamingCtx;
+        this.classifyNamingCtx = classifyNamingCtx;
+        this.ifcDisableContext = ifcDisableContext;
     }
 
     @Override
@@ -91,14 +94,14 @@ public final class InterfacesStateReaderFactory implements ReaderFactory {
         // InterfacesState(Structural)
         registry.addStructuralReader(IFC_STATE_ID, InterfacesStateBuilder.class);
         //  Interface
-        registry.add(new GenericListReader<>(IFC_ID, new InterfaceCustomizer(jvpp, ifcCtx)));
+        registry.add(new GenericListReader<>(IFC_ID, new InterfaceCustomizer(jvpp, ifcNamingCtx, ifcDisableContext)));
 
         // v3po.yang
         initVppIfcAugmentationReaders(registry, IFC_ID);
         // ietf-ip.yang
         initInterface2AugmentationReaders(registry, IFC_ID);
         // vpp-vlan.yang
-        new SubinterfaceStateAugmentationReaderFactory(jvpp, ifcCtx, bdCtx, classifyCtx).init(registry);
+        new SubinterfaceStateAugmentationReaderFactory(jvpp, ifcNamingCtx, bdNamingCtx, classifyNamingCtx).init(registry);
     }
 
     private void initInterface2AugmentationReaders(final ModifiableReaderRegistryBuilder registry,
@@ -111,13 +114,13 @@ public final class InterfacesStateReaderFactory implements ReaderFactory {
         registry.add(new GenericReader<>(ipv4Id, new Ipv4Customizer(jvpp)));
         //     Address
         final InstanceIdentifier<Address> ipv4AddrId = ipv4Id.child(Address.class);
-        registry.add(new GenericListReader<>(ipv4AddrId, new Ipv4AddressCustomizer(jvpp, ifcCtx)));
+        registry.add(new GenericListReader<>(ipv4AddrId, new Ipv4AddressCustomizer(jvpp, ifcNamingCtx)));
         //     Neighbor
         final InstanceIdentifier<Neighbor> neighborId = ipv4Id.child(Neighbor.class);
         registry.add(new GenericListReader<>(neighborId, new Ipv4NeighbourCustomizer(jvpp)));
         //    Ipv6
         final InstanceIdentifier<Ipv6> ipv6Id = ifc2AugId.child(Ipv6.class);
-        registry.add(new GenericReader<>(ipv6Id, new Ipv6Customizer(jvpp, ifcCtx)));
+        registry.add(new GenericReader<>(ipv6Id, new Ipv6Customizer(jvpp, ifcNamingCtx)));
     }
 
     private void initVppIfcAugmentationReaders(final ModifiableReaderRegistryBuilder registry,
@@ -126,26 +129,27 @@ public final class InterfacesStateReaderFactory implements ReaderFactory {
         final InstanceIdentifier<VppInterfaceStateAugmentation> vppIfcAugId = ifcId.augmentation(VppInterfaceStateAugmentation.class);
         registry.addStructuralReader(vppIfcAugId, VppInterfaceStateAugmentationBuilder.class);
         //    Ethernet
-        registry.add(new GenericReader<>(vppIfcAugId.child(Ethernet.class), new EthernetCustomizer(jvpp, ifcCtx)));
+        registry.add(new GenericReader<>(vppIfcAugId.child(Ethernet.class), new EthernetCustomizer(jvpp, ifcNamingCtx)));
         //    Tap
-        registry.add(new GenericReader<>(vppIfcAugId.child(Tap.class), new TapCustomizer(jvpp, ifcCtx)));
+        registry.add(new GenericReader<>(vppIfcAugId.child(Tap.class), new TapCustomizer(jvpp, ifcNamingCtx)));
         //    VhostUser
-        registry.add(new GenericReader<>(vppIfcAugId.child(VhostUser.class), new VhostUserCustomizer(jvpp, ifcCtx)));
+        registry.add(new GenericReader<>(vppIfcAugId.child(VhostUser.class), new VhostUserCustomizer(jvpp, ifcNamingCtx)));
         //    Vxlan
-        registry.add(new GenericReader<>(vppIfcAugId.child(Vxlan.class), new VxlanCustomizer(jvpp, ifcCtx)));
+        registry.add(new GenericReader<>(vppIfcAugId.child(Vxlan.class), new VxlanCustomizer(jvpp, ifcNamingCtx)));
         //    VxlanGpe
-        registry.add(new GenericReader<>(vppIfcAugId.child(VxlanGpe.class), new VxlanGpeCustomizer(jvpp, ifcCtx)));
+        registry.add(new GenericReader<>(vppIfcAugId.child(VxlanGpe.class), new VxlanGpeCustomizer(jvpp, ifcNamingCtx)));
         //    Gre
-        registry.add(new GenericReader<>(vppIfcAugId.child(Gre.class), new GreCustomizer(jvpp, ifcCtx)));
+        registry.add(new GenericReader<>(vppIfcAugId.child(Gre.class), new GreCustomizer(jvpp, ifcNamingCtx)));
         //    L2
-        registry.add(new GenericReader<>(vppIfcAugId.child(L2.class), new L2Customizer(jvpp, ifcCtx, bdCtx)));
+        registry.add(new GenericReader<>(vppIfcAugId.child(L2.class), new L2Customizer(jvpp, ifcNamingCtx, bdNamingCtx)));
         //    Acl(Subtree)
         final InstanceIdentifier<Acl> aclIdRelative = InstanceIdentifier.create(Acl.class);
         registry.subtreeAdd(
                 Sets.newHashSet(aclIdRelative.child(L2Acl.class), aclIdRelative.child(Ip4Acl.class), aclIdRelative.child(Ip6Acl.class)),
-                new GenericReader<>(vppIfcAugId.child(Acl.class), new AclCustomizer(jvpp, ifcCtx, classifyCtx)));
+                new GenericReader<>(vppIfcAugId.child(Acl.class), new AclCustomizer(jvpp, ifcNamingCtx,
+                        classifyNamingCtx)));
         //   Proxy ARP
         registry.add(new GenericReader<>(vppIfcAugId.child(ProxyArp.class), new ProxyArpCustomizer(jvpp,
-                ifcCtx)));
+                ifcNamingCtx)));
     }
 }
index bfef255..cc68d4d 100644 (file)
@@ -83,34 +83,38 @@ public final class InterfacesWriterFactory implements WriterFactory {
 
     private final FutureJVppCore jvpp;
     private final IetfAClWriter aclWriter;
-    private final NamingContext bdContext;
-    private final NamingContext ifcContext;
-    private final NamingContext classifyTableContext;
+    private final NamingContext bdNamingContext;
+    private final NamingContext ifcNamingContext;
+    private final NamingContext classifyTableNamingContext;
+    private final DisabledInterfacesManager ifcDisableContext;
 
     @Inject
     public InterfacesWriterFactory(final FutureJVppCore vppJvppIfcDependency,
                                    final IetfAClWriter aclWriter,
                                    @Named("bridge-domain-context") final NamingContext bridgeDomainContextDependency,
                                    @Named("interface-context") final NamingContext interfaceContextDependency,
-                                   @Named("classify-table-context") final NamingContext classifyTableContextDependency) {
+                                   @Named("classify-table-context") final NamingContext classifyTableContextDependency,
+                                   final DisabledInterfacesManager ifcDisableContext) {
         this.jvpp = vppJvppIfcDependency;
         this.aclWriter = aclWriter;
-        this.bdContext = bridgeDomainContextDependency;
-        this.ifcContext = interfaceContextDependency;
-        this.classifyTableContext = classifyTableContextDependency;
+        this.bdNamingContext = bridgeDomainContextDependency;
+        this.ifcNamingContext = interfaceContextDependency;
+        this.ifcDisableContext = ifcDisableContext;
+        this.classifyTableNamingContext = classifyTableContextDependency;
     }
 
     @Override
     public void init(final ModifiableWriterRegistryBuilder registry) {
         // Interfaces
         //  Interface =
-        registry.add(new GenericListWriter<>(IFC_ID, new InterfaceCustomizer(jvpp, ifcContext)));
+        registry.add(new GenericListWriter<>(IFC_ID, new InterfaceCustomizer(jvpp, ifcNamingContext)));
         //   VppInterfaceAugmentation
         addVppInterfaceAgmentationWriters(IFC_ID, registry);
         //   Interface1 (ietf-ip augmentation)
         addInterface1AugmentationWriters(IFC_ID, registry);
         //   SubinterfaceAugmentation
-        new SubinterfaceAugmentationWriterFactory(jvpp, aclWriter, ifcContext, bdContext, classifyTableContext).init(registry);
+        new SubinterfaceAugmentationWriterFactory(jvpp, aclWriter, ifcNamingContext, bdNamingContext,
+                classifyTableNamingContext).init(registry);
     }
 
     private void addInterface1AugmentationWriters(final InstanceIdentifier<Interface> ifcId,
@@ -121,14 +125,15 @@ public final class InterfacesWriterFactory implements WriterFactory {
                 ifcId);
         // Ipv4(after interface)
         final InstanceIdentifier<Ipv4> ipv4Id = ifc1AugId.child(Ipv4.class);
-        registry.addAfter(new GenericWriter<>(ipv4Id, new Ipv4Customizer(jvpp, ifcContext)),
+        registry.addAfter(new GenericWriter<>(ipv4Id, new Ipv4Customizer(jvpp, ifcNamingContext)),
                 ifcId);
         //  Address(after Ipv4) =
         final InstanceIdentifier<Address> ipv4AddressId = ipv4Id.child(Address.class);
-        registry.addAfter(new GenericListWriter<>(ipv4AddressId, new Ipv4AddressCustomizer(jvpp, ifcContext)),
+        registry.addAfter(new GenericListWriter<>(ipv4AddressId, new Ipv4AddressCustomizer(jvpp, ifcNamingContext)),
                 ipv4Id);
         //  Neighbor(after ipv4Address)
-        registry.addAfter(new GenericListWriter<>(ipv4Id.child(Neighbor.class), new Ipv4NeighbourCustomizer(jvpp, ifcContext)),
+        registry.addAfter(new GenericListWriter<>(ipv4Id.child(Neighbor.class), new Ipv4NeighbourCustomizer(jvpp,
+                        ifcNamingContext)),
                 ipv4AddressId);
     }
 
@@ -136,24 +141,24 @@ public final class InterfacesWriterFactory implements WriterFactory {
                                                    final ModifiableWriterRegistryBuilder registry) {
         // VhostUser(Needs to be executed before Interface customizer) =
         final InstanceIdentifier<VhostUser> vhostId = VPP_IFC_AUG_ID.child(VhostUser.class);
-        registry.addBefore(new GenericWriter<>(vhostId, new VhostUserCustomizer(jvpp, ifcContext)),
+        registry.addBefore(new GenericWriter<>(vhostId, new VhostUserCustomizer(jvpp, ifcNamingContext)),
                 ifcId);
         // Vxlan(Needs to be executed before Interface customizer) =
         final InstanceIdentifier<Vxlan> vxlanId = VPP_IFC_AUG_ID.child(Vxlan.class);
-        registry.addBefore(new GenericWriter<>(vxlanId, new VxlanCustomizer(jvpp, ifcContext)),
+        registry.addBefore(new GenericWriter<>(vxlanId, new VxlanCustomizer(jvpp, ifcNamingContext, ifcDisableContext)),
                 ifcId);
         // VxlanGpe(Needs to be executed before Interface customizer) =
         final InstanceIdentifier<VxlanGpe> vxlanGpeId = VPP_IFC_AUG_ID.child(VxlanGpe.class);
-        registry.addBefore(new GenericWriter<>(vxlanGpeId, new VxlanGpeCustomizer(jvpp, ifcContext)),
-                ifcId);
+        registry.addBefore(new GenericWriter<>(vxlanGpeId,
+                        new VxlanGpeCustomizer(jvpp, ifcNamingContext, ifcDisableContext)), ifcId);
         // Tap(Needs to be executed before Interface customizer) =
         final InstanceIdentifier<Tap> tapId = VPP_IFC_AUG_ID.child(Tap.class);
-        registry.addBefore(new GenericWriter<>(tapId, new TapCustomizer(jvpp, ifcContext)),
+        registry.addBefore(new GenericWriter<>(tapId, new TapCustomizer(jvpp, ifcNamingContext)),
                 ifcId);
 
         // Gre(Needs to be executed before Interface customizer) =
         final InstanceIdentifier<Gre> greId = VPP_IFC_AUG_ID.child(Gre.class);
-        registry.addBefore(new GenericWriter<>(greId, new GreCustomizer(jvpp, ifcContext)),
+        registry.addBefore(new GenericWriter<>(greId, new GreCustomizer(jvpp, ifcNamingContext)),
                 ifcId);
 
 
@@ -163,14 +168,14 @@ public final class InterfacesWriterFactory implements WriterFactory {
         registry.add(new GenericWriter<>(VPP_IFC_AUG_ID.child(Ethernet.class), new EthernetCustomizer(jvpp)));
         // Routing(Execute only after specific interface customizers) =
         registry.addAfter(
-                new GenericWriter<>(VPP_IFC_AUG_ID.child(Routing.class), new RoutingCustomizer(jvpp, ifcContext)),
+                new GenericWriter<>(VPP_IFC_AUG_ID.child(Routing.class), new RoutingCustomizer(jvpp, ifcNamingContext)),
                 specificIfcTypes);
         // Routing(Execute only after specific interface customizers) =
-        registry.addAfter(new GenericWriter<>(L2_ID, new L2Customizer(jvpp, ifcContext, bdContext)),
+        registry.addAfter(new GenericWriter<>(L2_ID, new L2Customizer(jvpp, ifcNamingContext, bdNamingContext)),
                 specificIfcTypes);
         // Proxy Arp (execute after specific interface customizers)
         registry.addAfter(
-                new GenericWriter<>(VPP_IFC_AUG_ID.child(ProxyArp.class), new ProxyArpCustomizer(jvpp, ifcContext)),
+                new GenericWriter<>(VPP_IFC_AUG_ID.child(ProxyArp.class), new ProxyArpCustomizer(jvpp, ifcNamingContext)),
                 specificIfcTypes);
         // ACL (execute after classify table and session writers)
         // also handles L2Acl, Ip4Acl and Ip6Acl:
@@ -178,7 +183,7 @@ public final class InterfacesWriterFactory implements WriterFactory {
         registry
             .subtreeAddAfter(
                 Sets.newHashSet(aclId.child(L2Acl.class), aclId.child(Ip4Acl.class), aclId.child(Ip6Acl.class)),
-                new GenericWriter<>(ACL_ID, new AclCustomizer(jvpp, ifcContext, classifyTableContext)),
+                new GenericWriter<>(ACL_ID, new AclCustomizer(jvpp, ifcNamingContext, classifyTableNamingContext)),
                 Sets.newHashSet(CLASSIFY_TABLE_ID, CLASSIFY_SESSION_ID));
 
         // IETF-ACL, also handles IetfAcl, AccessLists and Acl:
@@ -188,7 +193,7 @@ public final class InterfacesWriterFactory implements WriterFactory {
             org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.ietf.acl.base.attributes.access.lists.Acl.class);
         registry.subtreeAdd(
             Sets.newHashSet(accessListsID, aclListId),
-            new GenericWriter<>(IETF_ACL_ID, new IetfAclCustomizer(aclWriter, ifcContext)));
+            new GenericWriter<>(IETF_ACL_ID, new IetfAclCustomizer(aclWriter, ifcNamingContext)));
     }
 
 
index 8485519..b0ff0ea 100644 (file)
@@ -58,12 +58,16 @@ public class V3poModule extends AbstractModule {
 
         // Utils
         bind(IetfAClWriter.class).toProvider(IetfAClWriterProvider.class);
+        // Context utility for deleted interfaces
+        bind(DisabledInterfacesManager.class).toInstance(new DisabledInterfacesManager());
 
         // Readers
         final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
         readerFactoryBinder.addBinding().to(InterfacesStateReaderFactory.class);
         readerFactoryBinder.addBinding().to(VppStateHoneycombReaderFactory.class);
         readerFactoryBinder.addBinding().to(VppClassifierReaderFactory.class);
+        // Expose disabled interfaces in operational data
+        readerFactoryBinder.addBinding().to(DisabledInterfacesManager.ContextsReaderFactory.class);
 
         // Writers
         final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
index 294fdad..1513f7b 100644 (file)
@@ -19,11 +19,12 @@ package io.fd.honeycomb.translate.v3po.interfaces;
 import static com.google.common.base.Preconditions.checkArgument;
 
 import com.google.common.net.InetAddresses;
+import io.fd.honeycomb.translate.v3po.DisabledInterfacesManager;
 import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer;
-import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
 import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.WriteFailedException;
 import java.net.InetAddress;
 import java.util.concurrent.CompletionStage;
@@ -44,11 +45,16 @@ import org.slf4j.LoggerFactory;
 public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer<Vxlan> {
 
     private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class);
-    private final NamingContext interfaceContext;
 
-    public VxlanCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) {
+    private final NamingContext interfaceNamingContext;
+    private final DisabledInterfacesManager interfaceDisableContext;
+
+    public VxlanCustomizer(@Nonnull final FutureJVppCore vppApi,
+                           @Nonnull final NamingContext interfaceNamingContext,
+                           @Nonnull final DisabledInterfacesManager interfaceDisableContext) {
         super(vppApi);
-        this.interfaceContext = interfaceContext;
+        this.interfaceNamingContext = interfaceNamingContext;
+        this.interfaceDisableContext = interfaceDisableContext;
     }
 
     @Override
@@ -107,7 +113,7 @@ public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer<Vxlan> {
         final VxlanAddDelTunnelReply reply =
                 TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
         LOG.debug("Vxlan tunnel set successfully for: {}, vxlan: {}", swIfName, vxlan);
-        if(interfaceContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) {
+        if (interfaceNamingContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) {
             // VPP keeps vxlan tunnels present even after they are delete(reserving ID for next tunnel)
             // This may cause inconsistencies in mapping context when configuring tunnels like this:
             // 1. Add tunnel 2. Delete tunnel 3. Read interfaces (reserved mapping e.g. vxlan_tunnel0 -> 6
@@ -115,13 +121,22 @@ public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer<Vxlan> {
             // reserved ID and context is invalid)
             // That's why a check has to be performed here removing mapping vxlan_tunnel0 -> 6 mapping and storing
             // new name for that ID
-            final String formerName = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext());
+            final String formerName = interfaceNamingContext.getName(reply.swIfIndex, writeContext.getMappingContext());
             LOG.debug("Removing updated mapping of a vxlan tunnel, id: {}, former name: {}, new name: {}",
                 reply.swIfIndex, formerName, swIfName);
-            interfaceContext.removeName(formerName, writeContext.getMappingContext());
+            interfaceNamingContext.removeName(formerName, writeContext.getMappingContext());
+
         }
+
+        // Removing disability of an interface in case a vxlan tunnel formerly deleted is being reused in VPP
+        // further details in above comment
+        if (interfaceDisableContext.isInterfaceDisabled(reply.swIfIndex, writeContext.getMappingContext())) {
+            LOG.debug("Removing disability of vxlan tunnel, id: {}, name: {}", reply.swIfIndex, swIfName);
+            interfaceDisableContext.removeDisabledInterface(reply.swIfIndex, writeContext.getMappingContext());
+        }
+
         // Add new interface to our interface context
-        interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+        interfaceNamingContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
     }
 
     private boolean isIpv6(final Vxlan vxlan) {
@@ -156,8 +171,14 @@ public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer<Vxlan> {
 
         TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
         LOG.debug("Vxlan tunnel deleted successfully for: {}, vxlan: {}", swIfName, vxlan);
-        // Remove interface from our interface context
-        interfaceContext.removeName(swIfName, writeContext.getMappingContext());
+
+        final int index = interfaceNamingContext.getIndex(swIfName, writeContext.getMappingContext());
+        // Mark this interface as disabled to not include it in operational reads
+        // because VPP will keep the interface there
+        LOG.debug("Marking vxlan tunnel as disabled, id: {}, name: {}", index, swIfName);
+        interfaceDisableContext.disableInterface(index, writeContext.getMappingContext());
+        // Remove interface from our interface naming context
+        interfaceNamingContext.removeName(swIfName, writeContext.getMappingContext());
     }
 
     private static VxlanAddDelTunnel getVxlanTunnelRequest(final byte isAdd, final byte[] srcAddr, final byte[] dstAddr,
index b97ce12..699c33d 100644 (file)
@@ -19,6 +19,7 @@ package io.fd.honeycomb.translate.v3po.interfaces;
 import static com.google.common.base.Preconditions.checkArgument;
 
 import com.google.common.net.InetAddresses;
+import io.fd.honeycomb.translate.v3po.DisabledInterfacesManager;
 import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
@@ -44,11 +45,15 @@ import org.slf4j.LoggerFactory;
 public class VxlanGpeCustomizer extends AbstractInterfaceTypeCustomizer<VxlanGpe> {
 
     private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class);
-    private final NamingContext interfaceContext;
+    private final NamingContext interfaceNamingContext;
+    private final DisabledInterfacesManager interfaceDisableContext;
 
-    public VxlanGpeCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) {
+    public VxlanGpeCustomizer(@Nonnull final FutureJVppCore vppApi,
+                              @Nonnull final NamingContext interfaceNamingContext,
+                              @Nonnull final DisabledInterfacesManager interfaceDisableContext) {
         super(vppApi);
-        this.interfaceContext = interfaceContext;
+        this.interfaceNamingContext = interfaceNamingContext;
+        this.interfaceDisableContext = interfaceDisableContext;
     }
 
     @Override
@@ -110,24 +115,32 @@ public class VxlanGpeCustomizer extends AbstractInterfaceTypeCustomizer<VxlanGpe
         final VxlanGpeAddDelTunnelReply reply =
                 TranslateUtils.getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
         LOG.debug("VxlanGpe tunnel set successfully for: {}, VxlanGpe: {}", swIfName, vxlanGpe);
-        if(interfaceContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) {
-            final String formerName = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext());
+        if (interfaceNamingContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) {
+            final String formerName = interfaceNamingContext.getName(reply.swIfIndex, writeContext.getMappingContext());
             LOG.debug("Removing updated mapping of a vxlan-gpe tunnel, id: {}, former name: {}, new name: {}",
                 reply.swIfIndex, formerName, swIfName);
-            interfaceContext.removeName(formerName, writeContext.getMappingContext());
+            interfaceNamingContext.removeName(formerName, writeContext.getMappingContext());
         }
+
+        // Removing disability of an interface in case a vxlan-gpe tunnel formerly deleted is being reused in VPP
+        // further details in above comment
+        if (interfaceDisableContext.isInterfaceDisabled(reply.swIfIndex, writeContext.getMappingContext())) {
+            LOG.debug("Removing disability of vxlan tunnel, id: {}, name: {}", reply.swIfIndex, swIfName);
+            interfaceDisableContext.removeDisabledInterface(reply.swIfIndex, writeContext.getMappingContext());
+        }
+
         // Add new interface to our interface context
-        interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+        interfaceNamingContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
     }
 
-    private boolean isIpv6(final VxlanGpe VxlanGpe) {
-        if (VxlanGpe.getLocal().getIpv4Address() == null) {
-            checkArgument(VxlanGpe.getRemote().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s", VxlanGpe.getLocal(),
-                VxlanGpe.getRemote());
+    private boolean isIpv6(final VxlanGpe vxlanGpe) {
+        if (vxlanGpe.getLocal().getIpv4Address() == null) {
+            checkArgument(vxlanGpe.getRemote().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s", vxlanGpe.getLocal(),
+                vxlanGpe.getRemote());
             return true;
         } else {
-            checkArgument(VxlanGpe.getRemote().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s", VxlanGpe.getLocal(),
-                VxlanGpe.getRemote());
+            checkArgument(vxlanGpe.getRemote().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s", vxlanGpe.getLocal(),
+                vxlanGpe.getRemote());
             return false;
         }
     }
@@ -137,26 +150,31 @@ public class VxlanGpeCustomizer extends AbstractInterfaceTypeCustomizer<VxlanGpe
     }
 
     private void deleteVxlanGpeTunnel(final InstanceIdentifier<VxlanGpe> id, final String swIfName,
-                                      final VxlanGpe VxlanGpe, final WriteContext writeContext)
+                                      final VxlanGpe vxlanGpe, final WriteContext writeContext)
         throws VppBaseCallException, WriteTimeoutException {
-        final byte isIpv6 = (byte) (isIpv6(VxlanGpe) ? 1 : 0);
-        final InetAddress local = InetAddresses.forString(getAddressString(VxlanGpe.getLocal()));
-        final InetAddress remote = InetAddresses.forString(getAddressString(VxlanGpe.getRemote()));
+        final byte isIpv6 = (byte) (isIpv6(vxlanGpe) ? 1 : 0);
+        final InetAddress local = InetAddresses.forString(getAddressString(vxlanGpe.getLocal()));
+        final InetAddress remote = InetAddresses.forString(getAddressString(vxlanGpe.getRemote()));
 
-        int vni = VxlanGpe.getVni().getValue().intValue();
-        byte protocol = (byte) VxlanGpe.getNextProtocol().getIntValue();
-        int encapVrfId = VxlanGpe.getEncapVrfId().intValue();
-        int decapVrfId = VxlanGpe.getDecapVrfId().intValue();
+        int vni = vxlanGpe.getVni().getValue().intValue();
+        byte protocol = (byte) vxlanGpe.getNextProtocol().getIntValue();
+        int encapVrfId = vxlanGpe.getEncapVrfId().intValue();
+        int decapVrfId = vxlanGpe.getDecapVrfId().intValue();
 
-        LOG.debug("Deleting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, VxlanGpe);
+        LOG.debug("Deleting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, vxlanGpe);
         final CompletionStage<VxlanGpeAddDelTunnelReply> VxlanGpeAddDelTunnelReplyCompletionStage =
                 getFutureJVpp().vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 0 /* is delete */, local.getAddress(),
                     remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6));
 
         TranslateUtils.getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
-        LOG.debug("VxlanGpe tunnel deleted successfully for: {}, VxlanGpe: {}", swIfName, VxlanGpe);
-        // Remove interface from our interface context
-        interfaceContext.removeName(swIfName, writeContext.getMappingContext());
+
+        final int index = interfaceNamingContext.getIndex(swIfName, writeContext.getMappingContext());
+        // Mark this interface as disabled to not include it in operational reads
+        // because VPP will keep the interface there
+        LOG.debug("Marking vxlan tunnel as disabled, id: {}, name: {}", index, swIfName);
+        interfaceDisableContext.disableInterface(index, writeContext.getMappingContext());
+        // Remove interface from our interface naming context
+        interfaceNamingContext.removeName(swIfName, writeContext.getMappingContext());
     }
 
     private static VxlanGpeAddDelTunnel getVxlanGpeTunnelRequest(final byte isAdd, final byte[] local, final byte[] remote,
index b82a2dd..d0baf00 100644 (file)
 
 package io.fd.honeycomb.translate.v3po.interfacesstate;
 
-import io.fd.honeycomb.translate.read.ReadContext;
-import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.MappingContext;
 import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.read.ReadContext;
 import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.v3po.DisabledInterfacesManager;
 import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
@@ -27,6 +29,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
@@ -57,11 +60,15 @@ public class InterfaceCustomizer extends FutureJVppCustomizer
     public static final String DUMPED_IFCS_CONTEXT_KEY =
         InterfaceCustomizer.class.getName() + "dumpedInterfacesDuringGetAllIds";
 
-    private final NamingContext interfaceContext;
+    private final NamingContext interfaceNamingContext;
+    private final DisabledInterfacesManager interfaceDisableContext;
 
-    public InterfaceCustomizer(@Nonnull final FutureJVppCore jvpp, final NamingContext interfaceContext) {
+    public InterfaceCustomizer(@Nonnull final FutureJVppCore jvpp,
+                               @Nonnull final NamingContext interfaceNamingContext,
+                               @Nonnull final DisabledInterfacesManager interfaceDisableContext) {
         super(jvpp);
-        this.interfaceContext = interfaceContext;
+        this.interfaceNamingContext = interfaceNamingContext;
+        this.interfaceDisableContext = interfaceDisableContext;
     }
 
     @Nonnull
@@ -76,9 +83,17 @@ public class InterfaceCustomizer extends FutureJVppCustomizer
         LOG.debug("Reading attributes for interface: {}", id);
         final String ifaceName = id.firstKeyOf(id.getTargetType()).getName();
 
+        final int index = interfaceNamingContext.getIndex(ifaceName, ctx.getMappingContext());
+
+        // Ignore disabled interface (such as deleted VXLAN tunnels)
+        if (interfaceDisableContext.isInterfaceDisabled(index, ctx.getMappingContext())) {
+            LOG.debug("Skipping disabled interface: {}", id);
+            return;
+        }
+
         // Pass cached details from getAllIds to getDetails to avoid additional dumps
         final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, ifaceName,
-            interfaceContext.getIndex(ifaceName, ctx.getMappingContext()), ctx.getModificationCache());
+                index, ctx.getModificationCache());
         LOG.debug("Interface details for interface: {}, details: {}", ifaceName, iface);
 
         if (!isRegularInterface(iface)) {
@@ -139,23 +154,42 @@ public class InterfaceCustomizer extends FutureJVppCustomizer
             context.getModificationCache().put(DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream()
                 .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails)));
 
-            interfacesKeys = ifaces.swInterfaceDetails.stream()
-                .filter(elt -> elt != null)
-                .map((elt) -> {
-                    // Store interface name from VPP in context if not yet present
-                    if (!interfaceContext.containsName(elt.swIfIndex, context.getMappingContext())) {
-                        interfaceContext.addName(elt.swIfIndex, TranslateUtils.toString(elt.interfaceName),
-                            context.getMappingContext());
-                    }
-                    LOG.trace("Interface with name: {}, VPP name: {} and index: {} found in VPP",
-                        interfaceContext.getName(elt.swIfIndex, context.getMappingContext()), elt.interfaceName,
-                        elt.swIfIndex);
-
-                    return elt;
-                })
-                .filter(InterfaceCustomizer::isRegularInterface) // filter out sub-interfaces
-                .map((elt) -> new InterfaceKey(interfaceContext.getName(elt.swIfIndex, context.getMappingContext())))
-                .collect(Collectors.toList());
+            final MappingContext mappingCtx = context.getMappingContext();
+            final Set<Integer> interfacesIdxs = ifaces.swInterfaceDetails.stream()
+                    .filter(elt -> elt != null)
+                    // Filter out disabled interfaces, dont read them
+                    // This also prevents child readers in being invoked such as vxlan (which relies on disabling interfaces)
+                    .filter(elt -> !interfaceDisableContext
+                            .isInterfaceDisabled(elt.swIfIndex, mappingCtx))
+                    .map((elt) -> {
+                        // Store interface name from VPP in context if not yet present
+                        if (!interfaceNamingContext.containsName(elt.swIfIndex, mappingCtx)) {
+                            interfaceNamingContext.addName(elt.swIfIndex, TranslateUtils.toString(elt.interfaceName),
+                                    mappingCtx);
+                        }
+                        LOG.trace("Interface with name: {}, VPP name: {} and index: {} found in VPP",
+                                interfaceNamingContext.getName(elt.swIfIndex, mappingCtx),
+                                elt.interfaceName,
+                                elt.swIfIndex);
+
+                        return elt;
+                    })
+                    // filter out sub-interfaces
+                    .filter(InterfaceCustomizer::isRegularInterface)
+                    .map(elt -> elt.swIfIndex)
+                    .collect(Collectors.toSet());
+
+            // Clean disabled interfaces list
+            interfaceDisableContext.getDisabledInterfaces(mappingCtx).stream()
+                    // Find indices not currently in VPP
+                    .filter(interfacesIdxs::contains)
+                    // Remove from disabled list ... not disabled if not existing
+                    .forEach(idx -> interfaceDisableContext.removeDisabledInterface(idx, mappingCtx));
+
+            // Transform indices to keys
+            interfacesKeys = interfacesIdxs.stream()
+                    .map(index -> new InterfaceKey(interfaceNamingContext.getName(index, context.getMappingContext())))
+                    .collect(Collectors.toList());
 
             LOG.debug("Interfaces found in VPP: {}", interfacesKeys);
             return interfacesKeys;
@@ -174,5 +208,4 @@ public class InterfaceCustomizer extends FutureJVppCustomizer
                       @Nonnull final List<Interface> readData) {
         ((InterfacesStateBuilder) builder).setInterface(readData);
     }
-
 }
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/DisabledInterfacesManagerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/DisabledInterfacesManagerTest.java
new file mode 100644 (file)
index 0000000..7381533
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.translate.v3po;
+
+import static org.hamcrest.CoreMatchers.hasItems;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.DisabledInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.DisabledInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.disabled.interfaces.DisabledInterfaceIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.disabled.interfaces.DisabledInterfaceIndexBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.disabled.interfaces.DisabledInterfaceIndexKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+public class DisabledInterfacesManagerTest {
+
+    private static final InstanceIdentifier<DisabledInterfaces>
+            ROOT_ID = InstanceIdentifier.create(DisabledInterfaces.class);
+    private static final KeyedInstanceIdentifier<DisabledInterfaceIndex, DisabledInterfaceIndexKey> SPECIFIC_ID_1 =
+            ROOT_ID.child(DisabledInterfaceIndex.class, new DisabledInterfaceIndexKey(1));
+    private static final KeyedInstanceIdentifier<DisabledInterfaceIndex, DisabledInterfaceIndexKey> SPECIFIC_ID_4 =
+            ROOT_ID.child(DisabledInterfaceIndex.class, new DisabledInterfaceIndexKey(4));
+
+    @Mock
+    private MappingContext mappingContext;
+    private DisabledInterfacesManager manager;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        manager = new DisabledInterfacesManager();
+        doReturn(Optional.of(new DisabledInterfacesBuilder().setDisabledInterfaceIndex(toIndices(1, 2, 3)).build()))
+                .when(mappingContext)
+                .read(ROOT_ID);
+        doReturn(Optional.of(toIndex(1)))
+                .when(mappingContext)
+                .read(SPECIFIC_ID_1);
+        doReturn(Optional.absent())
+                .when(mappingContext)
+                .read(SPECIFIC_ID_4);
+    }
+
+    @Test
+    public void testGetAll() throws Exception {
+        final List<Integer> disabledInterfaces = manager.getDisabledInterfaces(mappingContext);
+        assertThat(disabledInterfaces, hasItems(1, 2, 3));
+    }
+
+    @Test
+    public void testCheckOne() throws Exception {
+        assertTrue(manager.isInterfaceDisabled(1, mappingContext));
+        assertFalse(manager.isInterfaceDisabled(4, mappingContext));
+    }
+
+    @Test
+    public void testDisable() throws Exception {
+        manager.disableInterface(1, mappingContext);
+        verify(mappingContext).put(SPECIFIC_ID_1, toIndex(1));
+    }
+
+    @Test
+    public void testRemoveDisability() throws Exception {
+        manager.removeDisabledInterface(1, mappingContext);
+        verify(mappingContext).delete(SPECIFIC_ID_1);
+    }
+
+    private List<DisabledInterfaceIndex> toIndices(final int... indices) {
+        return Arrays.stream(indices)
+                .mapToObj(this::toIndex)
+                .collect(Collectors.toList());
+    }
+
+    private DisabledInterfaceIndex toIndex(final int idx) {
+        return new DisabledInterfaceIndexBuilder()
+                .setIndex(idx)
+                .build();
+    }
+}
\ No newline at end of file
index 40a6b53..0d954de 100644 (file)
@@ -35,11 +35,12 @@ import static org.mockito.MockitoAnnotations.initMocks;
 
 import com.google.common.base.Optional;
 import com.google.common.net.InetAddresses;
-import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.MappingContext;
 import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.v3po.DisabledInterfacesManager;
 import io.fd.honeycomb.translate.v3po.test.TestHelperUtils;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.WriteFailedException;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
@@ -80,6 +81,8 @@ public class VxlanCustomizerTest {
     private WriteContext writeContext;
     @Mock
     private MappingContext mappingContext;
+    @Mock
+    private DisabledInterfacesManager disableContext;
 
     private VxlanCustomizer customizer;
     private String ifaceName;
@@ -96,7 +99,7 @@ public class VxlanCustomizerTest {
         doReturn(toBeReturned).when(writeContext).getModificationCache();
         doReturn(mappingContext).when(writeContext).getMappingContext();
 
-        customizer = new VxlanCustomizer(api, namingContext);
+        customizer = new VxlanCustomizer(api, namingContext, disableContext);
 
         ifaceName = "eth0";
         id = InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(ifaceName))
@@ -174,6 +177,22 @@ public class VxlanCustomizerTest {
         verify(mappingContext).put(eq(getMappingIid(ifaceName, "test-instance")), eq(getMapping(ifaceName, 0).get()));
     }
 
+    @Test
+    public void testWriteCurrentAttributesWithExistingVxlanPlaceholder() throws Exception {
+        final Vxlan vxlan = generateVxlan();
+
+        whenVxlanAddDelTunnelThenSuccess();
+
+        doReturn(Optional.absent())
+            .when(mappingContext).read(getMappingIid(ifaceName, "test-instance").firstIdentifierOf(Mappings.class));
+        doReturn(true).when(disableContext).isInterfaceDisabled(0, mappingContext);
+
+        customizer.writeCurrentAttributes(id, vxlan, writeContext);
+        verifyVxlanAddWasInvoked(vxlan);
+        verify(mappingContext).put(eq(getMappingIid(ifaceName, "test-instance")), eq(getMapping(ifaceName, 0).get()));
+        verify(disableContext).removeDisabledInterface(0, mappingContext);
+    }
+
     @Test
     public void testWriteCurrentAttributesMappingAlreadyPresent() throws Exception {
         final Vxlan vxlan = generateVxlan();
@@ -231,6 +250,7 @@ public class VxlanCustomizerTest {
         customizer.deleteCurrentAttributes(id, vxlan, writeContext);
         verifyVxlanDeleteWasInvoked(vxlan);
         verify(mappingContext).delete(eq(getMappingIid(ifaceName, "test-instance")));
+        verify(disableContext).disableInterface(1, mappingContext);
     }
 
     @Test
index 09e32ff..35dacab 100644 (file)
@@ -34,6 +34,7 @@ import static org.mockito.MockitoAnnotations.initMocks;
 import com.google.common.base.Optional;
 import com.google.common.net.InetAddresses;
 import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.v3po.DisabledInterfacesManager;
 import io.fd.honeycomb.translate.v3po.test.ContextTestUtils;
 import io.fd.honeycomb.translate.v3po.test.TestHelperUtils;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
@@ -80,6 +81,8 @@ public class VxlanGpeCustomizerTest {
     private WriteContext writeContext;
     @Mock
     private MappingContext mappingContext;
+    @Mock
+    private DisabledInterfacesManager interfaceDisableContext;
 
     private VxlanGpeCustomizer customizer;
     private String ifaceName;
@@ -96,7 +99,7 @@ public class VxlanGpeCustomizerTest {
         doReturn(toBeReturned).when(writeContext).getModificationCache();
         doReturn(mappingContext).when(writeContext).getMappingContext();
 
-        customizer = new VxlanGpeCustomizer(api, namingContext);
+        customizer = new VxlanGpeCustomizer(api, namingContext, interfaceDisableContext);
 
         ifaceName = "eth0";
         id = InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(ifaceName))
index a9a2a3c..f64d750 100644 (file)
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.verifyZeroInteractions;
 import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.v3po.DisabledInterfacesManager;
 import io.fd.honeycomb.translate.v3po.test.ContextTestUtils;
 import io.fd.honeycomb.translate.v3po.test.InterfaceTestUtils;
 import io.fd.honeycomb.translate.v3po.test.ListReaderCustomizerTest;
@@ -38,6 +39,7 @@ import java.util.List;
 import org.junit.Assert;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder;
 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
@@ -57,6 +59,8 @@ public class InterfaceCustomizerTest extends
         ListReaderCustomizerTest<Interface, InterfaceKey, InterfaceBuilder> {
 
     private NamingContext interfacesContext;
+    @Mock
+    private DisabledInterfacesManager interfaceDisableContext;
 
     public InterfaceCustomizerTest() {
         super(Interface.class);
@@ -89,7 +93,7 @@ public class InterfaceCustomizerTest extends
         doReturn(eth1).when(mappingContext).read(eth1Id);
         doReturn(subEth1).when(mappingContext).read(subEth1Id);
 
-        return new InterfaceCustomizer(api, interfacesContext);
+        return new InterfaceCustomizer(api, interfacesContext, interfaceDisableContext);
     }
 
     @Test
@@ -208,4 +212,28 @@ public class InterfaceCustomizerTest extends
         // sub-interface should not be on the list
         assertEquals(expectedIds, actualIds);
     }
+
+    @Test
+    public void testGetAllIdsWithDisabled() throws Exception {
+        final InstanceIdentifier<Interface> id = InstanceIdentifier.create(InterfacesState.class)
+            .child(Interface.class);
+
+        doReturn(true).when(interfaceDisableContext).isInterfaceDisabled(1, mappingContext);
+
+        final String swIf0Name = "eth0";
+        final SwInterfaceDetails swIf0 = new SwInterfaceDetails();
+        swIf0.swIfIndex = 0;
+        swIf0.interfaceName = swIf0Name.getBytes();
+        final String swIf1Name = "eth1";
+        final SwInterfaceDetails swIf1 = new SwInterfaceDetails();
+        swIf1.swIfIndex = 1;
+        swIf1.interfaceName = swIf1Name.getBytes();
+        InterfaceTestUtils.whenSwInterfaceDumpThenReturn(api, Arrays.asList(swIf0, swIf1));
+
+        final List<InterfaceKey> expectedIds = Arrays.asList(new InterfaceKey(swIf0Name));
+        final List<InterfaceKey> actualIds = getCustomizer().getAllIds(id, ctx);
+
+        // disabled interface should not be on the list
+        assertEquals(expectedIds, actualIds);
+    }
 }
index fa44bdd..c101b5c 100644 (file)
@@ -12,6 +12,8 @@ module naming-context {
     }
 
     container contexts {
+        config false;
+        // context data
 
         list naming-context {