HONEYCOMB-104: add Ipv4 support to sub-interfaces
authorMarek Gradzki <[email protected]>
Mon, 27 Jun 2016 13:23:28 +0000 (15:23 +0200)
committerMarek Gradzki <[email protected]>
Fri, 1 Jul 2016 11:21:14 +0000 (13:21 +0200)
* updates vpp-vlan.yang with Ipv4 and Ipv6 support
  based on ietf-ip rev. 2014-06-16
* adds Ipv4 support for sub-interfaces

Ipv6 support for interfaces and sub-interfaces will
be addded in the future (HONEYCOMB-102)

Change-Id: I0bf10fe3ff1c543685f651d8b6fb06bbeee3db92
Signed-off-by: Marek Gradzki <[email protected]>
17 files changed:
v3po/api/src/main/yang/vpp-vlan.yang
v3po/postman_rest_collection.json
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/SubInterfaceInitializationUtils.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizer.java [deleted file]
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java [new file with mode: 0644]
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4WriteUtils.java [new file with mode: 0644]
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java [new file with mode: 0644]
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java [new file with mode: 0644]
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java [new file with mode: 0644]
v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesHoneycombWriterModule.java
v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java
v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceAugmentationWriterFactory.java [new file with mode: 0644]
v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceStateAugmentationReaderFactory.java [new file with mode: 0644]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4AddressCustomizerTest.java [moved from v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizerTest.java with 98% similarity]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java
v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/SubInterfaceUtils.java

index fdf878b..fef8e72 100644 (file)
@@ -12,6 +12,9 @@ module vpp-vlan {
   import ietf-interfaces {
     prefix "if";
   }
+  import ietf-inet-types {
+    prefix inet;
+  }
   import ietf-yang-types {
     prefix "yang";
   }
@@ -242,6 +245,133 @@ module vpp-vlan {
     }
   }
 
+  grouping sub-interface-ip4-attributes {
+    container ipv4 {
+      // TODO: add currently unsupported:
+      // enabled, forwarding, mtu, address/origin(config false), neighbor/origin(config false)
+
+      // TODO: reuse groupings once ietf-ip provides them
+
+      description
+        "Parameters for the IPv4 address family (based on ietf-ip rev. 2014-06-16)";
+
+      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 {
+            type yang:dotted-quad;
+            description
+              "The subnet specified as a netmask (contiguous)";
+          }
+        }  // 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
+    }
+  }
+
+  grouping sub-interface-ip6-attributes {
+    container ipv6 {
+      // TODO: add currently unsupported:
+      // enabled, forwarding, mtu, neighbor, dup-addr-detect-transmits, autoconf,
+      // address(config false): origin, status
+      // neighbor(config false): origin, is-router, state
+
+      // TODO: reuse groupings once ietf-ip provides them
+
+      description
+        "Parameters for the IPv6 address family (based on ietf-ip rev. 2014-06-16)";
+
+      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
+    }
+  }
+
   augment /if:interfaces/if:interface {
     ext:augment-identifier "subinterface-augmentation";
 
@@ -257,6 +387,8 @@ module vpp-vlan {
 
         uses sub-interface-base-attributes;
         uses sub-interface-config-attributes;
+        uses sub-interface-ip4-attributes;
+        uses sub-interface-ip6-attributes;
       }
     }
   }
@@ -275,6 +407,8 @@ module vpp-vlan {
 
         uses sub-interface-base-attributes;
         uses sub-interface-operational-attributes;
+        uses sub-interface-ip4-attributes;
+        uses sub-interface-ip6-attributes;
       }
     }
   }
index 192f9ec..313a2ef 100644 (file)
@@ -23,7 +23,8 @@
                                "8d49cf41-facc-c4ac-cee7-475d50e2a0be",
                                "70835949-7252-a3cc-491b-f8aa69286399",
                                "d5a90cfd-fd7e-63b6-e1f1-16fc0671b0e1",
-                               "3f7ee49b-ae11-b032-915f-a14bf838246f"
+                               "3f7ee49b-ae11-b032-915f-a14bf838246f",
+                               "345ba26c-60cf-5fa1-37d0-f5af7a8c33bf"
                        ],
                        "owner": "45557"
                },
                        "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
                        "rawModeData": "{\r\n    \r\n        \"interface\": [\r\n            {\r\n                \"name\": \"testInterface\",\r\n                \"description\": \"for testing purposes\",\r\n                \"type\": \"iana-if-type:ethernetCsmacd\",\r\n                \"enabled\": \"true\",\r\n                \"link-up-down-trap-enable\": \"enabled\",\r\n                \"ietf-ip:ipv4\": {\r\n                    \"enabled\": \"true\",\r\n                    \"mtu\": \"1500\",\r\n                    \"address\": [\r\n                        {\r\n                            \"ip\": \"1.2.3.0\",\r\n                            \"netmask\": \"255.255.255.0\"\r\n                        }\r\n                    ]\r\n                }\r\n            }\r\n        ]\r\n    \r\n}"
                },
