HONEYCOMB-118: extend classifer model to support node names. 29/2029/4
authorMarek Gradzki <mgradzki@cisco.com>
Wed, 20 Jul 2016 07:48:14 +0000 (09:48 +0200)
committerMaros Marsalek <mmarsale@cisco.com>
Tue, 13 Sep 2016 10:52:08 +0000 (10:52 +0000)
* configuration write is supported (updates local cache
  with relative node mapping)
* operational read is supported only for nodes with existing
  relative node mapping
* ACL support (using vpp-classfier or ietf-acl model)
  is not affected by the patch (tables/sessions for access controll
  refer to neighbour nodes as packet-handling-action, not vpp-node-name)

Change-Id: Ice0c846803cc7e8960c3571fd2a13ed46ba53702
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
31 files changed:
v3po/api/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/vpp/classifier/rev150603/VppNodeBuilder.java
v3po/api/src/main/yang/vpp-classifier-context.yang [new file with mode: 0644]
v3po/api/src/main/yang/vpp-classifier.yang
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/SubinterfaceAugmentationWriterFactory.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/SubinterfaceStateAugmentationReaderFactory.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/V3poModule.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/VppClassifierHoneycombWriterFactory.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/VppClassifierReaderFactory.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclWriter.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclReader.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReader.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriter.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReader.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriter.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppClassifierContextManager.java [new file with mode: 0644]
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppClassifierContextManagerImpl.java [new file with mode: 0644]
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeReader.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeWriter.java [new file with mode: 0644]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReaderTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriterTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReaderTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriterTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppClassifierContextManagerImplTest.java [new file with mode: 0644]

index dd37bbe..4ae04d4 100644 (file)
@@ -18,7 +18,7 @@ public class VppNodeBuilder {
         } else if (PacketHandlingAction.Permit.toString().equalsIgnoreCase(defaultValue)) {
             return new VppNode(PacketHandlingAction.Permit);
         } else {
-            throw new IllegalArgumentException(String.format("Could not parse VppNode: %s", defaultValue));
+            return new VppNode(new VppNodeName(defaultValue));
         }
     }
 
