Add Vhost User implementation for VPP 91/39391/11
authorMichal Cmarada <mcmarada@cisco.com>
Mon, 30 May 2016 06:41:06 +0000 (08:41 +0200)
committerMichal Cmarada <mcmarada@cisco.com>
Mon, 30 May 2016 13:54:14 +0000 (15:54 +0200)
Change-Id: I3e2245e5152e8129f607fdcd632d84aabfe83c05
Signed-off-by: Michal Cmarada <mcmarada@cisco.com>
renderers/vpp/pom.xml
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/AbstractInterfaceCommand.java [new file with mode: 0644]
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/ConfigCommand.java [new file with mode: 0644]
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommand.java [new file with mode: 0644]
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/General.java [new file with mode: 0644]
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppIidFactory.java [new file with mode: 0644]
renderers/vpp/src/main/yang/vbd/ietf-ip@2014-06-16.yang [new file with mode: 0644]
renderers/vpp/src/main/yang/vbd/v3po@2015-01-05.yang [new file with mode: 0644]
renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/CustomDataBrokerTest.java [new file with mode: 0644]
renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/VppRendererDataBrokerTest.java [new file with mode: 0644]
renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommandTest.java [new file with mode: 0644]

index 0a1df5f39d30dfbc689dd2772035d764e6ae5f61..3ea402b0ca56eb32419ebcd3824a2f3432276a31 100644 (file)
 
   <dependencies>
     <!-- project specific dependencies -->
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-yang-types-20130715</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-inet-types-2013-07-15</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>yang-ext</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>iana-if-type-2014-05-08</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-interfaces</artifactId>
+    </dependency>
 
     <!-- testing dependencies -->
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-broker-impl</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
@@ -50,7 +76,7 @@
           <instructions>
             <Export-Package>
               org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.*
-            </Export-Package> -->
+            </Export-Package>
           </instructions>
         </configuration>
       </plugin>
diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/AbstractInterfaceCommand.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/AbstractInterfaceCommand.java
new file mode 100644 (file)
index 0000000..0493631
--- /dev/null
@@ -0,0 +1,50 @@
+/*\r
+ * Copyright (c) 2016 Cisco Systems. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.renderer.vpp.commands;\r
+\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;\r
+\r
+public abstract class AbstractInterfaceCommand<T extends AbstractInterfaceCommand<T>> implements ConfigCommand {\r
+\r
+    protected General.Operations operation;\r
+    protected String name;\r
+    protected String description;\r
+    protected Boolean enabled;\r
+\r
+    protected enum linkUpDownTrap {\r
+        ENABLED, DISABLED\r
+    }\r
+\r
+    public General.Operations getOperation() {\r
+        return operation;\r
+    }\r
+\r
+    public String getName() {\r
+        return name;\r
+    }\r
+\r
+    public String getDescription() {\r
+        return description;\r
+    }\r
+\r
+    public AbstractInterfaceCommand<T> setDescription(String description) {\r
+        this.description = description;\r
+        return this;\r
+    }\r
+\r
+    public Boolean getEnabled() {\r
+        return enabled;\r
+    }\r
+\r
+    public AbstractInterfaceCommand<T> setEnabled(Boolean enabled) {\r
+        this.enabled = enabled;\r
+        return this;\r
+    }\r
+\r
+}\r
diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/ConfigCommand.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/ConfigCommand.java
new file mode 100644 (file)
index 0000000..cd8b690
--- /dev/null
@@ -0,0 +1,22 @@
+/*\r
+ * Copyright (c) 2016 Cisco Systems. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.renderer.vpp.commands;\r
+\r
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;\r
+\r
+public interface ConfigCommand {\r
+\r
+    /**\r
+     * Execute command using a given data modification transaction\r
+     *\r
+     * @param readWriteTransaction Transaction for command execution\r
+     */\r
+    void execute(ReadWriteTransaction readWriteTransaction);\r
+\r
+}\r
diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommand.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommand.java
new file mode 100644 (file)
index 0000000..a47d04f
--- /dev/null
@@ -0,0 +1,221 @@
+/*\r
+ * Copyright (c) 2016 Cisco Systems. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.renderer.vpp.commands;\r
+\r
+import com.google.common.base.Preconditions;\r
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;\r
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUserBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBasedBuilder;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+public class VhostUserCommand extends AbstractInterfaceCommand {\r
+\r
+    private static final Logger LOG = LoggerFactory.getLogger(VhostUserCommand.class);\r
+    private String socket;\r
+    private VhostUserRole role;\r
+    private String bridgeDomain;\r
+\r
+    private VhostUserCommand(VhostUserCommandBuilder builder) {\r
+        this.name = builder.getName();\r
+        this.operation = builder.getOperation();\r
+        this.socket = builder.getSocket();\r
+        this.role = builder.getRole();\r
+        this.enabled = builder.isEnabled();\r
+        this.description = builder.getDescription();\r
+        this.bridgeDomain = builder.getBridgeDomain();\r
+\r
+    }\r
+\r
+    public static VhostUserCommandBuilder builder() {\r
+        return new VhostUserCommandBuilder();\r
+    }\r
+\r
+    public String getSocket() {\r
+        return socket;\r
+    }\r
+\r
+    public VhostUserRole getRole() {\r
+        return role;\r
+    }\r
+\r
+    public String getBridgeDomain() {\r
+        return bridgeDomain;\r
+    }\r
+\r
+    @Override\r
+    public void execute(ReadWriteTransaction readWriteTransaction) {\r
+        switch (getOperation()) {\r
+\r
+            case PUT:\r
+                LOG.info("Executing Add operation for command: {}", this);\r
+                put(readWriteTransaction);\r
+                break;\r
+            case DELETE:\r
+                LOG.info("Executing Delete operation for command: {}", this);\r
+                delete(readWriteTransaction);\r
+                break;\r
+            case MERGE:\r
+                LOG.info("Executing Update operation for command: {}", this);\r
+                merge(readWriteTransaction);\r
+                break;\r
+            default:\r
+                LOG.error("Execution failed for command: {}", this);\r
+                break;\r
+        }\r
+    }\r
+\r
+    private void put(ReadWriteTransaction readWriteTransaction) {\r
+        Preconditions.checkNotNull(name, "Interface name should not be null");\r
+\r
+        InterfaceBuilder interfaceBuilder = getVhostUserInterfaceBuilder();\r
+\r
+        readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION,\r
+                VppIidFactory.getInterfaceIID(interfaceBuilder.getKey()), interfaceBuilder.build(), true);\r
+    }\r
+\r
+    private void merge(ReadWriteTransaction readWriteTransaction) {\r
+        Preconditions.checkNotNull(name, "Interface name should not be null");\r
+\r
+        InterfaceBuilder interfaceBuilder = getVhostUserInterfaceBuilder();\r
+\r
+            readWriteTransaction.merge(LogicalDatastoreType.CONFIGURATION,\r
+                    VppIidFactory.getInterfaceIID(interfaceBuilder.getKey()), interfaceBuilder.build());\r
+    }\r
+\r
+    private InterfaceBuilder getVhostUserInterfaceBuilder() {\r
+        InterfaceBuilder interfaceBuilder =\r
+                new InterfaceBuilder().setKey(new InterfaceKey(name))\r
+                        .setEnabled(enabled)\r
+                        .setDescription(description)\r
+                        .setType(\r
+                                org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class)\r
+                        .setName(name)\r
+                        .setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Enabled);\r
+\r
+        // Create the vhost augmentation\r
+        VppInterfaceAugmentation vppAugmentation =\r
+                new VppInterfaceAugmentationBuilder()\r
+                        .setVhostUser(new VhostUserBuilder().setRole(role).setSocket(socket).build())\r
+                        .setL2(new L2Builder()\r
+                                .setInterconnection(new BridgeBasedBuilder().setBridgeDomain(bridgeDomain).build()).build())\r
+                        .build();\r
+\r
+        interfaceBuilder.addAugmentation(VppInterfaceAugmentation.class, vppAugmentation);\r
+        return interfaceBuilder;\r
+    }\r
+\r
+    private void delete(ReadWriteTransaction readWriteTransaction) {\r
+        try {\r
+            readWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION,\r
+                    VppIidFactory.getInterfaceIID(new InterfaceKey(name)));\r
+        } catch (IllegalStateException ex) {\r
+            LOG.debug("Vhost Interface is not present in DS", ex);\r
+        }\r
+\r
+    }\r
+\r
+    public static class VhostUserCommandBuilder {\r
+\r
+        private String name;\r
+        private General.Operations operation;\r
+        private String socket;\r
+        private VhostUserRole role = VhostUserRole.Server;\r
+        private boolean enabled = true;\r
+        private String description;\r
+        private String bridgeDomain;\r
+\r
+        public String getName() {\r
+            return name;\r
+        }\r
+\r
+        public VhostUserCommandBuilder setName(String name) {\r
+            this.name = name;\r
+            return this;\r
+        }\r
+\r
+        public General.Operations getOperation() {\r
+            return operation;\r
+        }\r
+\r
+        public VhostUserCommandBuilder setOperation(General.Operations operation) {\r
+            this.operation = operation;\r
+            return this;\r
+        }\r
+\r
+        public String getSocket() {\r
+            return socket;\r
+        }\r
+\r
+        public VhostUserCommandBuilder setSocket(String socket) {\r
+            this.socket = socket;\r
+            return this;\r
+        }\r
+\r
+        public VhostUserRole getRole() {\r
+            return role;\r
+        }\r
+\r
+        public VhostUserCommandBuilder setRole(VhostUserRole role) {\r
+            this.role = role;\r
+            return this;\r
+        }\r
+\r
+        public boolean isEnabled() {\r
+            return enabled;\r
+        }\r
+\r
+        public VhostUserCommandBuilder setEnabled(boolean enabled) {\r
+            this.enabled = enabled;\r
+            return this;\r
+        }\r
+\r
+        public String getDescription() {\r
+            return description;\r
+        }\r
+\r
+        public VhostUserCommandBuilder setDescription(String description) {\r
+            this.description = description;\r
+            return this;\r
+        }\r
+\r
+        public String getBridgeDomain() {\r
+            return bridgeDomain;\r
+        }\r
+\r
+        public VhostUserCommandBuilder setBridgeDomain(String bridgeDomain) {\r
+            this.bridgeDomain = bridgeDomain;\r
+            return this;\r
+        }\r
+\r
+        /**\r
+         * VhostUserCommand build method.\r
+         *\r
+         * @return VhostUserCommand\r
+         * @throws IllegalArgumentException if name, operation or socket is null.\r
+         */\r
+        public VhostUserCommand build() {\r
+            Preconditions.checkArgument(this.name != null);\r
+            Preconditions.checkArgument(this.operation != null);\r
+            Preconditions.checkArgument(this.socket != null);\r
+\r
+            return new VhostUserCommand(this);\r
+        }\r
+    }\r
+}\r
diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/General.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/General.java
new file mode 100644 (file)
index 0000000..ab59e4b
--- /dev/null
@@ -0,0 +1,31 @@
+/*\r
+ * Copyright (c) 2016 Cisco Systems. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.renderer.vpp.util;\r
+\r
+\r
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;\r
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.yangtools.yang.binding.DataObject;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+\r
+public class General {\r
+\r
+    /**\r
+     * Operations that can be executed over ConfigCommand. Operation names reflect operations used in WriteTransaction.\r
+     * For more information on these operations, please see the documentation in:\r
+     * <br>\r
+     * {@link WriteTransaction#put(LogicalDatastoreType, InstanceIdentifier, DataObject, boolean)}<br>\r
+     * {@link WriteTransaction#merge(LogicalDatastoreType, InstanceIdentifier, DataObject, boolean)}<br>\r
+     * {@link WriteTransaction#delete(LogicalDatastoreType, InstanceIdentifier)}<br>\r
+     *\r
+     */\r
+    public enum Operations {\r
+        PUT, DELETE, MERGE\r
+    }\r
+}\r
diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppIidFactory.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppIidFactory.java
new file mode 100644 (file)
index 0000000..19a672c
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016 Cisco Systems. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.vpp.util;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class VppIidFactory {
+
+    public static InstanceIdentifier<Interface> getInterfaceIID(InterfaceKey interfaceKey) {
+        return InstanceIdentifier.create(Interfaces.class).child(Interface.class, interfaceKey);
+    }
+}
diff --git a/renderers/vpp/src/main/yang/vbd/ietf-ip@2014-06-16.yang b/renderers/vpp/src/main/yang/vbd/ietf-ip@2014-06-16.yang
new file mode 100644 (file)
index 0000000..f6c59ed
--- /dev/null
@@ -0,0 +1,742 @@
+module ietf-ip {
+
+  yang-version 1;
+
+  namespace
+    "urn:ietf:params:xml:ns:yang:ietf-ip";
+
+  prefix ip;
+
+  import ietf-interfaces {
+    prefix if;
+  }
+  import ietf-inet-types {
+    prefix inet;
+  }
+  import ietf-yang-types {
+    prefix yang;
+  }
+
+  organization
+    "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+  contact
+    "WG Web:   <http://tools.ietf.org/wg/netmod/>
+  WG List:  <mailto:netmod@ietf.org>
+
+  WG Chair: Thomas Nadeau
+            <mailto:tnadeau@lucidvision.com>
+
+  WG Chair: Juergen Schoenwaelder
+            <mailto:j.schoenwaelder@jacobs-university.de>
+
+  Editor:   Martin Bjorklund
+            <mailto:mbj@tail-f.com>";
+
+  description
+    "This module contains a collection of YANG definitions for
+  configuring IP implementations.
+
+  Copyright (c) 2014 IETF Trust and the persons identified as
+  authors of the code.  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or
+  without modification, is permitted pursuant to, and subject
+  to the license terms contained in, the Simplified BSD License
+  set forth in Section 4.c of the IETF Trust's Legal Provisions
+  Relating to IETF Documents
+  (http://trustee.ietf.org/license-info).
+
+  This version of this YANG module is part of RFC 7277; see
+  the RFC itself for full legal notices.";
+
+  revision "2014-06-16" {
+    description "Initial revision.";
+    reference
+      "RFC 7277: A YANG Data Model for IP Management";
+
+  }
+
+
+  feature ipv4-non-contiguous-netmasks {
+    description
+      "Indicates support for configuring non-contiguous
+    subnet masks.";
+  }
+
+  feature ipv6-privacy-autoconf {
+    description
+      "Indicates support for Privacy Extensions for Stateless Address
+    Autoconfiguration in IPv6.";
+    reference
+      "RFC 4941: Privacy Extensions for Stateless Address
+         Autoconfiguration in IPv6";
+
+  }
+
+  typedef ip-address-origin {
+    type enumeration {
+      enum "other" {
+        value 0;
+        description
+          "None of the following.";
+      }
+      enum "static" {
+        value 1;
+        description
+          "Indicates that the address has been statically
+        configured - for example, using NETCONF or a Command Line
+        Interface.";
+      }
+      enum "dhcp" {
+        value 2;
+        description
+          "Indicates an address that has been assigned to this
+        system by a DHCP server.";
+      }
+      enum "link-layer" {
+        value 3;
+        description
+          "Indicates an address created by IPv6 stateless
+        autoconfiguration that embeds a link-layer address in its
+        interface identifier.";
+      }
+      enum "random" {
+        value 4;
+        description
+          "Indicates an address chosen by the system at
+
+        random, e.g., an IPv4 address within 169.254/16, an
+        RFC 4941 temporary address, or an RFC 7217 semantically
+        opaque address.";
+        reference
+          "RFC 4941: Privacy Extensions for Stateless Address
+                 Autoconfiguration in IPv6
+           RFC 7217: A Method for Generating Semantically Opaque
+                 Interface Identifiers with IPv6 Stateless
+                 Address Autoconfiguration (SLAAC)";
+
+      }
+    }
+    description
+      "The origin of an address.";
+  }
+
+  typedef neighbor-origin {
+    type enumeration {
+      enum "other" {
+        value 0;
+        description
+          "None of the following.";
+      }
+      enum "static" {
+        value 1;
+        description
+          "Indicates that the mapping has been statically
+        configured - for example, using NETCONF or a Command Line
+        Interface.";
+      }
+      enum "dynamic" {
+        value 2;
+        description
+          "Indicates that the mapping has been dynamically resolved
+        using, e.g., IPv4 ARP or the IPv6 Neighbor Discovery
+        protocol.";
+      }
+    }
+    description
+      "The origin of a neighbor entry.";
+  }
+
+  augment /if:interfaces/if:interface {
+    description
+      "Parameters for configuring IP on interfaces.
+
+    If an interface is not capable of running IP, the server
+    must not allow the client to configure these parameters.";
+    container ipv4 {
+      presence
+        "Enables IPv4 unless the 'enabled' leaf
+      (which defaults to 'true') is set to 'false'";
+      description
+        "Parameters for the IPv4 address family.";
+      leaf enabled {
+        type boolean;
+        default 'true';
+        description
+          "Controls whether IPv4 is enabled or disabled on this
+        interface.  When IPv4 is enabled, this interface is
+        connected to an IPv4 stack, and the interface can send
+        and receive IPv4 packets.";
+      }
+
+      leaf forwarding {
+        type boolean;
+        default 'false';
+        description
+          "Controls IPv4 packet forwarding of datagrams received by,
+        but not addressed to, this interface.  IPv4 routers
+        forward datagrams.  IPv4 hosts do not (except those
+        source-routed via the host).";
+      }
+
+      leaf mtu {
+        type uint16 {
+          range "68..max";
+        }
+        units "octets";
+        description
+          "The size, in octets, of the largest IPv4 packet that the
+        interface will send and receive.
+
+        The server may restrict the allowed values for this leaf,
+        depending on the interface's type.
+
+        If this leaf is not configured, the operationally used MTU
+        depends on the interface's type.";
+        reference
+          "RFC 791: Internet Protocol";
+
+      }
+
+      list address {
+        key "ip";
+        description
+          "The list of configured IPv4 addresses on the interface.";
+        leaf ip {
+          type inet:ipv4-address-no-zone;
+          description
+            "The IPv4 address on the interface.";
+        }
+
+        choice subnet {
+          mandatory true;
+          description
+            "The subnet can be specified as a prefix-length, or,
+          if the server supports non-contiguous netmasks, as
+          a netmask.";
+          leaf prefix-length {
+            type uint8 {
+              range "0..32";
+            }
+            description
+              "The length of the subnet prefix.";
+          }
+          leaf netmask {
+            if-feature ipv4-non-contiguous-netmasks;
+            type yang:dotted-quad;
+            description
+              "The subnet specified as a netmask.";
+          }
+        }  // choice subnet
+      }  // list address
+
+      list neighbor {
+        key "ip";
+        description
+          "A list of mappings from IPv4 addresses to
+        link-layer addresses.
+
+        Entries in this list are used as static entries in the
+        ARP Cache.";
+        reference
+          "RFC 826: An Ethernet Address Resolution Protocol";
+
+        leaf ip {
+          type inet:ipv4-address-no-zone;
+          description
+            "The IPv4 address of the neighbor node.";
+        }
+
+        leaf link-layer-address {
+          type yang:phys-address;
+          mandatory true;
+          description
+            "The link-layer address of the neighbor node.";
+        }
+      }  // list neighbor
+    }  // container ipv4
+
+    container ipv6 {
+      presence
+        "Enables IPv6 unless the 'enabled' leaf
+      (which defaults to 'true') is set to 'false'";
+      description
+        "Parameters for the IPv6 address family.";
+      leaf enabled {
+        type boolean;
+        default 'true';
+        description
+          "Controls whether IPv6 is enabled or disabled on this
+        interface.  When IPv6 is enabled, this interface is
+        connected to an IPv6 stack, and the interface can send
+        and receive IPv6 packets.";
+      }
+
+      leaf forwarding {
+        type boolean;
+        default 'false';
+        description
+          "Controls IPv6 packet forwarding of datagrams received by,
+        but not addressed to, this interface.  IPv6 routers
+        forward datagrams.  IPv6 hosts do not (except those
+        source-routed via the host).";
+        reference
+          "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
+                 Section 6.2.1, IsRouter";
+
+      }
+
+      leaf mtu {
+        type uint32 {
+          range "1280..max";
+        }
+        units "octets";
+        description
+          "The size, in octets, of the largest IPv6 packet that the
+        interface will send and receive.
+
+        The server may restrict the allowed values for this leaf,
+        depending on the interface's type.
+
+        If this leaf is not configured, the operationally used MTU
+        depends on the interface's type.";
+        reference
+          "RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+                 Section 5";
+
+      }
+
+      list address {
+        key "ip";
+        description
+          "The list of configured IPv6 addresses on the interface.";
+        leaf ip {
+          type inet:ipv6-address-no-zone;
+          description
+            "The IPv6 address on the interface.";
+        }
+
+        leaf prefix-length {
+          type uint8 {
+            range "0..128";
+          }
+          mandatory true;
+          description
+            "The length of the subnet prefix.";
+        }
+      }  // list address
+
+      list neighbor {
+        key "ip";
+        description
+          "A list of mappings from IPv6 addresses to
+        link-layer addresses.
+
+        Entries in this list are used as static entries in the
+        Neighbor Cache.";
+        reference
+          "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
+
+        leaf ip {
+          type inet:ipv6-address-no-zone;
+          description
+            "The IPv6 address of the neighbor node.";
+        }
+
+        leaf link-layer-address {
+          type yang:phys-address;
+          mandatory true;
+          description
+            "The link-layer address of the neighbor node.";
+        }
+      }  // list neighbor
+
+      leaf dup-addr-detect-transmits {
+        type uint32;
+        default '1';
+        description
+          "The number of consecutive Neighbor Solicitation messages
+        sent while performing Duplicate Address Detection on a
+        tentative address.  A value of zero indicates that
+        Duplicate Address Detection is not performed on
+        tentative addresses.  A value of one indicates a single
+        transmission with no follow-up retransmissions.";
+        reference
+          "RFC 4862: IPv6 Stateless Address Autoconfiguration";
+
+      }
+
+      container autoconf {
+        description
+          "Parameters to control the autoconfiguration of IPv6
+        addresses, as described in RFC 4862.";
+        reference
+          "RFC 4862: IPv6 Stateless Address Autoconfiguration";
+
+        leaf create-global-addresses {
+          type boolean;
+          default 'true';
+          description
+            "If enabled, the host creates global addresses as
+          described in RFC 4862.";
+          reference
+            "RFC 4862: IPv6 Stateless Address Autoconfiguration
+                 Section 5.5";
+
+        }
+
+        leaf create-temporary-addresses {
+          if-feature ipv6-privacy-autoconf;
+          type boolean;
+          default 'false';
+          description
+            "If enabled, the host creates temporary addresses as
+          described in RFC 4941.";
+          reference
+            "RFC 4941: Privacy Extensions for Stateless Address
+                 Autoconfiguration in IPv6";
+
+        }
+
+        leaf temporary-valid-lifetime {
+          if-feature ipv6-privacy-autoconf;
+          type uint32;
+          units "seconds";
+          default '604800';
+          description
+            "The time period during which the temporary address
+          is valid.";
+          reference
+            "RFC 4941: Privacy Extensions for Stateless Address
+                 Autoconfiguration in IPv6
+                 - TEMP_VALID_LIFETIME";
+
+        }
+
+        leaf temporary-preferred-lifetime {
+          if-feature ipv6-privacy-autoconf;
+          type uint32;
+          units "seconds";
+          default '86400';
+          description
+            "The time period during which the temporary address is
+          preferred.";
+          reference
+            "RFC 4941: Privacy Extensions for Stateless Address
+                 Autoconfiguration in IPv6
+                 - TEMP_PREFERRED_LIFETIME";
+
+        }
+      }  // container autoconf
+    }  // container ipv6
+  }
+
+  augment /if:interfaces-state/if:interface {
+    description
+      "Data nodes for the operational state of IP on interfaces.";
+    container ipv4 {
+      presence
+        "Present if IPv4 is enabled on this interface";
+      config false;
+      description
+        "Interface-specific parameters for the IPv4 address family.";
+      leaf forwarding {
+        type boolean;
+        description
+          "Indicates whether IPv4 packet forwarding is enabled or
+        disabled on this interface.";
+      }
+
+      leaf mtu {
+        type uint16 {
+          range "68..max";
+        }
+        units "octets";
+        description
+          "The size, in octets, of the largest IPv4 packet that the
+        interface will send and receive.";
+        reference
+          "RFC 791: Internet Protocol";
+
+      }
+
+      list address {
+        key "ip";
+        description
+          "The list of IPv4 addresses on the interface.";
+        leaf ip {
+          type inet:ipv4-address-no-zone;
+          description
+            "The IPv4 address on the interface.";
+        }
+
+        choice subnet {
+          description
+            "The subnet can be specified as a prefix-length, or,
+          if the server supports non-contiguous netmasks, as
+          a netmask.";
+          leaf prefix-length {
+            type uint8 {
+              range "0..32";
+            }
+            description
+              "The length of the subnet prefix.";
+          }
+          leaf netmask {
+            if-feature ipv4-non-contiguous-netmasks;
+            type yang:dotted-quad;
+            description
+              "The subnet specified as a netmask.";
+          }
+        }  // choice subnet
+
+        leaf origin {
+          type ip-address-origin;
+          description
+            "The origin of this address.";
+        }
+      }  // list address
+
+      list neighbor {
+        key "ip";
+        description
+          "A list of mappings from IPv4 addresses to
+        link-layer addresses.
+
+        This list represents the ARP Cache.";
+        reference
+          "RFC 826: An Ethernet Address Resolution Protocol";
+
+        leaf ip {
+          type inet:ipv4-address-no-zone;
+          description
+            "The IPv4 address of the neighbor node.";
+        }
+
+        leaf link-layer-address {
+          type yang:phys-address;
+          description
+            "The link-layer address of the neighbor node.";
+        }
+
+        leaf origin {
+          type neighbor-origin;
+          description
+            "The origin of this neighbor entry.";
+        }
+      }  // list neighbor
+    }  // container ipv4
+
+    container ipv6 {
+      presence
+        "Present if IPv6 is enabled on this interface";
+      config false;
+      description
+        "Parameters for the IPv6 address family.";
+      leaf forwarding {
+        type boolean;
+        default 'false';
+        description
+          "Indicates whether IPv6 packet forwarding is enabled or
+        disabled on this interface.";
+        reference
+          "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
+                 Section 6.2.1, IsRouter";
+
+      }
+
+      leaf mtu {
+        type uint32 {
+          range "1280..max";
+        }
+        units "octets";
+        description
+          "The size, in octets, of the largest IPv6 packet that the
+        interface will send and receive.";
+        reference
+          "RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+                 Section 5";
+
+      }
+
+      list address {
+        key "ip";
+        description
+          "The list of IPv6 addresses on the interface.";
+        leaf ip {
+          type inet:ipv6-address-no-zone;
+          description
+            "The IPv6 address on the interface.";
+        }
+
+        leaf prefix-length {
+          type uint8 {
+            range "0..128";
+          }
+          mandatory true;
+          description
+            "The length of the subnet prefix.";
+        }
+
+        leaf origin {
+          type ip-address-origin;
+          description
+            "The origin of this address.";
+        }
+
+        leaf status {
+          type enumeration {
+            enum "preferred" {
+              value 0;
+              description
+                "This is a valid address that can appear as the
+              destination or source address of a packet.";
+            }
+            enum "deprecated" {
+              value 1;
+              description
+                "This is a valid but deprecated address that should
+              no longer be used as a source address in new
+              communications, but packets addressed to such an
+              address are processed as expected.";
+            }
+            enum "invalid" {
+              value 2;
+              description
+                "This isn't a valid address, and it shouldn't appear
+              as the destination or source address of a packet.";
+            }
+            enum "inaccessible" {
+              value 3;
+              description
+                "The address is not accessible because the interface
+              to which this address is assigned is not
+              operational.";
+            }
+            enum "unknown" {
+              value 4;
+              description
+                "The status cannot be determined for some reason.";
+            }
+            enum "tentative" {
+              value 5;
+              description
+                "The uniqueness of the address on the link is being
+              verified.  Addresses in this state should not be
+              used for general communication and should only be
+              used to determine the uniqueness of the address.";
+            }
+            enum "duplicate" {
+              value 6;
+              description
+                "The address has been determined to be non-unique on
+              the link and so must not be used.";
+            }
+            enum "optimistic" {
+              value 7;
+              description
+                "The address is available for use, subject to
+              restrictions, while its uniqueness on a link is
+              being verified.";
+            }
+          }
+          description
+            "The status of an address.  Most of the states correspond
+          to states from the IPv6 Stateless Address
+          Autoconfiguration protocol.";
+          reference
+            "RFC 4293: Management Information Base for the
+                 Internet Protocol (IP)
+                 - IpAddressStatusTC
+             RFC 4862: IPv6 Stateless Address Autoconfiguration";
+
+        }
+      }  // list address
+
+      list neighbor {
+        key "ip";
+        description
+          "A list of mappings from IPv6 addresses to
+        link-layer addresses.
+
+        This list represents the Neighbor Cache.";
+        reference
+          "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
+
+        leaf ip {
+          type inet:ipv6-address-no-zone;
+          description
+            "The IPv6 address of the neighbor node.";
+        }
+
+        leaf link-layer-address {
+          type yang:phys-address;
+          description
+            "The link-layer address of the neighbor node.";
+        }
+
+        leaf origin {
+          type neighbor-origin;
+          description
+            "The origin of this neighbor entry.";
+        }
+
+        leaf is-router {
+          type empty;
+          description
+            "Indicates that the neighbor node acts as a router.";
+        }
+
+        leaf state {
+          type enumeration {
+            enum "incomplete" {
+              value 0;
+              description
+                "Address resolution is in progress, and the link-layer
+              address of the neighbor has not yet been
+              determined.";
+            }
+            enum "reachable" {
+              value 1;
+              description
+                "Roughly speaking, the neighbor is known to have been
+              reachable recently (within tens of seconds ago).";
+            }
+            enum "stale" {
+              value 2;
+              description
+                "The neighbor is no longer known to be reachable, but
+              until traffic is sent to the neighbor no attempt
+              should be made to verify its reachability.";
+            }
+            enum "delay" {
+              value 3;
+              description
+                "The neighbor is no longer known to be reachable, and
+              traffic has recently been sent to the neighbor.
+              Rather than probe the neighbor immediately, however,
+              delay sending probes for a short while in order to
+              give upper-layer protocols a chance to provide
+              reachability confirmation.";
+            }
+            enum "probe" {
+              value 4;
+              description
+                "The neighbor is no longer known to be reachable, and
+              unicast Neighbor Solicitation probes are being sent
+              to verify reachability.";
+            }
+          }
+          description
+            "The Neighbor Unreachability Detection state of this
+          entry.";
+          reference
+            "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
+                 Section 7.3.2";
+
+        }
+      }  // list neighbor
+    }  // container ipv6
+  }
+}  // module ietf-ip
diff --git a/renderers/vpp/src/main/yang/vbd/v3po@2015-01-05.yang b/renderers/vpp/src/main/yang/vbd/v3po@2015-01-05.yang
new file mode 100644 (file)
index 0000000..3a71ffd
--- /dev/null
@@ -0,0 +1,573 @@
+module v3po {
+  yang-version 1;
+  namespace "urn:opendaylight:params:xml:ns:yang:v3po";
+  prefix "v3po";
+
+  revision "2015-01-05" {
+    description "Initial revision of v3po model";
+  }
+
+  import iana-if-type {
+    prefix "ianaift";
+  }
+  import ietf-interfaces {
+    prefix "if";
+  }
+  import ietf-yang-types {
+    prefix "yang";
+  }
+  import ietf-inet-types {
+    prefix "inet";
+  }
+  import ietf-ip {
+    prefix "ip";
+  }
+  import yang-ext {
+    prefix "ext";
+  }
+
+  typedef bridge-domain-ref {
+    type leafref {
+      path "/vpp/bridge-domains/bridge-domain/name";
+    }
+    description
+      "This type is used by to reference a bridge domain table";
+  }
+
+  typedef bridged-virtual-interface-ref {
+    type leafref {
+      path "/if:interfaces/if:interface/l2/bridged-virtual-interface";
+    }
+    description
+      "This type is used by to reference a bridged virtual interface";
+  }
+
+  typedef vlan-type {
+    type enumeration {
+      enum 802dot1q;
+      enum 802dot1ad;
+    }
+  }
+
+  typedef tag-rewrite-operation {
+    type enumeration {
+      enum disabled;
+      enum push-1;
+      enum push-2;
+      enum pop-1;
+      enum pop-2;
+      enum translate-1-to-1;
+      enum translate-1-to-2;
+      enum translate-2-to-1;
+      enum translate-2-to-2;
+    }
+  }
+
+  typedef vlan-tag {
+    type uint16 {
+      range "1..4094";
+    }
+  }
+
+  identity vxlan-tunnel {
+    base if:interface-type;
+  }
+
+  identity vhost-user {
+    base if:interface-type;
+  }
+
+  identity tap {
+    base if:interface-type;
+  }
+
+  identity sub-interface {
+    base if:interface-type;
+  }
+
+  typedef vxlan-vni {
+    // FIXME: should be in a vxlan-specific model
+    description "VNI used in a VXLAN tunnel";
+    type uint32 {
+      range "0..16777215";
+    }
+  }
+
+  typedef vhost-user-role {
+    type enumeration {
+      enum "server";
+      enum "client";
+    }
+  }
+
+  grouping bridge-domain-attributes {
+    leaf flood {
+      type boolean;
+      default true;
+      description
+      "Enable/disable L2 flooding.";
+    }
+    leaf forward {
+      type boolean;
+      default true;
+      description
+      "Enable/disable L2 forwarding.";
+    }
+    leaf learn {
+      type boolean;
+      default true;
+      description
+      "Enable/disable L2 learning.";
+    }
+    leaf unknown-unicast-flood {
+      type boolean;
+      default true;
+    }
+    leaf arp-termination {
+      type boolean;
+      default false;
+    }
+  }
+
+  grouping sub-interface-base-attributes {
+    leaf identifier {
+      type uint32;
+    }
+    leaf vlan-type {
+      type vlan-type;
+      default '802dot1q';
+    }
+    leaf number-of-tags {
+      type uint8 {
+        range "0..2";
+      }
+      default 1;
+    }
+    leaf outer-id {
+      type vlan-tag;
+    }
+    leaf inner-id {
+      type vlan-tag;
+    }
+    leaf match-any-outer-id {
+      type empty;
+    }
+    leaf match-any-inner-id {
+      type empty;
+    }
+    leaf exact-match {
+      type empty;
+    }
+    leaf default-subif {
+      type empty;
+    }
+  }
+
+  grouping tap-interface-base-attributes {
+    leaf tap-name {
+      type string;
+    }
+  }
+
+  grouping tap-interface-config-attributes {
+    leaf mac {
+      type yang:phys-address;
+      mandatory false;
+      description "Mac address to be set for the tap interface. Random will be used if not configured";
+    }
+
+    leaf device-instance {
+      type uint32;
+      mandatory false;
+      description "Custom device instance. Autogenerated will be used if not configured";
+    }
+  }
+
+  grouping vhost-user-interface-base-attributes {
+    leaf socket {
+      type string {
+        length 1..255;
+      }
+    }
+    leaf role {
+      type vhost-user-role;
+      default "server";
+    }
+  }
+
+  grouping vhost-user-interface-state-attributes {
+      leaf features {
+        type uint64;
+        config false;
+      }
+      leaf virtio-net-hdr-size {
+        type uint32;
+        config false;
+      }
+      leaf num-memory-regions {
+        type uint32;
+        config false;
+      }
+      leaf connect-error {
+        type string;
+        config false;
+      }
+  }
+
+  grouping vlan-tag-rewrite-attributes {
+    leaf rewrite-operation {
+      type tag-rewrite-operation;
+      default 'disabled';
+    }
+    leaf first-pushed {
+      type vlan-type;
+      default '802dot1q';
+    }
+    leaf tag1 {
+      type vlan-tag;
+    }
+    leaf tag2 {
+      type vlan-tag;
+    }
+  }
+
+  augment /if:interfaces/if:interface {
+    ext:augment-identifier "vpp-interface-augmentation";
+
+    // FIXME using ietf-interfaces model for vpp interfaces makes it hard to implement because:
+    // 1. The link between interface type and this augmentation is unclear
+    // 2. Only this augmentation with combination of ifc type is trigger to do something for vpp, what if user only configures base interface stuff ? + We need to get leaves defined by ietf-interfaces when we are processing this augment
+
+    container sub-interface {
+      when "../if:type = 'v3po:sub-interface'";
+      leaf super-interface {
+        type if:interface-ref;
+      }
+      uses sub-interface-base-attributes;
+    }
+
+    container tap {
+      when "../if:type = 'v3po:tap'";
+      uses tap-interface-base-attributes;
+      uses tap-interface-config-attributes;
+    }
+
+    container ethernet {
+      when "../if:type = 'ianaift:ethernetCsmacd'";
+      leaf mtu {
+        type uint16 {
+          range "64..9216";
+        }
+        units "octets";
+        default 9216;
+        description
+        "The size, in octets, of the largest packet that the
+         hardware interface will send and receive.";
+      }
+    }
+    container routing {
+      leaf vrf-id {
+        type uint32;
+        default 0;
+      }
+    }
+    container vhost-user {
+      when "../if:type = 'v3po:vhost-user'";
+      uses vhost-user-interface-base-attributes;
+      description "vhost-user settings";
+    }
+    container vxlan {
+      // FIXME: this should be in an vxlan-specific extension
+      when "../if:type = 'v3po:vxlan-tunnel'";
+
+      leaf src {
+        /*mandatory true;*/
+        type inet:ip-address;
+      }
+      leaf dst {
+        /*mandatory true;*/
+        type inet:ip-address;
+      }
+      leaf vni {
+        /*mandatory true;*/
+        type vxlan-vni;
+      }
+      leaf encap-vrf-id {
+        type uint32;
+      }
+    }
+    container l2 {
+      description
+      "Parameters for configuring Layer2 features on interfaces.";
+      must "(not (../if:ipv4[if:enabled = 'true']/if:address/if:ip) and " +
+      "not (../if:ipv6[if:enabled = 'true']/if:address/if:ip))";
+
+      choice interconnection {
+        case xconnect-based {
+          leaf xconnect-outgoing-interface {
+            /* Don't allow selection of this interface */
+            must "../../if:name != current()";
+            type if:interface-ref;
+            description
+              "L2 xconnect mode";
+          }
+        }
+        case bridge-based {
+          leaf bridge-domain {
+            type bridge-domain-ref;
+            description
+              "Interfaces in a bridge-domain forward packets to other
+               interfaces in the same bridge-domain based on
+               destination mac address.";
+          }
+          leaf split-horizon-group {
+            when "../bridge-domain";
+            type uint8 {
+              range "0..255";
+            }
+            default 0;
+            description
+              "Interface's split-horizon group. Interfaces in the same
+               bridge-domain and split-horizon group can not forward
+               packets between each other. ";
+          }
+          leaf bridged-virtual-interface {
+            when "../bridge-domain";
+            type boolean;
+            default false;
+            description
+              "Interface forward packets in the bridge-domain
+               associated with the BVI.";
+          }
+        }
+      }
+      container vlan-tag-rewrite {
+        uses vlan-tag-rewrite-attributes;
+      }
+    }
+  }
+
+  container vpp {
+    description
+    "VPP config data";
+
+    container bridge-domains {
+      list bridge-domain {
+        key "name";
+        // TODO: where does this come from?
+        max-elements 1024;
+
+        leaf name {
+          type string;
+        }
+
+        uses bridge-domain-attributes;
+
+        list l2-fib {
+          key "phys-address";
+
+          leaf phys-address {
+            type yang:phys-address;
+          }
+          leaf action {
+            type enumeration {
+              enum "forward";
+              enum "filter";
+            }
+            mandatory true;
+          }
+          leaf outgoing-interface {
+            type if:interface-ref;
+          }
+        }
+      }
+    }
+  }
+
+  augment /if:interfaces-state/if:interface {
+    ext:augment-identifier "vpp-interface-state-augmentation";
+
+    leaf description {
+      type string;
+    }
+
+    container sub-interface {
+      when "../if:type = 'v3po:sub-interface'";
+      leaf super-interface {
+        type if:interface-state-ref;
+      }
+      uses sub-interface-base-attributes;
+    }
+
+    container tap {
+      when "../if:type = 'v3po:tap'";
+      uses tap-interface-base-attributes {
+        refine tap-name {
+            config false;
+        }
+      }
+    }
+
+    container ethernet {
+      when "../if:type = 'ianaift:ethernetCsmacd'";
+      leaf mtu {
+        type uint16;
+      }
+      leaf manufacturer-description {
+        type string;
+      }
+      leaf duplex {
+        type enumeration {
+          enum "half";
+          enum "full";
+        }
+      }
+    }
+    container vhost-user {
+      when "../if:type = 'v3po:vhost-user'";
+      uses vhost-user-interface-base-attributes {
+        refine socket {
+            config false;
+        }
+        refine role {
+            config false;
+        }
+      }
+      uses vhost-user-interface-state-attributes;
+    }
+    container vxlan {
+      when "../if:type = 'v3po:vxlan-tunnel'";
+
+      leaf src {
+        type inet:ip-address;
+      }
+      leaf dst {
+        type inet:ip-address;
+      }
+
+      leaf vni {
+        type uint32;
+      }
+      leaf encap-vrf-id {
+        type uint32;
+      }
+    }
+    container l2 {
+      choice interconnection {
+        case xconnect-based {
+          leaf xconnect-outgoing-interface {
+            type if:interface-ref;
+          }
+        }
+        case bridge-based {
+          leaf bridge-domain {
+            type bridge-domain-ref;
+          }
+          leaf split-horizon-group {
+            type uint8;
+          }
+          leaf bridged-virtual-interface {
+            type boolean;
+          }
+        }
+      }
+      container vlan-tag-rewrite {
+        uses vlan-tag-rewrite-attributes;
+      }
+    }
+  }
+
+  augment /if:interfaces-state/if:interface/if:statistics {
+    ext:augment-identifier "vpp-interface-statistics-augmentation";
+    leaf in-errors-no-buf {
+      type yang:counter64;
+    }
+    leaf in-errors-miss {
+      type yang:counter64;
+    }
+    leaf out-discards-fifo-full {
+      type yang:counter64;
+    }
+  }
+
+  container vpp-state {
+    config false;
+
+    description
+      "VPP operational data";
+
+    container bridge-domains {
+      // FIXME: Should this live in bridge-domain.yang in a modular fashion ?
+      list bridge-domain {
+
+        key "name";
+        leaf name {
+          type string;
+        }
+
+        uses bridge-domain-attributes;
+
+        list interface {
+          key "name";
+
+          leaf name {
+            type if:interface-state-ref;
+          }
+
+          leaf split-horizon-group {
+            type uint8;
+          }
+
+          leaf bridged-virtual-interface {
+            type boolean;
+          }
+        }
+
+        list l2-fib {
+          key "phys-address";
+
+          leaf phys-address {
+            type yang:phys-address;
+          }
+          leaf static-config {
+            type boolean;
+          }
+          leaf outgoing-interface {
+            when "../v3po:action = 'forward'";
+            type if:interface-state-ref;
+          }
+          leaf action {
+            type enumeration {
+              enum "forward";
+              enum "filter";
+            }
+            mandatory true;
+          }
+          leaf bridged-virtual-interface {
+            when "../v3po:action = 'forward'";
+            type boolean;
+          }
+        }
+        description
+          "bridge-domain operational data";
+      }
+    }
+
+    container version {
+      leaf name {
+        type string;
+      }
+      leaf build-directory {
+        type string;
+      }
+      leaf build-date {
+        type string;
+      }
+      leaf branch {
+        type string;
+      }
+      description
+      "vlib version info";
+    }
+  }
+}
diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/CustomDataBrokerTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/CustomDataBrokerTest.java
new file mode 100644 (file)
index 0000000..1528320
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.vpp;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+
+/**
+ * Loads only modules of GBP and it's dependencies for data broker.
+ * <br>
+ * Therefore this implementation is faster than {@link AbstractDataBrokerTest}
+ */
+public abstract class CustomDataBrokerTest extends AbstractDataBrokerTest {
+
+    public static void loadModuleInfos(Class<?> clazzFromModule, Builder<YangModuleInfo> moduleInfoSet)
+            throws Exception {
+        YangModuleInfo moduleInfo = BindingReflections.getModuleInfo(clazzFromModule);
+        checkState(moduleInfo != null, "Module Info for %s is not available.", clazzFromModule);
+        collectYangModuleInfo(moduleInfo, moduleInfoSet);
+    }
+
+    private static void collectYangModuleInfo(final YangModuleInfo moduleInfo,
+            final Builder<YangModuleInfo> moduleInfoSet) throws IOException {
+        moduleInfoSet.add(moduleInfo);
+        for (YangModuleInfo dependency : moduleInfo.getImportedModules()) {
+            collectYangModuleInfo(dependency, moduleInfoSet);
+        }
+    }
+
+    @Override
+    protected Iterable<YangModuleInfo> getModuleInfos() throws Exception {
+        Builder<YangModuleInfo> moduleInfoSet = ImmutableSet.<YangModuleInfo>builder();
+        for (Class<?> clazz : getClassesFromModules()) {
+            loadModuleInfos(clazz, moduleInfoSet);
+        }
+        return moduleInfoSet.build();
+    }
+
+    /**
+     * @return a class from every yang module which needs to be loaded. Cannot return {@code null}
+     *         or empty collection.
+     */
+    public abstract @Nonnull Collection<Class<?>> getClassesFromModules();
+}
diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/VppRendererDataBrokerTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/VppRendererDataBrokerTest.java
new file mode 100644 (file)
index 0000000..8cd7458
--- /dev/null
@@ -0,0 +1,26 @@
+/*\r
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.renderer.vpp;\r
+\r
+import com.google.common.collect.ImmutableList;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser;\r
+\r
+import javax.annotation.Nonnull;\r
+import java.util.Collection;\r
+\r
+public class VppRendererDataBrokerTest extends CustomDataBrokerTest {\r
+\r
+    @Nonnull\r
+    @Override\r
+    public Collection<Class<?>> getClassesFromModules() {\r
+        return ImmutableList.of(Interfaces.class, Interface.class, VhostUser.class);\r
+    }\r
+}\r
diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommandTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommandTest.java
new file mode 100644 (file)
index 0000000..63dc7b2
--- /dev/null
@@ -0,0 +1,183 @@
+/*\r
+ * Copyright (c) 2016 Cisco Systems. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.renderer.vpp.commands;\r
+\r
+import com.google.common.base.Optional;\r
+import org.junit.Assert;\r
+import org.junit.Before;\r
+import org.junit.Test;\r
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;\r
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;\r
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.VppRendererDataBrokerTest;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;\r
+import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUserBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBased;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBasedBuilder;\r
+\r
+public class VhostUserCommandTest extends VppRendererDataBrokerTest {\r
+\r
+    private final static String BRIDGE_DOMAIN = "testBD";\r
+    private final static String DESCRIPTION = "used for testing";\r
+    private final static String INTERFACE_NAME = "testInterface";\r
+    private final static String SOCKET_NAME = "soc1";\r
+\r
+    private final static String UPD_BRIDGE_DOMAIN = "testBD2";\r
+    private final static String UPD_DESCRIPTION = "updated description";\r
+    private final static String UPD_SOCKET_NAME = "soc2";\r
+    private final static short SPLIT_HORIZON_GROUP_DEFAULT = 0;\r
+    private final static boolean IS_BRIDGED_DEFAULT = false;\r
+\r
+    private static Interface BASIC_INTERFACE;\r
+\r
+    private DataBroker dataBroker;\r
+\r
+    @Before\r
+    public void init() {\r
+        dataBroker = getDataBroker();\r
+\r
+        VhostUser vhostUser = new VhostUserBuilder().setRole(VhostUserRole.Server).setSocket(SOCKET_NAME).build();\r
+\r
+        VppInterfaceAugmentation vppAugmentation = new VppInterfaceAugmentationBuilder().setVhostUser(vhostUser)\r
+            .setL2(new L2Builder().setInterconnection(new BridgeBasedBuilder().setBridgeDomain(BRIDGE_DOMAIN)\r
+                .setSplitHorizonGroup(SPLIT_HORIZON_GROUP_DEFAULT)\r
+                .setBridgedVirtualInterface(IS_BRIDGED_DEFAULT)\r
+                .build()).build())\r
+            .build();\r
+\r
+        BASIC_INTERFACE =\r
+                new InterfaceBuilder().setDescription(DESCRIPTION)\r
+                    .setEnabled(true)\r
+                    .setKey(new InterfaceKey(INTERFACE_NAME))\r
+                    .setName(INTERFACE_NAME)\r
+                    .setType(\r
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class)\r
+                    .setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Enabled)\r
+                    .addAugmentation(VppInterfaceAugmentation.class, vppAugmentation)\r
+                    .build();\r
+    }\r
+\r
+    @Test\r
+    public void AddVhostTest() {\r
+        ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();\r
+        VhostUserCommand addCommand = VhostUserCommand.builder()\r
+            .setOperation(General.Operations.PUT)\r
+            .setName(INTERFACE_NAME)\r
+            .setDescription(DESCRIPTION)\r
+            .setRole(VhostUserRole.Server)\r
+            .setSocket(SOCKET_NAME)\r
+            .setBridgeDomain(BRIDGE_DOMAIN)\r
+            .setEnabled(true)\r
+            .build();\r
+\r
+        addCommand.execute(transaction);\r
+\r
+        transaction.submit();\r
+\r
+        ReadOnlyTransaction readOnlyTransaction = dataBroker.newReadOnlyTransaction();\r
+\r
+        Optional<Interface> optional = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,\r
+                VppIidFactory.getInterfaceIID(new InterfaceKey(INTERFACE_NAME)), readOnlyTransaction);\r
+\r
+        Assert.assertTrue("Interface was not written to DS", optional.isPresent());\r
+\r
+        Interface anInterface = optional.get();\r
+\r
+        Assert.assertEquals(BASIC_INTERFACE, anInterface);\r
+\r
+    }\r
+\r
+    @Test\r
+    public void DeleteVhostTest() {\r
+        ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();\r
+\r
+        transaction.put(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getInterfaceIID(BASIC_INTERFACE.getKey()),\r
+                BASIC_INTERFACE, true);\r
+        transaction.submit();\r
+\r
+        Optional<Interface> optional = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,\r
+                VppIidFactory.getInterfaceIID(BASIC_INTERFACE.getKey()), dataBroker.newReadOnlyTransaction());\r
+\r
+        Assert.assertTrue("Interface was not written to DS", optional.isPresent());\r
+\r
+        VhostUserCommand deleteCommand = VhostUserCommand.builder()\r
+                .setOperation(General.Operations.DELETE)\r
+                .setName(INTERFACE_NAME)\r
+                .setSocket(SOCKET_NAME)\r
+                .build();\r
+\r
+        ReadWriteTransaction deleteTransaction = dataBroker.newReadWriteTransaction();\r
+        deleteCommand.execute(deleteTransaction);\r
+        deleteTransaction.submit();\r
+\r
+        Optional<Interface> optionalDeleted = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,\r
+                VppIidFactory.getInterfaceIID(new InterfaceKey(deleteCommand.getName())),\r
+                dataBroker.newReadOnlyTransaction());\r
+\r
+        Assert.assertFalse("Interface was not deleted from DS", optionalDeleted.isPresent());\r
+    }\r
+\r
+    @Test\r
+    public void UpdateVhostTest() {\r
+        ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();\r
+\r
+        transaction.put(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getInterfaceIID(BASIC_INTERFACE.getKey()),\r
+                BASIC_INTERFACE, true);\r
+        transaction.submit();\r
+\r
+        Optional<Interface> optional = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,\r
+                VppIidFactory.getInterfaceIID(BASIC_INTERFACE.getKey()), dataBroker.newReadOnlyTransaction());\r
+\r
+        Assert.assertTrue("Interface was not written to DS", optional.isPresent());\r
+\r
+        VhostUserCommand updateCommand = VhostUserCommand.builder()\r
+            .setOperation(General.Operations.MERGE)\r
+            .setName(INTERFACE_NAME)\r
+            .setDescription(UPD_DESCRIPTION)\r
+            .setEnabled(false)\r
+            .setRole(VhostUserRole.Client)\r
+            .setSocket(UPD_SOCKET_NAME)\r
+            .setBridgeDomain(UPD_BRIDGE_DOMAIN)\r
+            .build();\r
+\r
+        ReadWriteTransaction deleteTransaction = dataBroker.newReadWriteTransaction();\r
+        updateCommand.execute(deleteTransaction);\r
+        deleteTransaction.submit();\r
+\r
+        Optional<Interface> optionalUpdated = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,\r
+                VppIidFactory.getInterfaceIID(new InterfaceKey(updateCommand.getName())),\r
+                dataBroker.newReadOnlyTransaction());\r
+\r
+        Assert.assertTrue("Interface was not found in DS", optionalUpdated.isPresent());\r
+        Interface updatedInterface = optionalUpdated.get();\r
+\r
+        Assert.assertEquals(UPD_DESCRIPTION, updatedInterface.getDescription());\r
+        Assert.assertFalse(updatedInterface.isEnabled());\r
+        VppInterfaceAugmentation vppInterfaceAugmentation =\r
+                updatedInterface.getAugmentation(VppInterfaceAugmentation.class);\r
+        Assert.assertEquals(VhostUserRole.Client, vppInterfaceAugmentation.getVhostUser().getRole());\r
+        Assert.assertEquals(UPD_SOCKET_NAME, vppInterfaceAugmentation.getVhostUser().getSocket());\r
+\r
+        Assert.assertTrue(vppInterfaceAugmentation.getL2().getInterconnection() instanceof BridgeBased);\r
+\r
+        Assert.assertEquals(UPD_BRIDGE_DOMAIN,\r
+                ((BridgeBased) vppInterfaceAugmentation.getL2().getInterconnection()).getBridgeDomain());\r
+    }\r
+}\r