-
+               {
+                       "id": "345ba26c-60cf-5fa1-37d0-f5af7a8c33bf",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/ipv4/address/1.2.3.4",
+                       "pathVariables": {},
+                       "preRequestScript": "",
+                       "method": "PUT",
+                       "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+                       "data": [],
+                       "dataMode": "raw",
+                       "name": "Set ipv4 for sub-interface - cfg",
+                       "description": "Correponds to the following command:\n\nvppctl set interface ip address GigabitEthernet0/9/0.1 1.2.3.4/8\n\nTo verify invoke:\nvppctl show int",
+                       "descriptionFormat": "html",
+                       "time": 1467117222646,
+                       "version": 2,
+                       "responses": [],
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
+                       "rawModeData": "{\r\n            \"address\": [{\r\n                \"ip\" : \"1.2.3.4\",\r\n                \"prefix-length\" : \"8\"\r\n            }]\r\n}"
+               },
                {
                        "id": "ac161bec-e046-4bb7-d695-60bdfb0c6cea",
                        "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
index 76caf16..2d22174 100644 (file)
@@ -74,7 +74,8 @@ final class SubInterfaceInitializationUtils {
         subInterfaceCfgBuilder.setMatch(operationalData.getMatch());
         subInterfaceCfgBuilder.setTags(operationalData.getTags());
         subInterfaceCfgBuilder.setVlanType(operationalData.getVlanType());
-
+        subInterfaceCfgBuilder.setIpv4(operationalData.getIpv4());
+        subInterfaceCfgBuilder.setIpv6(operationalData.getIpv6());
         return subInterfaceCfgBuilder.build();
     }
 
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizer.java
deleted file mode 100644 (file)
index 6505574..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * 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.v3po.translate.v3po.interfaces.ip;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.base.Optional;
-import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer;
-import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
-import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
-import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils;
-import io.fd.honeycomb.v3po.translate.write.WriteContext;
-import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
-import java.util.List;
-import java.util.concurrent.CompletionStage;
-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.ip.rev140616.interfaces._interface.Ipv4;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressKey;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.openvpp.jvpp.VppBaseCallException;
-import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress;
-import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply;
-import org.openvpp.jvpp.future.FutureJVpp;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Customizer for writing {@link Address}
- */
-public class AddressCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer<Address, AddressKey> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(AddressCustomizer.class);
-    private final NamingContext interfaceContext;
-
-    public AddressCustomizer(FutureJVpp futureJvpp, NamingContext interfaceContext) {
-        super(futureJvpp);
-        this.interfaceContext = interfaceContext;
-    }
-
-    @Override
-    public void writeCurrentAttributes(InstanceIdentifier<Address> id, Address dataAfter, WriteContext writeContext)
-        throws WriteFailedException {
-        setAddress(true, id, dataAfter, writeContext);
-    }
-
-    @Override
-    public void updateCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, Address dataAfter,
-                                        WriteContext writeContext) throws WriteFailedException {
-        throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
-            new UnsupportedOperationException("Operation not supported"));
-    }
-
-    @Override
-    public void deleteCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, WriteContext writeContext)
-        throws WriteFailedException {
-        setAddress(false, id, dataBefore, writeContext);
-    }
-
-    @Override
-    public Optional<List<Address>> extract(InstanceIdentifier<Address> currentId, DataObject parentData) {
-        return Optional.fromNullable((((Ipv4) parentData).getAddress()));
-    }
-
-    private void setAddress(boolean add, final InstanceIdentifier<Address> id, final Address address,
-                            final WriteContext writeContext) throws WriteFailedException {
-
-        final String interfaceName = id.firstKeyOf(Interface.class).getName();
-        final int swIfc = interfaceContext.getIndex(interfaceName, writeContext.getMappingContext());
-
-        Subnet subnet = address.getSubnet();
-
-        if (subnet instanceof PrefixLength) {
-            setPrefixLengthSubnet(add, id, interfaceName, swIfc, address, (PrefixLength) subnet);
-        } else if (subnet instanceof Netmask) {
-            setNetmaskSubnet(add, id, interfaceName, swIfc, address, (Netmask) subnet);
-        } else {
-            // FIXME how does choice extensibility work
-            // FIXME it is not even possible to create a dedicated
-            // customizer for Interconnection, since it's not a DataObject
-            // FIXME we might need a choice customizer
-            // THis choice is already from augment, so its probably not
-            // possible to augment augmented choice
-            LOG.error("Unable to handle subnet of type {}", subnet.getClass());
-            throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass());
-        }
-    }
-
-    private void setNetmaskSubnet(final boolean add, final InstanceIdentifier<Address> id, final String name,
-                                  final int swIfc,
-                                  final Address ipv4Addr, final Netmask subnet) throws WriteFailedException {
-        LOG.debug("Setting Subnet(subnet-mask) for interface: {}, {}. Subnet: {}, Ipv4: {}", name, swIfc, subnet,
-            ipv4Addr);
-
-        byte[] addr = TranslateUtils.ipv4AddressNoZoneToArray(ipv4Addr.getIp());
-        final DottedQuad netmask = subnet.getNetmask();
-
-        checkNotNull(addr, "Null address");
-        checkNotNull(netmask, "Null netmask");
-
-        // find netmask bit-length
-        final short subnetLength = getSubnetMaskLength(netmask.getValue());
-        PrefixLengthBuilder lengthBuilder = new PrefixLengthBuilder().setPrefixLength(subnetLength);
-
-        setPrefixLengthSubnet(add, id, name, swIfc, ipv4Addr, lengthBuilder.build());
-    }
-
-    /**
-     * Returns the prefix size in bits of the specified subnet mask. Example: For the subnet mask 255.255.255.128 it
-     * returns 25 while for 255.0.0.0 it returns 8. If the passed subnetMask array is not complete or contains not only
-     * leading ones, IllegalArgumentExpression is thrown
-     *
-     * @param mask the subnet mask in dot notation 255.255.255.255
-     * @return the prefix length as number of bits
-     */
-    private static short getSubnetMaskLength(final String mask) {
-        String[] maskParts = mask.split("\\.");
-
-        final int DOTTED_QUAD_MASK_LENGHT = 4;
-        final int IPV4_ADDRESS_PART_BITS_COUNT = 8;
-        final int NETMASK_PART_LIMIT = 256; // 2 power to 8
-
-        checkArgument(maskParts.length == DOTTED_QUAD_MASK_LENGHT,
-            "Network mask %s is not in Quad Dotted Decimal notation!", mask);
-
-        long maskAsNumber = 0;
-        for (int i = 0; i < DOTTED_QUAD_MASK_LENGHT; i++) {
-            maskAsNumber <<= IPV4_ADDRESS_PART_BITS_COUNT;
-            int value = Integer.parseInt(maskParts[i]);
-            checkArgument(value < NETMASK_PART_LIMIT, "Network mask %s contains invalid number(s) over 255!", mask);
-            checkArgument(value >= 0, "Network mask %s contains invalid negative number(s)!", mask);
-            maskAsNumber += value;
-        }
-
-        String bits = Long.toBinaryString(maskAsNumber);
-        checkArgument(bits.length() == IPV4_ADDRESS_PART_BITS_COUNT * DOTTED_QUAD_MASK_LENGHT,
-            "Incorrect network mask %s", mask);
-        final int leadingOnes = bits.indexOf('0');
-        checkArgument(leadingOnes != -1, "Broadcast address %s is not allowed!", mask);
-        checkArgument(bits.substring(leadingOnes).indexOf('1') == -1,
-            "Non-contiguous network mask %s is not allowed!", mask);
-        return (short) leadingOnes;
-    }
-
-    private void setPrefixLengthSubnet(boolean add, final InstanceIdentifier<Address> id, final String name,
-                                       final int swIfc,
-                                       final Address address, final PrefixLength subnet) throws WriteFailedException {
-        try {
-            LOG.debug("Setting Subnet(prefix-length) for interface: {}, {}. Subnet: {}, Address: {}", name, swIfc,
-                subnet, address);
-
-            final Short plen = subnet.getPrefixLength();
-            checkArgument(plen > 0, "Invalid length");
-
-            final byte[] addr = TranslateUtils.ipv4AddressNoZoneToArray(address.getIp());
-            checkNotNull(addr, "Null address");
-
-            final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage =
-                getFutureJVpp()
-                    .swInterfaceAddDelAddress(
-                        getSwInterfaceAddDelAddressRequest(swIfc, TranslateUtils.booleanToByte(add) /* isAdd */,
-                            (byte) 0 /* isIpv6 */, (byte) 0 /* delAll */, plen.byteValue(), addr));
-
-            TranslateUtils.getReplyForWrite(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture(), id);
-
-            LOG.debug("Subnet(prefix-length) set successfully for interface: {}, {},  Subnet: {}, Address: {}", name,
-                swIfc, subnet, address);
-        } catch (VppBaseCallException e) {
-            LOG.warn("Failed to set Subnet(prefix-length) for interface: {}, {},  Subnet: {}, Address: {}", name, swIfc,
-                subnet, address);
-            throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e);
-        }
-    }
-
-    private SwInterfaceAddDelAddress getSwInterfaceAddDelAddressRequest(final int swIfc, final byte isAdd,
-                                                                        final byte ipv6, final byte deleteAll,
-                                                                        final byte length, final byte[] addr) {
-        final SwInterfaceAddDelAddress swInterfaceAddDelAddress = new SwInterfaceAddDelAddress();
-        swInterfaceAddDelAddress.swIfIndex = swIfc;
-        swInterfaceAddDelAddress.isAdd = isAdd;
-        swInterfaceAddDelAddress.isIpv6 = ipv6;
-        swInterfaceAddDelAddress.delAll = deleteAll;
-        swInterfaceAddDelAddress.address = addr;
-        swInterfaceAddDelAddress.addressLength = length;
-        return swInterfaceAddDelAddress;
-    }
-
-}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java
new file mode 100644 (file)
index 0000000..a05bd8f
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * 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.v3po.translate.v3po.interfaces.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4WriteUtils.addDelAddress;
+import static io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4WriteUtils.getSubnetMaskLength;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
+import java.util.List;
+import javax.annotation.Nonnull;
+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.ip.rev140616.interfaces._interface.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for writing {@link Address}
+ */
+public class Ipv4AddressCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer<Address, AddressKey> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class);
+    private final NamingContext interfaceContext;
+
+    public Ipv4AddressCustomizer(FutureJVpp futureJvpp, NamingContext interfaceContext) {
+        super(futureJvpp);
+        this.interfaceContext = interfaceContext;
+    }
+
+    @Override
+    public void writeCurrentAttributes(InstanceIdentifier<Address> id, Address dataAfter, WriteContext writeContext)
+        throws WriteFailedException {
+        setAddress(true, id, dataAfter, writeContext);
+    }
+
+    @Override
+    public void updateCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, Address dataAfter,
+                                        WriteContext writeContext) throws WriteFailedException {
+        throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+            new UnsupportedOperationException("Operation not supported"));
+    }
+
+    @Override
+    public void deleteCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, WriteContext writeContext)
+        throws WriteFailedException {
+        setAddress(false, id, dataBefore, writeContext);
+    }
+
+    @Override
+    public Optional<List<Address>> extract(InstanceIdentifier<Address> currentId, DataObject parentData) {
+        return Optional.fromNullable((((Ipv4) parentData).getAddress()));
+    }
+
+    private void setAddress(boolean add, final InstanceIdentifier<Address> id, final Address address,
+                            final WriteContext writeContext) throws WriteFailedException {
+
+        final String interfaceName = id.firstKeyOf(Interface.class).getName();
+        final int interfaceIndex = interfaceContext.getIndex(interfaceName, writeContext.getMappingContext());
+
+        Subnet subnet = address.getSubnet();
+
+        if (subnet instanceof PrefixLength) {
+            setPrefixLengthSubnet(add, id, interfaceName, interfaceIndex, address, (PrefixLength) subnet);
+        } else if (subnet instanceof Netmask) {
+            setNetmaskSubnet(add, id, interfaceName, interfaceIndex, address, (Netmask) subnet);
+        } else {
+            // FIXME how does choice extensibility work
+            // FIXME it is not even possible to create a dedicated
+            // customizer for Interconnection, since it's not a DataObject
+            // FIXME we might need a choice customizer
+            // THis choice is already from augment, so its probably not
+            // possible to augment augmented choice
+            LOG.error("Unable to handle subnet of type {}", subnet.getClass());
+            throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass());
+        }
+    }
+
+    private void setNetmaskSubnet(final boolean add, @Nonnull final InstanceIdentifier<Address> id,
+                                  @Nonnull final String interfaceName, final int interfaceIndex,
+                                  @Nonnull final Address address, @Nonnull final Netmask subnet)
+        throws WriteFailedException {
+        try {
+            LOG.debug("Setting Subnet(subnet-mask) for interface: {}(id={}). Subnet: {}, address: {}",
+                interfaceName, interfaceIndex, subnet, address);
+
+            final DottedQuad netmask = subnet.getNetmask();
+            checkNotNull(netmask, "netmask value should not be null");
+
+            final byte subnetLength = getSubnetMaskLength(netmask.getValue());
+            addDelAddress(getFutureJVpp(), add, id, interfaceIndex, address.getIp(), subnetLength);
+        } catch (VppBaseCallException e) {
+            LOG.warn("Failed to set Subnet(subnet-mask) for interface: {}(id={}). Subnet: {}, address: {}",
+                interfaceName, interfaceIndex, subnet, address);
+            throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e);
+        }
+    }
+
+    private void setPrefixLengthSubnet(final boolean add, @Nonnull final InstanceIdentifier<Address> id,
+                                       @Nonnull final String interfaceName, final int interfaceIndex,
+                                       @Nonnull final Address address, @Nonnull final PrefixLength subnet)
+        throws WriteFailedException {
+        try {
+            LOG.debug("Setting Subnet(prefix-length) for interface: {}(id={}). Subnet: {}, address: {}",
+                interfaceName, interfaceIndex, subnet, address);
+
+            addDelAddress(getFutureJVpp(), add, id, interfaceIndex, address.getIp(),
+                subnet.getPrefixLength().byteValue());
+
+            LOG.debug("Subnet(prefix-length) set successfully for interface: {}(id={}). Subnet: {}, address: {}",
+                interfaceName, interfaceIndex, subnet, address);
+        } catch (VppBaseCallException e) {
+            LOG.warn("Failed to set Subnet(prefix-length) for interface: {}(id={}). Subnet: {}, address: {}",
+                interfaceName, interfaceIndex, subnet, address);
+            throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e);
+        }
+    }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4WriteUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4WriteUtils.java
new file mode 100644 (file)
index 0000000..c9fd2e6
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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.v3po.translate.v3po.interfaces.ip;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress;
+import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply;
+import org.openvpp.jvpp.future.FutureJVpp;
+
+/**
+ * Utility class providing Ipv4 CUD support.
+ */
+// TODO replace with interface with default methods or abstract class
+final class Ipv4WriteUtils {
+
+    private static final int DOTTED_QUAD_MASK_LENGTH = 4;
+    private static final int IPV4_ADDRESS_PART_BITS_COUNT = 8;
+    private static final int NETMASK_PART_LIMIT = 256; // 2 power to 8
+
+    private Ipv4WriteUtils() {
+        throw new UnsupportedOperationException("This utility class cannot be instantiated");
+    }
+
+    static void addDelAddress(@Nonnull final FutureJVpp futureJvpp, final boolean add, final InstanceIdentifier<?> id,
+                              @Nonnegative final int ifaceId,
+                              @Nonnull final Ipv4AddressNoZone address, @Nonnegative final byte prefixLength)
+        throws VppBaseCallException, WriteTimeoutException {
+        checkArgument(prefixLength > 0, "Invalid prefix length");
+        checkNotNull(address, "address should not be null");
+
+        final byte[] addressBytes = TranslateUtils.ipv4AddressNoZoneToArray(address);
+
+        final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage =
+            futureJvpp.swInterfaceAddDelAddress(
+                getSwInterfaceAddDelAddressRequest(ifaceId, TranslateUtils.booleanToByte(add) /* isAdd */,
+                    (byte) 0 /* isIpv6 */, (byte) 0 /* delAll */, prefixLength, addressBytes));
+
+        TranslateUtils.getReplyForWrite(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture(), id);
+    }
+
+    static SwInterfaceAddDelAddress getSwInterfaceAddDelAddressRequest(final int swIfc, final byte isAdd,
+                                                                       final byte ipv6, final byte deleteAll,
+                                                                       final byte length, final byte[] addr) {
+        final SwInterfaceAddDelAddress swInterfaceAddDelAddress = new SwInterfaceAddDelAddress();
+        swInterfaceAddDelAddress.swIfIndex = swIfc;
+        swInterfaceAddDelAddress.isAdd = isAdd;
+        swInterfaceAddDelAddress.isIpv6 = ipv6;
+        swInterfaceAddDelAddress.delAll = deleteAll;
+        swInterfaceAddDelAddress.address = addr;
+        swInterfaceAddDelAddress.addressLength = length;
+        return swInterfaceAddDelAddress;
+    }
+
+    /**
+     * Returns the prefix size in bits of the specified subnet mask. Example: For the subnet mask 255.255.255.128 it
+     * returns 25 while for 255.0.0.0 it returns 8. If the passed subnetMask array is not complete or contains not only
+     * leading ones, IllegalArgumentExpression is thrown
+     *
+     * @param mask the subnet mask in dot notation 255.255.255.255
+     * @return the prefix length as number of bits
+     */
+    static byte getSubnetMaskLength(final String mask) {
+        String[] maskParts = mask.split("\\.");
+
+        checkArgument(maskParts.length == DOTTED_QUAD_MASK_LENGTH,
+            "Network mask %s is not in Quad Dotted Decimal notation!", mask);
+
+        long maskAsNumber = 0;
+        for (int i = 0; i < DOTTED_QUAD_MASK_LENGTH; i++) {
+            maskAsNumber <<= IPV4_ADDRESS_PART_BITS_COUNT;
+            int value = Integer.parseInt(maskParts[i]);
+            checkArgument(value < NETMASK_PART_LIMIT, "Network mask %s contains invalid number(s) over 255!", mask);
+            checkArgument(value >= 0, "Network mask %s contains invalid negative number(s)!", mask);
+            maskAsNumber += value;
+        }
+
+        String bits = Long.toBinaryString(maskAsNumber);
+        checkArgument(bits.length() == IPV4_ADDRESS_PART_BITS_COUNT * DOTTED_QUAD_MASK_LENGTH,
+            "Incorrect network mask %s", mask);
+        final int leadingOnes = bits.indexOf('0');
+        checkArgument(leadingOnes != -1, "Broadcast address %s is not allowed!", mask);
+        checkArgument(bits.substring(leadingOnes).indexOf('1') == -1,
+            "Non-contiguous network mask %s is not allowed!", mask);
+        return (byte) leadingOnes;
+    }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java
new file mode 100644 (file)
index 0000000..ccdcc6c
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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.v3po.translate.v3po.interfaces.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4WriteUtils.addDelAddress;
+import static io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4WriteUtils.getSubnetMaskLength;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.v3po.translate.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
+import java.util.List;
+import javax.annotation.Nonnull;
+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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.Netmask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLength;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Write customizer for sub-interface {@link Address}
+ */
+public class SubInterfaceIpv4AddressCustomizer extends FutureJVppCustomizer
+    implements ListWriterCustomizer<Address, AddressKey> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIpv4AddressCustomizer.class);
+    private final NamingContext interfaceContext;
+
+    public SubInterfaceIpv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp,
+                                             @Nonnull final NamingContext interfaceContext) {
+        super(futureJvpp);
+        this.interfaceContext = checkNotNull(interfaceContext, "interface context should not be null");
+    }
+
+    @Override
+    public void writeCurrentAttributes(InstanceIdentifier<Address> id, Address dataAfter, WriteContext writeContext)
+        throws WriteFailedException {
+        setAddress(true, id, dataAfter, writeContext);
+    }
+
+    @Override
+    public void updateCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, Address dataAfter,
+                                        WriteContext writeContext) throws WriteFailedException {
+        throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+            new UnsupportedOperationException("Operation not supported"));
+    }
+
+    @Override
+    public void deleteCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, WriteContext writeContext)
+        throws WriteFailedException {
+        setAddress(false, id, dataBefore, writeContext);
+    }
+
+    @Override
+    public Optional<List<Address>> extract(InstanceIdentifier<Address> currentId, DataObject parentData) {
+        return Optional.fromNullable((((Ipv4) parentData).getAddress()));
+    }
+
+    private void setAddress(boolean add, final InstanceIdentifier<Address> id, final Address address,
+                            final WriteContext writeContext) throws WriteFailedException {
+
+        final String interfaceName = id.firstKeyOf(Interface.class).getName();
+        final String subInterfaceName = getSubInterfaceName(id);
+        final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+
+        Subnet subnet = address.getSubnet();
+
+        if (subnet instanceof PrefixLength) {
+            setPrefixLengthSubnet(add, id, interfaceName, subInterfaceIndex, address, (PrefixLength) subnet);
+        } else if (subnet instanceof Netmask) {
+            setNetmaskSubnet(add, id, interfaceName, subInterfaceIndex, address, (Netmask) subnet);
+        } else {
+            // FIXME how does choice extensibility work
+            // FIXME it is not even possible to create a dedicated
+            // customizer for Interconnection, since it's not a DataObject
+            // FIXME we might need a choice customizer
+            // THis choice is already from augment, so its probably not
+            // possible to augment augmented choice
+            LOG.error("Unable to handle subnet of type {}", subnet.getClass());
+            throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass());
+        }
+    }
+
+    private String getSubInterfaceName(@Nonnull final InstanceIdentifier<Address> id) {
+        final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+        final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+        return SubInterfaceUtils
+            .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+    }
+
+    private void setNetmaskSubnet(final boolean add, @Nonnull final InstanceIdentifier<Address> id,
+                                  @Nonnull final String subInterfaceName, final int subInterfaceIndex,
+                                  @Nonnull final Address address, @Nonnull final Netmask subnet)
+        throws WriteFailedException {
+        try {
+            LOG.debug("Setting Subnet(subnet-mask) for sub-interface: {}(id={}). Subnet: {}, address: {}",
+                subInterfaceName, subInterfaceIndex, subnet, address);
+
+            final DottedQuad netmask = subnet.getNetmask();
+            checkNotNull(netmask, "netmask value should not be null");
+
+            final byte subnetLength = getSubnetMaskLength(netmask.getValue());
+            addDelAddress(getFutureJVpp(), add, id, subInterfaceIndex, address.getIp(), subnetLength);
+
+        } catch (VppBaseCallException e) {
+            LOG.warn("Failed to set Subnet(subnet-mask) for sub-interface: {}(id={}). Subnet: {}, address: {}",
+                subInterfaceName, subInterfaceIndex, subnet, address);
+            throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e);
+        }
+    }
+
+    private void setPrefixLengthSubnet(final boolean add, @Nonnull final InstanceIdentifier<Address> id,
+                                       @Nonnull final String subInterfaceName, final int subInterfaceIndex,
+                                       @Nonnull final Address address, @Nonnull final PrefixLength subnet)
+        throws WriteFailedException {
+        try {
+            LOG.debug("Setting Subnet(prefix-length) for sub-interface: {}(id={}). Subnet: {}, address: {}",
+                subInterfaceName, subInterfaceIndex, subnet, address);
+
+            addDelAddress(getFutureJVpp(), add, id, subInterfaceIndex, address.getIp(),
+                subnet.getPrefixLength().byteValue());
+
+            LOG.debug("Subnet(prefix-length) set successfully for sub-interface: {}(id={}). Subnet: {}, address: {}",
+                subInterfaceName, subInterfaceIndex, subnet, address);
+        } catch (VppBaseCallException e) {
+            LOG.warn("Failed to set Subnet(prefix-length) for sub-interface: {}(id={}). Subnet: {}, address: {}",
+                subInterfaceName, subInterfaceIndex, subnet, address);
+            throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e);
+        }
+    }
+}
index 2121337..1d90d8c 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.dumpAddresses;
+import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.findIpAddressDetailsByIp;
+import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.getAllIpv4AddressIds;
+
 import com.google.common.base.Optional;