diff --git a/v3po/api/src/main/yang/vpp-classifier-context.yang b/v3po/api/src/main/yang/vpp-classifier-context.yang
new file mode 100644 (file)
index 0000000..01eae86
--- /dev/null
@@ -0,0 +1,68 @@
+module vpp-classifier-context {
+  yang-version 1;
+  namespace "urn:opendaylight:params:xml:ns:yang:vpp:classifier";
+  prefix "vpp-classifier-context";
+
+  description
+    "This module contains vpp classfier metadata definition";
+
+  revision "2016-09-09" {
+    description
+      "Initial revision.";
+  }
+
+  container vpp-classifier-context {
+
+    config "false";
+
+    description
+      "Classify tables and sessions contain relative node indexes. Management agent like Honeycomb,
+       needs to use node names instead (indexes might change after vpp restart).
+       VPP does not provide relative index to node name conversion (https://jira.fd.io/browse/VPP-219),
+       also finding base node that is needed to perform the conversion
+       is not allways possible (https://jira.fd.io/browse/VPP-220).
+
+       Therefore Honeycomb needs to provide relative node to index mapping.
+       ";
+
+    list classify-table-context {
+      key "name";
+      unique "index";
+
+      leaf name {
+        type string;
+        description
+          "Name of the classify table.";
+      }
+
+      leaf index {
+        type int32;
+        description
+          "Classify table index used by VPP.";
+      }
+
+      leaf classifier-node-name {
+        type string;
+        description
+          "Name of VPP node the table is defined for.";
+      }
+
+      list node-context {
+        key "name";
+        unique "index";
+
+        leaf name {
+          type string;
+          description
+            "Name of vpp node (neighbour of classifier-node-name)";
+        }
+
+        leaf index {
+          type int32;
+          description
+            "Inted of the vpp node relative to classifier-node-name";
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
index 46bff20..8bf9399 100644 (file)
@@ -38,14 +38,18 @@ module vpp-classifier {
     }
   }
 
+  typedef vpp-node-name {
+    type string;
+  }
+
   typedef vpp-node {
     type union {
-      // FIXME: enable after VPP-203 is fixed
-      // type string; // name of vpp-node neighbour, TODO: base node also needs to be defined
       type packet-handling-action;
+      type vpp-node-name;
     }
     description
-      "Defines VPP node reference using relative node name or packet handling action.";
+      "Defines VPP node reference using packet handling action or relative node name
+       (if definition in terms of packet handling action is not possible).";
   }
 
   typedef opaque-index {
@@ -85,6 +89,11 @@ module vpp-classifier {
     description
       "Defines classify table attributes that are mapped to classify_add_del_table message parameters.";
 
+    leaf classifier-node {
+      type vpp-node-name;
+      description
+        "Name of VPP node the table is defined for.";
+    }
     leaf nbuckets {
       mandatory true;
       type uint32;
index ef020e9..50ba2e5 100644 (file)
@@ -38,6 +38,7 @@ import io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4Customizer;
 import io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4NeighbourCustomizer;
 import io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv6Customizer;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
@@ -68,7 +69,7 @@ public final class InterfacesStateReaderFactory implements ReaderFactory {
 
     private final NamingContext ifcNamingCtx;
     private final NamingContext bdNamingCtx;
-    private final NamingContext classifyNamingCtx;
+    private final VppClassifierContextManager classifyContext;
     private final DisabledInterfacesManager ifcDisableContext;
     private final FutureJVppCore jvpp;
 
@@ -80,12 +81,12 @@ public final class InterfacesStateReaderFactory implements ReaderFactory {
     public InterfacesStateReaderFactory(final FutureJVppCore jvpp,
                                         @Named("interface-context") final NamingContext ifcNamingCtx,
                                         @Named("bridge-domain-context") final NamingContext bdNamingCtx,
-                                        @Named("classify-table-context") final NamingContext classifyNamingCtx,
+                                        @Named("classify-table-context") final VppClassifierContextManager classifyContext,
                                         final DisabledInterfacesManager ifcDisableContext) {
         this.jvpp = jvpp;
         this.ifcNamingCtx = ifcNamingCtx;
         this.bdNamingCtx = bdNamingCtx;
-        this.classifyNamingCtx = classifyNamingCtx;
+        this.classifyContext = classifyContext;
         this.ifcDisableContext = ifcDisableContext;
     }
 
@@ -101,7 +102,7 @@ public final class InterfacesStateReaderFactory implements ReaderFactory {
         // ietf-ip.yang
         initInterface2AugmentationReaders(registry, IFC_ID);
         // vpp-vlan.yang
-        new SubinterfaceStateAugmentationReaderFactory(jvpp, ifcNamingCtx, bdNamingCtx, classifyNamingCtx).init(registry);
+        new SubinterfaceStateAugmentationReaderFactory(jvpp, ifcNamingCtx, bdNamingCtx, classifyContext).init(registry);
     }
 
     private void initInterface2AugmentationReaders(final ModifiableReaderRegistryBuilder registry,
@@ -147,7 +148,7 @@ public final class InterfacesStateReaderFactory implements ReaderFactory {
         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, ifcNamingCtx,
-                        classifyNamingCtx)));
+                    classifyContext)));
         //   Proxy ARP
         registry.add(new GenericReader<>(vppIfcAugId.child(ProxyArp.class), new ProxyArpCustomizer(jvpp,
                 ifcNamingCtx)));
index cc68d4d..97f21fb 100644 (file)
@@ -42,6 +42,7 @@ import io.fd.honeycomb.translate.v3po.interfaces.ip.Ipv4Customizer;
 import io.fd.honeycomb.translate.v3po.interfaces.ip.Ipv4NeighbourCustomizer;
 import io.fd.honeycomb.translate.v3po.interfaces.ip.Ipv6Customizer;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import io.fd.honeycomb.translate.write.WriterFactory;
 import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
 import java.util.Set;
@@ -85,7 +86,7 @@ public final class InterfacesWriterFactory implements WriterFactory {
     private final IetfAClWriter aclWriter;
     private final NamingContext bdNamingContext;
     private final NamingContext ifcNamingContext;
-    private final NamingContext classifyTableNamingContext;
+    private final VppClassifierContextManager classifyTableContext;
     private final DisabledInterfacesManager ifcDisableContext;
 
     @Inject
@@ -93,14 +94,14 @@ public final class InterfacesWriterFactory implements WriterFactory {
                                    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 VppClassifierContextManager classifyTableContext,
                                    final DisabledInterfacesManager ifcDisableContext) {
         this.jvpp = vppJvppIfcDependency;
         this.aclWriter = aclWriter;
         this.bdNamingContext = bridgeDomainContextDependency;
         this.ifcNamingContext = interfaceContextDependency;
         this.ifcDisableContext = ifcDisableContext;
-        this.classifyTableNamingContext = classifyTableContextDependency;
+        this.classifyTableContext = classifyTableContext;
     }
 
     @Override
@@ -114,7 +115,7 @@ public final class InterfacesWriterFactory implements WriterFactory {
         addInterface1AugmentationWriters(IFC_ID, registry);
         //   SubinterfaceAugmentation
         new SubinterfaceAugmentationWriterFactory(jvpp, aclWriter, ifcNamingContext, bdNamingContext,
-                classifyTableNamingContext).init(registry);
+            classifyTableContext).init(registry);
     }
 
     private void addInterface1AugmentationWriters(final InstanceIdentifier<Interface> ifcId,
@@ -183,7 +184,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, ifcNamingContext, classifyTableNamingContext)),
+                new GenericWriter<>(ACL_ID, new AclCustomizer(jvpp, ifcNamingContext, classifyTableContext)),
                 Sets.newHashSet(CLASSIFY_TABLE_ID, CLASSIFY_SESSION_ID));
 
         // IETF-ACL, also handles IetfAcl, AccessLists and Acl:
index 4f47f49..152a21f 100644 (file)
@@ -30,6 +30,7 @@ import io.fd.honeycomb.translate.v3po.interfaces.acl.IetfAClWriter;
 import io.fd.honeycomb.translate.v3po.interfaces.acl.SubInterfaceIetfAclCustomizer;
 import io.fd.honeycomb.translate.v3po.interfaces.ip.SubInterfaceIpv4AddressCustomizer;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import io.fd.honeycomb.translate.write.WriterFactory;
 import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
 import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag;
@@ -60,7 +61,7 @@ public final class SubinterfaceAugmentationWriterFactory implements WriterFactor
     private final IetfAClWriter aclWriter;
     private final NamingContext ifcContext;
     private final NamingContext bdContext;
-    private final NamingContext classifyTableContext;
+    private final VppClassifierContextManager classifyTableContext;
 
     public static final InstanceIdentifier<SubinterfaceAugmentation> SUB_IFC_AUG_ID =
             InterfacesWriterFactory.IFC_ID.augmentation(SubinterfaceAugmentation.class);
@@ -73,7 +74,7 @@ public final class SubinterfaceAugmentationWriterFactory implements WriterFactor
 
     public SubinterfaceAugmentationWriterFactory(final FutureJVppCore jvpp,
                                                  final IetfAClWriter aclWriter,
-            final NamingContext ifcContext, final NamingContext bdContext, final NamingContext classifyTableContext) {
+            final NamingContext ifcContext, final NamingContext bdContext, final VppClassifierContextManager classifyTableContext) {
         this.jvpp = jvpp;
         this.aclWriter = aclWriter;
         this.ifcContext = ifcContext;
index ad7eabc..ed17954 100644 (file)
@@ -27,6 +27,7 @@ import io.fd.honeycomb.translate.v3po.interfacesstate.SubInterfaceCustomizer;
 import io.fd.honeycomb.translate.v3po.interfacesstate.SubInterfaceL2Customizer;
 import io.fd.honeycomb.translate.v3po.interfacesstate.ip.SubInterfaceIpv4AddressCustomizer;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6Acl;
@@ -55,10 +56,10 @@ final class SubinterfaceStateAugmentationReaderFactory implements ReaderFactory
     private final FutureJVppCore jvpp;
     private final NamingContext ifcCtx;
     private final NamingContext bdCtx;
-    private final NamingContext classifyCtx;
+    private final VppClassifierContextManager classifyCtx;
 
     SubinterfaceStateAugmentationReaderFactory(final FutureJVppCore jvpp, final NamingContext ifcCtx,
-                                               final NamingContext bdCtx, final NamingContext classifyCtx) {
+                                               final NamingContext bdCtx, final VppClassifierContextManager classifyCtx) {
         this.jvpp = jvpp;
         this.ifcCtx = ifcCtx;
         this.bdCtx = bdCtx;
index b0ff0ea..c83e213 100644 (file)
@@ -29,6 +29,8 @@ import io.fd.honeycomb.translate.v3po.initializers.VppInitializer;
 import io.fd.honeycomb.translate.v3po.interfaces.acl.IetfAClWriter;
 import io.fd.honeycomb.translate.v3po.notification.InterfaceChangeNotificationProducer;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManagerImpl;
 import io.fd.honeycomb.translate.write.WriterFactory;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
@@ -49,9 +51,9 @@ public class V3poModule extends AbstractModule {
         bind(NamingContext.class)
                 .annotatedWith(Names.named("bridge-domain-context"))
                 .toInstance(new NamingContext("bridge-domain-", "bridge-domain-context"));
-        bind(NamingContext.class)
+        bind(VppClassifierContextManager.class)
                 .annotatedWith(Names.named("classify-table-context"))
-                .toInstance(new NamingContext("classify-table-", "classify-table-context"));
+                .toInstance(new VppClassifierContextManagerImpl("classify-table-"));
 
         // Executor needed for keepalives
         bind(ScheduledExecutorService.class).toInstance(Executors.newScheduledThreadPool(1));
@@ -68,6 +70,8 @@ public class V3poModule extends AbstractModule {
         readerFactoryBinder.addBinding().to(VppClassifierReaderFactory.class);
         // Expose disabled interfaces in operational data
         readerFactoryBinder.addBinding().to(DisabledInterfacesManager.ContextsReaderFactory.class);
+        // Expose vpp-classfier-context interfaces in operational data
+        readerFactoryBinder.addBinding().to(VppClassifierContextManagerImpl.ContextsReaderFactory.class);
 
         // Writers
         final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
index 6c52811..371287d 100644 (file)
@@ -21,9 +21,9 @@ import static io.fd.honeycomb.translate.v3po.InterfacesWriterFactory.ACL_ID;
 import com.google.inject.Inject;
 import com.google.inject.name.Named;
 import io.fd.honeycomb.translate.impl.write.GenericListWriter;
-import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.vppclassifier.ClassifySessionWriter;
 import io.fd.honeycomb.translate.v3po.vppclassifier.ClassifyTableWriter;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import io.fd.honeycomb.translate.write.WriterFactory;
 import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
 import javax.annotation.Nonnull;
@@ -42,11 +42,11 @@ public final class VppClassifierHoneycombWriterFactory implements WriterFactory
             CLASSIFY_TABLE_ID.child(ClassifySession.class);
 
     private final FutureJVppCore jvpp;
-    private final NamingContext classifyTableContext;
+    private final VppClassifierContextManager classifyTableContext;
 
     @Inject
     public VppClassifierHoneycombWriterFactory(@Nonnull final FutureJVppCore jvpp,
-                                               @Named("classify-table-context") @Nonnull final NamingContext classifyTableContext) {
+                                               @Named("classify-table-context") @Nonnull final VppClassifierContextManager classifyTableContext) {
         this.jvpp = jvpp;
         this.classifyTableContext = classifyTableContext;
     }
index 90fbb87..0048181 100644 (file)
@@ -21,9 +21,9 @@ import com.google.inject.name.Named;
 import io.fd.honeycomb.translate.impl.read.GenericListReader;
 import io.fd.honeycomb.translate.read.ReaderFactory;
 import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
-import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.vppclassifier.ClassifySessionReader;
 import io.fd.honeycomb.translate.v3po.vppclassifier.ClassifyTableReader;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import javax.annotation.Nonnull;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierStateBuilder;
@@ -35,11 +35,11 @@ import org.openvpp.jvpp.core.future.FutureJVppCore;
 public final class VppClassifierReaderFactory implements ReaderFactory {
 
     private final FutureJVppCore jvpp;
-    private final NamingContext classifyCtx;
+    private final VppClassifierContextManager classifyCtx;
 
     @Inject
     public VppClassifierReaderFactory(final FutureJVppCore jvpp,
-                                      @Named("classify-table-context") final NamingContext classifyCtx) {
+                                      @Named("classify-table-context") final VppClassifierContextManager classifyCtx) {
         this.jvpp = jvpp;
         this.classifyCtx = classifyCtx;
     }
index ab71e65..a920f38 100644 (file)
@@ -22,6 +22,7 @@ import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
 import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.WriteFailedException;
 import javax.annotation.Nonnull;
@@ -40,10 +41,10 @@ public class AclCustomizer extends FutureJVppCustomizer implements WriterCustomi
 
     private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class);
     private final NamingContext interfaceContext;
-    private final NamingContext classifyTableContext;
+    private final VppClassifierContextManager classifyTableContext;
 
     public AclCustomizer(@Nonnull final FutureJVppCore vppApi, @Nonnull final NamingContext interfaceContext,
-                         @Nonnull final NamingContext classifyTableContext) {
+                         @Nonnull final VppClassifierContextManager classifyTableContext) {
         super(vppApi);
         this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
         this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
index d29d213..a1bdf6a 100644 (file)
@@ -19,10 +19,10 @@ package io.fd.honeycomb.translate.v3po.interfaces;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte;
 
-import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
 import io.fd.honeycomb.translate.MappingContext;
-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.v3po.vppclassifier.VppClassifierContextManager;
 import java.util.concurrent.CompletionStage;
 import javax.annotation.Nonnegative;
 import javax.annotation.Nonnull;
@@ -40,7 +40,7 @@ interface AclWriter {
 
     default void inputAclSetInterface(@Nonnull final FutureJVppCore futureJVppCore, final boolean isAdd,
                                       @Nonnull final InstanceIdentifier<?> id, @Nonnull final AclBaseAttributes acl,
-                                      @Nonnegative final int ifIndex, @Nonnull final NamingContext classifyTableContext,
+                                      @Nonnegative final int ifIndex, @Nonnull final VppClassifierContextManager classifyTableContext,
                                       @Nonnull final MappingContext mappingContext)
         throws VppBaseCallException, WriteTimeoutException {
         final InputAclSetInterface request = new InputAclSetInterface();
@@ -53,17 +53,17 @@ interface AclWriter {
         final L2Acl l2Acl = acl.getL2Acl();
         if (l2Acl != null) {
             final String tableName = checkNotNull(l2Acl.getClassifyTable(), "L2 classify table is null");
-            request.l2TableIndex = classifyTableContext.getIndex(tableName, mappingContext);
+            request.l2TableIndex = classifyTableContext.getTableIndex(tableName, mappingContext);
         }
         final Ip4Acl ip4Acl = acl.getIp4Acl();
         if (ip4Acl != null) {
             final String tableName = checkNotNull(ip4Acl.getClassifyTable(), "IPv4 classify table is null");
-            request.ip4TableIndex = classifyTableContext.getIndex(tableName, mappingContext);
+            request.ip4TableIndex = classifyTableContext.getTableIndex(tableName, mappingContext);
         }
         final Ip6Acl ip6Acl = acl.getIp6Acl();
         if (ip6Acl != null) {
             final String tableName = checkNotNull(ip6Acl.getClassifyTable(), "IPv6 classify table is null");
-            request.ip6TableIndex = classifyTableContext.getIndex(tableName, mappingContext);
+            request.ip6TableIndex = classifyTableContext.getTableIndex(tableName, mappingContext);
         }
 
         final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage =
index 962801a..1238267 100644 (file)
@@ -23,6 +23,7 @@ import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils;
 import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.WriteFailedException;
 import javax.annotation.Nonnull;
@@ -45,11 +46,11 @@ public class SubInterfaceAclCustomizer extends FutureJVppCustomizer
 
     private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class);
     private final NamingContext interfaceContext;
-    private final NamingContext classifyTableContext;
+    private final VppClassifierContextManager classifyTableContext;
 
     public SubInterfaceAclCustomizer(@Nonnull final FutureJVppCore vppApi,
                                      @Nonnull final NamingContext interfaceContext,
-                                     @Nonnull final NamingContext classifyTableContext) {
+                                     @Nonnull final VppClassifierContextManager classifyTableContext) {
         super(vppApi);
         this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
         this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
index 9145d84..639b366 100644 (file)
@@ -25,6 +25,7 @@ import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
 import io.fd.honeycomb.translate.read.ReadFailedException;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import javax.annotation.Nonnull;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
@@ -49,10 +50,10 @@ public class AclCustomizer extends FutureJVppCustomizer
 
     private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class);
     private final NamingContext interfaceContext;
-    private final NamingContext classifyTableContext;
+    private final VppClassifierContextManager classifyTableContext;
 
     public AclCustomizer(@Nonnull final FutureJVppCore jvpp, @Nonnull final NamingContext interfaceContext,
-                         @Nonnull final NamingContext classifyTableContext) {
+                         @Nonnull final VppClassifierContextManager classifyTableContext) {
         super(jvpp);
         this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
         this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
index c64c096..c16bfe6 100644 (file)
@@ -17,7 +17,7 @@
 package io.fd.honeycomb.translate.v3po.interfacesstate;
 
 import io.fd.honeycomb.translate.MappingContext;
-import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import javax.annotation.Nonnull;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4AclBuilder;
@@ -29,32 +29,32 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev
 interface AclReader {
 
     @Nonnull
-    default L2Acl readL2Acl(final int l2TableId, @Nonnull final NamingContext classifyTableContext,
+    default L2Acl readL2Acl(final int l2TableId, @Nonnull final VppClassifierContextManager classifyTableContext,
                             @Nonnull final MappingContext mappingContext) {
         if (l2TableId == ~0) {
             return null;
         }
         return new L2AclBuilder()
-            .setClassifyTable(classifyTableContext.getName(l2TableId, mappingContext)).build();
+            .setClassifyTable(classifyTableContext.getTableName(l2TableId, mappingContext)).build();
     }
 
     @Nonnull
-    default Ip4Acl readIp4Acl(final int ip4TableId, @Nonnull final NamingContext classifyTableContext,
+    default Ip4Acl readIp4Acl(final int ip4TableId, @Nonnull final VppClassifierContextManager classifyTableContext,
                               @Nonnull final MappingContext mappingContext) {
         if (ip4TableId == ~0) {
             return null;
         }
         return new Ip4AclBuilder()
-            .setClassifyTable(classifyTableContext.getName(ip4TableId, mappingContext)).build();
+            .setClassifyTable(classifyTableContext.getTableName(ip4TableId, mappingContext)).build();
     }
 
     @Nonnull
-    default Ip6Acl readIp6Acl(final int ip6TableId, @Nonnull final NamingContext classifyTableContext,
+    default Ip6Acl readIp6Acl(final int ip6TableId, @Nonnull final VppClassifierContextManager classifyTableContext,
                               @Nonnull final MappingContext mappingContext) {
         if (ip6TableId == ~0) {
             return null;
         }
         return new Ip6AclBuilder()
-            .setClassifyTable(classifyTableContext.getName(ip6TableId, mappingContext)).build();
+            .setClassifyTable(classifyTableContext.getTableName(ip6TableId, mappingContext)).build();
     }
 }
index bad919f..cbc8c7e 100644 (file)
@@ -26,6 +26,7 @@ import io.fd.honeycomb.translate.read.ReadFailedException;
 import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import javax.annotation.Nonnull;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
@@ -52,10 +53,10 @@ public class SubInterfaceAclCustomizer extends FutureJVppCustomizer
 
     private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class);
     private final NamingContext interfaceContext;
-    private final NamingContext classifyTableContext;
+    private final VppClassifierContextManager classifyTableContext;
 
     public SubInterfaceAclCustomizer(@Nonnull final FutureJVppCore jvpp, @Nonnull final NamingContext interfaceContext,
-                                     @Nonnull final NamingContext classifyTableContext) {
+                                     @Nonnull final VppClassifierContextManager classifyTableContext) {
         super(jvpp);
         this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
         this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
index f8e94d1..558e6ba 100644 (file)
@@ -23,11 +23,11 @@ import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.prin
 
 import com.google.common.base.Optional;
 import com.google.common.primitives.UnsignedInts;
+import io.fd.honeycomb.translate.MappingContext;
 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.util.FutureJVppCustomizer;
-import io.fd.honeycomb.translate.read.ReadFailedException;
-import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
 import java.util.Arrays;
 import java.util.Collections;
@@ -66,10 +66,10 @@ public class ClassifySessionReader extends FutureJVppCustomizer
     private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionReader.class);
     static final String CACHE_KEY = ClassifySessionReader.class.getName();
 
-    private final NamingContext classifyTableContext;
+    private final VppClassifierContextManager classifyTableContext;
 
     public ClassifySessionReader(@Nonnull final FutureJVppCore futureJVppCore,
-                                 @Nonnull final NamingContext classifyTableContext) {
+                                 @Nonnull final VppClassifierContextManager classifyTableContext) {
         super(futureJVppCore);
         this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
     }
@@ -102,10 +102,11 @@ public class ClassifySessionReader extends FutureJVppCustomizer
 
         if (classifySession.isPresent()) {
             final ClassifySessionDetails detail = classifySession.get();
-            builder.setHitNext(readVppNode(detail.hitNextIndex, LOG));
+            builder.setHitNext(
+                readVppNode(detail.tableId, detail.hitNextIndex, classifyTableContext, ctx.getMappingContext(), LOG).get());
             if (detail.opaqueIndex != ~0) {
                 // value is specified:
-                builder.setOpaqueIndex(readOpaqueIndex(detail.opaqueIndex));
+                builder.setOpaqueIndex(readOpaqueIndex(detail.tableId, detail.opaqueIndex, ctx.getMappingContext()));
             }
             builder.setAdvance(detail.advance);
             builder.setMatch(key.getMatch());
@@ -116,13 +117,14 @@ public class ClassifySessionReader extends FutureJVppCustomizer
         }
     }
 
-    private OpaqueIndex readOpaqueIndex(final int opaqueIndex) {
+    private OpaqueIndex readOpaqueIndex(final int tableIndex, final int opaqueIndex, final MappingContext ctx) {
         // We first try to map the value to a vpp node, if that fails, simply wrap the u32 value
         // TODO: HONEYCOMB-118 the approach might fail if the opaqueIndex contains small value that collides
         // with some of the adjacent nodes
-        final VppNode node = readVppNode(opaqueIndex, LOG);
-        if (node != null) {
-            return new OpaqueIndex(node);
+
+        final Optional<VppNode> node = readVppNode(tableIndex, opaqueIndex, classifyTableContext, ctx, LOG);
+        if (node.isPresent()) {
+            return new OpaqueIndex(node.get());
         } else {
             return new OpaqueIndex(UnsignedInts.toLong(opaqueIndex));
         }
@@ -145,10 +147,10 @@ public class ClassifySessionReader extends FutureJVppCustomizer
         }
 
         final String tableName = tableKey.getName();
-        checkState(classifyTableContext.containsIndex(tableName, ctx.getMappingContext()),
+        checkState(classifyTableContext.containsTable(tableName, ctx.getMappingContext()),
             "Reading classify sessions for table {}, but table index could not be found in the classify table context",
             tableName);
-        final int tableId = classifyTableContext.getIndex(tableName, ctx.getMappingContext());
+        final int tableId = classifyTableContext.getTableIndex(tableName, ctx.getMappingContext());
         LOG.debug("Dumping classify sessions for classify table id={}", tableId);
 
         try {
@@ -157,8 +159,11 @@ public class ClassifySessionReader extends FutureJVppCustomizer
             classifySessionDump = TranslateUtils
                 .getReplyForRead(getFutureJVpp().classifySessionDump(dumpRequest).toCompletableFuture(), id);
 
-            // update the cache:
-            ctx.getModificationCache().put(cacheKey, classifySessionDump);
+            if (classifySessionDump != null) {
+                // update the cache:
+                ctx.getModificationCache().put(cacheKey, classifySessionDump);
+            }
+
             return classifySessionDump;
         } catch (VppBaseCallException e) {
             throw new ReadFailedException(id, e);
index 8967dcf..d2029a3 100644 (file)
@@ -21,15 +21,15 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte;
 
-import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
-import io.fd.honeycomb.translate.write.WriteContext;
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
 import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
-import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
-import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.WriteFailedException;
 import java.util.concurrent.CompletionStage;
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import javax.xml.bind.DatatypeConverter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession;
@@ -48,14 +48,14 @@ import org.slf4j.LoggerFactory;
  * Writer customizer responsible for classify session create/delete.<br> Sends {@code classify_add_del_session} message
  * to VPP.<br> Equivalent to invoking {@code vppctl classify table} command.
  */
-public class ClassifySessionWriter extends FutureJVppCustomizer
+public class ClassifySessionWriter extends VppNodeWriter
     implements ListWriterCustomizer<ClassifySession, ClassifySessionKey> {
 
     private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionWriter.class);
-    private final NamingContext classifyTableContext;
+    private final VppClassifierContextManager classifyTableContext;
 
     public ClassifySessionWriter(@Nonnull final FutureJVppCore futureJVppCore,
-                                 @Nonnull final NamingContext classifyTableContext) {
+                                 @Nonnull final VppClassifierContextManager classifyTableContext) {
         super(futureJVppCore);
         this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
     }
@@ -97,37 +97,51 @@ public class ClassifySessionWriter extends FutureJVppCustomizer
     private void classifyAddDelSession(final boolean isAdd, @Nonnull final InstanceIdentifier<ClassifySession> id,
                                        @Nonnull final ClassifySession classifySession,
                                        @Nonnull final WriteContext writeContext)
-        throws VppBaseCallException, WriteTimeoutException {
+        throws VppBaseCallException, WriteFailedException {
         final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class);
         checkArgument(tableKey != null, "could not find classify table key in {}", id);
 
         final String tableName = tableKey.getName();
-        checkState(classifyTableContext.containsIndex(tableName, writeContext.getMappingContext()),
+        checkState(classifyTableContext.containsTable(tableName, writeContext.getMappingContext()),
             "Could not find classify table index for {} in the classify table context", tableName);
-        final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext());
+        final int tableIndex = classifyTableContext.getTableIndex(tableName, writeContext.getMappingContext());
+
+        final ClassifyTable classifyTable =
+            getClassifyTable(writeContext, id.firstIdentifierOf(ClassifyTable.class), isAdd);
+        final int hitNextIndex = getNodeIndex(classifySession.getHitNext(), classifyTable, classifyTableContext,
+            writeContext.getMappingContext(), id);
+        final int opaqueIndex =
+            getOpaqueIndex(classifySession.getOpaqueIndex(), classifyTable, writeContext.getMappingContext(), id);
 
         final CompletionStage<ClassifyAddDelSessionReply> createClassifyTableReplyCompletionStage = getFutureJVpp()
             .classifyAddDelSession(
-                getClassifyAddDelSessionRequest(isAdd, tableIndex, classifySession));
+                getClassifyAddDelSessionRequest(isAdd, classifySession, tableIndex, hitNextIndex, opaqueIndex));
 
         TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
     }
 
-    private static ClassifyAddDelSession getClassifyAddDelSessionRequest(final boolean isAdd, final int tableIndex,
-                                                                         @Nonnull final ClassifySession classifySession) {
+    private ClassifyTable getClassifyTable(final WriteContext writeContext,
+                                            @Nonnull final InstanceIdentifier<ClassifyTable> id,
+                                            final boolean isAdd) {
+        final Optional<ClassifyTable> classifyTable;
+        if (isAdd) {
+            classifyTable = writeContext.readAfter(id);
+        } else {
+            classifyTable = writeContext.readBefore(id);
+        }
+        return classifyTable.get();
+    }
+
+    private static ClassifyAddDelSession getClassifyAddDelSessionRequest(final boolean isAdd,
+                                                                         @Nonnull final ClassifySession classifySession,
+                                                                         final int tableIndex,
+                                                                         final int hitNextIndex,
+                                                                         final int opaqueIndex) {
         ClassifyAddDelSession request = new ClassifyAddDelSession();
         request.isAdd = booleanToByte(isAdd);
         request.tableIndex = tableIndex;
-
-        // mandatory:
-        // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed
-        request.hitNextIndex = classifySession.getHitNext().getPacketHandlingAction().getIntValue();
-
-        if (classifySession.getOpaqueIndex() != null) {
-            request.opaqueIndex = getOpaqueIndexValue(classifySession.getOpaqueIndex());
-        } else {
-            request.opaqueIndex = ~0; // value not specified
-        }
+        request.hitNextIndex = hitNextIndex;
+        request.opaqueIndex = opaqueIndex;
 
         // default 0:
         request.advance = classifySession.getAdvance();
@@ -136,12 +150,16 @@ public class ClassifySessionWriter extends FutureJVppCustomizer
         return request;
     }
 
-    private static int getOpaqueIndexValue(@Nonnull final OpaqueIndex opaqueIndex) {
+    private int getOpaqueIndex(@Nullable final OpaqueIndex opaqueIndex, final ClassifyTable classifyTable,
+                               final MappingContext ctx, final InstanceIdentifier<ClassifySession> id)
+        throws VppBaseCallException, WriteFailedException {
+        if (opaqueIndex == null) {
+            return ~0; // value not specified
+        }
         if (opaqueIndex.getUint32() != null) {
             return opaqueIndex.getUint32().intValue();
         } else {
-            // TODO: implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed
-            return opaqueIndex.getVppNode().getPacketHandlingAction().getIntValue();
+            return getNodeIndex(opaqueIndex.getVppNode(), classifyTable, classifyTableContext, ctx, id);
         }
     }
 }
index b7d54ab..ad238d8 100644 (file)
@@ -20,12 +20,12 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.printHexBinary;
 
+import com.google.common.base.Optional;
 import com.google.common.primitives.UnsignedInts;
 import io.fd.honeycomb.translate.read.ReadContext;
-import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
 import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
 import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
-import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
 import java.util.Arrays;
 import java.util.Collections;
@@ -34,6 +34,7 @@ import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey;
@@ -57,10 +58,10 @@ public class ClassifyTableReader extends FutureJVppCustomizer
     implements ListReaderCustomizer<ClassifyTable, ClassifyTableKey, ClassifyTableBuilder>, VppNodeReader {
 
     private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableReader.class);
-    private final NamingContext classifyTableContext;
+    private final VppClassifierContextManager classifyTableContext;
 
     public ClassifyTableReader(@Nonnull final FutureJVppCore futureJVppCore,
-                               @Nonnull final NamingContext classifyTableContext) {
+                               @Nonnull final VppClassifierContextManager classifyTableContext) {
         super(futureJVppCore);
         this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
     }
@@ -89,11 +90,11 @@ public class ClassifyTableReader extends FutureJVppCustomizer
         final ClassifyTableInfo request = new ClassifyTableInfo();
 
         final String tableName = key.getName();
-        if (!classifyTableContext.containsIndex(tableName, ctx.getMappingContext())) {
+        if (!classifyTableContext.containsTable(tableName, ctx.getMappingContext())) {
             LOG.debug("Could not find classify table {} in the naming context", tableName);
             return;
         }
-        request.tableId = classifyTableContext.getIndex(tableName, ctx.getMappingContext());
+        request.tableId = classifyTableContext.getTableIndex(tableName, ctx.getMappingContext());
 
         try {
             final ClassifyTableInfoReply reply =
@@ -105,14 +106,22 @@ public class ClassifyTableReader extends FutureJVppCustomizer
             builder.setNbuckets(UnsignedInts.toLong(reply.nbuckets));
             builder.setSkipNVectors(UnsignedInts.toLong(reply.skipNVectors));
 
+            // optional value read from context
+            final Optional<String> tableBaseNode =
+                classifyTableContext.getTableBaseNode(tableName, ctx.getMappingContext());
+            if (tableBaseNode.isPresent()) {
+                builder.setClassifierNode(new VppNodeName(tableBaseNode.get()));
+            }
 
-            builder.setMissNext(readVppNode(reply.missNextIndex, LOG));
+            builder.setMissNext(
+                readVppNode(reply.tableId, reply.missNextIndex, classifyTableContext, ctx.getMappingContext(), LOG)
+                    .get());
             builder.setMask(new HexString(printHexBinary(reply.mask)));
             builder.setActiveSessions(UnsignedInts.toLong(reply.activeSessions));
 
             if (reply.nextTableIndex != ~0) {
                 // next table index is present:
-                builder.setNextTable(classifyTableContext.getName(reply.nextTableIndex, ctx.getMappingContext()));
+                builder.setNextTable(classifyTableContext.getTableName(reply.nextTableIndex, ctx.getMappingContext()));
             }
 
             if (LOG.isTraceEnabled()) {
@@ -133,7 +142,7 @@ public class ClassifyTableReader extends FutureJVppCustomizer
                 .getReplyForRead(getFutureJVpp().classifyTableIds(new ClassifyTableIds()).toCompletableFuture(), id);
             if (classifyTableIdsReply.ids != null) {
                 return Arrays.stream(classifyTableIdsReply.ids).mapToObj(i -> {
-                    final String tableName = classifyTableContext.getName(i, context.getMappingContext());
+                    final String tableName = classifyTableContext.getTableName(i, context.getMappingContext());
                     LOG.trace("Classify table with name: {} and index: {} found in VPP", tableName, i);
                     return new ClassifyTableKey(tableName);
                 }).collect(Collectors.toList());
index 3c3f981..3dc3cf7 100644 (file)
@@ -21,14 +21,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte;
 
+import io.fd.honeycomb.translate.MappingContext;
 import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
-import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
-import io.fd.honeycomb.translate.v3po.util.NamingContext;
-import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
 import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.WriteFailedException;
-import io.fd.honeycomb.translate.MappingContext;
-import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
 import java.util.concurrent.CompletionStage;
 import javax.annotation.Nonnull;
 import javax.xml.bind.DatatypeConverter;
@@ -46,14 +43,14 @@ import org.slf4j.LoggerFactory;
  * Writer customizer responsible for classify table create/delete. <br> Sends {@code classify_add_del_table} message to
  * VPP.<br> Equivalent to invoking {@code vppctl classify table} command.
  */
-public class ClassifyTableWriter extends FutureJVppCustomizer
+public class ClassifyTableWriter extends VppNodeWriter
     implements ListWriterCustomizer<ClassifyTable, ClassifyTableKey> {
 
     private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableWriter.class);
-    private final NamingContext classifyTableContext;
+    private final VppClassifierContextManager classifyTableContext;
 
     public ClassifyTableWriter(@Nonnull final FutureJVppCore futureJVppCore,
-                               @Nonnull final NamingContext classifyTableContext) {
+                               @Nonnull final VppClassifierContextManager classifyTableContext) {
         super(futureJVppCore);
         this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
     }
@@ -68,7 +65,7 @@ public class ClassifyTableWriter extends FutureJVppCustomizer
                 classifyAddDelTable(true, id, dataAfter, ~0 /* value not present */, writeContext.getMappingContext());
 
             // Add classify table name <-> vpp index mapping to the naming context:
-            classifyTableContext.addName(newTableIndex, dataAfter.getName(), writeContext.getMappingContext());
+            classifyTableContext.addTable(newTableIndex, dataAfter.getName(), dataAfter.getClassifierNode(), writeContext.getMappingContext());
             LOG.debug("Successfully created classify table(id={]): iid={} dataAfter={}", newTableIndex, id, dataAfter);
         } catch (VppBaseCallException e) {
             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
@@ -88,15 +85,15 @@ public class ClassifyTableWriter extends FutureJVppCustomizer
                                         @Nonnull final WriteContext writeContext) throws WriteFailedException {
         LOG.debug("Removing classify table: iid={} dataBefore={}", id, dataBefore);
         final String tableName = dataBefore.getName();
-        checkState(classifyTableContext.containsIndex(tableName, writeContext.getMappingContext()),
+        checkState(classifyTableContext.containsTable(tableName, writeContext.getMappingContext()),
             "Removing classify table {}, but index could not be found in the classify table context", tableName);
 
-        final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext());
+        final int tableIndex = classifyTableContext.getTableIndex(tableName, writeContext.getMappingContext());
         try {
             classifyAddDelTable(false, id, dataBefore, tableIndex, writeContext.getMappingContext());
 
             // Remove deleted interface from interface context:
-            classifyTableContext.removeName(dataBefore.getName(), writeContext.getMappingContext());
+            classifyTableContext.removeTable(dataBefore.getName(), writeContext.getMappingContext());
             LOG.debug("Successfully removed classify table(id={]): iid={} dataAfter={}", tableIndex, id, dataBefore);
         } catch (VppBaseCallException e) {
             throw new WriteFailedException.DeleteFailedException(id, e);
@@ -105,18 +102,23 @@ public class ClassifyTableWriter extends FutureJVppCustomizer
 
     private int classifyAddDelTable(final boolean isAdd, @Nonnull final InstanceIdentifier<ClassifyTable> id,
                                     @Nonnull final ClassifyTable table, final int tableId, final MappingContext ctx)
-        throws VppBaseCallException, WriteTimeoutException {
+        throws VppBaseCallException, WriteFailedException {
+
+        final int missNextIndex =
+            getNodeIndex(table.getMissNext(), table, classifyTableContext, ctx, id);
+
         final CompletionStage<ClassifyAddDelTableReply> createClassifyTableReplyCompletionStage =
-            getFutureJVpp().classifyAddDelTable(getClassifyAddDelTableRequest(isAdd, tableId, table, ctx));
+            getFutureJVpp()
+                .classifyAddDelTable(getClassifyAddDelTableRequest(isAdd, tableId, table, missNextIndex, ctx));
 
         final ClassifyAddDelTableReply reply =
             TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
         return reply.newTableIndex;
-
     }
 
     private ClassifyAddDelTable getClassifyAddDelTableRequest(final boolean isAdd, final int tableIndex,
                                                               @Nonnull final ClassifyTable table,
+                                                              final int missNextIndex,
                                                               @Nonnull final MappingContext ctx) {
         final ClassifyAddDelTable request = new ClassifyAddDelTable();
         request.isAdd = booleanToByte(isAdd);
@@ -128,12 +130,11 @@ public class ClassifyTableWriter extends FutureJVppCustomizer
         request.skipNVectors = table.getSkipNVectors().intValue();
 
         // mandatory
-        // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed
-        request.missNextIndex = table.getMissNext().getPacketHandlingAction().getIntValue();
+        request.missNextIndex = missNextIndex;
 
         final String nextTable = table.getNextTable();
         if (isAdd && nextTable != null) {
-            request.nextTableIndex = classifyTableContext.getIndex(nextTable, ctx);
+            request.nextTableIndex = classifyTableContext.getTableIndex(nextTable, ctx);
         } else {
             request.nextTableIndex = ~0; // value not specified
         }
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppClassifierContextManager.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppClassifierContextManager.java
new file mode 100644 (file)
index 0000000..7e9b6d6
--- /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.vppclassifier;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNodeName;
+
+/**
+ * Manages metadata for vpp-classifier
+ */
+public interface VppClassifierContextManager {
+
+    /**
+     * Creates metadata for classify table.
+     *
+     * @param id             classify table index
+     * @param name           classify table name
+     * @param classifierNode name of VPP node the table is defined for
+     * @param ctx            mapping context providing context data for current transaction
+     */
+    void addTable(final int id, @Nonnull final String name, @Nullable final VppNodeName classifierNode,
+                  @Nonnull final MappingContext ctx);
+
+    /**
+     * Check whether metadata for given classify table metadata is present.
+     *
+     * @param name classify table name
+     * @param ctx  mapping context providing context data for current transaction
+     * @return true if present, false otherwise
+     */
+    boolean containsTable(@Nonnull String name, @Nonnull final MappingContext ctx);
+
+    /**
+     * Returns classify table index associated with the given name.
+     *
+     * @param name classify table name
+     * @param ctx  mapping context providing context data for current transaction
+     * @return integer index value matching supplied classify table name
+     * @throws IllegalArgumentException if classify table was not found
+     */
+    int getTableIndex(@Nonnull final String name, @Nonnull final MappingContext ctx);
+
+    /**
+     * Retrieves classify table name for given id. If not present, artificial name will be generated.
+     *
+     * @param id  classify table index
+     * @param ctx mapping context providing context data for current transaction
+     * @return classify table name matching supplied index
+     */
+    String getTableName(final int id, @Nonnull final MappingContext ctx);
+
+    /**
+     * Returns name of the base vpp node associated with the classify table.
+     *
+     * @param name classify table name
+     * @param ctx  mapping context providing context data for current transaction
+     * @return name of VPP node the table is defined for
+     */
+    Optional<String> getTableBaseNode(final String name, @Nonnull final MappingContext ctx);
+
+    /**
+     * Removes classify table metadata from current context.
+     *
+     * @param name classify table name
+     * @param ctx  mapping context providing context data for current transaction
+     */
+    void removeTable(@Nonnull final String name, @Nonnull final MappingContext ctx);
+
+    /**
+     * Adds relative node index to node name mapping for given classify table.
+     *
+     * @param tableName classify table name
+     * @param nodeIndex index of a vpp node, relative to table's base node
+     * @param nodeName  name of a vpp node
+     * @param ctx       mapping context providing context data for current transaction
+     */
+    void addNodeName(@Nonnull String tableName, final int nodeIndex, @Nonnull final String nodeName,
+                     @Nonnull final MappingContext ctx);
+
+    /**
+     * Retrieves node name associated with the given classify table and node index.
+     *
+     * @param tableIndex classify table index
+     * @param nodeIndex  relative index of a vpp node
+     * @param ctx        mapping context providing context data for current transaction
+     * @return name of vpp node
+     */
+    Optional<String> getNodeName(final int tableIndex, final int nodeIndex, @Nonnull final MappingContext ctx);
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppClassifierContextManagerImpl.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppClassifierContextManagerImpl.java
new file mode 100644 (file)
index 0000000..9f61ab0
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * 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.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.inject.Inject;
+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.RWUtils;
+import io.fd.honeycomb.translate.util.read.BindingBrokerReader;
+import java.util.stream.Collector;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.inject.Named;
+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.vpp.classifier.rev150603.VppNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.VppClassifierContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.VppClassifierContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.ClassifyTableContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.ClassifyTableContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.ClassifyTableContextKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.classify.table.context.NodeContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.classify.table.context.NodeContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.classify.table.context.NodeContextKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+/**
+ * Facade on top of {@link MappingContext} that manages {@link ClassifyTableContext}.
+ */
+public final class VppClassifierContextManagerImpl implements VppClassifierContextManager {
+    private static final Collector<ClassifyTableContext, ?, ClassifyTableContext> SINGLE_ITEM_COLLECTOR =
+        RWUtils.singleItemCollector();
+
+    @VisibleForTesting
+    static final InstanceIdentifier<VppClassifierContext>
+        VPP_CLASSIFIER_CONTEXT_IID = KeyedInstanceIdentifier.create(VppClassifierContext.class);
+    private final String artificialNamePrefix;
+
+    /**
+     * Creates new VppClassifierContextManagerImpl.
+     *
+     * @param artificialNamePrefix artificial name to be used to generate names for classify tables without existing
+     *                             metadata
+     */
+    public VppClassifierContextManagerImpl(@Nonnull final String artificialNamePrefix) {
+        this.artificialNamePrefix =
+            Preconditions.checkNotNull(artificialNamePrefix, "artificialNamePrefix should not be null");
+    }
+
+    private KeyedInstanceIdentifier<ClassifyTableContext, ClassifyTableContextKey> getMappingIid(final String name) {
+        return VPP_CLASSIFIER_CONTEXT_IID.child(ClassifyTableContext.class, new ClassifyTableContextKey(name));
+    }
+
+    @Override
+    public void addTable(final int id, @Nonnull final String name, @Nullable final VppNodeName classifierNode,
+                         @Nonnull final MappingContext ctx) {
+        final KeyedInstanceIdentifier<ClassifyTableContext, ClassifyTableContextKey> mappingIid = getMappingIid(name);
+        final ClassifyTableContextBuilder tableCtx = new ClassifyTableContextBuilder().setIndex(id).setName(name);
+        if (classifierNode != null) {
+            tableCtx.setClassifierNodeName(classifierNode.getValue());
+        }
+        ctx.put(mappingIid, tableCtx.build());
+    }
+
+    @Override
+    public boolean containsTable(@Nonnull final String name, @Nonnull final MappingContext ctx) {
+        final Optional<ClassifyTableContext> read = ctx.read(getMappingIid(name));
+        return read.isPresent();
+    }
+
+    @Override
+    public int getTableIndex(@Nonnull final String name, @Nonnull final MappingContext ctx) {
+        final Optional<ClassifyTableContext> read = ctx.read(getMappingIid(name));
+        checkArgument(read.isPresent(), "No mapping stored for name: %s", name);
+        return read.get().getIndex();
+    }
+
+    @Override
+    public String getTableName(final int id, @Nonnull final MappingContext ctx) {
+        if (!containsName(id, ctx)) {
+            final String artificialName = getArtificialName(id);
+            addTable(id, artificialName, null, ctx);
+        }
+
+        final Optional<VppClassifierContext> read = ctx.read(VPP_CLASSIFIER_CONTEXT_IID);
+        checkState(read.isPresent(), "VppClassifierContext for index: %s is not present. But should be", id);
+
+        return read.get().getClassifyTableContext().stream()
+            .filter(t -> t.getIndex().equals(id))
+            .collect(SINGLE_ITEM_COLLECTOR).getName();
+    }
+
+    private boolean containsName(final int index, @Nonnull final MappingContext mappingContext) {
+        final Optional<VppClassifierContext> read = mappingContext.read(VPP_CLASSIFIER_CONTEXT_IID);
+        return read.isPresent()
+            ? read.get().getClassifyTableContext().stream().anyMatch(t -> t.getIndex().equals(index))
+            : false;
+    }
+
+    @Override
+    public Optional<String> getTableBaseNode(@Nonnull final String name, @Nonnull final MappingContext ctx) {
+        final Optional<ClassifyTableContext> read = ctx.read(getMappingIid(name));
+        if (read.isPresent()) {
+            return Optional.fromNullable(read.get().getClassifierNodeName());
+        }
+        return Optional.absent();
+    }
+
+    @Override
+    public void removeTable(@Nonnull final String name, @Nonnull final MappingContext ctx) {
+        ctx.delete(getMappingIid(name));
+    }
+
+    @Override
+    public void addNodeName(@Nonnull final String tableName, final int nodeIndex,
+                            @Nonnull final String nodeName,
+                            @Nonnull final MappingContext ctx) {
+        final KeyedInstanceIdentifier<NodeContext, NodeContextKey> iid =
+            getMappingIid(tableName).child(NodeContext.class, new NodeContextKey(nodeName));
+        ctx.put(iid, new NodeContextBuilder().setName(nodeName).setIndex(nodeIndex).build());
+    }
+
+    @Override
+    public Optional<String> getNodeName(final int tableIndex, final int nodeIndex, @Nonnull final MappingContext ctx) {
+        if (!containsName(tableIndex, ctx)) {
+            return Optional.absent();
+        }
+        final String tableName = getTableName(tableIndex, ctx);
+        final Optional<ClassifyTableContext> tableCtx = ctx.read(getMappingIid(tableName));
+        return Optional.fromNullable(tableCtx.get().getNodeContext().stream()
+            .filter(n -> n.getIndex().equals(nodeIndex))
+            .findFirst()
+            .map(nodes -> nodes.getName())
+            .orElse(null));
+    }
+
+    private String getArtificialName(final int index) {
+        return artificialNamePrefix + index;
+    }
+
+    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<>(VPP_CLASSIFIER_CONTEXT_IID,
+                contextBindingBrokerDependency,
+                LogicalDatastoreType.OPERATIONAL, VppClassifierContextBuilder.class));
+        }
+    }
+}
index 6061b86..9fca416 100644 (file)
 
 package io.fd.honeycomb.translate.v3po.vppclassifier;
 
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
 import javax.annotation.Nonnull;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNodeName;
 import org.slf4j.Logger;
 
 interface VppNodeReader {
@@ -29,13 +32,14 @@ interface VppNodeReader {
      * @param nodeIndex index of vpp node treated as signed integer.
      * @return vpp node representation
      */
-    default VppNode readVppNode(final int nodeIndex, @Nonnull final Logger log) {
+    default Optional<VppNode> readVppNode(final int tableIndex, final int nodeIndex,
+                                          @Nonnull final VppClassifierContextManager vppClassifierContextManager,
+                                          @Nonnull final MappingContext ctx, @Nonnull final Logger log) {
         final PacketHandlingAction action = PacketHandlingAction.forValue(nodeIndex);
         if (action == null) {
-            // TODO: implement node index to name conversion after https://jira.fd.io/browse/VPP-203 is fixed
-            log.debug("VPP node index {} cannot be mapped to PacketHandlingAction", nodeIndex);
-            return null;
+            return vppClassifierContextManager.getNodeName(tableIndex, nodeIndex, ctx)
+                .transform(nodeName -> new VppNode(new VppNodeName(nodeName)));
         }
-        return new VppNode(action);
+        return Optional.of(new VppNode(action));
     }
 }
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeWriter.java
new file mode 100644 (file)
index 0000000..a4667bf
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.ReadTimeoutException;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.core.dto.GetNextIndex;
+import org.openvpp.jvpp.core.dto.GetNextIndexReply;
+import org.openvpp.jvpp.core.future.FutureJVppCore;
+
+abstract class VppNodeWriter extends FutureJVppCustomizer {
+
+    protected VppNodeWriter(@Nonnull final FutureJVppCore futureJvpp) {
+        super(futureJvpp);
+    }
+
+    protected int getNodeIndex(@Nonnull final VppNode node, @Nonnull final ClassifyTable classifyTable,
+                               @Nonnull final VppClassifierContextManager vppClassifierContextManager,
+                               @Nonnull final MappingContext ctx, @Nonnull final InstanceIdentifier<?> id)
+        throws VppBaseCallException, WriteFailedException {
+        if (node.getPacketHandlingAction() != null) {
+            return node.getPacketHandlingAction().getIntValue();
+        } else {
+            return nodeNameToIndex(classifyTable, node.getVppNodeName().getValue(), vppClassifierContextManager, ctx, id);
+        }
+    }
+
+    private int nodeNameToIndex(@Nonnull final ClassifyTable classifyTable, @Nonnull final String nextNodeName,
+                                @Nonnull final VppClassifierContextManager vppClassifierContextManager,
+                                @Nonnull final MappingContext ctx, @Nonnull final InstanceIdentifier<?> id)
+        throws VppBaseCallException, WriteFailedException {
+        checkArgument(classifyTable != null && classifyTable.getClassifierNode() != null, "to use relative node names, table classifier node needs to be provided");
+        final GetNextIndex request = new GetNextIndex();
+        request.nodeName = classifyTable.getClassifierNode().getValue().getBytes();
+        request.nextName = nextNodeName.getBytes();
+        final CompletionStage<GetNextIndexReply> getNextIndexCompletionStage =
+            getFutureJVpp().getNextIndex(request);
+
+        final GetNextIndexReply reply;
+        try {
+            reply = TranslateUtils.getReplyForRead(getNextIndexCompletionStage.toCompletableFuture(), id);
+
+            // vpp does not provide relative node index to node name conversion (https://jira.fd.io/browse/VPP-219)
+            // as a workaround we need to add mapping to vpp-classfier-context
+            vppClassifierContextManager.addNodeName(classifyTable.getName(), reply.nextIndex, nextNodeName, ctx);
+        } catch (ReadTimeoutException e) {
+            throw new WriteFailedException(id, String.format("Failed to get node index for %s relative to %s",
+                nextNodeName, classifyTable.getClassifierNode()), e);
+        }
+        return reply.nextIndex;
+    }
+}
index 66e96b4..578b245 100644 (file)
@@ -27,21 +27,18 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.MockitoAnnotations.initMocks;
 
 import com.google.common.base.Optional;
-import com.google.common.collect.Lists;
 import io.fd.honeycomb.translate.MappingContext;
 import io.fd.honeycomb.translate.v3po.test.TestHelperUtils;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.WriteFailedException;
-import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import org.junit.Before;
 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;
 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
@@ -68,13 +65,13 @@ public class AclCustomizerTest {
     private WriteContext writeContext;
     @Mock
     private MappingContext mappingContext;
+    @Mock
+    private VppClassifierContextManager classifyTableContext;
 
     private NamingContext interfaceContext;
-    private NamingContext classifyTableContext;
     private AclCustomizer customizer;
 
     private static final String IFC_TEST_INSTANCE = "ifc-test-instance";
-    private static final String CT_TEST_INSTANCE = "ct-test-instance";
     private static final String IF_NAME = "local0";
     private static final int IF_INDEX = 1;
 
@@ -85,23 +82,12 @@ public class AclCustomizerTest {
     public void setUp() throws Exception {
         initMocks(this);
         interfaceContext = new NamingContext("generatedInterfaceName", IFC_TEST_INSTANCE);
-        classifyTableContext = new NamingContext("generatedClassifyTable", CT_TEST_INSTANCE);
         doReturn(mappingContext).when(writeContext).getMappingContext();
         customizer = new AclCustomizer(api, interfaceContext, classifyTableContext);
 
         final KeyedInstanceIdentifier<Mapping, MappingKey> ifcMappingKey = getMappingIid(IF_NAME, IFC_TEST_INSTANCE);
         final Optional<Mapping> ifcMapping = getMapping(IF_NAME, IF_INDEX);
         doReturn(ifcMapping).when(mappingContext).read(ifcMappingKey);
-
-        final KeyedInstanceIdentifier<Mapping, MappingKey> ctMappingKey =
-            getMappingIid(ACL_TABLE_NAME, CT_TEST_INSTANCE);
-        final Optional<Mapping> ctMapping = getMapping(ACL_TABLE_NAME, ACL_TABLE_INDEX);
-        doReturn(ctMapping).when(mappingContext).read(ctMappingKey);
-
-        final List<Mapping> allCtMappings = Lists.newArrayList(ctMapping.get());
-        final Mappings allCtMappingsBaObject = new MappingsBuilder().setMapping(allCtMappings).build();
-        doReturn(Optional.of(allCtMappingsBaObject)).when(mappingContext)
-            .read(ctMappingKey.firstIdentifierOf(Mappings.class));
     }
 
 
index 84d2306..86cb6b9 100644 (file)
@@ -27,9 +27,11 @@ import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
 import io.fd.honeycomb.translate.v3po.test.ContextTestUtils;
 import io.fd.honeycomb.translate.v3po.test.ReaderCustomizerTest;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import org.junit.Test;
+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;
@@ -55,10 +57,11 @@ public class AclCustomizerTest extends ReaderCustomizerTest<Acl, AclBuilder> {
     private static final String TABLE_NAME = "table123";
 
     private static final String IFC_TEST_INSTANCE = "ifc-test-instance";
-    private static final String CT_TEST_INSTANCE = "ct-test-instance";
 
     private NamingContext interfaceContext;
-    private NamingContext classifyTableContext;
+
+    @Mock
+    private VppClassifierContextManager classifyTableContext;
 
     public AclCustomizerTest() {
         super(Acl.class);
@@ -67,23 +70,12 @@ public class AclCustomizerTest extends ReaderCustomizerTest<Acl, AclBuilder> {
     @Override
     public void setUpBefore() {
         interfaceContext = new NamingContext("generatedIfaceName", IFC_TEST_INSTANCE);
-        classifyTableContext = new NamingContext("generatedTableContext", CT_TEST_INSTANCE);
 
         final KeyedInstanceIdentifier<Mapping, MappingKey> ifcMappingKey = ContextTestUtils
                 .getMappingIid(IF_NAME, IFC_TEST_INSTANCE);
         final Optional<Mapping> ifcMapping = ContextTestUtils.getMapping(IF_NAME, IF_INDEX);
         doReturn(ifcMapping).when(mappingContext).read(ifcMappingKey);
 
-        final KeyedInstanceIdentifier<Mapping, MappingKey> ctMappingKey = ContextTestUtils
-                .getMappingIid(TABLE_NAME, CT_TEST_INSTANCE);
-        final Optional<Mapping> ctMapping = ContextTestUtils.getMapping(TABLE_NAME, TABLE_INDEX);
-        doReturn(ctMapping).when(mappingContext).read(ctMappingKey);
-
-        final List<Mapping> allCtMappings = Lists.newArrayList(ctMapping.get());
-        final Mappings allCtMappingsBaObject = new MappingsBuilder().setMapping(allCtMappings).build();
-        doReturn(Optional.of(allCtMappingsBaObject)).when(mappingContext)
-            .read(ctMappingKey.firstIdentifierOf(Mappings.class));
-
         final List<Mapping> allIfcMappings = Lists.newArrayList(ifcMapping.get());
         final Mappings allIfcMappingsBaObject = new MappingsBuilder().setMapping(allIfcMappings).build();
         doReturn(Optional.of(allIfcMappingsBaObject)).when(mappingContext)
@@ -122,6 +114,8 @@ public class AclCustomizerTest extends ReaderCustomizerTest<Acl, AclBuilder> {
         replyFuture.complete(reply);
         doReturn(replyFuture).when(api).classifyTableByInterface(any(ClassifyTableByInterface.class));
 
+        doReturn(TABLE_NAME).when(classifyTableContext).getTableName(TABLE_INDEX, mappingContext);
+
         getCustomizer().readCurrentAttributes(id, builder, ctx);
 
         verify(builder).setL2Acl(new L2AclBuilder().setClassifyTable(TABLE_NAME).build());
index f515991..d1bda87 100644 (file)
@@ -23,19 +23,16 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import com.google.common.base.Optional;
 import io.fd.honeycomb.translate.ModificationCache;
 import io.fd.honeycomb.translate.read.ReadFailedException;
 import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
-import io.fd.honeycomb.translate.v3po.test.ContextTestUtils;
 import io.fd.honeycomb.translate.v3po.test.ListReaderCustomizerTest;
-import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import org.junit.Test;
-import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.mockito.Mock;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession;
@@ -58,23 +55,16 @@ public class ClassifySessionReaderTest extends
     private static final int TABLE_INDEX = 1;
     private static final String TABLE_NAME = "table1";
 
-    private NamingContext classifyTableContext;
+    @Mock
+    private VppClassifierContextManager classifierContext;
 
     public ClassifySessionReaderTest() {
         super(ClassifySession.class);
     }
 
-    @Override
-    public void setUpBefore() {
-        classifyTableContext = new NamingContext("classifyTableContext", "test-instance");
-
-        final Optional<Mapping> ifcMapping = ContextTestUtils.getMapping(TABLE_NAME, TABLE_INDEX);
-        doReturn(ifcMapping).when(mappingContext).read(any());
-    }
-
     @Override
     protected ReaderCustomizer<ClassifySession, ClassifySessionBuilder> initCustomizer() {
-        return new ClassifySessionReader(api, classifyTableContext);
+        return new ClassifySessionReader(api, classifierContext);
     }
 
     private static InstanceIdentifier<ClassifySession> getClassifySessionId(final String tableName,
@@ -127,6 +117,9 @@ public class ClassifySessionReaderTest extends
         replyFuture.complete(dump);
         doReturn(replyFuture).when(api).classifySessionDump(any(ClassifySessionDump.class));
 
+        when(classifierContext.containsTable(TABLE_NAME, mappingContext)).thenReturn(true);
+        when(classifierContext.getTableIndex(TABLE_NAME, mappingContext)).thenReturn(TABLE_INDEX);
+
         final List<ClassifySessionKey> allIds = getCustomizer().getAllIds(id, ctx);
         assertEquals(2, allIds.size());
         assertEquals(MATCH_1, allIds.get(0).getMatch().getValue());
index 85f7b86..d7d7ded 100644 (file)
 
 package io.fd.honeycomb.translate.v3po.vppclassifier;
 
-import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMapping;
-import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
 import com.google.common.base.Optional;
 import io.fd.honeycomb.translate.MappingContext;
 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;
@@ -38,12 +38,12 @@ import org.junit.Before;
 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.Mapping;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey;
@@ -66,21 +66,26 @@ public class ClassifySessionWriterTest {
     @Mock
     private WriteContext writeContext;
     @Mock
-    private MappingContext mappingContext;
+    private MappingContext ctx;
+    @Mock
+    private VppClassifierContextManager classfierContext;
 
-    private NamingContext classifyTableContext;
     private ClassifySessionWriter customizer;
     private static final int SESSION_INDEX = 456;
 
     @Before
     public void setUp() throws Exception {
         initMocks(this);
-        classifyTableContext = new NamingContext("generatedClassifyTableName", "test-instance");
-        doReturn(mappingContext).when(writeContext).getMappingContext();
-        customizer = new ClassifySessionWriter(api, classifyTableContext);
+        doReturn(ctx).when(writeContext).getMappingContext();
+        customizer = new ClassifySessionWriter(api, classfierContext);
+
+        when(classfierContext.containsTable(TABLE_NAME, ctx)).thenReturn(true);
+        when(classfierContext.getTableIndex(TABLE_NAME, ctx)).thenReturn(TABLE_INDEX);
 
-        final Optional<Mapping> ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX);
-        doReturn(ifcMapping).when(mappingContext).read(any());
+        final ClassifyTable table = mock(ClassifyTable.class);
+        when(table.getClassifierNode()).thenReturn(new VppNodeName("ip4-classifier"));
+        when(writeContext.readAfter(any())).thenReturn(Optional.of(table));
+        when(writeContext.readBefore(any())).thenReturn(Optional.of(table));
     }
 
     private static ClassifySession generateClassifySession(final long opaqueIndex, final String match) {
index 38ca324..d4a8c43 100644 (file)
@@ -23,21 +23,16 @@ import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import com.google.common.base.Optional;
-import com.google.common.collect.Lists;
+import io.fd.honeycomb.translate.read.ReadFailedException;
 import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
-import io.fd.honeycomb.translate.v3po.test.ContextTestUtils;
 import io.fd.honeycomb.translate.v3po.test.ListReaderCustomizerTest;
-import io.fd.honeycomb.translate.read.ReadFailedException;
-import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import org.junit.Test;
-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;
-import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey;
+import org.mockito.Mock;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierState;
@@ -47,7 +42,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.clas
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.openvpp.jvpp.core.dto.ClassifyTableIds;
 import org.openvpp.jvpp.core.dto.ClassifyTableIdsReply;
 import org.openvpp.jvpp.core.dto.ClassifyTableInfo;
@@ -61,32 +55,16 @@ public class ClassifyTableReaderTest extends
     private static final int TABLE_INDEX_2 = 2;
     private static final String TABLE_NAME_2 = "table2";
 
-    private NamingContext classifyTableContext;
+    @Mock
+    private VppClassifierContextManager classifierContext;
 
     public ClassifyTableReaderTest() {
         super(ClassifyTable.class);
     }
 
-    @Override
-    public void setUpBefore() {
-        classifyTableContext = new NamingContext("classifyTableContext", "test-instance");
-
-        final KeyedInstanceIdentifier<Mapping, MappingKey> t0Id = ContextTestUtils
-                .getMappingIid(TABLE_NAME_1, "test-instance");
-        final KeyedInstanceIdentifier<Mapping, MappingKey> t1Id = ContextTestUtils
-                .getMappingIid(TABLE_NAME_2, "test-instance");
-        final Optional<Mapping> t0 = ContextTestUtils.getMapping(TABLE_NAME_1, TABLE_INDEX_1);
-        final Optional<Mapping> t1 = ContextTestUtils.getMapping(TABLE_NAME_2, TABLE_INDEX_2);
-        final List<Mapping> allMappings = Lists.newArrayList(t0.get(), t1.get());
-        final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build();
-        doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(t0Id.firstIdentifierOf(Mappings.class));
-        doReturn(t0).when(mappingContext).read(t0Id);
-        doReturn(t1).when(mappingContext).read(t1Id);
-    }
-
     @Override
     protected ReaderCustomizer<ClassifyTable, ClassifyTableBuilder> initCustomizer() {
-        return new ClassifyTableReader(api, classifyTableContext);
+        return new ClassifyTableReader(api, classifierContext);
     }
 
     private static InstanceIdentifier<ClassifyTable> getClassifyTableId(final String name) {
@@ -131,6 +109,10 @@ public class ClassifyTableReaderTest extends
         replyFuture.complete(generateClassifyTableInfoReply());
         doReturn(replyFuture).when(api).classifyTableInfo(any(ClassifyTableInfo.class));
 
+        when(classifierContext.containsTable(TABLE_NAME_1, mappingContext)).thenReturn(true);
+        when(classifierContext.getTableIndex(TABLE_NAME_1, mappingContext)).thenReturn(TABLE_INDEX_1);
+        when(classifierContext.getTableBaseNode(TABLE_NAME_1, mappingContext)).thenReturn(Optional.absent());
+
         final ClassifyTableBuilder builder = mock(ClassifyTableBuilder.class);
         getCustomizer().readCurrentAttributes(getClassifyTableId(TABLE_NAME_1), builder, ctx);
 
@@ -145,6 +127,9 @@ public class ClassifyTableReaderTest extends
         replyFuture.complete(reply);
         doReturn(replyFuture).when(api).classifyTableIds(any(ClassifyTableIds.class));
 
+        when(classifierContext.getTableName(TABLE_INDEX_1, mappingContext)).thenReturn(TABLE_NAME_1);
+        when(classifierContext.getTableName(TABLE_INDEX_2, mappingContext)).thenReturn(TABLE_NAME_2);
+
         final List<ClassifyTableKey> allIds = getCustomizer().getAllIds(getClassifyTableId(TABLE_NAME_1), ctx);
 
         assertEquals(reply.ids.length, allIds.size());
index 5a3717e..af91ead 100644 (file)
 
 package io.fd.honeycomb.translate.v3po.vppclassifier;
 
-import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMapping;
-import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMappingIid;
-import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
-import com.google.common.base.Optional;
 import io.fd.honeycomb.translate.MappingContext;
 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;
@@ -41,11 +37,11 @@ import org.junit.Before;
 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.Mapping;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
@@ -66,22 +62,23 @@ public class ClassifyTableWriterTest {
     @Mock
     private WriteContext writeContext;
     @Mock
-    private MappingContext mappingContext;
+    private MappingContext ctx;
+    @Mock
+    private VppClassifierContextManager classifierContext;
 
-    private NamingContext classifyTableContext;
     private ClassifyTableWriter customizer;
 
     @Before
     public void setUp() throws Exception {
         initMocks(this);
-        classifyTableContext = new NamingContext("generatedClassifyTableName", "test-instance");
-        doReturn(mappingContext).when(writeContext).getMappingContext();
-        customizer = new ClassifyTableWriter(api, classifyTableContext);
+        customizer = new ClassifyTableWriter(api, classifierContext);
+        doReturn(ctx).when(writeContext).getMappingContext();
     }
 
     private static ClassifyTable generateClassifyTable(final String name) {
         final ClassifyTableBuilder builder = new ClassifyTableBuilder();
         builder.setName(name);
+        builder.setClassifierNode(new VppNodeName("ip4-classifier"));
         builder.setKey(new ClassifyTableKey(name));
         builder.setSkipNVectors(0L);
         builder.setNbuckets(2L);
@@ -158,8 +155,7 @@ public class ClassifyTableWriterTest {
         customizer.writeCurrentAttributes(id, classifyTable, writeContext);
 
         verifyClassifyAddDelTableAddWasInvoked(generateClassifyAddDelTable((byte) 1, TABLE_INDEX));
-        verify(mappingContext)
-            .put(eq(getMappingIid(TABLE_NAME, "test-instance")), eq(getMapping(TABLE_NAME, TABLE_INDEX).get()));
+        verify(classifierContext).addTable(TABLE_INDEX, classifyTable.getName(), classifyTable.getClassifierNode(), ctx);
     }
 
     @Test
@@ -174,9 +170,8 @@ public class ClassifyTableWriterTest {
         } catch (WriteFailedException.CreateFailedException e) {
             assertTrue(e.getCause() instanceof VppBaseCallException);
             verifyClassifyAddDelTableAddWasInvoked(generateClassifyAddDelTable((byte) 1, TABLE_INDEX));
-            verify(mappingContext, times(0)).put(
-                eq(getMappingIid(TABLE_NAME, "test-instance")),
-                eq(getMapping(TABLE_NAME, TABLE_INDEX).get()));
+            verify(classifierContext, times(0))
+                .addTable(TABLE_INDEX, classifyTable.getName(), classifyTable.getClassifierNode(), ctx);
             return;
         }
         fail("WriteFailedException.CreateFailedException was expected");
@@ -187,9 +182,8 @@ public class ClassifyTableWriterTest {
         final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME);
         final InstanceIdentifier<ClassifyTable> id = getClassifyTableId(TABLE_NAME);
 
-        final Optional<Mapping> ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX);
-        doReturn(ifcMapping).when(mappingContext).read(any());
-
+        when(classifierContext.containsTable(TABLE_NAME, ctx)).thenReturn(true);
+        when(classifierContext.getTableIndex(TABLE_NAME, ctx)).thenReturn(TABLE_INDEX);
         whenClassifyAddDelTableThenSuccess();
 
         customizer.deleteCurrentAttributes(id, classifyTable, writeContext);
@@ -202,9 +196,8 @@ public class ClassifyTableWriterTest {
         final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME);
         final InstanceIdentifier<ClassifyTable> id = getClassifyTableId(TABLE_NAME);
 
-        final Optional<Mapping> ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX);
-        doReturn(ifcMapping).when(mappingContext).read(any());
-
+        when(classifierContext.containsTable(TABLE_NAME, ctx)).thenReturn(true);
+        when(classifierContext.getTableIndex(TABLE_NAME, ctx)).thenReturn(TABLE_INDEX);
         whenClassifyAddDelTableThenFailure();
 
         try {
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppClassifierContextManagerImplTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppClassifierContextManagerImplTest.java
new file mode 100644 (file)
index 0000000..cbc0c38
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * 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.vppclassifier;
+
+import static io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManagerImpl.VPP_CLASSIFIER_CONTEXT_IID;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.VppClassifierContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.VppClassifierContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.ClassifyTableContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.ClassifyTableContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.ClassifyTableContextKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.classify.table.context.NodeContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.classify.table.context.NodeContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.classify.table.context.NodeContextKey;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+public class VppClassifierContextManagerImplTest {
+
+    private static final int TABLE_ID_0 = 0;
+    private static final String TABLE_NAME_0 = "table0";
+    private static final KeyedInstanceIdentifier<ClassifyTableContext, ClassifyTableContextKey> TABLE_IID_0 =
+        VPP_CLASSIFIER_CONTEXT_IID.child(ClassifyTableContext.class, new ClassifyTableContextKey(TABLE_NAME_0));
+
+    private static final int TABLE_ID_1 = 1;
+    private static final String TABLE_NAME_1 = "table1";
+
+    private VppClassifierContextManagerImpl vppClassfierContext;
+
+    @Mock
+    private MappingContext ctx;
+
+    @Before
+    public void setUp() throws Exception {
+        initMocks(this);
+        vppClassfierContext = new VppClassifierContextManagerImpl("classify-table-");
+    }
+
+    @Test
+    public void testAddTable() throws Exception {
+        final String classfierNodeName = "node123";
+        vppClassfierContext.addTable(TABLE_ID_0, TABLE_NAME_0, new VppNodeName(classfierNodeName), ctx);
+        verify(ctx).put(TABLE_IID_0, table(TABLE_ID_0, TABLE_NAME_0, classfierNodeName));
+    }
+
+    @Test
+    public void testContainsTable() throws Exception {
+        when(ctx.read(TABLE_IID_0)).thenReturn(Optional.absent());
+        assertFalse(vppClassfierContext.containsTable(TABLE_NAME_0, ctx));
+    }
+
+    @Test
+    public void testGetTableIndex() throws Exception {
+        when(ctx.read(TABLE_IID_0)).thenReturn(Optional.of(table(TABLE_ID_0, TABLE_NAME_0)));
+        assertEquals(TABLE_ID_0, vppClassfierContext.getTableIndex(TABLE_NAME_0, ctx));
+    }
+
+    @Test
+    public void testGetTableName() throws Exception {
+        when(ctx.read(VPP_CLASSIFIER_CONTEXT_IID))
+            .thenReturn(Optional.of(context(table(TABLE_ID_0, TABLE_NAME_0), table(TABLE_ID_1, TABLE_NAME_1))));
+        assertEquals(TABLE_NAME_0, (vppClassfierContext.getTableName(TABLE_ID_0, ctx)));
+    }
+
+    @Test
+    public void testGetTableBaseNode() throws Exception {
+        final String classfierNodeName = "node123";
+        when(ctx.read(TABLE_IID_0)).thenReturn(Optional.of(table(TABLE_ID_0, TABLE_NAME_0, classfierNodeName)));
+        vppClassfierContext.getTableBaseNode(TABLE_NAME_0, ctx);
+        assertEquals(Optional.of(classfierNodeName), (vppClassfierContext.getTableBaseNode(TABLE_NAME_0, ctx)));
+    }
+
+    @Test
+    public void testRemoveTable() throws Exception {
+        vppClassfierContext.removeTable(TABLE_NAME_0, ctx);
+        verify(ctx).delete(TABLE_IID_0);
+    }
+
+    @Test
+    public void testAddNodeName() throws Exception {
+        final String nodeName = "node123";
+        final int nodeIndex = 1;
+
+        vppClassfierContext.addNodeName(TABLE_NAME_0, nodeIndex, nodeName, ctx);
+        verify(ctx).put(
+            TABLE_IID_0.child(NodeContext.class, new NodeContextKey(nodeName)),
+            node(nodeName, nodeIndex)
+        );
+    }
+
+    @Test
+    public void testGetNonExistingNodeName() throws Exception {
+        when(ctx.read(VPP_CLASSIFIER_CONTEXT_IID)).thenReturn(Optional.of(context(table(TABLE_ID_1, TABLE_NAME_1))));
+        assertFalse(vppClassfierContext.getNodeName(TABLE_ID_0, 123, ctx).isPresent());
+    }
+
+    @Test
+    public void testGetNodeName() throws Exception {
+        final ClassifyTableContext tableCtx = table(TABLE_ID_0, TABLE_NAME_0, "aa", node("node123", 123));
+        when(ctx.read(VPP_CLASSIFIER_CONTEXT_IID)).thenReturn(Optional.of(context(tableCtx)));
+        when(ctx.read(TABLE_IID_0)).thenReturn(Optional.of(tableCtx));
+        assertEquals(Optional.of("node123"), vppClassfierContext.getNodeName(TABLE_ID_0, 123, ctx));
+    }
+
+    private VppClassifierContext context(ClassifyTableContext... tables) {
+        VppClassifierContextBuilder context = new VppClassifierContextBuilder();
+        context.setClassifyTableContext(Arrays.asList(tables));
+        return context.build();
+    }
+
+    private static ClassifyTableContext table(final Integer id, final String name) {
+        return table(id, name, null);
+    }
+
+    private static ClassifyTableContext table(final Integer id, final String name, final String classfierNodeName,
+                                              final NodeContext... nodeContexts) {
+        final ClassifyTableContextBuilder builder =
+            new ClassifyTableContextBuilder().setIndex(id).setName(name).setClassifierNodeName(classfierNodeName);
+
+        if (nodeContexts.length > 0) {
+            builder.setNodeContext(Arrays.asList(nodeContexts));
+        }
+
+        return builder.build();
+    }
+
+    private NodeContext node(final String nodeName, final int nodeIndex) {
+        return new NodeContextBuilder().setName(nodeName).setIndex(nodeIndex).build();
+    }
+}
\ No newline at end of file