-import io.fd.honeycomb.v3po.translate.MappingContext;
-import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer;
-import io.fd.honeycomb.v3po.translate.util.RWUtils;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
-import io.fd.honeycomb.v3po.translate.v3po.util.ReadTimeoutException;
 import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils;
-import java.util.Collections;
 import java.util.List;
-import java.util.stream.Collectors;
 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.ip.rev140616.interfaces.state._interface.Ipv4;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressBuilder;
@@ -41,29 +39,25 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev14061
 import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.openvpp.jvpp.VppBaseCallException;
 import org.openvpp.jvpp.dto.IpAddressDetails;
 import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump;
-import org.openvpp.jvpp.dto.IpAddressDump;
 import org.openvpp.jvpp.future.FutureJVpp;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Customizer for read operations for {@link Address} of {@link Ipv4}.
+ * Read customizer for interface Ipv4 addresses.
  */
 public class Ipv4AddressCustomizer extends FutureJVppCustomizer
     implements ListReaderCustomizer<Address, AddressKey, AddressBuilder> {
 
     private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class);
 
-    private static final String CACHE_KEY = Ipv4AddressCustomizer.class.getName();
-
     private final NamingContext interfaceContext;
 
     public Ipv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext) {
         super(futureJvpp);
-        this.interfaceContext = interfaceContext;
+        this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
     }
 
     @Override
@@ -76,50 +70,39 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer
     public void readCurrentAttributes(@Nonnull InstanceIdentifier<Address> id, @Nonnull AddressBuilder builder,
                                       @Nonnull ReadContext ctx)
         throws ReadFailedException {
-        LOG.debug("Reading attributes...");
-
-        Optional<IpAddressDetailsReplyDump> dumpOptional = dumpAddresses(id, ctx);
+        LOG.debug("Reading attributes for interface address: {}", id);
 
-        if (dumpOptional.isPresent() && dumpOptional.get().ipAddressDetails != null) {
-            List<IpAddressDetails> details = dumpOptional.get().ipAddressDetails;
+        final String interfaceName = id.firstKeyOf(Interface.class).getName();
+        final int interfaceIndex = interfaceContext.getIndex(interfaceName, ctx.getMappingContext());
+        final Optional<IpAddressDetailsReplyDump> dumpOptional =
+            dumpAddresses(getFutureJVpp(), id, interfaceName, interfaceIndex, ctx);
 
-            AddressKey key = id.firstKeyOf(Address.class);
-
-            IpAddressDetails detail = details.stream()
-                .filter(singleDetail -> key.getIp().equals(TranslateUtils.arrayToIpv4AddressNoZone(singleDetail.ip)))
-                .collect(RWUtils.singleItemCollector());
+        final Optional<IpAddressDetails> ipAddressDetails =
+            findIpAddressDetailsByIp(dumpOptional, id.firstKeyOf(Address.class).getIp());
 
+        if (ipAddressDetails.isPresent()) {
+            final IpAddressDetails detail = ipAddressDetails.get();
             builder.setIp(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip))
-                .setSubnet(new PrefixLengthBuilder()
-                    .setPrefixLength(Short.valueOf(detail.prefixLength)).build());
-            LOG.info("Address read successful");
-        } else {
-            LOG.warn("No address dump present");
+                .setSubnet(new PrefixLengthBuilder().setPrefixLength(Short.valueOf(detail.prefixLength)).build());
+
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Attributes for {} interface (id={}) address {} successfully read: {}",
+                    interfaceName, interfaceIndex, id, builder.build());
+            }
         }
     }
 
     @Override
-    public List<AddressKey> getAllIds(@Nonnull InstanceIdentifier<Address> id, @Nonnull ReadContext context)
+    public List<AddressKey> getAllIds(@Nonnull InstanceIdentifier<Address> id, @Nonnull ReadContext ctx)
         throws ReadFailedException {
-        // FIXME: this kind of logs provide very little information. At least the ID should be included so we know
-        // from the logs what exact data is being processed
-        // + Logs should be consistent in using punctuation
-        LOG.debug("Extracting keys..");
-
-        Optional<IpAddressDetailsReplyDump> dumpOptional = dumpAddresses(id, context);
-
-        if (dumpOptional.isPresent() && dumpOptional.get().ipAddressDetails != null) {
-
-            return dumpOptional.get().ipAddressDetails.stream()
-                .map(detail -> new AddressKey(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip)))
-                .collect(Collectors.toList());
-        } else {
-            // FIXME if this is expected then WARN should not be emitted
-            // FIXME if this is not expected, throw an exception instead
-            // Same in readCurrentAttributes()
-            LOG.warn("No dump present");
-            return Collections.emptyList();
-        }
+        LOG.debug("Reading list of keys for interface addresses: {}", id);
+
+        final String interfaceName = id.firstKeyOf(Interface.class).getName();
+        final int interfaceIndex = interfaceContext.getIndex(interfaceName, ctx.getMappingContext());
+        final Optional<IpAddressDetailsReplyDump> dumpOptional =
+            dumpAddresses(getFutureJVpp(), id, interfaceName, interfaceIndex, ctx);
+
+        return getAllIpv4AddressIds(dumpOptional, AddressKey::new);
     }
 
     @Override
@@ -127,48 +110,4 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer
         ((Ipv4Builder) builder).setAddress(readData);
     }
 
-    // TODO refactor after there is a more generic implementation of cache operations
-    // FIXME update TODO with what exactly should be refactored and how
-    // TODO refactor after there is an more generic implementation of cache
-    // operations
-    private Optional<IpAddressDetailsReplyDump> dumpAddresses(InstanceIdentifier<Address> id, ReadContext ctx)
-            throws ReadFailedException {
-        final String cacheKey = CACHE_KEY + id.firstKeyOf(Interface.class).getName();
-        Optional<IpAddressDetailsReplyDump> dumpFromCache = dumpAddressFromCache(cacheKey, ctx.getModificationCache());
-
-        if (dumpFromCache.isPresent()) {
-            return dumpFromCache;
-        }
-
-        Optional<IpAddressDetailsReplyDump> dumpFromOperational;
-        try {
-            dumpFromOperational = dumpAddressFromOperationalData(id, ctx.getMappingContext());
-        } catch (VppBaseCallException e) {
-            throw new ReadFailedException(id, e);
-        }
-
-        if (dumpFromOperational.isPresent()) {
-            ctx.getModificationCache().put(cacheKey, dumpFromOperational.get());
-        }
-
-        return dumpFromOperational;
-    }
-
-    private Optional<IpAddressDetailsReplyDump> dumpAddressFromCache(final String cacheKey,
-                                                                     ModificationCache cache) {
-        LOG.debug("Dumping from cache...");
-        return Optional.fromNullable((IpAddressDetailsReplyDump) cache.get(cacheKey));
-    }
-
-    private Optional<IpAddressDetailsReplyDump> dumpAddressFromOperationalData(final InstanceIdentifier<Address> id,
-                                                                               final MappingContext mappingContext)
-        throws VppBaseCallException, ReadTimeoutException {
-        LOG.debug("Dumping from operational data...");
-        final IpAddressDump dumpRequest = new IpAddressDump();
-        dumpRequest.isIpv6 = 0;
-        dumpRequest.swIfIndex = interfaceContext.getIndex(id.firstKeyOf(Interface.class).getName(), mappingContext);
-        return Optional.fromNullable(
-            TranslateUtils.getReplyForRead(getFutureJVpp().ipAddressDump(dumpRequest).toCompletableFuture(), id));
-    }
-
 }
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java
new file mode 100644 (file)
index 0000000..e7dfffd
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * 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.v3po.translate.v3po.interfacesstate.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.util.RWUtils;
+import io.fd.honeycomb.v3po.translate.v3po.util.ReadTimeoutException;
+import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.dto.IpAddressDetails;
+import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump;
+import org.openvpp.jvpp.dto.IpAddressDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class providing Ipv4 read support.
+ */
+final class Ipv4ReadUtils {
+
+    static final String CACHE_KEY = Ipv4ReadUtils.class.getName();
+    private static final Logger LOG = LoggerFactory.getLogger(Ipv4ReadUtils.class);
+
+    private Ipv4ReadUtils() {
+        throw new UnsupportedOperationException("This utility class cannot be instantiated");
+    }
+
+    // Many VPP APIs do not provide get operation for single item. Dump requests for all items are used instead.
+    // To improve HC performance, caching dump requests is a common pattern.
+    // TODO: use more generic caching implementation, once provided
+    static Optional<IpAddressDetailsReplyDump> dumpAddresses(@Nonnull final FutureJVpp futureJvpp,
+                                                             @Nonnull final InstanceIdentifier<?> id,
+                                                             @Nonnull final String interfaceName,
+                                                             final int interfaceIndex, @Nonnull final ReadContext ctx)
+        throws ReadFailedException {
+
+        final String cacheKey = CACHE_KEY + interfaceName;
+        Optional<IpAddressDetailsReplyDump> dumpFromCache = dumpAddressFromCache(cacheKey, ctx.getModificationCache());
+
+        if (dumpFromCache.isPresent()) {
+            return dumpFromCache;
+        }
+
+        Optional<IpAddressDetailsReplyDump> dumpFromOperational;
+        try {
+            dumpFromOperational = dumpAddressFromOperationalData(futureJvpp, id, interfaceIndex);
+        } catch (VppBaseCallException e) {
+            throw new ReadFailedException(id, e);
+        }
+
+        if (dumpFromOperational.isPresent()) {
+            ctx.getModificationCache().put(cacheKey, dumpFromOperational.get());
+        }
+
+        return dumpFromOperational;
+    }
+
+    private static Optional<IpAddressDetailsReplyDump> dumpAddressFromCache(@Nonnull final String cacheKey,
+                                                                            @Nonnull final ModificationCache cache) {
+        LOG.debug("Retrieving Ipv4 addresses from cache for {}", cacheKey);
+        return Optional.fromNullable((IpAddressDetailsReplyDump) cache.get(cacheKey));
+    }
+
+    private static Optional<IpAddressDetailsReplyDump> dumpAddressFromOperationalData(
+        @Nonnull final FutureJVpp futureJvpp, @Nonnull final InstanceIdentifier<?> id, final int interfaceIndex)
+        throws VppBaseCallException, ReadTimeoutException {
+        LOG.debug("Dumping Ipv4 addresses for interface id={}", interfaceIndex);
+        final IpAddressDump dumpRequest = new IpAddressDump();
+        dumpRequest.isIpv6 = 0;
+        dumpRequest.swIfIndex = interfaceIndex;
+        return Optional.fromNullable(
+            TranslateUtils.getReplyForRead(futureJvpp.ipAddressDump(dumpRequest).toCompletableFuture(), id));
+    }
+
+    @Nonnull static <T extends Identifier> List<T> getAllIpv4AddressIds(
+        final Optional<IpAddressDetailsReplyDump> dumpOptional,
+        @Nonnull final Function<Ipv4AddressNoZone, T> keyConstructor) {
+        if (dumpOptional.isPresent() && dumpOptional.get().ipAddressDetails != null) {
+            return dumpOptional.get().ipAddressDetails.stream()
+                .map(detail -> keyConstructor.apply(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip)))
+                .collect(Collectors.toList());
+        } else {
+            return Collections.emptyList();
+        }
+    }
+
+    static Optional<IpAddressDetails> findIpAddressDetailsByIp(
+        final Optional<IpAddressDetailsReplyDump> dump,
+        @Nonnull final Ipv4AddressNoZone ip) {
+        checkNotNull(ip, "ip address should not be null");
+
+        if (dump.isPresent() && dump.get().ipAddressDetails != null) {
+            final List<IpAddressDetails> details = dump.get().ipAddressDetails;
+
+            return Optional.of(details.stream()
+                .filter(singleDetail -> ip.equals(TranslateUtils.arrayToIpv4AddressNoZone(singleDetail.ip)))
+                .collect(RWUtils.singleItemCollector()));
+        }
+        return Optional.absent();
+    }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java
new file mode 100644 (file)
index 0000000..a8a47d7
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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.v3po.translate.v3po.interfacesstate.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.dumpAddresses;
+import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.findIpAddressDetailsByIp;
+import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.getAllIpv4AddressIds;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.v3po.translate.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils;
+import java.util.List;
+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.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLengthBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.dto.IpAddressDetails;
+import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump;
+import org.openvpp.jvpp.future.FutureJVpp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Read customizer for sub-interface Ipv4 addresses.
+ */
+public class SubInterfaceIpv4AddressCustomizer extends FutureJVppCustomizer
+    implements ListReaderCustomizer<Address, AddressKey, AddressBuilder> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIpv4AddressCustomizer.class);
+
+    private final NamingContext interfaceContext;
+
+    public SubInterfaceIpv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp,
+                                             @Nonnull final NamingContext interfaceContext) {
+        super(futureJvpp);
+        this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+    }
+
+    @Override
+    @Nonnull
+    public AddressBuilder getBuilder(@Nonnull InstanceIdentifier<Address> id) {
+        return new AddressBuilder();
+    }
+
+    @Override
+    public void readCurrentAttributes(@Nonnull InstanceIdentifier<Address> id, @Nonnull AddressBuilder builder,
+                                      @Nonnull ReadContext ctx)
+        throws ReadFailedException {
+        LOG.debug("Reading attributes for sub-interface address: {}", id);
+
+        final String subInterfaceName = getSubInterfaceName(id);
+        final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext());
+        final Optional<IpAddressDetailsReplyDump> dumpOptional =
+            dumpAddresses(getFutureJVpp(), id, subInterfaceName, subInterfaceIndex, ctx);
+
+        final Optional<IpAddressDetails> ipAddressDetails =
+            findIpAddressDetailsByIp(dumpOptional, id.firstKeyOf(Address.class).getIp());
+
+        if (ipAddressDetails.isPresent()) {
+            final IpAddressDetails detail = ipAddressDetails.get();
+            builder.setIp(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip))
+                .setSubnet(new PrefixLengthBuilder().setPrefixLength(Short.valueOf(detail.prefixLength)).build());
+
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Attributes for {} sub-interface (id={}) address {} successfully read: {}",
+                    subInterfaceName, subInterfaceIndex, id, builder.build());
+            }
+        }
+    }
+
+    @Override
+    public List<AddressKey> getAllIds(@Nonnull InstanceIdentifier<Address> id, @Nonnull ReadContext ctx)
+        throws ReadFailedException {
+        LOG.debug("Reading list of keys for sub-interface addresses: {}", id);
+
+        final String subInterfaceName = getSubInterfaceName(id);
+        final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext());
+        final Optional<IpAddressDetailsReplyDump> dumpOptional =
+            dumpAddresses(getFutureJVpp(), id, subInterfaceName, subInterfaceIndex, ctx);
+
+        return getAllIpv4AddressIds(dumpOptional, AddressKey::new);
+    }
+
+    @Override
+    public void merge(@Nonnull Builder<? extends DataObject> builder, @Nonnull List<Address> readData) {
+        ((Ipv4Builder) builder).setAddress(readData);
+    }
+
+    private static String getSubInterfaceName(@Nonnull final InstanceIdentifier<Address> id) {
+        return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(),
+            Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier()));
+    }
+}
index 9215f39..e1513c2 100644 (file)
@@ -1,7 +1,5 @@
 package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406;
 
-import static io.fd.honeycomb.v3po.translate.util.RWUtils.singletonChildWriterList;
-
 import com.google.common.collect.Lists;
 import io.fd.honeycomb.v3po.translate.impl.TraversalType;
 import io.fd.honeycomb.v3po.translate.impl.write.CompositeChildWriter;
@@ -11,19 +9,15 @@ import io.fd.honeycomb.v3po.translate.util.RWUtils;
 import io.fd.honeycomb.v3po.translate.util.write.CloseableWriter;
 import io.fd.honeycomb.v3po.translate.util.write.NoopWriterCustomizer;
 import io.fd.honeycomb.v3po.translate.util.write.ReflexiveAugmentWriterCustomizer;
-import io.fd.honeycomb.v3po.translate.util.write.ReflexiveChildWriterCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfaces.EthernetCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfaces.InterfaceCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfaces.L2Customizer;
-import io.fd.honeycomb.v3po.translate.v3po.interfaces.RewriteCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfaces.RoutingCustomizer;
-import io.fd.honeycomb.v3po.translate.v3po.interfaces.SubInterfaceCustomizer;
-import io.fd.honeycomb.v3po.translate.v3po.interfaces.SubInterfaceL2Customizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfaces.TapCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfaces.VhostUserCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfaces.VxlanCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfaces.VxlanGpeCustomizer;
-import io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.AddressCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4AddressCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4Customizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv6Customizer;
 import io.fd.honeycomb.v3po.translate.write.ChildWriter;
@@ -43,16 +37,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpe;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfaces;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.ChildOf;
 
 public class InterfacesHoneycombWriterModule extends
-        org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.AbstractInterfacesHoneycombWriterModule {
+    org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.AbstractInterfacesHoneycombWriterModule {
     public InterfacesHoneycombWriterModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
                                            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
         super(identifier, dependencyResolver);
@@ -76,15 +65,17 @@ public class InterfacesHoneycombWriterModule extends
         final List<ChildWriter<? extends Augmentation<Interface>>> ifcAugmentations = Lists.newArrayList();
         ifcAugmentations.add(getVppIfcAugmentationWriter());
         ifcAugmentations.add(getInterface1AugmentationWriter());
-        ifcAugmentations.add(getSubinterfaceAugmentationWriter());
+        ifcAugmentations.add(
+            SubinterfaceAugmentationWriterFactory.createInstance(getVppJvppIfcDependency(), getInterfaceContextDependency(),
+                getBridgeDomainContextDependency()));
 
         final ChildWriter<Interface> interfaceWriter = new CompositeListWriter<>(Interface.class,
-                RWUtils.emptyChildWriterList(),
-                ifcAugmentations,
-                new InterfaceCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()),
-                // It's important that this customizer is handled in a postorder way, because you first have to handle child nodes
-                // e.g. Vxlan before setting other interface or vppInterfaceAugmentation leaves
-                TraversalType.POSTORDER);
+            RWUtils.emptyChildWriterList(),
+            ifcAugmentations,
+            new InterfaceCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()),
+            // It's important that this customizer is handled in a postorder way, because you first have to handle child nodes
+            // e.g. Vxlan before setting other interface or vppInterfaceAugmentation leaves
+            TraversalType.POSTORDER);
 
         final List<ChildWriter<? extends ChildOf<Interfaces>>> childWriters = new ArrayList<>();
         childWriters.add(interfaceWriter);
@@ -93,51 +84,51 @@ public class InterfacesHoneycombWriterModule extends
         // we loose the ordering information for root writers
         // Or can we rely to the order in which readers are configured ?
         return new CloseableWriter<>(new CompositeRootWriter<>(Interfaces.class,
-                childWriters, new NoopWriterCustomizer<>()));
+            childWriters, new NoopWriterCustomizer<>()));
     }
 
     private ChildWriter<? extends Augmentation<Interface>> getInterface1AugmentationWriter() {
 
         final ChildWriter<Address> addressWriter = new CompositeListWriter<>(Address.class,
-                new AddressCustomizer(getVppJvppIfcDependency(),getInterfaceContextDependency()));
+            new Ipv4AddressCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
 
         final ChildWriter<Ipv4> ipv4Writer = new CompositeChildWriter<>(Ipv4.class,
-                RWUtils.singletonChildWriterList(addressWriter),
-                new Ipv4Customizer(getVppJvppIfcDependency(),getInterfaceContextDependency()));
+            RWUtils.singletonChildWriterList(addressWriter),
+            new Ipv4Customizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
         final ChildWriter<Ipv6> ipv6Writer = new CompositeChildWriter<>(Ipv6.class,
-                new Ipv6Customizer(getVppJvppIfcDependency()));
+            new Ipv6Customizer(getVppJvppIfcDependency()));
 
         final List<ChildWriter<? extends ChildOf<Interface1>>> interface1ChildWriters = Lists.newArrayList();
         interface1ChildWriters.add(ipv4Writer);
         interface1ChildWriters.add(ipv6Writer);
 
         return new CompositeChildWriter<>(Interface1.class,
-                interface1ChildWriters, new ReflexiveAugmentWriterCustomizer<>());
+            interface1ChildWriters, new ReflexiveAugmentWriterCustomizer<>());
     }
 
     private ChildWriter<VppInterfaceAugmentation> getVppIfcAugmentationWriter() {
 
         final ChildWriter<Ethernet> ethernetWriter = new CompositeChildWriter<>(Ethernet.class,
-                new EthernetCustomizer(getVppJvppIfcDependency()));
+            new EthernetCustomizer(getVppJvppIfcDependency()));
 
         final ChildWriter<Routing> routingWriter = new CompositeChildWriter<>(Routing.class,
-                new RoutingCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
+            new RoutingCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
 
         final ChildWriter<Vxlan> vxlanWriter = new CompositeChildWriter<>(Vxlan.class,
-                new VxlanCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
+            new VxlanCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
 
         final ChildWriter<VxlanGpe> vxlanGpeWriter = new CompositeChildWriter<>(VxlanGpe.class,
-                new VxlanGpeCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
+            new VxlanGpeCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
 
         final ChildWriter<VhostUser> vhostUserWriter = new CompositeChildWriter<>(VhostUser.class,
-                new VhostUserCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
+            new VhostUserCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
 
         final ChildWriter<Tap> tapWriter = new CompositeChildWriter<>(Tap.class,
-                new TapCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
+            new TapCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
 
         final ChildWriter<L2> l2Writer = new CompositeChildWriter<>(L2.class,
-                new L2Customizer(getVppJvppIfcDependency(), getInterfaceContextDependency(),
-                        getBridgeDomainContextDependency())
+            new L2Customizer(getVppJvppIfcDependency(), getInterfaceContextDependency(),
+                getBridgeDomainContextDependency())
         );
 
         final List<ChildWriter<? extends ChildOf<VppInterfaceAugmentation>>> vppIfcChildWriters = Lists.newArrayList();
@@ -150,43 +141,8 @@ public class InterfacesHoneycombWriterModule extends
         vppIfcChildWriters.add(routingWriter);
 
         return new CompositeChildWriter<>(VppInterfaceAugmentation.class,
-                vppIfcChildWriters,
-                RWUtils.emptyAugWriterList(),
-                new ReflexiveAugmentWriterCustomizer<>());
-    }
-
-    private ChildWriter<SubinterfaceAugmentation> getSubinterfaceAugmentationWriter() {
-        final ChildWriter<? extends ChildOf<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2>> rewriteWriter =
-                new CompositeChildWriter<>(Rewrite.class,
-                        new RewriteCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
-
-        final List<ChildWriter<? extends ChildOf<SubInterface>>> childWriters = new ArrayList<>();
-        final ChildWriter<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2>
-                l2Writer = new CompositeChildWriter<>(
-                org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2.class,
-                singletonChildWriterList(rewriteWriter),
-                new SubInterfaceL2Customizer(getVppJvppIfcDependency(), getInterfaceContextDependency(),
-                        getBridgeDomainContextDependency())
-        );
-
-        // TODO L2 is ChildOf<SubInterfaceBaseAttributes>, but SubInterface extends SubInterfaceBaseAttributes
-        // If we use containers inside groupings, we need to cast and lose static type checking.
-        // Can we get rid of the cast?
-        childWriters.add((ChildWriter) l2Writer);
-
-        final CompositeListWriter<SubInterface, SubInterfaceKey> subInterfaceWriter = new CompositeListWriter<>(
-                SubInterface.class,
-                childWriters,
-                new SubInterfaceCustomizer(getVppJvppIfcDependency(), getInterfaceContextDependency()));
-
-        final ChildWriter<SubInterfaces> subInterfacesWriter = new CompositeChildWriter<>(
-                SubInterfaces.class,
-                singletonChildWriterList(subInterfaceWriter),
-                new ReflexiveChildWriterCustomizer<>());
-
-        return new CompositeChildWriter<>(SubinterfaceAugmentation.class,
-                singletonChildWriterList(subInterfacesWriter),
-                RWUtils.emptyAugWriterList(),
-                new ReflexiveAugmentWriterCustomizer<>());
+            vppIfcChildWriters,
+            RWUtils.emptyAugWriterList(),
+            new ReflexiveAugmentWriterCustomizer<>());
     }
 }
index 644a272..3b8c5a8 100644 (file)
@@ -12,14 +12,10 @@ import io.fd.honeycomb.v3po.translate.read.ChildReader;
 import io.fd.honeycomb.v3po.translate.util.RWUtils;
 import io.fd.honeycomb.v3po.translate.util.read.CloseableReader;
 import io.fd.honeycomb.v3po.translate.util.read.ReflexiveAugmentReaderCustomizer;
-import io.fd.honeycomb.v3po.translate.util.read.ReflexiveChildReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.util.read.ReflexiveRootReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.EthernetCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.L2Customizer;
-import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.RewriteCustomizer;
-import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.SubInterfaceCustomizer;
-import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.SubInterfaceL2Customizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.TapCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.VhostUserCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.VxlanCustomizer;
@@ -47,14 +43,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUser;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpe;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceStateAugmentation;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceStateAugmentationBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfaces;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfacesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.ChildOf;
 
@@ -83,7 +71,7 @@ public class InterfacesStateHoneycombReaderModule extends
                 interfaceAugReaders = new ArrayList<>();
         interfaceAugReaders.add(getVppInterfaceStateAugmentationReader());
         interfaceAugReaders.add(getInterface1AugmentationReader());
-        interfaceAugReaders.add(getSubinterfaceStateAugmentationReader());
+        interfaceAugReaders.add(SubinterfaceStateAugmentationReaderFactory.createInstance(getVppJvppDependency(), getInterfaceContextIfcStateDependency(), getBridgeDomainContextIfcStateDependency()));
 
         final CompositeListReader<Interface, InterfaceKey, InterfaceBuilder> interfaceReader =
                 new CompositeListReader<>(Interface.class,
@@ -159,35 +147,4 @@ public class InterfacesStateHoneycombReaderModule extends
                                 VppInterfaceStateAugmentation.class));
         return vppInterfaceStateAugmentationChildReader;
     }
-
-    private ChildReader<SubinterfaceStateAugmentation> getSubinterfaceStateAugmentationReader() {
-
-        final ChildReader<Rewrite> rewriteReader =
-        new CompositeChildReader<>(Rewrite.class,
-                new RewriteCustomizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency()));
-
-        final ChildReader<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2> l2Reader =
-                new CompositeChildReader<>(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2.class,
-                        singletonChildReaderList(rewriteReader),
-                        new SubInterfaceL2Customizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency(), getBridgeDomainContextIfcStateDependency()));
-
-        List<ChildReader<? extends ChildOf<SubInterface>>> childReaders = new ArrayList<>();
-        childReaders.add((ChildReader) l2Reader); // TODO can get rid of that cast?
-
-        final CompositeListReader<SubInterface, SubInterfaceKey, SubInterfaceBuilder> subInterfaceReader =
-                new CompositeListReader<>(SubInterface.class, childReaders, new SubInterfaceCustomizer(getVppJvppDependency(),
-                        getInterfaceContextIfcStateDependency()));
-
-        final ChildReader<SubInterfaces> subInterfacesReader = new CompositeChildReader<>(
-                SubInterfaces.class,
-                RWUtils.singletonChildReaderList(subInterfaceReader),
-                new ReflexiveChildReaderCustomizer<>(SubInterfacesBuilder.class));
-
-        final ChildReader<SubinterfaceStateAugmentation> subinterfaceStateAugmentationReader =
-                new CompositeChildReader<>(SubinterfaceStateAugmentation.class,
-                        singletonChildReaderList(subInterfacesReader),
-                        new ReflexiveAugmentReaderCustomizer<>(SubinterfaceStateAugmentationBuilder.class,
-                                SubinterfaceStateAugmentation.class));
-        return subinterfaceStateAugmentationReader;
-    }
 }
diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceAugmentationWriterFactory.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceAugmentationWriterFactory.java
new file mode 100644 (file)
index 0000000..f24dbf7
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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 org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406;
+
+import static io.fd.honeycomb.v3po.translate.util.RWUtils.singletonChildWriterList;
+
+import io.fd.honeycomb.v3po.translate.impl.write.CompositeChildWriter;
+import io.fd.honeycomb.v3po.translate.impl.write.CompositeListWriter;
+import io.fd.honeycomb.v3po.translate.util.RWUtils;
+import io.fd.honeycomb.v3po.translate.util.write.ReflexiveAugmentWriterCustomizer;
+import io.fd.honeycomb.v3po.translate.util.write.ReflexiveChildWriterCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.interfaces.RewriteCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.interfaces.SubInterfaceCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.interfaces.SubInterfaceL2Customizer;
+import io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.SubInterfaceIpv4AddressCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.v3po.translate.write.ChildWriter;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
+import org.openvpp.jvpp.future.FutureJVpp;
+
+final class SubinterfaceAugmentationWriterFactory {
+
+    private SubinterfaceAugmentationWriterFactory() {
+    }
+
+    private static ChildWriter<Ipv4> getIp4Writer(
+        @Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext) {
+
+        final ChildWriter<Address> addressWriter = new CompositeListWriter<>(
+            Address.class,
+            new SubInterfaceIpv4AddressCustomizer(futureJvpp, interfaceContext));
+
+        return new CompositeChildWriter<>(
+            Ipv4.class,
+            RWUtils.singletonChildWriterList(addressWriter),
+            new ReflexiveChildWriterCustomizer<>());
+    }
+
+    private static ChildWriter<L2> getL2Writer(
+        @Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext,
+        @Nonnull final NamingContext bridgeDomainContext) {
+
+        final ChildWriter<? extends ChildOf<L2>> rewriteWriter =
+            new CompositeChildWriter<>(Rewrite.class, new RewriteCustomizer(futureJvpp, interfaceContext));
+
+        return new CompositeChildWriter<>(
+            L2.class,
+            singletonChildWriterList(rewriteWriter),
+            new SubInterfaceL2Customizer(futureJvpp, interfaceContext, bridgeDomainContext)
+        );
+    }
+
+    static ChildWriter<SubinterfaceAugmentation> createInstance(
+        @Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext,
+        @Nonnull final NamingContext bridgeDomainContext) {
+        final List<ChildWriter<? extends ChildOf<SubInterface>>> childWriters = new ArrayList<>();
+
+        // TODO L2 is ChildOf<SubInterfaceBaseAttributes>, but SubInterface extends SubInterfaceBaseAttributes
+        // If we use containers inside groupings, we need to cast and lose static type checking.
+        // Can we get rid of the cast?
+        childWriters.add((ChildWriter) getL2Writer(futureJvpp, interfaceContext, bridgeDomainContext));
+        childWriters.add((ChildWriter) getIp4Writer(futureJvpp, interfaceContext));
+
+        final CompositeListWriter<SubInterface, SubInterfaceKey> subInterfaceWriter = new CompositeListWriter<>(
+            SubInterface.class,
+            childWriters,
+            new SubInterfaceCustomizer(futureJvpp, interfaceContext));
+
+        final ChildWriter<SubInterfaces> subInterfacesWriter = new CompositeChildWriter<>(
+            SubInterfaces.class,
+            singletonChildWriterList(subInterfaceWriter),
+            new ReflexiveChildWriterCustomizer<>());
+
+        return new CompositeChildWriter<>(
+            SubinterfaceAugmentation.class,
+            singletonChildWriterList(subInterfacesWriter),
+            RWUtils.emptyAugWriterList(),
+            new ReflexiveAugmentWriterCustomizer<>());
+    }
+}
diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceStateAugmentationReaderFactory.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceStateAugmentationReaderFactory.java
new file mode 100644 (file)
index 0000000..9e182b1
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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 org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406;
+
+import static io.fd.honeycomb.v3po.translate.util.RWUtils.singletonChildReaderList;
+
+import io.fd.honeycomb.v3po.translate.impl.read.CompositeChildReader;
+import io.fd.honeycomb.v3po.translate.impl.read.CompositeListReader;
+import io.fd.honeycomb.v3po.translate.read.ChildReader;
+import io.fd.honeycomb.v3po.translate.util.RWUtils;
+import io.fd.honeycomb.v3po.translate.util.read.ReflexiveAugmentReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.util.read.ReflexiveChildReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.RewriteCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.SubInterfaceCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.SubInterfaceL2Customizer;
+import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.SubInterfaceIpv4AddressCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
+import org.openvpp.jvpp.future.FutureJVpp;
+
+final class SubinterfaceStateAugmentationReaderFactory {
+
+    private SubinterfaceStateAugmentationReaderFactory() {
+    }
+
+    private static ChildReader<L2> getL2Reader(@Nonnull final FutureJVpp futureJvpp,
+                                                 @Nonnull final NamingContext interfaceContext,
+                                                 @Nonnull final NamingContext bridgeDomainContext) {
+        final ChildReader<Rewrite> rewriteReader = new CompositeChildReader<>(
+            Rewrite.class, new RewriteCustomizer(futureJvpp, interfaceContext));
+
+        return new CompositeChildReader<>(L2.class,
+                singletonChildReaderList(rewriteReader),
+                new SubInterfaceL2Customizer(futureJvpp, interfaceContext, bridgeDomainContext));
+    }
+
+    private static ChildReader<Ipv4> getIpv4Reader(@Nonnull final FutureJVpp futureJvpp,
+                                                   @Nonnull final NamingContext interfaceContext) {
+
+        final ChildReader<Address> addressReader = new CompositeListReader<>(Address.class,
+            new SubInterfaceIpv4AddressCustomizer(futureJvpp, interfaceContext));
+
+        return new CompositeChildReader<>(
+            Ipv4.class,
+            RWUtils.singletonChildReaderList(addressReader),
+            new ReflexiveChildReaderCustomizer<>(Ipv4Builder.class));
+
+    }
+
+    static ChildReader<SubinterfaceStateAugmentation> createInstance(
+        @Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext,
+        @Nonnull final NamingContext bridgeDomainContext) {
+
+        List<ChildReader<? extends ChildOf<SubInterface>>> childReaders = new ArrayList<>();
+
+        // TODO can get rid of that cast?
+        childReaders.add((ChildReader) getL2Reader(futureJvpp, interfaceContext, bridgeDomainContext));
+        childReaders.add((ChildReader) getIpv4Reader(futureJvpp, interfaceContext));
+
+        final CompositeListReader<SubInterface, SubInterfaceKey, SubInterfaceBuilder> subInterfaceReader =
+            new CompositeListReader<>(SubInterface.class, childReaders, new SubInterfaceCustomizer(futureJvpp,
+                interfaceContext));
+
+        final ChildReader<SubInterfaces> subInterfacesReader = new CompositeChildReader<>(
+            SubInterfaces.class,
+            RWUtils.singletonChildReaderList(subInterfaceReader),
+            new ReflexiveChildReaderCustomizer<>(SubInterfacesBuilder.class));
+
+        final ChildReader<SubinterfaceStateAugmentation> subinterfaceStateAugmentationReader =
+            new CompositeChildReader<>(SubinterfaceStateAugmentation.class,
+                singletonChildReaderList(subInterfacesReader),
+                new ReflexiveAugmentReaderCustomizer<>(
+                    SubinterfaceStateAugmentationBuilder.class,
+                    SubinterfaceStateAugmentation.class));
+
+        return subinterfaceStateAugmentationReader;
+    }
+}
@@ -61,7 +61,7 @@ import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress;
 import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply;
 import org.openvpp.jvpp.future.FutureJVpp;
 
-public class AddressCustomizerTest {
+public class Ipv4AddressCustomizerTest {
 
     private static final String IFC_CTX_NAME = "ifc-test-instance";
     private static final String IFACE_NAME = "eth0";
@@ -75,7 +75,7 @@ public class AddressCustomizerTest {
     private FutureJVpp api;
 
     private NamingContext interfaceContext;
-    private AddressCustomizer customizer;
+    private Ipv4AddressCustomizer customizer;
 
     @Before
     public void setUp() throws Exception {
@@ -83,7 +83,7 @@ public class AddressCustomizerTest {
         doReturn(mappingContext).when(writeContext).getMappingContext();
         interfaceContext = new NamingContext("generatedlIfaceName", IFC_CTX_NAME);
 
-        customizer = new AddressCustomizer(api, interfaceContext);
+        customizer = new Ipv4AddressCustomizer(api, interfaceContext);
     }
 
     private static InstanceIdentifier<Address> getAddressId(final String ifaceName) {
index 5844646..be67771 100644 (file)
@@ -126,7 +126,7 @@ public class Ipv4AddressCustomizerTest extends ListReaderCustomizerTest<Address,
         IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump();
         reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3);
 
-        cache.put(Ipv4AddressCustomizer.class.getName() + IFACE_NAME, reply);
+        cache.put(Ipv4ReadUtils.CACHE_KEY + IFACE_NAME, reply);
         when(ctx.getModificationCache()).thenReturn(cache);
 
         final AddressBuilder builder = new AddressBuilder();
@@ -231,7 +231,7 @@ public class Ipv4AddressCustomizerTest extends ListReaderCustomizerTest<Address,
         IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump();
         reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3);
 
-        cache.put(Ipv4AddressCustomizer.class.getName() + IFACE_NAME, reply);
+        cache.put(Ipv4ReadUtils.CACHE_KEY + IFACE_NAME, reply);
         when(ctx.getModificationCache()).thenReturn(cache);
 
         final InstanceIdentifier<Address> id = getId("192.168.2.1", IFACE_NAME);
index 1df82af..0aff6c1 100644 (file)
@@ -21,6 +21,35 @@ public final class SubInterfaceUtils {
     private SubInterfaceUtils() {
         throw new UnsupportedOperationException("Utility class cannot be instantiated.");
     }
+//
+//    @Nullable
+//    private static String getCfgIfaceName(@Nonnull final InstanceIdentifier<?> id) {
+//        final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey key = id.firstKeyOf(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface.class);
+//        if (key == null) {
+//            return null;
+//        } else {
+//            return key.getName();
+//        }
+//    }
+//
+//    @Nullable
+//    private static String getOperIfaceName(@Nonnull final InstanceIdentifier<?> id) {
+//        final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey key = id.firstKeyOf(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
+//        if (key == null) {
+//            return null;
+//        } else {
+//            return key.getName();
+//        }
+//    }
+//
+//    @Nullable
+//    public static String getSubInterfaceName(@Nonnull final InstanceIdentifier<?> id) {
+//        String ifaceName = getCfgIfaceName(id);
+//        if (ifaceName == null) {
+//            ifaceName = getOperIfaceName(id);
+//        }
+//        if (i)
+//    }
 
     public static String getSubInterfaceName(final String superIfName, final int subIfaceId) {
         return String.format("%s.%d", superIfName, subIfaceId);