summaryrefslogtreecommitdiffstats
path: root/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp
diff options
context:
space:
mode:
authorMaros Marsalek <mmarsale@cisco.com>2016-11-10 13:31:25 +0100
committerMarek Gradzki <mgradzki@cisco.com>2016-11-19 21:29:39 +0100
commit175197da8ea43335df3daeba4c6296fcd83a057c (patch)
tree110298a990c6191933c2ad65d1a06333bab76cee /v3po/v3po2vpp/src/main/java/io/fd/hc2vpp
parent1813bf59fa53e8eb913d34b212d45b227dead799 (diff)
Post split cleanup
- change groupIds - change packages - update poms Change-Id: I343c5a292a67de1dd50687870ca4ab5b7276e93e Signed-off-by: Maros Marsalek <mmarsale@cisco.com> Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
Diffstat (limited to 'v3po/v3po2vpp/src/main/java/io/fd/hc2vpp')
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/AclWriterFactory.java58
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/DisabledInterfacesManager.java106
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/EgressIetfAClWriterProvider.java39
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/IngressIetfAClWriterProvider.java39
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesStateReaderFactory.java187
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesWriterFactory.java244
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/SubinterfaceAugmentationWriterFactory.java158
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/SubinterfaceStateAugmentationReaderFactory.java118
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/V3poModule.java92
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppClassifierHoneycombWriterFactory.java64
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppClassifierReaderFactory.java60
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppHoneycombWriterFactory.java81
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppStateHoneycombReaderFactory.java90
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/cfgattrs/V3poConfiguration.java24
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/EthernetCustomizer.java58
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/GreCustomizer.java166
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/InterconnectionWriteUtils.java159
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/InterfaceCustomizer.java121
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/L2Customizer.java89
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/LoopbackCustomizer.java112
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ProxyArpCustomizer.java108
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/RewriteCustomizer.java136
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/RoutingCustomizer.java122
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/SubInterfaceCustomizer.java193
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/SubInterfaceL2Customizer.java100
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/TapCustomizer.java182
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/VhostUserCustomizer.java157
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/VxlanCustomizer.java192
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/VxlanGpeCustomizer.java194
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/IetfAclWriter.java106
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AbstractIetfAclWriter.java251
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceEthWriter.java85
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceIp4Writer.java94
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceIp6Writer.java99
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceIpAndEthWriter.java129
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceWriter.java54
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AclTableContextManager.java53
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AclTableContextManagerImpl.java68
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AclTranslator.java74
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/IetfAclWriter.java47
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/Ip4AclTranslator.java149
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/Ip6AclTranslator.java182
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/L2AclTranslator.java90
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/PortPair.java126
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/egress/EgressIetfAclWriter.java120
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/egress/IetfAclCustomizer.java85
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/egress/SubInterfaceIetfAclCustomizer.java105
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/AclCustomizer.java83
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/AclWriter.java73
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/IetfAclCustomizer.java89
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/IngressIetfAclWriter.java118
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/SubInterfaceAclCustomizer.java93
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizer.java108
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4AddressCustomizer.java151
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4Customizer.java56
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java126
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4Writer.java108
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv6Customizer.java55
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java131
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/subnet/validation/SubnetValidationException.java50
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/subnet/validation/SubnetValidator.java80
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/pbb/PbbRewriteCustomizer.java130
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/EthernetCustomizer.java108
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/GreCustomizer.java157
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterconnectionReadUtils.java125
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterfaceCustomizer.java232
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterfaceDataTranslator.java287
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/L2Customizer.java116
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ProxyArpCustomizer.java79
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/RewriteCustomizer.java147
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/SubInterfaceCustomizer.java264
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/SubInterfaceL2Customizer.java93
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/TapCustomizer.java143
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/VhostUserCustomizer.java154
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/VxlanCustomizer.java162
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/VxlanGpeCustomizer.java168
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/acl/ingress/AclCustomizer.java118
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/acl/ingress/AclReader.java60
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/acl/ingress/SubInterfaceAclCustomizer.java120
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java166
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4Customizer.java59
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java73
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4Reader.java84
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv6Customizer.java66
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java143
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/dump/params/AddressDumpParams.java44
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/pbb/PbbRewriteStateCustomizer.java57
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/notification/InterfaceChangeNotificationProducer.java163
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/util/SubInterfaceUtils.java52
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vpp/ArpTerminationTableEntryCustomizer.java118
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vpp/BridgeDomainCustomizer.java137
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vpp/L2FibEntryCustomizer.java129
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifySessionReader.java207
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifySessionWriter.java165
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifyTableReader.java171
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifyTableWriter.java149
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppClassifierContextManager.java106
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppClassifierContextManagerImpl.java181
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppNodeReader.java45
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppNodeWriter.java79
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppstate/BridgeDomainCustomizer.java181
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppstate/L2FibEntryCustomizer.java165
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppstate/VersionCustomizer.java82
103 files changed, 12172 insertions, 0 deletions
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/AclWriterFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/AclWriterFactory.java
new file mode 100644
index 000000000..dbac5f342
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/AclWriterFactory.java
@@ -0,0 +1,58 @@
+/*
+ * 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.hc2vpp.v3po;
+
+import static io.fd.hc2vpp.v3po.InterfacesWriterFactory.IETF_ACL_ID;
+import static io.fd.hc2vpp.v3po.SubinterfaceAugmentationWriterFactory.SUBIF_IETF_ACL_ID;
+
+import com.google.common.collect.Sets;
+import io.fd.honeycomb.translate.impl.write.GenericListWriter;
+import io.fd.hc2vpp.v3po.interfaces.acl.IetfAclWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.AccessListEntries;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.Actions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.DestinationPortRange;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRange;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class AclWriterFactory implements WriterFactory {
+
+ public static final InstanceIdentifier<Acl> ACL_ID =
+ InstanceIdentifier.create(AccessLists.class).child(Acl.class);
+
+ @Override
+ public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+
+ final InstanceIdentifier<Acl> aclIdRelative = InstanceIdentifier.create(Acl.class);
+
+ final InstanceIdentifier<Ace> aceId = aclIdRelative.child(AccessListEntries.class).child(Ace.class);
+ final InstanceIdentifier<Actions> actionsId = aceId.child(Actions.class);
+ final InstanceIdentifier<Matches> matchesId = aceId.child(Matches.class);
+ final InstanceIdentifier<SourcePortRange> srcPortId = matchesId.child((Class)SourcePortRange.class);
+ final InstanceIdentifier<DestinationPortRange> dstPortId = matchesId.child((Class)DestinationPortRange.class);
+
+ registry.subtreeAddBefore(Sets.newHashSet(aceId, actionsId, matchesId, srcPortId, dstPortId),
+ new GenericListWriter<>(ACL_ID, new IetfAclWriter()),
+ Sets.newHashSet(IETF_ACL_ID, SUBIF_IETF_ACL_ID));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/DisabledInterfacesManager.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/DisabledInterfacesManager.java
new file mode 100644
index 000000000..97bab706d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/DisabledInterfacesManager.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.v3po;
+
+import com.google.common.base.Optional;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.honeycomb.translate.util.read.BindingBrokerReader;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.DisabledInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.DisabledInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.disabled.interfaces.DisabledInterfaceIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.disabled.interfaces.DisabledInterfaceIndexBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.context.rev160909.disabled.interfaces.DisabledInterfaceIndexKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+/**
+ * Facade on top of {@link MappingContext} making access to {@link DisabledInterfaces} easier.
+ */
+public class DisabledInterfacesManager {
+
+ private static final InstanceIdentifier<DisabledInterfaces>
+ DISABLED_IFCS_ROOT = InstanceIdentifier.create(DisabledInterfaces.class);
+
+ /**
+ * Read the list of currently disabled interfaces.
+ */
+ public List<Integer> getDisabledInterfaces(@Nonnull final MappingContext ctx) {
+ final Optional<DisabledInterfaces> read = ctx.read(DISABLED_IFCS_ROOT);
+ if (read.isPresent()) {
+ return read.get().getDisabledInterfaceIndex().stream()
+ .map(DisabledInterfaceIndex::getIndex)
+ .collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * Check whether a specific interface is disabled.
+ */
+ public boolean isInterfaceDisabled(final int index, @Nonnull final MappingContext ctx) {
+ return ctx.read(getKeyedId(index))
+ .isPresent();
+ }
+
+ /**
+ * Make a specific interface disabled.
+ */
+ public void disableInterface(final int index, @Nonnull final MappingContext ctx) {
+ ctx.put(getKeyedId(index), getDisabledInterfaceIndex(index));
+ }
+
+ /**
+ * Remove interface disability.
+ */
+ public void removeDisabledInterface(final int index, @Nonnull final MappingContext ctx) {
+ ctx.delete(getKeyedId(index));
+ }
+
+ private static DisabledInterfaceIndex getDisabledInterfaceIndex(final int index) {
+ return new DisabledInterfaceIndexBuilder().setIndex(index).build();
+ }
+
+ private static KeyedInstanceIdentifier<DisabledInterfaceIndex, DisabledInterfaceIndexKey> getKeyedId(final int id) {
+ return DISABLED_IFCS_ROOT.child(DisabledInterfaceIndex.class, new DisabledInterfaceIndexKey(id));
+ }
+
+ public static final class ContextsReaderFactory implements ReaderFactory {
+
+ @Inject
+ @Named("honeycomb-context")
+ private DataBroker contextBindingBrokerDependency;
+
+ @Override
+ public void init(final ModifiableReaderRegistryBuilder registry) {
+ registry.add(new BindingBrokerReader<>(DISABLED_IFCS_ROOT,
+ contextBindingBrokerDependency,
+ LogicalDatastoreType.OPERATIONAL, DisabledInterfacesBuilder.class));
+ }
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/EgressIetfAClWriterProvider.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/EgressIetfAClWriterProvider.java
new file mode 100644
index 000000000..0e4aaa80d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/EgressIetfAClWriterProvider.java
@@ -0,0 +1,39 @@
+/*
+ * 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.hc2vpp.v3po;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import io.fd.hc2vpp.v3po.interfaces.acl.egress.EgressIetfAclWriter;
+import io.fd.hc2vpp.v3po.interfaces.acl.common.AclTableContextManagerImpl;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.MappingTable;
+
+class EgressIetfAClWriterProvider implements Provider<EgressIetfAclWriter> {
+
+ private final FutureJVppCore jvpp;
+
+ @Inject
+ public EgressIetfAClWriterProvider(final FutureJVppCore jvpp) {
+ this.jvpp = jvpp;
+ }
+
+ @Override
+ public EgressIetfAclWriter get() {
+ return new EgressIetfAclWriter(jvpp, new AclTableContextManagerImpl(MappingTable.Direction.Egress));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/IngressIetfAClWriterProvider.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/IngressIetfAClWriterProvider.java
new file mode 100644
index 000000000..12349a356
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/IngressIetfAClWriterProvider.java
@@ -0,0 +1,39 @@
+/*
+ * 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.hc2vpp.v3po;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import io.fd.hc2vpp.v3po.interfaces.acl.common.AclTableContextManagerImpl;
+import io.fd.hc2vpp.v3po.interfaces.acl.ingress.IngressIetfAclWriter;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.MappingTable;
+
+class IngressIetfAClWriterProvider implements Provider<IngressIetfAclWriter> {
+
+ private final FutureJVppCore jvpp;
+
+ @Inject
+ public IngressIetfAClWriterProvider(final FutureJVppCore jvpp) {
+ this.jvpp = jvpp;
+ }
+
+ @Override
+ public IngressIetfAclWriter get() {
+ return new IngressIetfAclWriter(jvpp, new AclTableContextManagerImpl(MappingTable.Direction.Ingress));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesStateReaderFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesStateReaderFactory.java
new file mode 100644
index 000000000..f01cd9e99
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesStateReaderFactory.java
@@ -0,0 +1,187 @@
+/*
+ * 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.hc2vpp.v3po;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.v3po.interfacesstate.ip.Ipv4AddressCustomizer;
+import io.fd.honeycomb.translate.impl.read.GenericInitListReader;
+import io.fd.honeycomb.translate.impl.read.GenericInitReader;
+import io.fd.honeycomb.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.translate.impl.read.GenericReader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.hc2vpp.v3po.interfacesstate.EthernetCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.GreCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.InterfaceCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.L2Customizer;
+import io.fd.hc2vpp.v3po.interfacesstate.ProxyArpCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.TapCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.VhostUserCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.VxlanCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.VxlanGpeCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.acl.ingress.AclCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.ip.Ipv4Customizer;
+import io.fd.hc2vpp.v3po.interfacesstate.ip.Ipv4NeighbourCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.ip.Ipv6Customizer;
+import io.fd.hc2vpp.v3po.interfacesstate.pbb.PbbRewriteStateCustomizer;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder;
+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.Ipv6;
+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.Neighbor;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Ethernet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Gre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.ProxyArp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Tap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.VhostUser;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Vxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.VxlanGpe;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.L2Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.pbb.rev161214.PbbRewriteStateInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.pbb.rev161214.PbbRewriteStateInterfaceAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.pbb.rev161214.interfaces.state._interface.PbbRewriteState;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class InterfacesStateReaderFactory implements ReaderFactory {
+
+ private final NamingContext ifcNamingCtx;
+ private final NamingContext bdNamingCtx;
+ private final VppClassifierContextManager classifyContext;
+ private final DisabledInterfacesManager ifcDisableContext;
+ private final FutureJVppCore jvpp;
+
+ static final InstanceIdentifier<InterfacesState> IFC_STATE_ID =
+ InstanceIdentifier.create(InterfacesState.class);
+ static final InstanceIdentifier<Interface> IFC_ID = IFC_STATE_ID.child(Interface.class);
+
+ @Inject
+ public InterfacesStateReaderFactory(final FutureJVppCore jvpp,
+ @Named("interface-context") final NamingContext ifcNamingCtx,
+ @Named("bridge-domain-context") final NamingContext bdNamingCtx,
+ @Named("classify-table-context") final VppClassifierContextManager classifyContext,
+ final DisabledInterfacesManager ifcDisableContext) {
+ this.jvpp = jvpp;
+ this.ifcNamingCtx = ifcNamingCtx;
+ this.bdNamingCtx = bdNamingCtx;
+ this.classifyContext = classifyContext;
+ this.ifcDisableContext = ifcDisableContext;
+ }
+
+ @Override
+ public void init(final ModifiableReaderRegistryBuilder registry) {
+ // InterfacesState(Structural)
+ registry.addStructuralReader(IFC_STATE_ID, InterfacesStateBuilder.class);
+ // Interface
+ registry.add(new GenericInitListReader<>(IFC_ID, new InterfaceCustomizer(jvpp, ifcNamingCtx, ifcDisableContext)));
+
+ // v3po.yang
+ initVppIfcAugmentationReaders(registry, IFC_ID);
+ // ietf-ip.yang
+ initInterface2AugmentationReaders(registry, IFC_ID);
+ // vpp-vlan.yang
+ new SubinterfaceStateAugmentationReaderFactory(jvpp, ifcNamingCtx, bdNamingCtx, classifyContext).init(registry);
+ //vpp-pbb.yang
+ initPbbRewriteAugmentation(registry, IFC_ID);
+ }
+
+ private void initInterface2AugmentationReaders(final ModifiableReaderRegistryBuilder registry,
+ final InstanceIdentifier<Interface> ifcId) {
+ // Interface2Augmentation(Structural)
+ final InstanceIdentifier<Interface2> ifc2AugId = ifcId.augmentation(Interface2.class);
+ registry.addStructuralReader(ifc2AugId, Interface2Builder.class);
+ // Ipv4
+ final InstanceIdentifier<Ipv4> ipv4Id = ifc2AugId.child(Ipv4.class);
+ registry.add(new GenericReader<>(ipv4Id, new Ipv4Customizer(jvpp)));
+ // Address
+ final InstanceIdentifier<Address> ipv4AddrId = ipv4Id.child(Address.class);
+ registry.add(new GenericInitListReader<>(ipv4AddrId, new Ipv4AddressCustomizer(jvpp, ifcNamingCtx)));
+ // Neighbor
+ final InstanceIdentifier<Neighbor> neighborId = ipv4Id.child(Neighbor.class);
+ registry.add(new GenericListReader<>(neighborId, new Ipv4NeighbourCustomizer(jvpp)));
+ // Ipv6
+ final InstanceIdentifier<Ipv6> ipv6Id = ifc2AugId.child(Ipv6.class);
+ registry.add(new GenericReader<>(ipv6Id, new Ipv6Customizer(jvpp, ifcNamingCtx)));
+ }
+
+ private void initVppIfcAugmentationReaders(final ModifiableReaderRegistryBuilder registry,
+ final InstanceIdentifier<Interface> ifcId) {
+ // VppInterfaceStateAugmentation
+ final InstanceIdentifier<VppInterfaceStateAugmentation> vppIfcAugId =
+ ifcId.augmentation(VppInterfaceStateAugmentation.class);
+ registry.addStructuralReader(vppIfcAugId, VppInterfaceStateAugmentationBuilder.class);
+ // Ethernet
+ registry.add(new GenericInitReader<>(vppIfcAugId.child(Ethernet.class),
+ new EthernetCustomizer(jvpp, ifcNamingCtx)));
+ // Tap
+ registry.add(new GenericInitReader<>(vppIfcAugId.child(Tap.class), new TapCustomizer(jvpp, ifcNamingCtx)));
+ // VhostUser
+ registry.add(new GenericInitReader<>(vppIfcAugId.child(VhostUser.class),
+ new VhostUserCustomizer(jvpp, ifcNamingCtx)));
+ // Vxlan
+ registry.add(new GenericInitReader<>(vppIfcAugId.child(Vxlan.class), new VxlanCustomizer(jvpp, ifcNamingCtx)));
+ // VxlanGpe
+ registry.add(new GenericInitReader<>(vppIfcAugId.child(VxlanGpe.class),
+ new VxlanGpeCustomizer(jvpp, ifcNamingCtx)));
+ // Gre
+ registry.add(new GenericInitReader<>(vppIfcAugId.child(Gre.class), new GreCustomizer(jvpp, ifcNamingCtx)));
+ // L2
+ registry.add(new GenericInitReader<>(vppIfcAugId.child(L2.class),
+ new L2Customizer(jvpp, ifcNamingCtx, bdNamingCtx)));
+
+ // Acl(Structural)
+ final InstanceIdentifier<Acl> aclIid = vppIfcAugId.child(Acl.class);
+ registry.addStructuralReader(aclIid, AclBuilder.class);
+ // Ingress(Subtree)
+ final InstanceIdentifier<Ingress> ingressIdRelative = InstanceIdentifier.create(Ingress.class);
+ registry.subtreeAdd(
+ Sets.newHashSet(ingressIdRelative.child(L2Acl.class), ingressIdRelative.child(Ip4Acl.class),
+ ingressIdRelative.child(Ip6Acl.class)),
+ new GenericInitReader<>(aclIid.child(Ingress.class),
+ new AclCustomizer(jvpp, ifcNamingCtx, classifyContext)));
+
+ // Proxy ARP
+ registry.add(new GenericReader<>(vppIfcAugId.child(ProxyArp.class), new ProxyArpCustomizer(jvpp,
+ ifcNamingCtx)));
+ }
+
+ private void initPbbRewriteAugmentation(final ModifiableReaderRegistryBuilder registry,
+ final InstanceIdentifier<Interface> ifcId) {
+ registry.addStructuralReader(ifcId.augmentation(PbbRewriteStateInterfaceAugmentation.class),
+ PbbRewriteStateInterfaceAugmentationBuilder.class);
+
+ registry.add(new GenericReader<>(ifcId.augmentation(PbbRewriteStateInterfaceAugmentation.class).child(
+ PbbRewriteState.class), new PbbRewriteStateCustomizer(jvpp)));
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesWriterFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesWriterFactory.java
new file mode 100644
index 000000000..eb68b6fbf
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/InterfacesWriterFactory.java
@@ -0,0 +1,244 @@
+/*
+ * 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.hc2vpp.v3po;
+
+import static io.fd.hc2vpp.v3po.VppClassifierHoneycombWriterFactory.CLASSIFY_SESSION_ID;
+import static io.fd.hc2vpp.v3po.VppClassifierHoneycombWriterFactory.CLASSIFY_TABLE_ID;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.v3po.interfaces.EthernetCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.GreCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.L2Customizer;
+import io.fd.hc2vpp.v3po.interfaces.LoopbackCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.TapCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.VxlanCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.VxlanGpeCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.acl.egress.EgressIetfAclWriter;
+import io.fd.hc2vpp.v3po.interfaces.acl.ingress.AclCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.ip.Ipv4NeighbourCustomizer;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.impl.write.GenericListWriter;
+import io.fd.honeycomb.translate.impl.write.GenericWriter;
+import io.fd.hc2vpp.v3po.interfaces.InterfaceCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.ProxyArpCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.RoutingCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.VhostUserCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.acl.ingress.IngressIetfAclWriter;
+import io.fd.hc2vpp.v3po.interfaces.ip.Ipv4AddressCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.ip.Ipv4Customizer;
+import io.fd.hc2vpp.v3po.interfaces.ip.Ipv6Customizer;
+import io.fd.hc2vpp.v3po.interfaces.pbb.PbbRewriteCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Set;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1;
+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.Ipv6;
+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.Neighbor;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Ethernet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Gre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.IetfAcl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Loopback;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ProxyArp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Routing;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Tap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VhostUser;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Vxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VxlanGpe;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.L2Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.pbb.rev161214.PbbRewriteInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.pbb.rev161214.interfaces._interface.PbbRewrite;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class InterfacesWriterFactory implements WriterFactory {
+
+ public static final InstanceIdentifier<Interface> IFC_ID =
+ InstanceIdentifier.create(Interfaces.class).child(Interface.class);
+ public static final InstanceIdentifier<VppInterfaceAugmentation> VPP_IFC_AUG_ID =
+ IFC_ID.augmentation(VppInterfaceAugmentation.class);
+ public static final InstanceIdentifier<Acl> ACL_ID = VPP_IFC_AUG_ID.child(Acl.class);
+ public static final InstanceIdentifier<Ingress> INGRESS_ACL_ID = ACL_ID.child(Ingress.class);
+ public static final InstanceIdentifier<L2> L2_ID = VPP_IFC_AUG_ID.child(L2.class);
+ public static final InstanceIdentifier<IetfAcl> IETF_ACL_ID = VPP_IFC_AUG_ID.child(IetfAcl.class);
+ public static final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ietf.acl.Ingress>
+ INGRESS_IETF_ACL_ID = IETF_ACL_ID.child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ietf.acl.Ingress.class);
+ public static final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ietf.acl.Egress>
+ EGRESS_IETF_ACL_ID = IETF_ACL_ID.child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ietf.acl.Egress.class);
+
+ private final FutureJVppCore jvpp;
+ private final IngressIetfAclWriter ingressAclWriter;
+ private final EgressIetfAclWriter egressAclWriter;
+ private final NamingContext bdNamingContext;
+ private final NamingContext ifcNamingContext;
+ private final VppClassifierContextManager classifyTableContext;
+ private final DisabledInterfacesManager ifcDisableContext;
+
+ @Inject
+ public InterfacesWriterFactory(final FutureJVppCore vppJvppIfcDependency,
+ final IngressIetfAclWriter ingressAclWriter,
+ final EgressIetfAclWriter egressAclWriter,
+ @Named("bridge-domain-context") final NamingContext bridgeDomainContextDependency,
+ @Named("interface-context") final NamingContext interfaceContextDependency,
+ @Named("classify-table-context") final VppClassifierContextManager classifyTableContext,
+ final DisabledInterfacesManager ifcDisableContext) {
+ this.jvpp = vppJvppIfcDependency;
+ this.ingressAclWriter = ingressAclWriter;
+ this.egressAclWriter = egressAclWriter;
+ this.bdNamingContext = bridgeDomainContextDependency;
+ this.ifcNamingContext = interfaceContextDependency;
+ this.ifcDisableContext = ifcDisableContext;
+ this.classifyTableContext = classifyTableContext;
+ }
+
+ @Override
+ public void init(final ModifiableWriterRegistryBuilder registry) {
+ // Interfaces
+ // Interface =
+ registry.add(new GenericListWriter<>(IFC_ID, new InterfaceCustomizer(jvpp, ifcNamingContext)));
+ // VppInterfaceAugmentation
+ addVppInterfaceAgmentationWriters(IFC_ID, registry);
+ // Interface1 (ietf-ip augmentation)
+ addInterface1AugmentationWriters(IFC_ID, registry);
+ // SubinterfaceAugmentation
+ new SubinterfaceAugmentationWriterFactory(jvpp, ingressAclWriter, egressAclWriter, ifcNamingContext, bdNamingContext,
+ classifyTableContext).init(registry);
+
+ addPbbAugmentationWriters(IFC_ID, registry);
+ }
+
+ private void addInterface1AugmentationWriters(final InstanceIdentifier<Interface> ifcId,
+ final ModifiableWriterRegistryBuilder registry) {
+ final InstanceIdentifier<Interface1> ifc1AugId = ifcId.augmentation(Interface1.class);
+ // Ipv6(after interface) =
+ registry.addAfter(new GenericWriter<>(ifc1AugId.child(Ipv6.class), new Ipv6Customizer(jvpp)),
+ ifcId);
+ // Ipv4(after interface)
+ final InstanceIdentifier<Ipv4> ipv4Id = ifc1AugId.child(Ipv4.class);
+ registry.addAfter(new GenericWriter<>(ipv4Id, new Ipv4Customizer(jvpp)),
+ ifcId);
+ // Address(after Ipv4) =
+ final InstanceIdentifier<Address> ipv4AddressId = ipv4Id.child(Address.class);
+ registry.addAfter(new GenericListWriter<>(ipv4AddressId, new Ipv4AddressCustomizer(jvpp, ifcNamingContext)),
+ ipv4Id);
+ // Neighbor(after ipv4Address)
+ registry.addAfter(new GenericListWriter<>(ipv4Id.child(Neighbor.class), new Ipv4NeighbourCustomizer(jvpp,
+ ifcNamingContext)),
+ ipv4AddressId);
+ }
+
+ private void addVppInterfaceAgmentationWriters(final InstanceIdentifier<Interface> ifcId,
+ final ModifiableWriterRegistryBuilder registry) {
+ // VhostUser(Needs to be executed before Interface customizer) =
+ final InstanceIdentifier<VhostUser> vhostId = VPP_IFC_AUG_ID.child(VhostUser.class);
+ registry.addBefore(new GenericWriter<>(vhostId, new VhostUserCustomizer(jvpp, ifcNamingContext)),
+ ifcId);
+ // Vxlan(Needs to be executed before Interface customizer) =
+ final InstanceIdentifier<Vxlan> vxlanId = VPP_IFC_AUG_ID.child(Vxlan.class);
+ registry.addBefore(new GenericWriter<>(vxlanId, new VxlanCustomizer(jvpp, ifcNamingContext, ifcDisableContext)),
+ ifcId);
+ // VxlanGpe(Needs to be executed before Interface customizer) =
+ final InstanceIdentifier<VxlanGpe> vxlanGpeId = VPP_IFC_AUG_ID.child(VxlanGpe.class);
+ registry.addBefore(new GenericWriter<>(vxlanGpeId,
+ new VxlanGpeCustomizer(jvpp, ifcNamingContext, ifcDisableContext)), ifcId);
+ // Tap(Needs to be executed before Interface customizer) =
+ final InstanceIdentifier<Tap> tapId = VPP_IFC_AUG_ID.child(Tap.class);
+ registry.addBefore(new GenericWriter<>(tapId, new TapCustomizer(jvpp, ifcNamingContext)),
+ ifcId);
+ // Loopback(Needs to be executed before Interface customizer) =
+ final InstanceIdentifier<Loopback> loopbackId = VPP_IFC_AUG_ID.child(Loopback.class);
+ registry.addBefore(new GenericWriter<>(loopbackId, new LoopbackCustomizer(jvpp, ifcNamingContext)),
+ ifcId);
+
+ // Gre(Needs to be executed before Interface customizer) =
+ final InstanceIdentifier<Gre> greId = VPP_IFC_AUG_ID.child(Gre.class);
+ registry.addBefore(new GenericWriter<>(greId, new GreCustomizer(jvpp, ifcNamingContext)),
+ ifcId);
+
+
+ final Set<InstanceIdentifier<?>> specificIfcTypes = Sets.newHashSet(vhostId, vxlanGpeId, vxlanGpeId, tapId);
+
+ // Ethernet =
+ registry.add(new GenericWriter<>(VPP_IFC_AUG_ID.child(Ethernet.class), new EthernetCustomizer(jvpp)));
+ // Routing(Execute only after specific interface customizers) =
+ registry.addAfter(
+ new GenericWriter<>(VPP_IFC_AUG_ID.child(Routing.class), new RoutingCustomizer(jvpp, ifcNamingContext)),
+ specificIfcTypes);
+ // L2(Execute only after subinterface (and all other ifc types) =
+ registry.addAfter(new GenericWriter<>(L2_ID, new L2Customizer(jvpp, ifcNamingContext, bdNamingContext)),
+ SubinterfaceAugmentationWriterFactory.SUB_IFC_ID);
+ // Proxy Arp (execute after specific interface customizers)
+ registry.addAfter(
+ new GenericWriter<>(VPP_IFC_AUG_ID.child(ProxyArp.class), new ProxyArpCustomizer(jvpp)),
+ specificIfcTypes);
+ // Ingress (execute after classify table and session writers)
+ // also handles L2Acl, Ip4Acl and Ip6Acl:
+ final InstanceIdentifier<Ingress> ingressId = InstanceIdentifier.create(Ingress.class);
+ registry
+ .subtreeAddAfter(
+ Sets.newHashSet(ingressId.child(L2Acl.class), ingressId.child(Ip4Acl.class),
+ ingressId.child(Ip6Acl.class)),
+ new GenericWriter<>(INGRESS_ACL_ID,
+ new AclCustomizer(jvpp, ifcNamingContext, classifyTableContext)),
+ Sets.newHashSet(CLASSIFY_TABLE_ID, CLASSIFY_SESSION_ID));
+
+ // Ingress IETF-ACL, also handles AccessLists and Acl:
+ final InstanceIdentifier<AccessLists> accessListsIdIngress = InstanceIdentifier.create(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ietf.acl.Ingress.class)
+ .child(AccessLists.class);
+ final InstanceIdentifier<?> aclIdIngress = accessListsIdIngress.child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl.class);
+ registry.subtreeAdd(
+ Sets.newHashSet(accessListsIdIngress, aclIdIngress),
+ new GenericWriter<>(INGRESS_IETF_ACL_ID, new io.fd.hc2vpp.v3po.interfaces.acl.ingress.IetfAclCustomizer(ingressAclWriter, ifcNamingContext)));
+
+ // Ingress IETF-ACL, also handles AccessLists and Acl:
+ final InstanceIdentifier<AccessLists> accessListsIdEgress = InstanceIdentifier.create(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ietf.acl.Egress.class)
+ .child(AccessLists.class);
+ final InstanceIdentifier<?> aclIdEgress = accessListsIdEgress.child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl.class);
+ registry.subtreeAdd(
+ Sets.newHashSet(accessListsIdEgress, aclIdEgress),
+ new GenericWriter<>(EGRESS_IETF_ACL_ID,
+ new io.fd.hc2vpp.v3po.interfaces.acl.egress.IetfAclCustomizer(egressAclWriter,
+ ifcNamingContext)));
+ }
+
+ private void addPbbAugmentationWriters(final InstanceIdentifier<Interface> ifcId,
+ final ModifiableWriterRegistryBuilder registry) {
+ final InstanceIdentifier<PbbRewrite> pbbRewriteId =
+ ifcId.augmentation(PbbRewriteInterfaceAugmentation.class).child(PbbRewrite.class);
+
+ registry.add(new GenericWriter<>(pbbRewriteId, new PbbRewriteCustomizer(jvpp, ifcNamingContext)));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/SubinterfaceAugmentationWriterFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/SubinterfaceAugmentationWriterFactory.java
new file mode 100644
index 000000000..c8a7d281c
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/SubinterfaceAugmentationWriterFactory.java
@@ -0,0 +1,158 @@
+/*
+ * 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.hc2vpp.v3po;
+
+import static io.fd.hc2vpp.v3po.VppClassifierHoneycombWriterFactory.CLASSIFY_SESSION_ID;
+import static io.fd.hc2vpp.v3po.VppClassifierHoneycombWriterFactory.CLASSIFY_TABLE_ID;
+
+import com.google.common.collect.Sets;
+import io.fd.hc2vpp.v3po.interfaces.acl.egress.EgressIetfAclWriter;
+import io.fd.hc2vpp.v3po.interfaces.acl.ingress.SubInterfaceAclCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.acl.ingress.SubInterfaceIetfAclCustomizer;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.impl.write.GenericListWriter;
+import io.fd.honeycomb.translate.impl.write.GenericWriter;
+import io.fd.hc2vpp.v3po.interfaces.RewriteCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.SubInterfaceCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.SubInterfaceL2Customizer;
+import io.fd.hc2vpp.v3po.interfaces.acl.ingress.IngressIetfAclWriter;
+import io.fd.hc2vpp.v3po.interfaces.ip.SubInterfaceIpv4AddressCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.L2Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.SubinterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.SubInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.match.attributes.match.type.vlan.tagged.VlanTagged;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.IetfAcl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.Tags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.l2.Rewrite;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.tags.Tag;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.tag.rewrite.PushTags;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class SubinterfaceAugmentationWriterFactory implements WriterFactory {
+
+ private final FutureJVppCore jvpp;
+ private final IngressIetfAclWriter ingressAclWriter;
+ private final EgressIetfAclWriter egressAclWriter;
+ private final NamingContext ifcContext;
+ private final NamingContext bdContext;
+ private final VppClassifierContextManager classifyTableContext;
+
+ public static final InstanceIdentifier<SubinterfaceAugmentation> SUB_IFC_AUG_ID =
+ InterfacesWriterFactory.IFC_ID.augmentation(SubinterfaceAugmentation.class);
+ public static final InstanceIdentifier<SubInterface> SUB_IFC_ID =
+ SUB_IFC_AUG_ID.child(SubInterfaces.class).child(SubInterface.class);
+ public static final InstanceIdentifier<L2> L2_ID = SUB_IFC_ID.child(
+ L2.class);
+ public static final InstanceIdentifier<Acl> SUBIF_ACL_ID = SUB_IFC_ID.child(Acl.class);
+ public static final InstanceIdentifier<Ingress> SUBIF_INGRESS_ACL_ID = SUBIF_ACL_ID.child(Ingress.class);
+ public static final InstanceIdentifier<IetfAcl> SUBIF_IETF_ACL_ID = SUB_IFC_ID.child(IetfAcl.class);
+ public static final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.ietf.acl.Ingress> SUBIF_INGRESS_IETF_ACL_ID = SUBIF_IETF_ACL_ID.child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.ietf.acl.Ingress.class);
+ public static final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.ietf.acl.Egress> SUBIF_EGRESS_IETF_ACL_ID = SUBIF_IETF_ACL_ID.child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.ietf.acl.Egress.class);
+
+ public SubinterfaceAugmentationWriterFactory(final FutureJVppCore jvpp,
+ final IngressIetfAclWriter ingressAclWriter,
+ final EgressIetfAclWriter egressAclWriter,
+ final NamingContext ifcContext, final NamingContext bdContext, final VppClassifierContextManager classifyTableContext) {
+ this.jvpp = jvpp;
+ this.ingressAclWriter = ingressAclWriter;
+ this.egressAclWriter = egressAclWriter;
+ this.ifcContext = ifcContext;
+ this.bdContext = bdContext;
+ this.classifyTableContext = classifyTableContext;
+ }
+
+ @Override
+ public void init(final ModifiableWriterRegistryBuilder registry) {
+ // Subinterfaces
+ // Subinterface(Handle only after all interface related stuff gets processed) =
+ registry.subtreeAddAfter(
+ // TODO HONEYCOMB-188 this customizer covers quite a lot of complex child nodes (maybe refactor ?)
+ Sets.newHashSet(
+ InstanceIdentifier.create(SubInterface.class).child(Tags.class),
+ InstanceIdentifier.create(SubInterface.class).child(Tags.class).child(Tag.class),
+ InstanceIdentifier.create(SubInterface.class).child(Tags.class).child(Tag.class).child(
+ Dot1qTag.class),
+ InstanceIdentifier.create(SubInterface.class).child(Match.class),
+ InstanceIdentifier.create(SubInterface.class).child(Match.class).child(VlanTagged.class)),
+ new GenericListWriter<>(SUB_IFC_ID, new SubInterfaceCustomizer(jvpp, ifcContext)),
+ InterfacesWriterFactory.IFC_ID);
+ // L2 =
+ registry.addAfter(new GenericWriter<>(L2_ID, new SubInterfaceL2Customizer(jvpp, ifcContext, bdContext)),
+ SUB_IFC_ID);
+ // Rewrite(also handles pushTags + pushTags/dot1qtag) =
+ final InstanceIdentifier<Rewrite> rewriteId = L2_ID.child(Rewrite.class);
+ registry.subtreeAddAfter(
+ Sets.newHashSet(
+ InstanceIdentifier.create(Rewrite.class).child(PushTags.class),
+ InstanceIdentifier.create(Rewrite.class).child(PushTags.class)
+ .child(org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.Dot1qTag.class)),
+ new GenericWriter<>(rewriteId, new RewriteCustomizer(jvpp, ifcContext)),
+ L2_ID);
+ // Ipv4(handled after L2 and L2/rewrite is done) =
+ final InstanceIdentifier<Address> ipv4SubifcAddressId = SUB_IFC_ID.child(Ipv4.class).child(Address.class);
+ registry.addAfter(new GenericListWriter<>(ipv4SubifcAddressId,
+ new SubInterfaceIpv4AddressCustomizer(jvpp, ifcContext)),
+ rewriteId);
+
+ // Ingress (execute after classify table and session writers)
+ // also handles L2Acl, Ip4Acl and Ip6Acl:
+ final InstanceIdentifier<Ingress> aclId = InstanceIdentifier.create(Ingress.class);
+ registry
+ .subtreeAddAfter(
+ Sets.newHashSet(aclId.child(L2Acl.class), aclId.child(Ip4Acl.class), aclId.child(Ip6Acl.class)),
+ new GenericWriter<>(SUBIF_INGRESS_ACL_ID, new SubInterfaceAclCustomizer(jvpp, ifcContext, classifyTableContext)),
+ Sets.newHashSet(CLASSIFY_TABLE_ID, CLASSIFY_SESSION_ID));
+
+ // Ingress IETF-ACL, also handles AccessLists and Acl:
+ final InstanceIdentifier<AccessLists> accessListsIdIngress = InstanceIdentifier.create(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.ietf.acl.Ingress.class)
+ .child(AccessLists.class);
+ final InstanceIdentifier<?> aclIdIngress = accessListsIdIngress.child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl.class);
+ registry.subtreeAdd(
+ Sets.newHashSet(accessListsIdIngress, aclIdIngress),
+ new GenericWriter<>(SUBIF_INGRESS_IETF_ACL_ID, new SubInterfaceIetfAclCustomizer(ingressAclWriter, ifcContext)));
+
+ // Egress IETF-ACL, also handles AccessLists and Acl:
+ final InstanceIdentifier<AccessLists> accessListsIdEgress = InstanceIdentifier.create(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.ietf.acl.Egress.class)
+ .child(AccessLists.class);
+ final InstanceIdentifier<?> aclIdEgress = accessListsIdEgress.child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl.class);
+ registry.subtreeAdd(
+ Sets.newHashSet(accessListsIdEgress, aclIdEgress),
+ new GenericWriter<>(SUBIF_EGRESS_IETF_ACL_ID, new io.fd.hc2vpp.v3po.interfaces.acl.egress.SubInterfaceIetfAclCustomizer(
+ egressAclWriter, ifcContext)));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/SubinterfaceStateAugmentationReaderFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/SubinterfaceStateAugmentationReaderFactory.java
new file mode 100644
index 000000000..ec4c50659
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/SubinterfaceStateAugmentationReaderFactory.java
@@ -0,0 +1,118 @@
+/*
+ * 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.hc2vpp.v3po;
+
+import com.google.common.collect.Sets;
+import io.fd.hc2vpp.v3po.interfacesstate.RewriteCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.SubInterfaceCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.SubInterfaceL2Customizer;
+import io.fd.hc2vpp.v3po.interfacesstate.acl.ingress.SubInterfaceAclCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.ip.SubInterfaceIpv4AddressCustomizer;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.impl.read.GenericInitListReader;
+import io.fd.honeycomb.translate.impl.read.GenericInitReader;
+import io.fd.honeycomb.translate.impl.read.GenericReader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.L2Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.SubinterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.SubinterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.SubInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.SubInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.match.attributes.match.type.vlan.tagged.VlanTagged;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.Tags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.l2.Rewrite;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.tags.Tag;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.tag.rewrite.PushTags;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+final class SubinterfaceStateAugmentationReaderFactory implements ReaderFactory {
+
+ private final FutureJVppCore jvpp;
+ private final NamingContext ifcCtx;
+ private final NamingContext bdCtx;
+ private final VppClassifierContextManager classifyCtx;
+
+ SubinterfaceStateAugmentationReaderFactory(final FutureJVppCore jvpp, final NamingContext ifcCtx,
+ final NamingContext bdCtx,
+ final VppClassifierContextManager classifyCtx) {
+ this.jvpp = jvpp;
+ this.ifcCtx = ifcCtx;
+ this.bdCtx = bdCtx;
+ this.classifyCtx = classifyCtx;
+ }
+
+ @Override
+ public void init(final ModifiableReaderRegistryBuilder registry) {
+ // SubinterfaceStateAugmentation(Structural)
+ final InstanceIdentifier<SubinterfaceStateAugmentation> subIfcAugId =
+ InterfacesStateReaderFactory.IFC_ID.augmentation(SubinterfaceStateAugmentation.class);
+ registry.addStructuralReader(subIfcAugId, SubinterfaceStateAugmentationBuilder.class);
+ // SubInterfaces(Structural)
+ final InstanceIdentifier<SubInterfaces> subIfcsId = subIfcAugId.child(SubInterfaces.class);
+ registry.addStructuralReader(subIfcsId, SubInterfacesBuilder.class);
+ // SubInterface(Subtree)
+ final InstanceIdentifier<SubInterface> subIfcId = subIfcsId.child(SubInterface.class);
+ registry.subtreeAdd(Sets.newHashSet(
+ InstanceIdentifier.create(SubInterface.class).child(Tags.class),
+ InstanceIdentifier.create(SubInterface.class).child(Tags.class).child(Tag.class),
+ InstanceIdentifier.create(SubInterface.class).child(Tags.class).child(Tag.class).child(Dot1qTag.class),
+ InstanceIdentifier.create(SubInterface.class).child(Match.class),
+ InstanceIdentifier.create(SubInterface.class).child(Match.class).child(VlanTagged.class)),
+ new GenericInitListReader<>(subIfcId, new SubInterfaceCustomizer(jvpp, ifcCtx)));
+ // L2
+ final InstanceIdentifier<L2> l2Id = subIfcId.child(L2.class);
+ registry.add(new GenericInitReader<>(l2Id, new SubInterfaceL2Customizer(jvpp, ifcCtx, bdCtx)));
+ // Rewrite(Subtree)
+ registry.subtreeAdd(Sets.newHashSet(
+ InstanceIdentifier.create(Rewrite.class).child(PushTags.class),
+ InstanceIdentifier.create(Rewrite.class).child(PushTags.class)
+ .child(
+ org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.Dot1qTag.class)),
+ new GenericReader<>(l2Id.child(Rewrite.class), new RewriteCustomizer(jvpp, ifcCtx)));
+ // Ipv4(Structural)
+ final InstanceIdentifier<Ipv4> ipv4Id = subIfcId.child(Ipv4.class);
+ registry.addStructuralReader(ipv4Id, Ipv4Builder.class);
+ // Address
+ registry.add(
+ new GenericInitListReader<>(ipv4Id.child(Address.class), new SubInterfaceIpv4AddressCustomizer(jvpp, ifcCtx)));
+ // Acl(Structural)
+ final InstanceIdentifier<Acl> aclIid = subIfcId.child(Acl.class);
+ registry.addStructuralReader(aclIid, AclBuilder.class);
+ // Ingress(Subtree)
+ final InstanceIdentifier<Ingress> ingressIdRelative = InstanceIdentifier.create(Ingress.class);
+ registry.subtreeAdd(
+ Sets.newHashSet(ingressIdRelative.child(L2Acl.class), ingressIdRelative.child(Ip4Acl.class),
+ ingressIdRelative.child(Ip6Acl.class)),
+ new GenericInitReader<>(aclIid.child(Ingress.class),
+ new SubInterfaceAclCustomizer(jvpp, ifcCtx, classifyCtx)));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/V3poModule.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/V3poModule.java
new file mode 100644
index 000000000..ad9d04888
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/V3poModule.java
@@ -0,0 +1,92 @@
+/*
+ * 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.hc2vpp.v3po;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
+import io.fd.hc2vpp.v3po.interfaces.acl.egress.EgressIetfAclWriter;
+import io.fd.hc2vpp.v3po.notification.InterfaceChangeNotificationProducer;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManagerImpl;
+import io.fd.honeycomb.notification.ManagedNotificationProducer;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.hc2vpp.v3po.cfgattrs.V3poConfiguration;
+import io.fd.hc2vpp.v3po.interfaces.acl.ingress.IngressIetfAclWriter;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import net.jmob.guice.conf.core.ConfigurationModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class V3poModule extends AbstractModule {
+
+ private static final Logger LOG = LoggerFactory.getLogger(V3poModule.class);
+
+ @Override
+ protected void configure() {
+ LOG.debug("Installing V3PO module");
+ install(ConfigurationModule.create());
+ requestInjection(V3poConfiguration.class);
+
+ // TODO HONEYCOMB-173 put into constants
+ // Naming contexts
+ bind(NamingContext.class)
+ .annotatedWith(Names.named("interface-context"))
+ .toInstance(new NamingContext("interface-", "interface-context"));
+ bind(NamingContext.class)
+ .annotatedWith(Names.named("bridge-domain-context"))
+ .toInstance(new NamingContext("bridge-domain-", "bridge-domain-context"));
+ bind(VppClassifierContextManager.class)
+ .annotatedWith(Names.named("classify-table-context"))
+ .toInstance(new VppClassifierContextManagerImpl("classify-table-"));
+
+ // Executor needed for keepalives
+ bind(ScheduledExecutorService.class).toInstance(Executors.newScheduledThreadPool(1));
+
+ // Utils
+ bind(IngressIetfAclWriter.class).toProvider(IngressIetfAClWriterProvider.class);
+ bind(EgressIetfAclWriter.class).toProvider(EgressIetfAClWriterProvider.class);
+ // Context utility for deleted interfaces
+ bind(DisabledInterfacesManager.class).toInstance(new DisabledInterfacesManager());
+
+ // Readers
+ final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
+ readerFactoryBinder.addBinding().to(InterfacesStateReaderFactory.class);
+ readerFactoryBinder.addBinding().to(VppStateHoneycombReaderFactory.class);
+ readerFactoryBinder.addBinding().to(VppClassifierReaderFactory.class);
+ // Expose disabled interfaces in operational data
+ readerFactoryBinder.addBinding().to(DisabledInterfacesManager.ContextsReaderFactory.class);
+ // Expose vpp-classfier-context interfaces in operational data
+ readerFactoryBinder.addBinding().to(VppClassifierContextManagerImpl.ContextsReaderFactory.class);
+
+ // Writers
+ final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+ writerFactoryBinder.addBinding().to(InterfacesWriterFactory.class);
+ writerFactoryBinder.addBinding().to(VppHoneycombWriterFactory.class);
+ writerFactoryBinder.addBinding().to(VppClassifierHoneycombWriterFactory.class);
+ writerFactoryBinder.addBinding().to(AclWriterFactory.class);
+
+ // Notifications
+ final Multibinder<ManagedNotificationProducer> notifiersBinder =
+ Multibinder.newSetBinder(binder(), ManagedNotificationProducer.class);
+ notifiersBinder.addBinding().to(InterfaceChangeNotificationProducer.class);
+ LOG.info("Module V3PO successfully configured");
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppClassifierHoneycombWriterFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppClassifierHoneycombWriterFactory.java
new file mode 100644
index 000000000..1443c5576
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppClassifierHoneycombWriterFactory.java
@@ -0,0 +1,64 @@
+/*
+ * 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.hc2vpp.v3po;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.v3po.vppclassifier.ClassifySessionWriter;
+import io.fd.hc2vpp.v3po.vppclassifier.ClassifyTableWriter;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.impl.write.GenericListWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppClassifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+
+public final class VppClassifierHoneycombWriterFactory implements WriterFactory {
+
+ public static final InstanceIdentifier<ClassifyTable> CLASSIFY_TABLE_ID =
+ InstanceIdentifier.create(VppClassifier.class).child(ClassifyTable.class);
+
+ public static final InstanceIdentifier<ClassifySession> CLASSIFY_SESSION_ID =
+ CLASSIFY_TABLE_ID.child(ClassifySession.class);
+
+ private final FutureJVppCore jvpp;
+ private final VppClassifierContextManager classifyTableContext;
+
+ @Inject
+ public VppClassifierHoneycombWriterFactory(@Nonnull final FutureJVppCore jvpp,
+ @Named("classify-table-context") @Nonnull final VppClassifierContextManager classifyTableContext) {
+ this.jvpp = jvpp;
+ this.classifyTableContext = classifyTableContext;
+ }
+
+ @Override
+ public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+ // Ordering here is: First create table, then create sessions and then assign as ACL
+ // ClassifyTable
+ registry.addBefore(
+ new GenericListWriter<>(CLASSIFY_TABLE_ID, new ClassifyTableWriter(jvpp, classifyTableContext)),
+ CLASSIFY_SESSION_ID);
+ // ClassifyTableSession
+ registry.addBefore(
+ new GenericListWriter<>(CLASSIFY_SESSION_ID, new ClassifySessionWriter(jvpp, classifyTableContext)),
+ InterfacesWriterFactory.ACL_ID);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppClassifierReaderFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppClassifierReaderFactory.java
new file mode 100644
index 000000000..d612314e1
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppClassifierReaderFactory.java
@@ -0,0 +1,60 @@
+/*
+ * 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.hc2vpp.v3po;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.honeycomb.translate.impl.read.GenericInitListReader;
+import io.fd.honeycomb.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.hc2vpp.v3po.vppclassifier.ClassifySessionReader;
+import io.fd.hc2vpp.v3po.vppclassifier.ClassifyTableReader;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppClassifierState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppClassifierStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class VppClassifierReaderFactory implements ReaderFactory {
+
+ private final FutureJVppCore jvpp;
+ private final VppClassifierContextManager classifyCtx;
+
+ @Inject
+ public VppClassifierReaderFactory(final FutureJVppCore jvpp,
+ @Named("classify-table-context") final VppClassifierContextManager classifyCtx) {
+ this.jvpp = jvpp;
+ this.classifyCtx = classifyCtx;
+ }
+
+ @Override
+ public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) {
+ // VppClassifierState
+ final InstanceIdentifier<VppClassifierState> vppStateId = InstanceIdentifier.create(VppClassifierState.class);
+ registry.addStructuralReader(vppStateId, VppClassifierStateBuilder.class);
+ // ClassifyTable
+ final InstanceIdentifier<ClassifyTable> classTblId = vppStateId.child(ClassifyTable.class);
+ registry.add(new GenericInitListReader<>(classTblId, new ClassifyTableReader(jvpp, classifyCtx)));
+ // ClassifySession
+ final InstanceIdentifier<ClassifySession> classSesId = classTblId.child(ClassifySession.class);
+ registry.add(new GenericListReader<>(classSesId, new ClassifySessionReader(jvpp, classifyCtx)));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppHoneycombWriterFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppHoneycombWriterFactory.java
new file mode 100644
index 000000000..0f836d632
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppHoneycombWriterFactory.java
@@ -0,0 +1,81 @@
+/*
+ * 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.hc2vpp.v3po;
+
+import static io.fd.hc2vpp.v3po.InterfacesWriterFactory.L2_ID;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.v3po.vpp.ArpTerminationTableEntryCustomizer;
+import io.fd.hc2vpp.v3po.vpp.BridgeDomainCustomizer;
+import io.fd.hc2vpp.v3po.vpp.L2FibEntryCustomizer;
+import io.fd.honeycomb.translate.impl.write.GenericListWriter;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.Vpp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.bridge.domain.attributes.ArpTerminationTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.bridge.domain.attributes.arp.termination.table.ArpTerminationTableEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.fib.attributes.L2FibTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.fib.attributes.l2.fib.table.L2FibEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.BridgeDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+
+public final class VppHoneycombWriterFactory implements WriterFactory {
+
+ private final FutureJVppCore jvpp;
+ private final NamingContext bdContext;
+ private final NamingContext ifcContext;
+
+ @Inject
+ public VppHoneycombWriterFactory(final FutureJVppCore vppJvppWriterDependency,
+ @Named("bridge-domain-context") final NamingContext bridgeDomainContextVppDependency,
+ @Named("interface-context") final NamingContext interfaceContextVppDependency) {
+ this.jvpp = vppJvppWriterDependency;
+ this.bdContext = bridgeDomainContextVppDependency;
+ this.ifcContext = interfaceContextVppDependency;
+ }
+
+ @Override
+ public void init(final ModifiableWriterRegistryBuilder registry) {
+ // Vpp has no handlers
+ // BridgeDomains has no handlers
+ // BridgeDomain =
+ final InstanceIdentifier<BridgeDomain> bdId =
+ InstanceIdentifier.create(Vpp.class).child(BridgeDomains.class).child(BridgeDomain.class);
+ registry.add(new GenericListWriter<>(bdId, new BridgeDomainCustomizer(jvpp, bdContext)));
+ // L2FibTable has no handlers
+ // L2FibEntry(handled after BridgeDomain and L2 of ifc and subifc) =
+ final InstanceIdentifier<L2FibEntry> l2FibEntryId = bdId.child(L2FibTable.class).child(L2FibEntry.class);
+ registry.addAfter(
+ new GenericListWriter<>(l2FibEntryId, new L2FibEntryCustomizer(jvpp, bdContext, ifcContext)),
+ Sets.newHashSet(
+ bdId,
+ L2_ID,
+ SubinterfaceAugmentationWriterFactory.L2_ID));
+ // ArpTerminationTable has no handlers
+ // ArpTerminationTableEntry(handled after BridgeDomain) =
+ final InstanceIdentifier<ArpTerminationTableEntry> arpEntryId =
+ bdId.child(ArpTerminationTable.class).child(ArpTerminationTableEntry.class);
+ registry.addAfter(
+ new GenericListWriter<>(arpEntryId, new ArpTerminationTableEntryCustomizer(jvpp, bdContext)),
+ bdId);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppStateHoneycombReaderFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppStateHoneycombReaderFactory.java
new file mode 100644
index 000000000..03da2c755
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/VppStateHoneycombReaderFactory.java
@@ -0,0 +1,90 @@
+/*
+ * 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.hc2vpp.v3po;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.v3po.vppstate.BridgeDomainCustomizer;
+import io.fd.hc2vpp.v3po.vppstate.L2FibEntryCustomizer;
+import io.fd.hc2vpp.v3po.vppstate.VersionCustomizer;
+import io.fd.honeycomb.translate.impl.read.GenericInitListReader;
+import io.fd.honeycomb.translate.impl.read.GenericReader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.honeycomb.translate.util.read.KeepaliveReaderWrapper;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.common.translate.util.ReadTimeoutException;
+import io.fd.hc2vpp.common.translate.util.VppStatusListener;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.ScheduledExecutorService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.fib.attributes.L2FibTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.fib.attributes.L2FibTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.fib.attributes.l2.fib.table.L2FibEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.BridgeDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.BridgeDomainsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.Version;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.bridge.domains.BridgeDomain;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class VppStateHoneycombReaderFactory implements ReaderFactory {
+
+ private final FutureJVppCore jVpp;
+ private final NamingContext ifcCtx;
+ private final NamingContext bdCtx;
+ private final ScheduledExecutorService keepaliveExecutor;
+ private final VppStatusListener vppStatusListener;
+
+ @Inject
+ public VppStateHoneycombReaderFactory(final FutureJVppCore jVpp,
+ @Named("interface-context") final NamingContext ifcCtx,
+ @Named("bridge-domain-context") final NamingContext bdCtx,
+ final ScheduledExecutorService keepaliveExecutorDependency,
+ final VppStatusListener vppStatusListener) {
+ this.jVpp = jVpp;
+ this.ifcCtx = ifcCtx;
+ this.bdCtx = bdCtx;
+ this.keepaliveExecutor = keepaliveExecutorDependency;
+ this.vppStatusListener = vppStatusListener;
+ }
+
+ @Override
+ public void init(final ModifiableReaderRegistryBuilder registry) {
+ // VppState(Structural)
+ final InstanceIdentifier<VppState> vppStateId = InstanceIdentifier.create(VppState.class);
+ registry.addStructuralReader(vppStateId, VppStateBuilder.class);
+ // Version
+ // Wrap with keepalive reader to detect connection issues
+ // Relying on VersionCustomizer to provide a "timing out read"
+ registry.add(new KeepaliveReaderWrapper<>(
+ new GenericReader<>(vppStateId.child(Version.class), new VersionCustomizer(jVpp)),
+ keepaliveExecutor, ReadTimeoutException.class, 30, vppStatusListener));
+ // BridgeDomains(Structural)
+ final InstanceIdentifier<BridgeDomains> bridgeDomainsId = vppStateId.child(BridgeDomains.class);
+ registry.addStructuralReader(bridgeDomainsId, BridgeDomainsBuilder.class);
+ // BridgeDomain
+ final InstanceIdentifier<BridgeDomain> bridgeDomainId = bridgeDomainsId.child(BridgeDomain.class);
+ registry.add(new GenericInitListReader<>(bridgeDomainId, new BridgeDomainCustomizer(jVpp, bdCtx)));
+ // L2FibTable(Structural)
+ final InstanceIdentifier<L2FibTable> l2FibTableId = bridgeDomainId.child(L2FibTable.class);
+ registry.addStructuralReader(l2FibTableId, L2FibTableBuilder.class);
+ // L2FibEntry
+ registry.add(new GenericInitListReader<>(l2FibTableId.child(L2FibEntry.class),
+ new L2FibEntryCustomizer(jVpp, bdCtx, ifcCtx)));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/cfgattrs/V3poConfiguration.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/cfgattrs/V3poConfiguration.java
new file mode 100644
index 000000000..6676956d8
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/cfgattrs/V3poConfiguration.java
@@ -0,0 +1,24 @@
+/*
+ * 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.hc2vpp.v3po.cfgattrs;
+
+import net.jmob.guice.conf.core.BindConfig;
+import net.jmob.guice.conf.core.Syntax;
+
+@BindConfig(value = "v3po", syntax = Syntax.JSON)
+public class V3poConfiguration {
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/EthernetCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/EthernetCustomizer.java
new file mode 100644
index 000000000..ec83df831
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/EthernetCustomizer.java
@@ -0,0 +1,58 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Ethernet;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EthernetCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Ethernet> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(EthernetCustomizer.class);
+
+ public EthernetCustomizer(final FutureJVppCore vppApi) {
+ super(vppApi);
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ethernet> id,
+ @Nonnull final Ethernet dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.warn("Unsupported, ignoring configuration {}", dataAfter);
+ // VPP API does not support setting MTU
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ethernet> id,
+ @Nonnull final Ethernet dataBefore, @Nonnull final Ethernet dataAfter,
+ @Nonnull final WriteContext writeContext) {
+ LOG.warn("Unsupported, ignoring configuration {}", dataAfter);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ethernet> id,
+ @Nonnull final Ethernet dataBefore, @Nonnull final WriteContext writeContext) {
+ LOG.warn("Unsupported, ignoring configuration delete {}", id);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/GreCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/GreCustomizer.java
new file mode 100644
index 000000000..b91d26364
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/GreCustomizer.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2016 Intel 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.hc2vpp.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.net.InetAddresses;
+import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.GreAddDelTunnel;
+import io.fd.vpp.jvpp.core.dto.GreAddDelTunnelReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.net.InetAddress;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.GreTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Gre;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GreCustomizer extends AbstractInterfaceTypeCustomizer<Gre> implements JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(GreCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public GreCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ private static GreAddDelTunnel getGreTunnelRequest(final byte isAdd, final byte[] srcAddr, final byte[] dstAddr,
+ final int outerFibId, final byte isIpv6) {
+ final GreAddDelTunnel greAddDelTunnel = new GreAddDelTunnel();
+ greAddDelTunnel.isAdd = isAdd;
+ greAddDelTunnel.srcAddress = srcAddr;
+ greAddDelTunnel.dstAddress = dstAddr;
+ greAddDelTunnel.outerFibId = outerFibId;
+ greAddDelTunnel.isIpv6 = isIpv6;
+ return greAddDelTunnel;
+ }
+
+ @Override
+ protected Class<? extends InterfaceType> getExpectedInterfaceType() {
+ return GreTunnel.class;
+ }
+
+ @Override
+ protected final void writeInterface(@Nonnull final InstanceIdentifier<Gre> id, @Nonnull final Gre dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+
+ createGreTunnel(id, swIfName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Gre> id, @Nonnull final Gre dataBefore,
+ @Nonnull final Gre dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException.UpdateFailedException {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("Gre tunnel update is not supported"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Gre> id, @Nonnull final Gre dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ deleteGreTunnel(id, swIfName, dataBefore, writeContext);
+ }
+
+ private void createGreTunnel(final InstanceIdentifier<Gre> id, final String swIfName, final Gre gre,
+ final WriteContext writeContext) throws WriteFailedException {
+ final byte isIpv6 = (byte) (isIpv6(gre)
+ ? 1
+ : 0);
+ final InetAddress srcAddress = InetAddresses.forString(getAddressString(gre.getSrc()));
+ final InetAddress dstAddress = InetAddresses.forString(getAddressString(gre.getDst()));
+
+ int outerFibId = gre.getOuterFibId().intValue();
+
+ LOG.debug("Setting gre tunnel for interface: {}. Gre: {}", swIfName, gre);
+ final CompletionStage<GreAddDelTunnelReply> greAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().greAddDelTunnel(getGreTunnelRequest((byte) 1 /* is add */, srcAddress.getAddress(),
+ dstAddress.getAddress(), outerFibId, isIpv6));
+
+ final GreAddDelTunnelReply reply =
+ getReplyForCreate(greAddDelTunnelReplyCompletionStage.toCompletableFuture(), id, gre);
+ LOG.debug("Gre tunnel set successfully for: {}, gre: {}", swIfName, gre);
+ if (interfaceContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) {
+ // VPP keeps gre tunnels present even after they are delete(reserving ID for next tunnel)
+ // This may cause inconsistencies in mapping context when configuring tunnels like this:
+ // 1. Add tunnel 2. Delete tunnel 3. Read interfaces (reserved mapping e.g. gre_tunnel0 -> 6
+ // will get into mapping context) 4. Add tunnel (this will add another mapping with the same
+ // reserved ID and context is invalid)
+ // That's why a check has to be performed here removing mapping gre_tunnel0 -> 6 mapping and storing
+ // new name for that ID
+ final String formerName = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext());
+ LOG.debug("Removing updated mapping of a gre tunnel, id: {}, former name: {}, new name: {}",
+ reply.swIfIndex, formerName, swIfName);
+ interfaceContext.removeName(formerName, writeContext.getMappingContext());
+ }
+ // Add new interface to our interface context
+ interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+ }
+
+ private boolean isIpv6(final Gre gre) {
+ if (gre.getSrc().getIpv4Address() == null) {
+ checkArgument(gre.getDst().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s", gre.getSrc(),
+ gre.getDst());
+ return true;
+ } else {
+ checkArgument(gre.getDst().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s", gre.getSrc(),
+ gre.getDst());
+ return false;
+ }
+ }
+
+ private String getAddressString(final IpAddress addr) {
+ return addr.getIpv4Address() == null
+ ? addr.getIpv6Address().getValue()
+ : addr.getIpv4Address().getValue();
+ }
+
+ private void deleteGreTunnel(final InstanceIdentifier<Gre> id, final String swIfName, final Gre gre,
+ final WriteContext writeContext) throws WriteFailedException {
+ final byte isIpv6 = (byte) (isIpv6(gre)
+ ? 1
+ : 0);
+ final InetAddress srcAddress = InetAddresses.forString(getAddressString(gre.getSrc()));
+ final InetAddress dstAddress = InetAddresses.forString(getAddressString(gre.getDst()));
+
+ int outerFibId = gre.getOuterFibId().intValue();
+
+ LOG.debug("Deleting gre tunnel for interface: {}. Gre: {}", swIfName, gre);
+ final CompletionStage<GreAddDelTunnelReply> greAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().greAddDelTunnel(getGreTunnelRequest((byte) 0 /* is add */, srcAddress.getAddress(),
+ dstAddress.getAddress(), outerFibId, isIpv6));
+
+ getReplyForDelete(greAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Gre tunnel deleted successfully for: {}, gre: {}", swIfName, gre);
+ // Remove interface from our interface context
+ interfaceContext.removeName(swIfName, writeContext.getMappingContext());
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/InterconnectionWriteUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/InterconnectionWriteUtils.java
new file mode 100644
index 000000000..0702717bc
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/InterconnectionWriteUtils.java
@@ -0,0 +1,159 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceSetL2Bridge;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceSetL2BridgeReply;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceSetL2Xconnect;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceSetL2XconnectReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.base.attributes.Interconnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.base.attributes.interconnection.BridgeBased;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.base.attributes.interconnection.XconnectBased;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class providing Interconnection CUD support.
+ */
+final class InterconnectionWriteUtils implements JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterconnectionWriteUtils.class);
+
+ private final FutureJVppCore futureJVppCore;
+ private final NamingContext interfaceContext;
+ private final NamingContext bridgeDomainContext;
+
+ InterconnectionWriteUtils(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext interfaceContext,
+ @Nonnull final NamingContext bridgeDomainContext) {
+ this.futureJVppCore = requireNonNull(futureJVppCore, "futureJVppCore should not be null");
+ this.interfaceContext = requireNonNull(interfaceContext, "interfaceContext should not be null");
+ this.bridgeDomainContext = requireNonNull(bridgeDomainContext, "bridgeDomainContext should not be null");
+ }
+
+ void setInterconnection(final InstanceIdentifier<? extends DataObject> id, final int swIfIndex,
+ final String ifcName, final Interconnection ic, final WriteContext writeContext)
+ throws WriteFailedException {
+
+ if (ic == null) { // TODO in case of update we should delete interconnection
+ LOG.trace("Interconnection is not set. Skipping");
+ } else if (ic instanceof XconnectBased) {
+ setXconnectBasedL2(id, swIfIndex, ifcName, (XconnectBased) ic, writeContext, (byte) 1 /*enable*/);
+ } else if (ic instanceof BridgeBased) {
+ setBridgeBasedL2(id, swIfIndex, ifcName, (BridgeBased) ic, writeContext, (byte) 1 /*enable*/);
+ } else {
+ // Choices&cases are not data objects, so they cannot have a dedicated Reader/Writer
+ // This choice is already from augment, so its not possible to augment augmented choice
+ LOG.error("Unable to handle Interconnection of type {}", ic.getClass());
+ throw new WriteFailedException(id, "Unable to handle Interconnection of type " + ic.getClass());
+ }
+ }
+
+ void deleteInterconnection(final InstanceIdentifier<? extends DataObject> id, final int swIfIndex,
+ final String ifcName, final Interconnection ic, final WriteContext writeContext)
+ throws WriteFailedException {
+
+ if (ic == null) { // TODO in case of update we should delete interconnection
+ LOG.trace("Interconnection is not set. Skipping");
+ } else if (ic instanceof XconnectBased) {
+ setXconnectBasedL2(id, swIfIndex, ifcName, (XconnectBased) ic, writeContext, (byte) 0 /*disable*/);
+ } else if (ic instanceof BridgeBased) {
+ setBridgeBasedL2(id, swIfIndex, ifcName, (BridgeBased) ic, writeContext, (byte) 0 /*disable*/);
+ } else {
+ LOG.error("Unable to delete Interconnection of type {}", ic.getClass());
+ throw new WriteFailedException(id, "Unable to delete Interconnection of type " + ic.getClass());
+ }
+ }
+
+ private void setBridgeBasedL2(final InstanceIdentifier<? extends DataObject> id, final int swIfIndex,
+ final String ifcName, final BridgeBased bb,
+ final WriteContext writeContext, final byte enabled) throws WriteFailedException {
+ LOG.debug("Setting bridge based interconnection(bridge-domain={}) for interface: {}", bb.getBridgeDomain(),
+ ifcName);
+
+ String bdName = bb.getBridgeDomain();
+
+ int bdId = bridgeDomainContext.getIndex(bdName, writeContext.getMappingContext());
+ checkArgument(bdId > 0, "Unable to set Interconnection for Interface: %s, bridge domain: %s does not exist",
+ ifcName, bdName);
+
+ byte bvi = bb.isBridgedVirtualInterface()
+ ? (byte) 1
+ : (byte) 0;
+ byte shg = 0;
+ if (bb.getSplitHorizonGroup() != null) {
+ shg = bb.getSplitHorizonGroup().byteValue();
+ }
+
+ final CompletionStage<SwInterfaceSetL2BridgeReply> swInterfaceSetL2BridgeReplyCompletionStage = futureJVppCore
+ .swInterfaceSetL2Bridge(getL2BridgeRequest(swIfIndex, bdId, shg, bvi, enabled));
+ getReplyForWrite(swInterfaceSetL2BridgeReplyCompletionStage.toCompletableFuture(), id);
+
+ LOG.debug("Bridge based interconnection updated successfully for: {}, interconnection: {}", ifcName, bb);
+ }
+
+ private SwInterfaceSetL2Bridge getL2BridgeRequest(final int swIfIndex, final int bdId, final byte shg,
+ final byte bvi, final byte enabled) {
+ final SwInterfaceSetL2Bridge swInterfaceSetL2Bridge = new SwInterfaceSetL2Bridge();
+ swInterfaceSetL2Bridge.rxSwIfIndex = swIfIndex;
+ swInterfaceSetL2Bridge.bdId = bdId;
+ swInterfaceSetL2Bridge.shg = shg;
+ swInterfaceSetL2Bridge.bvi = bvi;
+ swInterfaceSetL2Bridge.enable = enabled;
+ return swInterfaceSetL2Bridge;
+ }
+
+ private void setXconnectBasedL2(final InstanceIdentifier<? extends DataObject> id, final int swIfIndex,
+ final String ifcName, final XconnectBased ic,
+ final WriteContext writeContext, final byte enabled) throws WriteFailedException {
+ String outSwIfName = ic.getXconnectOutgoingInterface();
+ LOG.debug("Setting xconnect based interconnection(outgoing ifc={}) for interface: {}", outSwIfName, ifcName);
+
+ int outSwIfIndex = interfaceContext.getIndex(outSwIfName, writeContext.getMappingContext());
+ checkArgument(outSwIfIndex > 0,
+ "Unable to set Interconnection for Interface: %s, outgoing interface: %s does not exist",
+ ifcName, outSwIfIndex);
+
+ final CompletionStage<SwInterfaceSetL2XconnectReply> swInterfaceSetL2XconnectReplyCompletionStage =
+ futureJVppCore
+ .swInterfaceSetL2Xconnect(getL2XConnectRequest(swIfIndex, outSwIfIndex, enabled));
+ getReplyForWrite(swInterfaceSetL2XconnectReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Xconnect based interconnection updated successfully for: {}, interconnection: {}", ifcName, ic);
+ }
+
+ private SwInterfaceSetL2Xconnect getL2XConnectRequest(final int rxIfc, final int txIfc,
+ final byte enabled) {
+
+ final SwInterfaceSetL2Xconnect swInterfaceSetL2Xconnect = new SwInterfaceSetL2Xconnect();
+ swInterfaceSetL2Xconnect.enable = enabled;
+ swInterfaceSetL2Xconnect.rxSwIfIndex = rxIfc;
+ swInterfaceSetL2Xconnect.txSwIfIndex = txIfc;
+ return swInterfaceSetL2Xconnect;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/InterfaceCustomizer.java
new file mode 100644
index 000000000..336a66152
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/InterfaceCustomizer.java
@@ -0,0 +1,121 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlags;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlagsReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+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.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Ietf interface write customizer that only caches interface objects for child writers
+ */
+public class InterfaceCustomizer extends FutureJVppCustomizer
+ implements ListWriterCustomizer<Interface, InterfaceKey>, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public InterfaceCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Interface> id,
+ @Nonnull final Interface dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ setInterface(id, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Interface> id,
+ @Nonnull final Interface dataBefore,
+ @Nonnull final Interface dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ updateInterface(id, dataBefore, dataAfter, writeContext);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Interface> id,
+ @Nonnull final Interface dataBefore,
+ @Nonnull final WriteContext writeContext) {
+ // Nothing to be done here, customizers for specific interface types e.g. vxlan handle the delete
+ }
+
+ private void setInterface(final InstanceIdentifier<Interface> id, final Interface swIf,
+ final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Setting interface: {} to: {}", id, swIf);
+ setInterfaceAttributes(id, swIf, swIf.getName(), writeContext);
+ }
+
+ private void setInterfaceAttributes(final InstanceIdentifier<Interface> id, final Interface swIf,
+ final String swIfName, final WriteContext writeContext)
+ throws WriteFailedException {
+
+ setInterfaceFlags(id, swIfName, interfaceContext.getIndex(swIfName, writeContext.getMappingContext()),
+ swIf.isEnabled()
+ ? (byte) 1
+ : (byte) 0);
+ }
+
+ private void updateInterface(final InstanceIdentifier<Interface> id,
+ final Interface dataBefore,
+ final Interface dataAfter, final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Updating interface:{} to: {}", id, dataAfter);
+ setInterfaceAttributes(id, dataAfter, dataAfter.getName(), writeContext);
+ }
+
+ private void setInterfaceFlags(final InstanceIdentifier<Interface> id, final String swIfName, final int swIfIndex,
+ final byte enabled) throws WriteFailedException {
+ final CompletionStage<SwInterfaceSetFlagsReply> swInterfaceSetFlagsReplyFuture =
+ getFutureJVpp().swInterfaceSetFlags(
+ getSwInterfaceSetFlagsInput(swIfIndex, enabled, (byte) 0 /* deleted */));
+
+ LOG.debug("Updating interface flags for: {}, index: {}, enabled: {}", swIfName, swIfIndex, enabled);
+
+ getReplyForWrite(swInterfaceSetFlagsReplyFuture.toCompletableFuture(), id);
+ LOG.debug("Interface flags updated successfully for: {}, index: {}, enabled: {}",
+ swIfName, swIfIndex, enabled);
+ }
+
+ private SwInterfaceSetFlags getSwInterfaceSetFlagsInput(final int swIfIndex, final byte enabled,
+ final byte deleted) {
+ final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags();
+ swInterfaceSetFlags.swIfIndex = swIfIndex;
+ swInterfaceSetFlags.adminUpDown = enabled;
+ swInterfaceSetFlags.linkUpDown = enabled;
+ swInterfaceSetFlags.deleted = deleted;
+ return swInterfaceSetFlags;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/L2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/L2Customizer.java
new file mode 100644
index 000000000..cb47725b5
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/L2Customizer.java
@@ -0,0 +1,89 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.L2;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class L2Customizer extends FutureJVppCustomizer implements WriterCustomizer<L2> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(L2Customizer.class);
+ private final NamingContext interfaceContext;
+ private final InterconnectionWriteUtils icWriteUtils;
+
+ public L2Customizer(final FutureJVppCore vppApi, final NamingContext interfaceContext,
+ final NamingContext bridgeDomainContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ this.icWriteUtils = new InterconnectionWriteUtils(vppApi, interfaceContext, bridgeDomainContext);
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2 dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
+ setL2(id, swIfc, ifcName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2 dataBefore,
+ @Nonnull final L2 dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
+ // No update, again calling set
+ setL2(id, swIfc, ifcName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2 dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
+ deleteL2(id, swIfc, ifcName, dataBefore, writeContext);
+ }
+
+ private void setL2(final InstanceIdentifier<L2> id, final int swIfIndex, final String ifcName, final L2 l2,
+ final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Setting L2 for interface: {}", ifcName);
+ // Nothing besides interconnection here
+ icWriteUtils.setInterconnection(id, swIfIndex, ifcName, l2.getInterconnection(), writeContext);
+ }
+
+ private void deleteL2(final InstanceIdentifier<L2> id, final int swIfIndex, final String ifcName, final L2 l2Before,
+ final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Deleting L2 for interface: {}", ifcName);
+ // Nothing besides interconnection here
+ icWriteUtils.deleteInterconnection(id, swIfIndex, ifcName, l2Before.getInterconnection(), writeContext);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/LoopbackCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/LoopbackCustomizer.java
new file mode 100644
index 000000000..a1b3184ed
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/LoopbackCustomizer.java
@@ -0,0 +1,112 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.MacTranslator;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.CreateLoopback;
+import io.fd.vpp.jvpp.core.dto.CreateLoopbackReply;
+import io.fd.vpp.jvpp.core.dto.DeleteLoopback;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Loopback;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class LoopbackCustomizer extends AbstractInterfaceTypeCustomizer<Loopback>
+ implements MacTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(LoopbackCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public LoopbackCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ protected Class<? extends InterfaceType> getExpectedInterfaceType() {
+ return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.Loopback.class;
+ }
+
+ @Override
+ protected final void writeInterface(@Nonnull final InstanceIdentifier<Loopback> id, @Nonnull final Loopback dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ createLoopback(id, ifcName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Loopback> id, @Nonnull final Loopback dataBefore,
+ @Nonnull final Loopback dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("Modification of loopback interface is not supported"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Loopback> id, @Nonnull final Loopback dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+
+ final int index;
+ try {
+ index = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
+ } catch (IllegalArgumentException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+
+ deleteLoopback(id, ifcName, index, dataBefore, writeContext);
+ }
+
+ private void createLoopback(final InstanceIdentifier<Loopback> id, final String swIfName, final Loopback loopback,
+ final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Setting loopback interface: {}. Loopback: {}", swIfName, loopback);
+
+ final CreateLoopback createLoopback = new CreateLoopback();
+ if (loopback.getMac() != null) {
+ createLoopback.macAddress = parseMac(loopback.getMac().getValue());
+ }
+ final CreateLoopbackReply reply =
+ getReplyForCreate(getFutureJVpp().createLoopback(createLoopback).toCompletableFuture(), id, loopback);
+
+ LOG.debug("Loopback set successfully for: {}, loopback: {}", swIfName, loopback);
+ // Add new interface to our interface context
+ interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+ }
+
+ private void deleteLoopback(final InstanceIdentifier<Loopback> id, final String swIfName, final int index,
+ final Loopback dataBefore, final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Deleting loopback interface: {}. Loopback: {}", swIfName, dataBefore);
+ final DeleteLoopback deleteLoopback = new DeleteLoopback();
+ deleteLoopback.swIfIndex = index;
+ getReplyForDelete(getFutureJVpp().deleteLoopback(deleteLoopback).toCompletableFuture(), id);
+ LOG.debug("Loopback deleted successfully for: {}, loopback: {}", swIfName, dataBefore);
+ // Remove deleted interface from interface context
+ interfaceContext.removeName(swIfName, writeContext.getMappingContext());
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ProxyArpCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ProxyArpCustomizer.java
new file mode 100644
index 000000000..66f2e3e81
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ProxyArpCustomizer.java
@@ -0,0 +1,108 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import com.google.common.net.InetAddresses;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.ProxyArpAddDel;
+import io.fd.vpp.jvpp.core.dto.ProxyArpAddDelReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.net.InetAddress;
+import java.util.concurrent.Future;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ProxyArp;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProxyArpCustomizer extends FutureJVppCustomizer implements WriterCustomizer<ProxyArp>, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ProxyArpCustomizer.class);
+
+ public ProxyArpCustomizer(final FutureJVppCore vppApi) {
+ super(vppApi);
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull InstanceIdentifier<ProxyArp> id, @Nonnull ProxyArp dataAfter,
+ @Nonnull WriteContext writeContext) throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ createProxyArp(getProxyArpRequestFuture(id, swIfName, dataAfter, (byte) 1 /* 1 is add */), id, dataAfter);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull InstanceIdentifier<ProxyArp> id, @Nonnull ProxyArp dataBefore,
+ @Nonnull ProxyArp dataAfter, @Nonnull WriteContext writeContext)
+ throws WriteFailedException.UpdateFailedException {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("ARP proxy update is not supported"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull InstanceIdentifier<ProxyArp> id, @Nonnull ProxyArp dataBefore,
+ @Nonnull WriteContext writeContext) throws WriteFailedException {
+
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ deleteProxyArp(getProxyArpRequestFuture(id, swIfName, dataBefore, (byte) 0 /* 0 is delete */), id);
+ }
+
+ private Future<ProxyArpAddDelReply> getProxyArpRequestFuture(InstanceIdentifier<ProxyArp> id, String swIfName,
+ ProxyArp proxyArp, byte operation)
+ throws WriteFailedException {
+ LOG.debug("Setting Proxy ARP settings for interface: {}", swIfName);
+ final InetAddress srcAddress = InetAddresses.forString(getv4AddressString(proxyArp.getLowAddr()));
+ final InetAddress dstAddress = InetAddresses.forString(getv4AddressString(proxyArp.getHighAddr()));
+ final int vrfId = proxyArp.getVrfId().intValue();
+ return getFutureJVpp().proxyArpAddDel(
+ getProxyArpConfRequest(operation, srcAddress.getAddress(), dstAddress.getAddress(), vrfId))
+ .toCompletableFuture();
+ }
+
+ private void createProxyArp(final Future<ProxyArpAddDelReply> future, final InstanceIdentifier<ProxyArp> identifier,
+ final ProxyArp data)
+ throws WriteFailedException {
+ final ProxyArpAddDelReply reply = getReplyForCreate(future, identifier, data);
+ LOG.debug("Proxy ARP setting create successful, with reply context:", reply.context);
+ }
+
+ private void deleteProxyArp(final Future<ProxyArpAddDelReply> future, final InstanceIdentifier<ProxyArp> identifier)
+ throws WriteFailedException {
+ final ProxyArpAddDelReply reply = getReplyForDelete(future, identifier);
+ LOG.debug("Proxy ARP setting delete successful, with reply context:", reply.context);
+ }
+
+ private static ProxyArpAddDel getProxyArpConfRequest(final byte isAdd, final byte[] lAddr, final byte[] hAddr,
+ final int vrfId) {
+
+ final ProxyArpAddDel proxyArpAddDel = new ProxyArpAddDel();
+ proxyArpAddDel.isAdd = isAdd;
+ proxyArpAddDel.lowAddress = lAddr;
+ proxyArpAddDel.hiAddress = hAddr;
+ proxyArpAddDel.vrfId = vrfId;
+ return proxyArpAddDel;
+ }
+
+ private String getv4AddressString(@Nonnull final Ipv4Address addr) {
+ return addr.getValue();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/RewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/RewriteCustomizer.java
new file mode 100644
index 000000000..4ad632166
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/RewriteCustomizer.java
@@ -0,0 +1,136 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.hc2vpp.common.translate.util.TagRewriteOperation;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.L2InterfaceVlanTagRewrite;
+import io.fd.vpp.jvpp.core.dto.L2InterfaceVlanTagRewriteReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+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.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214._802dot1q;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.l2.Rewrite;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.l2.RewriteBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.tag.rewrite.PushTags;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer Customizer responsible for vlan tag rewrite.<br> Sends {@code l2_interface_vlan_tag_rewrite} message to
+ * VPP.<br> Equivalent of invoking {@code vppctl set interface l2 tag-rewrite} command.
+ */
+public class RewriteCustomizer extends FutureJVppCustomizer
+ implements WriterCustomizer<Rewrite>, ByteDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RewriteCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public RewriteCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJVppCore);
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(final InstanceIdentifier<Rewrite> id, final Rewrite dataAfter,
+ final WriteContext writeContext)
+ throws WriteFailedException {
+ final String subifName = getSubInterfaceName(id);
+ setTagRewrite(id, subifName, dataAfter, writeContext);
+ }
+
+ private static String getSubInterfaceName(final InstanceIdentifier<Rewrite> id) {
+ return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(),
+ Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier()));
+ }
+
+ private void setTagRewrite(final InstanceIdentifier<Rewrite> id, final String ifname, final Rewrite rewrite,
+ final WriteContext writeContext) throws WriteFailedException {
+ final int swIfIndex = interfaceContext.getIndex(ifname, writeContext.getMappingContext());
+ LOG.debug("Setting tag rewrite for interface {}(id=): {}", ifname, swIfIndex, rewrite);
+
+ final CompletionStage<L2InterfaceVlanTagRewriteReply> replyCompletionStage =
+ getFutureJVpp().l2InterfaceVlanTagRewrite(getTagRewriteRequest(swIfIndex, rewrite));
+
+ getReplyForWrite(replyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Tag rewrite for interface {}(id=) set successfully: {}", ifname, swIfIndex, rewrite);
+ }
+
+ private L2InterfaceVlanTagRewrite getTagRewriteRequest(final int swIfIndex, final Rewrite rewrite) {
+ final L2InterfaceVlanTagRewrite request = new L2InterfaceVlanTagRewrite();
+ request.swIfIndex = swIfIndex;
+ request.pushDot1Q = booleanToByte(_802dot1q.class == rewrite.getVlanType());
+
+ final List<PushTags> pushTags = rewrite.getPushTags();
+ final Short popTags = rewrite.getPopTags();
+
+ final int numberOfTagsToPop = popTags == null
+ ? 0
+ : popTags.intValue();
+ final int numberOfTagsToPush = pushTags == null
+ ? 0
+ : pushTags.size();
+
+ request.vtrOp = TagRewriteOperation.get(numberOfTagsToPop, numberOfTagsToPush).ordinal();
+
+ if (numberOfTagsToPush > 0) {
+ for (final PushTags tag : pushTags) {
+ if (tag.getIndex() == 0) {
+ request.tag1 = tag.getDot1qTag().getVlanId().getValue();
+ } else {
+ request.tag2 = tag.getDot1qTag().getVlanId().getValue();
+ }
+ }
+ }
+
+ LOG.debug("Generated tag rewrite request: {}", request);
+ return request;
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Rewrite> id,
+ @Nonnull final Rewrite dataBefore,
+ @Nonnull final Rewrite dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String subifName = getSubInterfaceName(id);
+ setTagRewrite(id, subifName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Rewrite> id,
+ @Nonnull final Rewrite dataBefore, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String subifName = getSubInterfaceName(id);
+
+ LOG.debug("Disabling tag rewrite for interface {}", subifName);
+ final Rewrite rewrite = new RewriteBuilder().build(); // rewrite without push and pops will cause delete
+ setTagRewrite(id, subifName, rewrite, writeContext);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/RoutingCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/RoutingCustomizer.java
new file mode 100644
index 000000000..574fcebec
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/RoutingCustomizer.java
@@ -0,0 +1,122 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceSetTable;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceSetTableReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+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.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Routing;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RoutingCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Routing>, JvppReplyConsumer,
+ ByteDataTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RoutingCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public RoutingCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> id,
+ @Nonnull final Routing dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ setRouting(id, ifName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> id,
+ @Nonnull final Routing dataBefore, @Nonnull final Routing dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ setRouting(id, ifName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> id,
+ @Nonnull final Routing dataBefore, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ disableRouting(id, ifName, writeContext);
+ }
+
+ private void setRouting(@Nonnull final InstanceIdentifier<Routing> id, @Nonnull final String name,
+ @Nonnull final Routing rt,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext());
+ LOG.debug("Setting routing for interface: {}, {}. Routing: {}", name, swIfc, rt);
+ checkArgument(rt.getIpv4VrfId() != null || rt.getIpv6VrfId() != null, "No vrf-id given");
+
+ setVrfId(id, swIfc, rt.getIpv4VrfId(), false);
+ setVrfId(id, swIfc, rt.getIpv6VrfId(), true);
+
+ LOG.debug("Routing set successfully for interface: {}, {}, routing: {}", name, swIfc, rt);
+ }
+
+ private void setVrfId(final InstanceIdentifier<Routing> id, final int swIfc, final Long vrfId, boolean isIp6)
+ throws WriteFailedException {
+ if (vrfId == null) {
+ return;
+ }
+ final CompletionStage<SwInterfaceSetTableReply> cs = getFutureJVpp()
+ .swInterfaceSetTable(getInterfaceSetTableRequest(swIfc, booleanToByte(isIp6), vrfId.intValue()));
+ getReplyForWrite(cs.toCompletableFuture(), id);
+ }
+
+ /**
+ * In this case, there is no such thing as delete routing,only thing that can be done is to disable it by setting
+ * default value 0
+ */
+ private void disableRouting(final InstanceIdentifier<Routing> id, final String name,
+ final WriteContext writeContext) throws WriteFailedException {
+ final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext());
+ LOG.debug("Disabling routing for interface: {}, {}.", name, swIfc);
+
+ getReplyForDelete(getFutureJVpp()
+ .swInterfaceSetTable(getInterfaceSetTableRequest(swIfc, (byte) 0, 0)).toCompletableFuture(), id);
+ LOG.debug("Routing for interface: {}, {} successfully disabled", name, swIfc);
+
+ }
+
+ private SwInterfaceSetTable getInterfaceSetTableRequest(final int swIfc, final byte isIpv6, final int vrfId) {
+ final SwInterfaceSetTable swInterfaceSetTable = new SwInterfaceSetTable();
+ swInterfaceSetTable.isIpv6 = isIpv6;
+ swInterfaceSetTable.swIfIndex = swIfc;
+ swInterfaceSetTable.vrfId = vrfId;
+ return swInterfaceSetTable;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/SubInterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/SubInterfaceCustomizer.java
new file mode 100644
index 000000000..c39cfa6ec
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/SubInterfaceCustomizer.java
@@ -0,0 +1,193 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.getNumberOfTags;
+import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.getSubInterfaceName;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.CreateSubif;
+import io.fd.vpp.jvpp.core.dto.CreateSubifReply;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlags;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlagsReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214._802dot1ad;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.match.attributes.MatchType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.match.attributes.match.type.Default;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.match.attributes.match.type.vlan.tagged.VlanTagged;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.tags.Tag;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer Customizer responsible for sub interface creation.<br> Sends {@code create_subif} message to VPP.<br>
+ * Equivalent of invoking {@code vppclt create subif} command.
+ */
+public class SubInterfaceCustomizer extends FutureJVppCustomizer
+ implements ListWriterCustomizer<SubInterface, SubInterfaceKey>, ByteDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public SubInterfaceCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJVppCore);
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<SubInterface> id,
+ @Nonnull final SubInterface dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String superIfName = id.firstKeyOf(Interface.class).getName();
+ createSubInterface(id, superIfName, dataAfter, writeContext);
+ }
+
+ private void createSubInterface(final InstanceIdentifier<SubInterface> id, @Nonnull final String superIfName,
+ @Nonnull final SubInterface subInterface, final WriteContext writeContext)
+ throws WriteFailedException {
+ final int superIfIndex = interfaceContext.getIndex(superIfName, writeContext.getMappingContext());
+ final CompletionStage<CreateSubifReply> createSubifReplyCompletionStage =
+ getFutureJVpp().createSubif(getCreateSubifRequest(subInterface, superIfIndex));
+
+ final CreateSubifReply reply =
+ getReplyForCreate(createSubifReplyCompletionStage.toCompletableFuture(), id, subInterface);
+
+ setInterfaceState(id, reply.swIfIndex, booleanToByte(subInterface.isEnabled()));
+ interfaceContext.addName(reply.swIfIndex,
+ getSubInterfaceName(superIfName, Math.toIntExact(subInterface.getIdentifier())),
+ writeContext.getMappingContext());
+ LOG.debug("Sub interface created successfully for: {}, subInterface: {}", superIfName, subInterface);
+ }
+
+ private CreateSubif getCreateSubifRequest(@Nonnull final SubInterface subInterface, final int swIfIndex) {
+ // TODO HONEYCOMB-183 add validation
+ CreateSubif request = new CreateSubif();
+ request.subId = Math.toIntExact(subInterface.getIdentifier().intValue());
+ request.swIfIndex = swIfIndex;
+
+ final int numberOfTags = getNumberOfTags(subInterface.getTags());
+ switch (numberOfTags) {
+ case 0:
+ request.noTags = 1;
+ break;
+ case 1:
+ request.oneTag = 1;
+ break;
+ case 2:
+ request.twoTags = 1;
+ break;
+ }
+ request.dot1Ad = booleanToByte(_802dot1ad.class == subInterface.getVlanType());
+
+ // TODO HONEYCOMB-183 match should be mandatory
+ final MatchType matchType = subInterface.getMatch().getMatchType();
+ request.exactMatch =
+ booleanToByte(matchType instanceof VlanTagged && ((VlanTagged) matchType).isMatchExactTags());
+ request.defaultSub = booleanToByte(matchType instanceof Default);
+
+ if (numberOfTags > 0) {
+ for (final Tag tag : subInterface.getTags().getTag()) {
+ if (tag.getIndex() == 0) {
+ setOuterTag(request, tag);
+ } else if (tag.getIndex() == 1) {
+ setInnerTag(request, tag);
+ }
+ }
+ }
+ return request;
+ }
+
+ private void setOuterTag(final CreateSubif request, final Tag outerTag) {
+ checkState(SVlan.class == outerTag.getDot1qTag().getTagType(), "Service Tag expected at index 0");
+ final Dot1qTag.VlanId vlanId = outerTag.getDot1qTag().getVlanId();
+
+ request.outerVlanId = dot1qVlanIdToShort(vlanId.getDot1qVlanId());
+ request.outerVlanIdAny = booleanToByte(Dot1qTag.VlanId.Enumeration.Any.equals(vlanId.getEnumeration()));
+ }
+
+ private void setInnerTag(final CreateSubif request, final Tag innerTag) {
+ checkState(CVlan.class == innerTag.getDot1qTag().getTagType(), "Customer Tag expected at index 1");
+ final Dot1qTag.VlanId vlanId = innerTag.getDot1qTag().getVlanId();
+
+ request.innerVlanId = dot1qVlanIdToShort(vlanId.getDot1qVlanId());
+ request.innerVlanIdAny = booleanToByte(Dot1qTag.VlanId.Enumeration.Any.equals(vlanId.getEnumeration()));
+ }
+
+ private static short dot1qVlanIdToShort(@Nullable Dot1qVlanId dot1qVlanId) {
+ if (dot1qVlanId == null) {
+ return 0; // tell VPP that optional argument is missing
+ } else {
+ return dot1qVlanId.getValue().shortValue();
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<SubInterface> id,
+ @Nonnull final SubInterface dataBefore, @Nonnull final SubInterface dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String subIfaceName = getSubInterfaceName(id.firstKeyOf(Interface.class).getName(),
+ Math.toIntExact(dataAfter.getIdentifier()));
+ setInterfaceState(id, interfaceContext.getIndex(subIfaceName, writeContext.getMappingContext()),
+ booleanToByte(dataAfter.isEnabled()));
+ }
+
+ private void setInterfaceState(final InstanceIdentifier<SubInterface> id, final int swIfIndex, final byte enabled)
+ throws WriteFailedException {
+ final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags();
+ swInterfaceSetFlags.swIfIndex = swIfIndex;
+ swInterfaceSetFlags.adminUpDown = enabled;
+
+ final CompletionStage<SwInterfaceSetFlagsReply> swInterfaceSetFlagsReplyFuture =
+ getFutureJVpp().swInterfaceSetFlags(swInterfaceSetFlags);
+
+ LOG.debug("Updating interface state for interface if={}, enabled: {}", swIfIndex, enabled);
+
+ SwInterfaceSetFlagsReply reply =
+ getReplyForWrite(swInterfaceSetFlagsReplyFuture.toCompletableFuture(), id);
+ LOG.debug("Interface state updated successfully for interface index: {}, enabled: {}, ctxId: {}",
+ swIfIndex, enabled, reply.context);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<SubInterface> id,
+ @Nonnull final SubInterface dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException.DeleteFailedException {
+ throw new UnsupportedOperationException("Sub interface delete is not supported");
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/SubInterfaceL2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/SubInterfaceL2Customizer.java
new file mode 100644
index 000000000..4a3e4435d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/SubInterfaceL2Customizer.java
@@ -0,0 +1,100 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.L2;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for writing vlan sub interface l2 configuration
+ */
+public class SubInterfaceL2Customizer extends FutureJVppCustomizer implements WriterCustomizer<L2> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceL2Customizer.class);
+ private final NamingContext interfaceContext;
+ private final InterconnectionWriteUtils icWriterUtils;
+
+ public SubInterfaceL2Customizer(final FutureJVppCore vppApi, final NamingContext interfaceContext,
+ final NamingContext bridgeDomainContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ this.icWriterUtils = new InterconnectionWriteUtils(vppApi, interfaceContext, bridgeDomainContext);
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2 dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ setL2(id, subInterfaceIndex, subInterfaceName, dataAfter, writeContext);
+ }
+
+ private String getSubInterfaceName(@Nonnull final InstanceIdentifier<L2> id) {
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ return SubInterfaceUtils
+ .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2 dataBefore,
+ @Nonnull final L2 dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ // Setting L2 to new values
+ setL2(id, subInterfaceIndex, subInterfaceName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2 dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ deleteL2(id, subInterfaceIndex, subInterfaceName, dataBefore, writeContext);
+ }
+
+ private void setL2(final InstanceIdentifier<L2> id, final int swIfIndex, final String ifcName, final L2 l2,
+ final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Setting L2 for sub-interface: {}", ifcName);
+ icWriterUtils.setInterconnection(id, swIfIndex, ifcName, l2.getInterconnection(), writeContext);
+ }
+
+ private void deleteL2(final InstanceIdentifier<L2> id, final int swIfIndex, final String ifcName, final L2 l2Before,
+ final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Deleting L2 for sub-interface: {}", ifcName);
+ icWriterUtils.deleteInterconnection(id, swIfIndex, ifcName, l2Before.getInterconnection(), writeContext);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/TapCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/TapCustomizer.java
new file mode 100644
index 000000000..220fb95e8
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/TapCustomizer.java
@@ -0,0 +1,182 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.MacTranslator;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.TapConnect;
+import io.fd.vpp.jvpp.core.dto.TapConnectReply;
+import io.fd.vpp.jvpp.core.dto.TapDelete;
+import io.fd.vpp.jvpp.core.dto.TapDeleteReply;
+import io.fd.vpp.jvpp.core.dto.TapModify;
+import io.fd.vpp.jvpp.core.dto.TapModifyReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+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.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Tap;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TapCustomizer extends AbstractInterfaceTypeCustomizer<Tap> implements MacTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TapCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public TapCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ protected Class<? extends InterfaceType> getExpectedInterfaceType() {
+ return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.Tap.class;
+ }
+
+ @Override
+ protected final void writeInterface(@Nonnull final InstanceIdentifier<Tap> id, @Nonnull final Tap dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ createTap(id, ifcName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Tap> id, @Nonnull final Tap dataBefore,
+ @Nonnull final Tap dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+
+ final int index;
+ try {
+ index = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
+ } catch (IllegalArgumentException e) {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
+ }
+
+ modifyTap(id, ifcName, index, dataBefore, dataAfter);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Tap> id, @Nonnull final Tap dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+
+ final int index;
+ try {
+ index = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
+ } catch (IllegalArgumentException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+
+ deleteTap(id, ifcName, index, dataBefore, writeContext);
+ }
+
+ private void createTap(final InstanceIdentifier<Tap> id, final String swIfName, final Tap tap,
+ final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Setting tap interface: {}. Tap: {}", swIfName, tap);
+ final CompletionStage<TapConnectReply> tapConnectFuture = getFutureJVpp()
+ .tapConnect(getTapConnectRequest(tap.getTapName(), tap.getMac(), tap.getDeviceInstance()));
+ final TapConnectReply reply = getReplyForCreate(tapConnectFuture.toCompletableFuture(), id, tap);
+ LOG.debug("Tap set successfully for: {}, tap: {}", swIfName, tap);
+ // Add new interface to our interface context
+ interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+ }
+
+ private void modifyTap(final InstanceIdentifier<Tap> id, final String swIfName, final int index,
+ final Tap tapBefore, final Tap tapAfter) throws WriteFailedException {
+ LOG.debug("Modifying tap interface: {}. Tap: {}", swIfName, tapAfter);
+ final CompletionStage<TapModifyReply> vxlanAddDelTunnelReplyCompletionStage =
+ getFutureJVpp()
+ .tapModify(getTapModifyRequest(tapAfter.getTapName(), index, tapAfter.getMac(),
+ tapAfter.getDeviceInstance()));
+ getReplyForUpdate(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id, tapBefore, tapAfter);
+ LOG.debug("Tap modified successfully for: {}, tap: {}", swIfName, tapAfter);
+ }
+
+ private void deleteTap(final InstanceIdentifier<Tap> id, final String swIfName, final int index,
+ final Tap dataBefore, final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Deleting tap interface: {}. Tap: {}", swIfName, dataBefore);
+ final CompletionStage<TapDeleteReply> vxlanAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().tapDelete(getTapDeleteRequest(index));
+ getReplyForDelete(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Tap deleted successfully for: {}, tap: {}", swIfName, dataBefore);
+ // Remove deleted interface from interface context
+ interfaceContext.removeName(swIfName, writeContext.getMappingContext());
+ }
+
+ private TapConnect getTapConnectRequest(final String tapName, final PhysAddress mac, final Long deviceInstance) {
+ final TapConnect tapConnect = new TapConnect();
+ tapConnect.tapName = tapName.getBytes();
+
+ if (mac == null) {
+ tapConnect.useRandomMac = 1;
+ tapConnect.macAddress = new byte[6];
+ } else {
+ tapConnect.useRandomMac = 0;
+ tapConnect.macAddress = parseMac(mac.getValue());
+ }
+
+ if (deviceInstance == null) {
+ tapConnect.renumber = 0;
+ } else {
+ tapConnect.renumber = 1;
+ tapConnect.customDevInstance = Math.toIntExact(deviceInstance);
+ }
+
+ return tapConnect;
+ }
+
+ private TapModify getTapModifyRequest(final String tapName, final int swIndex, final PhysAddress mac,
+ final Long deviceInstance) {
+ final TapModify tapConnect = new TapModify();
+ tapConnect.tapName = tapName.getBytes();
+ tapConnect.swIfIndex = swIndex;
+
+ if (mac == null) {
+ tapConnect.useRandomMac = 1;
+ tapConnect.macAddress = new byte[6];
+ } else {
+ tapConnect.useRandomMac = 0;
+ tapConnect.macAddress = parseMac(mac.getValue());
+ }
+
+ if (deviceInstance == null) {
+ tapConnect.renumber = 0;
+ } else {
+ tapConnect.renumber = 1;
+ tapConnect.customDevInstance = Math.toIntExact(deviceInstance);
+ }
+
+ return tapConnect;
+ }
+
+ private TapDelete getTapDeleteRequest(final int swIndex) {
+ final TapDelete tapConnect = new TapDelete();
+ tapConnect.swIfIndex = swIndex;
+ return tapConnect;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/VhostUserCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/VhostUserCustomizer.java
new file mode 100644
index 000000000..dc8fade2b
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/VhostUserCustomizer.java
@@ -0,0 +1,157 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import com.google.common.base.Preconditions;
+import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.CreateVhostUserIf;
+import io.fd.vpp.jvpp.core.dto.CreateVhostUserIfReply;
+import io.fd.vpp.jvpp.core.dto.DeleteVhostUserIf;
+import io.fd.vpp.jvpp.core.dto.DeleteVhostUserIfReply;
+import io.fd.vpp.jvpp.core.dto.ModifyVhostUserIf;
+import io.fd.vpp.jvpp.core.dto.ModifyVhostUserIfReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VhostUserRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VhostUser;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer Customizer responsible for passing vhost user interface CRD operations to VPP
+ */
+public class VhostUserCustomizer extends AbstractInterfaceTypeCustomizer<VhostUser>
+ implements ByteDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VhostUserCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public VhostUserCustomizer(@Nonnull final FutureJVppCore vppApi, @Nonnull final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ protected Class<? extends InterfaceType> getExpectedInterfaceType() {
+ return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VhostUser.class;
+ }
+
+ @Override
+ protected final void writeInterface(@Nonnull final InstanceIdentifier<VhostUser> id,
+ @Nonnull final VhostUser dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ createVhostUserIf(id, swIfName, dataAfter, writeContext);
+ }
+
+ private void createVhostUserIf(final InstanceIdentifier<VhostUser> id, final String swIfName,
+ final VhostUser vhostUser, final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Creating vhost user interface: name={}, vhostUser={}", swIfName, vhostUser);
+
+ final CompletionStage<CreateVhostUserIfReply> createVhostUserIfReplyCompletionStage =
+ getFutureJVpp().createVhostUserIf(getCreateVhostUserIfRequest(vhostUser));
+ final CreateVhostUserIfReply reply =
+ getReplyForCreate(createVhostUserIfReplyCompletionStage.toCompletableFuture(), id, vhostUser);
+ LOG.debug("Vhost user interface created successfully for: {}, vhostUser: {}", swIfName, vhostUser);
+ // Add new interface to our interface context
+ interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+ }
+
+ private CreateVhostUserIf getCreateVhostUserIfRequest(final VhostUser vhostUser) {
+ CreateVhostUserIf request = new CreateVhostUserIf();
+ request.isServer = booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole()));
+ request.sockFilename = vhostUser.getSocket().getBytes();
+ // TODO HONEYCOMB-177 expose device instance attribute just like for TAP
+ request.renumber = 0;
+ request.customDevInstance = 0;
+ request.useCustomMac = 0;
+ request.macAddress = new byte[]{};
+ return request;
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<VhostUser> id,
+ @Nonnull final VhostUser dataBefore, @Nonnull final VhostUser dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ modifyVhostUserIf(id, swIfName, dataBefore, dataAfter, writeContext);
+ }
+
+ private void modifyVhostUserIf(final InstanceIdentifier<VhostUser> id, final String swIfName,
+ final VhostUser vhostUserBefore, final VhostUser vhostUserAfter,
+ final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Updating vhost user interface: name={}, vhostUser={}", swIfName, vhostUserAfter);
+ final CompletionStage<ModifyVhostUserIfReply> modifyVhostUserIfReplyCompletionStage =
+ getFutureJVpp()
+ .modifyVhostUserIf(getModifyVhostUserIfRequest(vhostUserAfter,
+ interfaceContext.getIndex(swIfName, writeContext.getMappingContext())));
+
+ getReplyForUpdate(modifyVhostUserIfReplyCompletionStage.toCompletableFuture(), id, vhostUserBefore,
+ vhostUserAfter);
+ LOG.debug("Vhost user interface updated successfully for: {}, vhostUser: {}", swIfName, vhostUserAfter);
+ }
+
+ private ModifyVhostUserIf getModifyVhostUserIfRequest(final VhostUser vhostUser, final int swIfIndex) {
+ ModifyVhostUserIf request = new ModifyVhostUserIf();
+ request.isServer = booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole()));
+ request.sockFilename = vhostUser.getSocket().getBytes();
+ // TODO HONEYCOMB-177
+ request.renumber = 0;
+ request.customDevInstance = 0;
+ request.swIfIndex = swIfIndex;
+ return request;
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<VhostUser> id,
+ @Nonnull final VhostUser dataBefore, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ deleteVhostUserIf(id, swIfName, dataBefore, writeContext);
+ }
+
+ private void deleteVhostUserIf(final InstanceIdentifier<VhostUser> id, final String swIfName,
+ final VhostUser vhostUser, final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Deleting vhost user interface: name={}, vhostUser={}", swIfName, vhostUser);
+ final CompletionStage<DeleteVhostUserIfReply> deleteVhostUserIfReplyCompletionStage =
+ getFutureJVpp().deleteVhostUserIf(getDeleteVhostUserIfRequest(
+ interfaceContext.getIndex(swIfName, writeContext.getMappingContext())));
+
+ getReplyForDelete(deleteVhostUserIfReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Vhost user interface deleted successfully for: {}, vhostUser: {}", swIfName, vhostUser);
+ // Remove interface from our interface context
+ interfaceContext.removeName(swIfName, writeContext.getMappingContext());
+ }
+
+ private DeleteVhostUserIf getDeleteVhostUserIfRequest(final int swIfIndex) {
+ DeleteVhostUserIf request = new DeleteVhostUserIf();
+ request.swIfIndex = swIfIndex;
+ return request;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/VxlanCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/VxlanCustomizer.java
new file mode 100644
index 000000000..ec2193476
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/VxlanCustomizer.java
@@ -0,0 +1,192 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.net.InetAddresses;
+import io.fd.hc2vpp.v3po.DisabledInterfacesManager;
+import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.VxlanAddDelTunnel;
+import io.fd.vpp.jvpp.core.dto.VxlanAddDelTunnelReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.net.InetAddress;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Vxlan;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer<Vxlan> implements JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class);
+
+ private final NamingContext interfaceNamingContext;
+ private final DisabledInterfacesManager interfaceDisableContext;
+
+ public VxlanCustomizer(@Nonnull final FutureJVppCore vppApi,
+ @Nonnull final NamingContext interfaceNamingContext,
+ @Nonnull final DisabledInterfacesManager interfaceDisableContext) {
+ super(vppApi);
+ this.interfaceNamingContext = interfaceNamingContext;
+ this.interfaceDisableContext = interfaceDisableContext;
+ }
+
+ @Override
+ protected Class<? extends InterfaceType> getExpectedInterfaceType() {
+ return VxlanTunnel.class;
+ }
+
+ @Override
+ protected final void writeInterface(@Nonnull final InstanceIdentifier<Vxlan> id, @Nonnull final Vxlan dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ createVxlanTunnel(id, swIfName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Vxlan> id, @Nonnull final Vxlan dataBefore,
+ @Nonnull final Vxlan dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException.UpdateFailedException {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("Vxlan tunnel update is not supported"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Vxlan> id, @Nonnull final Vxlan dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ deleteVxlanTunnel(id, swIfName, dataBefore, writeContext);
+ }
+
+ private void createVxlanTunnel(final InstanceIdentifier<Vxlan> id, final String swIfName, final Vxlan vxlan,
+ final WriteContext writeContext)
+ throws WriteFailedException {
+ final byte isIpv6 = (byte) (isIpv6(vxlan)
+ ? 1
+ : 0);
+ final InetAddress srcAddress = InetAddresses.forString(getAddressString(vxlan.getSrc()));
+ final InetAddress dstAddress = InetAddresses.forString(getAddressString(vxlan.getDst()));
+
+ int encapVrfId = vxlan.getEncapVrfId().intValue();
+ int vni = vxlan.getVni().getValue().intValue();
+
+ LOG.debug("Setting vxlan tunnel for interface: {}. Vxlan: {}", swIfName, vxlan);
+ final CompletionStage<VxlanAddDelTunnelReply> vxlanAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().vxlanAddDelTunnel(getVxlanTunnelRequest((byte) 1 /* is add */, srcAddress.getAddress(),
+ dstAddress.getAddress(), encapVrfId, -1, vni, isIpv6));
+
+ final VxlanAddDelTunnelReply reply =
+ getReplyForCreate(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id, vxlan);
+ LOG.debug("Vxlan tunnel set successfully for: {}, vxlan: {}", swIfName, vxlan);
+ if (interfaceNamingContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) {
+ // VPP keeps vxlan tunnels present even after they are delete(reserving ID for next tunnel)
+ // This may cause inconsistencies in mapping context when configuring tunnels like this:
+ // 1. Add tunnel 2. Delete tunnel 3. Read interfaces (reserved mapping e.g. vxlan_tunnel0 -> 6
+ // will get into mapping context) 4. Add tunnel (this will add another mapping with the same
+ // reserved ID and context is invalid)
+ // That's why a check has to be performed here removing mapping vxlan_tunnel0 -> 6 mapping and storing
+ // new name for that ID
+ final String formerName = interfaceNamingContext.getName(reply.swIfIndex, writeContext.getMappingContext());
+ LOG.debug("Removing updated mapping of a vxlan tunnel, id: {}, former name: {}, new name: {}",
+ reply.swIfIndex, formerName, swIfName);
+ interfaceNamingContext.removeName(formerName, writeContext.getMappingContext());
+
+ }
+
+ // Removing disability of an interface in case a vxlan tunnel formerly deleted is being reused in VPP
+ // further details in above comment
+ if (interfaceDisableContext.isInterfaceDisabled(reply.swIfIndex, writeContext.getMappingContext())) {
+ LOG.debug("Removing disability of vxlan tunnel, id: {}, name: {}", reply.swIfIndex, swIfName);
+ interfaceDisableContext.removeDisabledInterface(reply.swIfIndex, writeContext.getMappingContext());
+ }
+
+ // Add new interface to our interface context
+ interfaceNamingContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+ }
+
+ private boolean isIpv6(final Vxlan vxlan) {
+ if (vxlan.getSrc().getIpv4Address() == null) {
+ checkArgument(vxlan.getDst().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s", vxlan.getSrc(),
+ vxlan.getDst());
+ return true;
+ } else {
+ checkArgument(vxlan.getDst().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s", vxlan.getSrc(),
+ vxlan.getDst());
+ return false;
+ }
+ }
+
+ private String getAddressString(final IpAddress addr) {
+ return addr.getIpv4Address() == null
+ ? addr.getIpv6Address().getValue()
+ : addr.getIpv4Address().getValue();
+ }
+
+ private void deleteVxlanTunnel(final InstanceIdentifier<Vxlan> id, final String swIfName, final Vxlan vxlan,
+ final WriteContext writeContext) throws WriteFailedException {
+ final byte isIpv6 = (byte) (isIpv6(vxlan)
+ ? 1
+ : 0);
+ final InetAddress srcAddress = InetAddresses.forString(getAddressString(vxlan.getSrc()));
+ final InetAddress dstAddress = InetAddresses.forString(getAddressString(vxlan.getDst()));
+
+ int encapVrfId = vxlan.getEncapVrfId().intValue();
+ int vni = vxlan.getVni().getValue().intValue();
+
+ LOG.debug("Deleting vxlan tunnel for interface: {}. Vxlan: {}", swIfName, vxlan);
+ final CompletionStage<VxlanAddDelTunnelReply> vxlanAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().vxlanAddDelTunnel(getVxlanTunnelRequest((byte) 0 /* is add */, srcAddress.getAddress(),
+ dstAddress.getAddress(), encapVrfId, -1, vni, isIpv6));
+
+ getReplyForDelete(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
+ LOG.debug("Vxlan tunnel deleted successfully for: {}, vxlan: {}", swIfName, vxlan);
+
+ final int index = interfaceNamingContext.getIndex(swIfName, writeContext.getMappingContext());
+ // Mark this interface as disabled to not include it in operational reads
+ // because VPP will keep the interface there
+ LOG.debug("Marking vxlan tunnel as disabled, id: {}, name: {}", index, swIfName);
+ interfaceDisableContext.disableInterface(index, writeContext.getMappingContext());
+ // Remove interface from our interface naming context
+ interfaceNamingContext.removeName(swIfName, writeContext.getMappingContext());
+ }
+
+ private static VxlanAddDelTunnel getVxlanTunnelRequest(final byte isAdd, final byte[] srcAddr, final byte[] dstAddr,
+ final int encapVrfId,
+ final int decapNextIndex, final int vni, final byte isIpv6) {
+ final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel();
+ vxlanAddDelTunnel.isAdd = isAdd;
+ vxlanAddDelTunnel.srcAddress = srcAddr;
+ vxlanAddDelTunnel.dstAddress = dstAddr;
+ vxlanAddDelTunnel.encapVrfId = encapVrfId;
+ vxlanAddDelTunnel.vni = vni;
+ vxlanAddDelTunnel.decapNextIndex = decapNextIndex;
+ vxlanAddDelTunnel.isIpv6 = isIpv6;
+ return vxlanAddDelTunnel;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/VxlanGpeCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/VxlanGpeCustomizer.java
new file mode 100644
index 000000000..59ec958f2
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/VxlanGpeCustomizer.java
@@ -0,0 +1,194 @@
+/*
+ * 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.hc2vpp.v3po.interfaces;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.net.InetAddresses;
+import io.fd.hc2vpp.v3po.DisabledInterfacesManager;
+import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.VxlanGpeAddDelTunnel;
+import io.fd.vpp.jvpp.core.dto.VxlanGpeAddDelTunnelReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.net.InetAddress;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanGpeTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VxlanGpe;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VxlanGpeCustomizer extends AbstractInterfaceTypeCustomizer<VxlanGpe> implements JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class);
+ private final NamingContext interfaceNamingContext;
+ private final DisabledInterfacesManager interfaceDisableContext;
+
+ public VxlanGpeCustomizer(@Nonnull final FutureJVppCore vppApi,
+ @Nonnull final NamingContext interfaceNamingContext,
+ @Nonnull final DisabledInterfacesManager interfaceDisableContext) {
+ super(vppApi);
+ this.interfaceNamingContext = interfaceNamingContext;
+ this.interfaceDisableContext = interfaceDisableContext;
+ }
+
+ @Override
+ protected Class<? extends InterfaceType> getExpectedInterfaceType() {
+ return VxlanGpeTunnel.class;
+ }
+
+ @Override
+ protected final void writeInterface(@Nonnull final InstanceIdentifier<VxlanGpe> id,
+ @Nonnull final VxlanGpe dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ createVxlanGpeTunnel(id, swIfName, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanGpe> id,
+ @Nonnull final VxlanGpe dataBefore,
+ @Nonnull final VxlanGpe dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException.UpdateFailedException {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("VxlanGpe tunnel update is not supported"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanGpe> id,
+ @Nonnull final VxlanGpe dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String swIfName = id.firstKeyOf(Interface.class).getName();
+ deleteVxlanGpeTunnel(id, swIfName, dataBefore, writeContext);
+ }
+
+ private void createVxlanGpeTunnel(final InstanceIdentifier<VxlanGpe> id, final String swIfName,
+ final VxlanGpe vxlanGpe, final WriteContext writeContext)
+ throws WriteFailedException {
+ final byte isIpv6 = (byte) (isIpv6(vxlanGpe)
+ ? 1
+ : 0);
+ final InetAddress Local = InetAddresses.forString(getAddressString(vxlanGpe.getLocal()));
+ final InetAddress Remote = InetAddresses.forString(getAddressString(vxlanGpe.getRemote()));
+
+ int vni = vxlanGpe.getVni().getValue().intValue();
+ byte protocol = (byte) vxlanGpe.getNextProtocol().getIntValue();
+ int encapVrfId = vxlanGpe.getEncapVrfId().intValue();
+ int decapVrfId = vxlanGpe.getDecapVrfId().intValue();
+
+ LOG.debug("Setting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, vxlanGpe);
+ final CompletionStage<VxlanGpeAddDelTunnelReply> VxlanGpeAddDelTunnelReplyCompletionStage =
+ getFutureJVpp().vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 1 /* is add */, Local.getAddress(),
+ Remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6));
+
+ final VxlanGpeAddDelTunnelReply reply =
+ getReplyForCreate(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id, vxlanGpe);
+ LOG.debug("VxlanGpe tunnel set successfully for: {}, VxlanGpe: {}", swIfName, vxlanGpe);
+ if (interfaceNamingContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) {
+ final String formerName = interfaceNamingContext.getName(reply.swIfIndex, writeContext.getMappingContext());
+ LOG.debug("Removing updated mapping of a vxlan-gpe tunnel, id: {}, former name: {}, new name: {}",
+ reply.swIfIndex, formerName, swIfName);
+ interfaceNamingContext.removeName(formerName, writeContext.getMappingContext());
+ }
+
+ // Removing disability of an interface in case a vxlan-gpe tunnel formerly deleted is being reused in VPP
+ // further details in above comment
+ if (interfaceDisableContext.isInterfaceDisabled(reply.swIfIndex, writeContext.getMappingContext())) {
+ LOG.debug("Removing disability of vxlan tunnel, id: {}, name: {}", reply.swIfIndex, swIfName);
+ interfaceDisableContext.removeDisabledInterface(reply.swIfIndex, writeContext.getMappingContext());
+ }
+
+ // Add new interface to our interface context
+ interfaceNamingContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
+ }
+
+ private boolean isIpv6(final VxlanGpe vxlanGpe) {
+ if (vxlanGpe.getLocal().getIpv4Address() == null) {
+ checkArgument(vxlanGpe.getRemote().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s",
+ vxlanGpe.getLocal(),
+ vxlanGpe.getRemote());
+ return true;
+ } else {
+ checkArgument(vxlanGpe.getRemote().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s",
+ vxlanGpe.getLocal(),
+ vxlanGpe.getRemote());
+ return false;
+ }
+ }
+
+ private String getAddressString(final IpAddress addr) {
+ return addr.getIpv4Address() == null
+ ? addr.getIpv6Address().getValue()
+ : addr.getIpv4Address().getValue();
+ }
+
+ private void deleteVxlanGpeTunnel(final InstanceIdentifier<VxlanGpe> id, final String swIfName,
+ final VxlanGpe vxlanGpe, final WriteContext writeContext)
+ throws WriteFailedException {
+ final byte isIpv6 = (byte) (isIpv6(vxlanGpe)
+ ? 1
+ : 0);
+ final InetAddress local = InetAddresses.forString(getAddressString(vxlanGpe.getLocal()));
+ final InetAddress remote = InetAddresses.forString(getAddressString(vxlanGpe.getRemote()));
+
+ int vni = vxlanGpe.getVni().getValue().intValue();
+ byte protocol = (byte) vxlanGpe.getNextProtocol().getIntValue();
+ int encapVrfId = vxlanGpe.getEncapVrfId().intValue();
+ int decapVrfId = vxlanGpe.getDecapVrfId().intValue();
+
+ LOG.debug("Deleting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, vxlanGpe);
+ final CompletionStage<VxlanGpeAddDelTunnelReply> VxlanGpeAddDelTunnelReplyCompletionStage =
+ getFutureJVpp()
+ .vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 0 /* is delete */, local.getAddress(),
+ remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6));
+ getReplyForDelete(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
+ final int index = interfaceNamingContext.getIndex(swIfName, writeContext.getMappingContext());
+ // Mark this interface as disabled to not include it in operational reads
+ // because VPP will keep the interface there
+ LOG.debug("Marking vxlan tunnel as disabled, id: {}, name: {}", index, swIfName);
+ interfaceDisableContext.disableInterface(index, writeContext.getMappingContext());
+ // Remove interface from our interface naming context
+ interfaceNamingContext.removeName(swIfName, writeContext.getMappingContext());
+ }
+
+ private static VxlanGpeAddDelTunnel getVxlanGpeTunnelRequest(final byte isAdd, final byte[] local,
+ final byte[] remote,
+ final int vni, final byte protocol,
+ final int encapVrfId, final int decapVrfId,
+ final byte isIpv6) {
+ final VxlanGpeAddDelTunnel VxlanGpeAddDelTunnel = new VxlanGpeAddDelTunnel();
+ VxlanGpeAddDelTunnel.isAdd = isAdd;
+ VxlanGpeAddDelTunnel.local = local;
+ VxlanGpeAddDelTunnel.remote = remote;
+ VxlanGpeAddDelTunnel.vni = vni;
+ VxlanGpeAddDelTunnel.protocol = protocol;
+ VxlanGpeAddDelTunnel.encapVrfId = encapVrfId;
+ VxlanGpeAddDelTunnel.decapVrfId = decapVrfId;
+ VxlanGpeAddDelTunnel.isIpv6 = isIpv6;
+ return VxlanGpeAddDelTunnel;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/IetfAclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/IetfAclWriter.java
new file mode 100644
index 000000000..d97bdee54
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/IetfAclWriter.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.v3po.interfaces.acl;
+
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.Optional;
+import java.util.stream.Stream;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer customizer responsible for Access Control Lists management. Does not send any messages to VPP. All the config
+ * data are stored in HC and used when acl is assigned/unassigned to/from an interface.
+ *
+ * ACLs that are currently assigned to an interface cannot be updated/deleted.
+ */
+public class IetfAclWriter implements ListWriterCustomizer<Acl, AclKey> {
+
+ public static final InstanceIdentifier<AccessLists> ACL_ID =
+ InstanceIdentifier.create(AccessLists.class);
+
+ private static final Logger LOG = LoggerFactory.getLogger(IetfAclWriter.class);
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Creating ACL: iid={} dataAfter={}", id, dataAfter);
+
+ // no vpp call, just updates DataTree
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
+ @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Updating ACL: iid={} dataBefore={} dataAfter={}", id, dataBefore, dataAfter);
+
+ if (isAssigned(dataAfter, writeContext)) {
+ throw new WriteFailedException(id,
+ String.format("Failed to update data at %s: acl %s is already assigned", id, dataAfter));
+ }
+
+ LOG.debug("Updating unassigned ACL: iid={} dataBefore={} dataAfter={}", id, dataBefore, dataAfter);
+
+ // no vpp call, just updates DataTree
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Deleting ACL: iid={} dataBefore={}", id, dataBefore);
+
+ if (isAssigned(dataBefore, writeContext)) {
+ throw new WriteFailedException(id,
+ String.format("Failed to delete data at %s: acl %s is already assigned", id, dataBefore));
+ }
+
+ LOG.debug("Deleting unassigned ACL: iid={} dataBefore={}", id, dataBefore);
+
+ // no vpp call, just updates DataTree
+ }
+
+ private static boolean isAssigned(@Nonnull final Acl acl,
+ @Nonnull final WriteContext writeContext) {
+ final String aclName = acl.getAclName();
+ final Class<? extends AclBase> aclType = acl.getAclType();
+ final Interfaces interfaces = writeContext.readAfter(InstanceIdentifier.create(Interfaces.class)).get();
+
+ return interfaces.getInterface().stream()
+ .map(i -> Optional.ofNullable(i.getAugmentation(VppInterfaceAugmentation.class))
+ .map(aug -> aug.getIetfAcl())
+ .map(ietfAcl -> ietfAcl.getIngress())
+ .map(ingress -> ingress.getAccessLists())
+ .map(accessLists -> accessLists.getAcl())
+ )
+ .flatMap(iacl -> iacl.isPresent()
+ ? iacl.get().stream()
+ : Stream.empty())
+ .filter(assignedAcl -> aclName.equals(assignedAcl.getName()) && aclType.equals(assignedAcl.getType()))
+ .findFirst().isPresent();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AbstractIetfAclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AbstractIetfAclWriter.java
new file mode 100644
index 000000000..29e92ae2a
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AbstractIetfAclWriter.java
@@ -0,0 +1,251 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSessionReply;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTableReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.concurrent.CompletionStage;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.AccessListEntries;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.PacketHandling;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.AceType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.AceIpVersion;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpAndEth;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractIetfAclWriter implements IetfAclWriter, JvppReplyConsumer, AclTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractIetfAclWriter.class);
+ protected static final int NOT_DEFINED = -1;
+ protected final FutureJVppCore jvpp;
+
+ private Map<AclType, AceWriter<? extends AceType>> aceWriters = new HashMap<>();
+
+ public AbstractIetfAclWriter(@Nonnull final FutureJVppCore futureJVppCore) {
+ this.jvpp = Preconditions.checkNotNull(futureJVppCore, "futureJVppCore should not be null");
+ aceWriters.put(AclType.ETH, new AceEthWriter());
+ aceWriters.put(AclType.IP4, new AceIp4Writer());
+ aceWriters.put(AclType.IP6, new AceIp6Writer());
+ aceWriters.put(AclType.ETH_AND_IP, new AceIpAndEthWriter());
+ }
+
+ private static Stream<Ace> aclToAceStream(@Nonnull final Acl assignedAcl,
+ @Nonnull final WriteContext writeContext) {
+ final String aclName = assignedAcl.getName();
+ final Class<? extends AclBase> aclType = assignedAcl.getType();
+
+ // ietf-acl updates are handled first, so we use writeContext.readAfter
+ final Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl>
+ aclOptional =
+ writeContext.readAfter(io.fd.hc2vpp.v3po.interfaces.acl.IetfAclWriter.ACL_ID.child(
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl.class,
+ new AclKey(aclName, aclType)));
+ checkArgument(aclOptional.isPresent(), "Acl lists not configured");
+ final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl
+ acl = aclOptional.get();
+
+ final AccessListEntries accessListEntries = acl.getAccessListEntries();
+ checkArgument(accessListEntries != null, "access list entries not configured");
+
+ return accessListEntries.getAce().stream();
+ }
+
+ protected void removeClassifyTables(@Nonnull final InstanceIdentifier<?> id, @Nonnull final MappingEntry entry)
+ throws WriteFailedException {
+ removeClassifyTable(id, entry.getL2TableId());
+ removeClassifyTable(id, entry.getIp4TableId());
+ removeClassifyTable(id, entry.getIp6TableId());
+ }
+
+ private void removeClassifyTable(@Nonnull final InstanceIdentifier<?> id, final int tableIndex)
+ throws WriteFailedException {
+
+ if (tableIndex == -1) {
+ return; // classify table id is absent
+ }
+ final ClassifyAddDelTable request = new ClassifyAddDelTable();
+ request.tableIndex = tableIndex;
+ final CompletionStage<ClassifyAddDelTableReply> cs = jvpp.classifyAddDelTable(request);
+ getReplyForDelete(cs.toCompletableFuture(), id);
+ }
+
+ protected static boolean appliesToIp4Path(final Ace ace) {
+ final AceType aceType = ace.getMatches().getAceType();
+ final AclType aclType = AclType.fromAce(ace);
+ if (aclType == AclType.IP4) {
+ return true;
+ }
+ if (aclType == AclType.ETH) {
+ return true; // L2 only rules are possible for IP4 traffic
+ }
+ if (aclType == AclType.ETH_AND_IP && ((AceIpAndEth) aceType)
+ .getAceIpVersion() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.version.AceIpv4) {
+ return true;
+ }
+ return false;
+ }
+
+ protected static boolean appliesToIp6Path(final Ace ace) {
+ final AceType aceType = ace.getMatches().getAceType();
+ final AclType aclType = AclType.fromAce(ace);
+ if (aclType == AclType.IP6) {
+ return true;
+ }
+ if (aclType == AclType.ETH) {
+ return true; // L2 only rules are possible for IP6 traffic
+ }
+ if (aclType == AclType.ETH_AND_IP && ((AceIpAndEth) aceType)
+ .getAceIpVersion() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.version.AceIpv6) {
+ return true;
+ }
+ return false;
+ }
+
+ protected static List<Ace> getACEs(@Nonnull final List<Acl> acls, @Nonnull final WriteContext writeContext,
+ final Predicate<? super Ace> filter) {
+ return acls.stream().flatMap(acl -> aclToAceStream(acl, writeContext)).filter(filter)
+ .collect(Collectors.toList());
+ }
+
+ protected int writeAces(final InstanceIdentifier<?> id, final List<Ace> aces,
+ final AccessLists.DefaultAction defaultAction, final InterfaceMode mode,
+ final int vlanTags) throws WriteFailedException {
+ if (aces.isEmpty()) {
+ return NOT_DEFINED;
+ }
+
+ int nextTableIndex = configureDefaultAction(id, defaultAction);
+ final ListIterator<Ace> iterator = aces.listIterator(aces.size());
+ while (iterator.hasPrevious()) {
+ final Ace ace = iterator.previous();
+ LOG.trace("Processing ACE: {}", ace);
+
+ final AceWriter aceWriter =
+ aceWriters.get(AclType.fromAce(ace));
+ if (aceWriter == null) {
+ LOG.warn("AceProcessor for {} not registered. Skipping ACE.", ace.getClass());
+ } else {
+ final AceType aceType = ace.getMatches().getAceType();
+ final PacketHandling action = ace.getActions().getPacketHandling();
+ final ClassifyAddDelTable ctRequest = aceWriter.createTable(aceType, mode, nextTableIndex, vlanTags);
+ nextTableIndex = createClassifyTable(id, ctRequest);
+ final List<ClassifyAddDelSession> sessionRequests =
+ aceWriter.createSession(action, aceType, mode, nextTableIndex, vlanTags);
+ for (ClassifyAddDelSession csRequest : sessionRequests) {
+ createClassifySession(id, csRequest);
+ }
+ }
+ }
+ return nextTableIndex;
+ }
+
+ private int configureDefaultAction(@Nonnull final InstanceIdentifier<?> id,
+ final AccessLists.DefaultAction defaultAction)
+ throws WriteFailedException {
+ ClassifyAddDelTable ctRequest = createTable(-1);
+ if (AccessLists.DefaultAction.Permit.equals(defaultAction)) {
+ ctRequest.missNextIndex = -1;
+ } else {
+ ctRequest.missNextIndex = 0;
+ }
+ ctRequest.mask = new byte[16];
+ ctRequest.skipNVectors = 0;
+ ctRequest.matchNVectors = 1;
+ return createClassifyTable(id, ctRequest);
+ }
+
+ private int createClassifyTable(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final ClassifyAddDelTable request)
+ throws WriteFailedException {
+ final CompletionStage<ClassifyAddDelTableReply> cs = jvpp.classifyAddDelTable(request);
+
+ final ClassifyAddDelTableReply reply = getReplyForWrite(cs.toCompletableFuture(), id);
+ return reply.newTableIndex;
+ }
+
+ private void createClassifySession(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final ClassifyAddDelSession request)
+ throws WriteFailedException {
+ final CompletionStage<ClassifyAddDelSessionReply> cs = jvpp.classifyAddDelSession(request);
+
+ getReplyForWrite(cs.toCompletableFuture(), id);
+ }
+
+ private enum AclType {
+ ETH, IP4, IP6, ETH_AND_IP;
+
+ @Nonnull
+ private static AclType fromAce(final Ace ace) {
+ AclType result = null;
+ final AceType aceType;
+ try {
+ aceType = ace.getMatches().getAceType();
+ if (aceType instanceof AceEth) {
+ result = ETH;
+ } else if (aceType instanceof AceIp) {
+ final AceIpVersion aceIpVersion = ((AceIp) aceType).getAceIpVersion();
+ if (aceIpVersion == null) {
+ throw new IllegalArgumentException("Incomplete ACE (ip-version was not provided): " + ace);
+ }
+ if (aceIpVersion instanceof AceIpv4) {
+ result = IP4;
+ } else if (aceIpVersion instanceof AceIpv6) {
+ result = IP6;
+ }
+ } else if (aceType instanceof AceIpAndEth) {
+ result = ETH_AND_IP;
+ }
+ } catch (NullPointerException e) {
+ throw new IllegalArgumentException("Incomplete ACE: " + ace, e);
+ }
+ if (result == null) {
+ throw new IllegalArgumentException(String.format("Not supported ace type %s", aceType));
+ }
+ return result;
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceEthWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceEthWriter.java
new file mode 100644
index 000000000..67351e0c6
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceEthWriter.java
@@ -0,0 +1,85 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import com.google.common.annotations.VisibleForTesting;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.PacketHandling;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class AceEthWriter implements AceWriter<AceEth>, AclTranslator, L2AclTranslator {
+
+ @VisibleForTesting
+ static final int MATCH_N_VECTORS = 1;
+ private static final Logger LOG = LoggerFactory.getLogger(AceEthWriter.class);
+
+ @Override
+ public ClassifyAddDelTable createTable(@Nonnull final AceEth aceEth,
+ @Nullable final InterfaceMode mode,
+ final int nextTableIndex,
+ final int vlanTags) {
+ final ClassifyAddDelTable request = createTable(nextTableIndex);
+
+ request.mask = new byte[16];
+ boolean aceIsEmpty =
+ destinationMacAddressMask(aceEth.getDestinationMacAddressMask(), aceEth.getDestinationMacAddress(),
+ request);
+ aceIsEmpty &=
+ sourceMacAddressMask(aceEth.getSourceMacAddressMask(), aceEth.getSourceMacAddress(), request);
+
+ if (aceIsEmpty) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", aceEth.toString()));
+ }
+
+ request.skipNVectors = 0;
+ request.matchNVectors = MATCH_N_VECTORS;
+
+ LOG.debug("ACE rule={} translated to table={}.", aceEth, request);
+ return request;
+ }
+
+ @Override
+ public List<ClassifyAddDelSession> createSession(@Nonnull final PacketHandling action,
+ @Nonnull final AceEth aceEth,
+ @Nullable final InterfaceMode mode,
+ final int tableIndex,
+ final int vlanTags) {
+ final ClassifyAddDelSession request = createSession(action, tableIndex);
+
+ request.match = new byte[16];
+ boolean noMatch = destinationMacAddressMatch(aceEth.getDestinationMacAddress(), request);
+ noMatch &= sourceMacAddressMatch(aceEth.getSourceMacAddress(), request);
+
+ if (noMatch) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define neither source nor destination MAC address",
+ aceEth.toString()));
+ }
+
+ LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceEth, request);
+ return Collections.singletonList(request);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceIp4Writer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceIp4Writer.java
new file mode 100644
index 000000000..78ed33aa4
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceIp4Writer.java
@@ -0,0 +1,94 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.annotations.VisibleForTesting;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.PacketHandling;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class AceIp4Writer implements AceWriter<AceIp>, AclTranslator, Ip4AclTranslator {
+
+ @VisibleForTesting
+ static final int MATCH_N_VECTORS = 3; // number of 16B vectors
+ private static final int TABLE_MASK_LENGTH = 48;
+ private static final Logger LOG = LoggerFactory.getLogger(AceIp4Writer.class);
+
+ @Override
+ public ClassifyAddDelTable createTable(@Nonnull final AceIp aceIp,
+ @Nullable final InterfaceMode mode,
+ final int nextTableIndex,
+ final int vlanTags) {
+ checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp);
+ final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion();
+
+ final int numberOfSessions = PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange()).size();
+ final ClassifyAddDelTable request = createTable(nextTableIndex, numberOfSessions);
+ request.skipNVectors = 0; // match entire L2 and L3 header
+ request.matchNVectors = MATCH_N_VECTORS;
+ request.mask = new byte[TABLE_MASK_LENGTH];
+
+ final int baseOffset = getVlanTagsLen(vlanTags);
+ boolean aceIsEmpty = ip4Mask(baseOffset, mode, aceIp, ipVersion, request);
+ if (aceIsEmpty) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", aceIp.toString()));
+ }
+
+ LOG.debug("ACE rule={} translated to table={}.", aceIp, request);
+ return request;
+ }
+
+ @Override
+ public List<ClassifyAddDelSession> createSession(@Nonnull final PacketHandling action,
+ @Nonnull final AceIp aceIp,
+ @Nullable final InterfaceMode mode,
+ final int tableIndex,
+ final int vlanTags) {
+ checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp);
+ final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion();
+
+ final List<PortPair> portPairs = PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange());
+ final List<ClassifyAddDelSession> requests = new ArrayList<>(portPairs.size());
+ for (final PortPair pair : portPairs) {
+ final ClassifyAddDelSession request = createSession(action, tableIndex);
+ request.match = new byte[TABLE_MASK_LENGTH];
+
+ final int baseOffset = getVlanTagsLen(vlanTags);
+ boolean noMatch = ip4Match(baseOffset, mode, aceIp, ipVersion, pair.getSrc(), pair.getDst(), request);
+ if (noMatch) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", aceIp.toString()));
+ }
+
+ LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceIp, request);
+ requests.add(request);
+ }
+ return requests;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceIp6Writer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceIp6Writer.java
new file mode 100644
index 000000000..d7cbb0009
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceIp6Writer.java
@@ -0,0 +1,99 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.PacketHandling;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class AceIp6Writer implements AceWriter<AceIp>, AclTranslator, Ip6AclTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AceIp6Writer.class);
+
+ @Override
+ public ClassifyAddDelTable createTable(@Nonnull final AceIp aceIp,
+ @Nullable final InterfaceMode mode,
+ final int nextTableIndex,
+ final int vlanTags) {
+ checkArgument(aceIp.getAceIpVersion() instanceof AceIpv6, "Expected AceIpv6 version, but was %", aceIp);
+ final AceIpv6 ipVersion = (AceIpv6) aceIp.getAceIpVersion();
+
+ final int numberOfSessions = PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange()).size();
+ final ClassifyAddDelTable request = createTable(nextTableIndex, numberOfSessions);
+ request.skipNVectors = 0; // match entire L2 and L3 header
+ request.mask = new byte[getTableMaskLength(vlanTags)];
+ request.matchNVectors = request.mask.length/16;
+
+ final int baseOffset = getVlanTagsLen(vlanTags);
+ boolean aceIsEmpty = ip6Mask(baseOffset, mode, aceIp, ipVersion, request);
+ if (aceIsEmpty) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", aceIp.toString()));
+ }
+
+ LOG.debug("ACE rule={} translated to table={}.", aceIp, request);
+ return request;
+ }
+
+ private static int getTableMaskLength(final int vlanTags) {
+ if (vlanTags == 2) {
+ return 80;
+ } else {
+ return 64;
+ }
+ }
+
+ @Override
+ public List<ClassifyAddDelSession> createSession(@Nonnull final PacketHandling action,
+ @Nonnull final AceIp aceIp,
+ @Nullable final InterfaceMode mode,
+ final int tableIndex,
+ final int vlanTags) {
+ checkArgument(aceIp.getAceIpVersion() instanceof AceIpv6, "Expected AceIpv6 version, but was %", aceIp);
+ final AceIpv6 ipVersion = (AceIpv6) aceIp.getAceIpVersion();
+ final List<PortPair> portPairs =
+ PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange());
+
+ final List<ClassifyAddDelSession> requests = new ArrayList<>(portPairs.size());
+ for (final PortPair pair : portPairs) {
+ final ClassifyAddDelSession request = createSession(action, tableIndex);
+ request.match = new byte[getTableMaskLength(vlanTags)];
+
+ final int baseOffset = getVlanTagsLen(vlanTags);
+ boolean noMatch = ip6Match(baseOffset, mode, aceIp, ipVersion, pair.getSrc(), pair.getDst(), request);
+ if (noMatch) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", aceIp.toString()));
+ }
+
+ LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceIp, request);
+ requests.add(request);
+ }
+ return requests;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceIpAndEthWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceIpAndEthWriter.java
new file mode 100644
index 000000000..164493cc5
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceIpAndEthWriter.java
@@ -0,0 +1,129 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.PacketHandling;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpAndEth;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.AceIpVersion;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.version.AceIpv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.version.AceIpv6;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class AceIpAndEthWriter
+ implements AceWriter<AceIpAndEth>, AclTranslator, L2AclTranslator, Ip4AclTranslator, Ip6AclTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AceIpAndEthWriter.class);
+
+ private static int maskLength(@Nonnull final AceIpAndEth ace, final int vlanTags) {
+ if (ace.getAceIpVersion() != null) {
+ if (ace.getAceIpVersion() instanceof AceIpv4) {
+ return 48;
+ } else {
+ return vlanTags == 2
+ ? 80
+ : 64;
+ }
+ }
+ return 16;
+ }
+
+ @Override
+ public ClassifyAddDelTable createTable(@Nonnull final AceIpAndEth ace, @Nullable final InterfaceMode mode,
+ final int nextTableIndex, final int vlanTags) {
+ final int numberOfSessions = PortPair.fromRange(ace.getSourcePortRange(), ace.getDestinationPortRange()).size();
+ final ClassifyAddDelTable request = createTable(nextTableIndex, numberOfSessions);
+ final int maskLength = maskLength(ace, vlanTags);
+ request.mask = new byte[maskLength];
+ request.skipNVectors = 0;
+ request.matchNVectors = maskLength / 16;
+
+ boolean aceIsEmpty =
+ destinationMacAddressMask(ace.getDestinationMacAddressMask(), ace.getDestinationMacAddress(), request);
+ aceIsEmpty &= sourceMacAddressMask(ace.getSourceMacAddressMask(), ace.getSourceMacAddress(), request);
+
+ // if we use classifier API, we need to know ip version (fields common for ip4 and ip6 have different offsets):
+ final AceIpVersion aceIpVersion = ace.getAceIpVersion();
+ checkArgument(aceIpVersion != null, "AceIpAndEth have to define IpVersion");
+
+ final int baseOffset = getVlanTagsLen(vlanTags);
+ if (aceIpVersion instanceof AceIpv4) {
+ final AceIpv4 ipVersion = (AceIpv4) aceIpVersion;
+ aceIsEmpty &= ip4Mask(baseOffset, mode, ace, ipVersion, request);
+ } else if (aceIpVersion instanceof AceIpv6) {
+ final AceIpv6 ipVersion = (AceIpv6) aceIpVersion;
+ aceIsEmpty &= ip6Mask(baseOffset, mode, ace, ipVersion, request);
+ } else {
+ throw new IllegalArgumentException(String.format("Unsupported IP version %s", aceIpVersion));
+ }
+
+ if (aceIsEmpty) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", ace.toString()));
+ }
+
+ LOG.debug("ACE rule={} translated to table={}.", ace, request);
+ return request;
+ }
+
+ @Override
+ public List<ClassifyAddDelSession> createSession(@Nonnull final PacketHandling action,
+ @Nonnull final AceIpAndEth ace,
+ @Nullable final InterfaceMode mode, final int tableIndex,
+ final int vlanTags) {
+ final List<PortPair> portPairs = PortPair.fromRange(ace.getSourcePortRange(), ace.getDestinationPortRange());
+ final List<ClassifyAddDelSession> requests = new ArrayList<>(portPairs.size());
+ for (final PortPair pair : portPairs) {
+ final ClassifyAddDelSession request = createSession(action, tableIndex);
+ request.match = new byte[maskLength(ace, vlanTags)];
+
+ boolean noMatch = destinationMacAddressMatch(ace.getDestinationMacAddress(), request);
+ noMatch &= sourceMacAddressMatch(ace.getSourceMacAddress(), request);
+
+ final AceIpVersion aceIpVersion = ace.getAceIpVersion();
+ checkArgument(aceIpVersion != null, "AceIpAndEth have to define IpVersion");
+
+ final int baseOffset = getVlanTagsLen(vlanTags);
+ if (aceIpVersion instanceof AceIpv4) {
+ final AceIpv4 ipVersion = (AceIpv4) aceIpVersion;
+ noMatch &= ip4Match(baseOffset, mode, ace, ipVersion, pair.getSrc(), pair.getDst(), request);
+ } else if (aceIpVersion instanceof AceIpv6) {
+ final AceIpv6 ipVersion = (AceIpv6) aceIpVersion;
+ noMatch &= ip6Match(baseOffset, mode, ace, ipVersion, pair.getSrc(), pair.getDst(), request);
+ } else {
+ throw new IllegalArgumentException(String.format("Unsupported IP version %s", aceIpVersion));
+ }
+
+ if (noMatch) {
+ throw new IllegalArgumentException(
+ String.format("Ace %s does not define packet field match values", ace.toString()));
+ }
+ LOG.debug("ACE action={}, rule={} translated to session={}.", action, ace, request);
+ requests.add(request);
+ }
+ return requests;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceWriter.java
new file mode 100644
index 000000000..75a10e40f
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AceWriter.java
@@ -0,0 +1,54 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.PacketHandling;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.AceType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+
+/**
+ * Writer responsible for translation of ietf-acl model ACEs to VPP's classify tables and sessions.
+ *
+ * @param <T> type of access control list entry
+ */
+interface AceWriter<T extends AceType> {
+ /**
+ * @param ace access list entry
+ * @param mode interface mode (L2/L3)
+ * @param nextTableIndex index of the next classify table in chain
+ * @param vlanTags number of vlan tags
+ */
+ @Nonnull
+ ClassifyAddDelTable createTable(@Nonnull final T ace, @Nullable final InterfaceMode mode, final int nextTableIndex,
+ final int vlanTags);
+
+ /**
+ * @param action to be taken when packet does match the specified ace
+ * @param ace access list entry
+ * @param mode interface mode (L2/L3)
+ * @param tableIndex index of corresponding classify table
+ * @param vlanTags number of vlan tags
+ */
+ @Nonnull
+ List<ClassifyAddDelSession> createSession(@Nonnull final PacketHandling action, @Nonnull T ace,
+ @Nullable final InterfaceMode mode, final int tableIndex, final int vlanTags);
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AclTableContextManager.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AclTableContextManager.java
new file mode 100644
index 000000000..0728944f2
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AclTableContextManager.java
@@ -0,0 +1,53 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntry;
+
+/**
+ * Manages interface metadata for ietf-acl model.
+ */
+public interface AclTableContextManager {
+
+ /**
+ * Obtains mapping entry for given interface.
+ *
+ * @param index interface index
+ * @param mappingContext mapping context providing context data for current transaction
+ * @return ietf-acl metadata for given interface
+ */
+ Optional<MappingEntry> getEntry(final int index, @Nonnull final MappingContext mappingContext);
+
+ /**
+ * Adds mapping entry.
+ *
+ * @param entry to be added
+ * @param mappingContext mapping context providing context data for current transaction
+ */
+ void addEntry(@Nonnull final MappingEntry entry, @Nonnull final MappingContext mappingContext);
+
+ /**
+ * Removes entry for given interface (if present).
+ *
+ * @param index interface index
+ * @param mappingContext mapping context providing context data for current transaction
+ */
+ void removeEntry(final int index, @Nonnull final MappingContext mappingContext);
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AclTableContextManagerImpl.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AclTableContextManagerImpl.java
new file mode 100644
index 000000000..659244fda
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AclTableContextManagerImpl.java
@@ -0,0 +1,68 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.ThreadSafe;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.AclMappingEntryCtxAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.AclMappingEntryContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.MappingTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.MappingTableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntryKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+@ThreadSafe
+public class AclTableContextManagerImpl implements AclTableContextManager {
+
+ private MappingTable.Direction direction;
+
+ public AclTableContextManagerImpl(@Nonnull final MappingTable.Direction direction) {
+ this.direction = checkNotNull(direction, "direction should not be null");
+ }
+
+ @Nonnull
+ @Override
+ public synchronized Optional<MappingEntry> getEntry(final int swIfIndex, @Nonnull final MappingContext mappingContext) {
+ return mappingContext.read(getId(swIfIndex));
+ }
+
+ @Override
+ public synchronized void addEntry(@Nonnull final MappingEntry entry, @Nonnull final MappingContext mappingContext) {
+ mappingContext.put(getId(entry.getIndex()), entry);
+ }
+
+ @Override
+ public synchronized void removeEntry(final int swIfIndex, @Nonnull final MappingContext mappingContext) {
+ mappingContext.delete(getId(swIfIndex));
+ }
+
+ @VisibleForTesting
+ protected InstanceIdentifier<MappingEntry> getId(final int index) {
+ return InstanceIdentifier.create(Contexts.class)
+ .augmentation(AclMappingEntryCtxAugmentation.class)
+ .child(AclMappingEntryContext.class)
+ .child(MappingTable.class, new MappingTableKey(direction))
+ .child(MappingEntry.class, new MappingEntryKey(index));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AclTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AclTranslator.java
new file mode 100644
index 000000000..e4291122d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/AclTranslator.java
@@ -0,0 +1,74 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.PacketHandling;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.packet.handling.Permit;
+
+/**
+ * Utility that helps translating of ietf-acl model ACEs to VPP's classify tables and sessions.
+ */
+interface AclTranslator {
+ int TABLE_MEM_SIZE = 8 * 1024;
+ int VLAN_TAG_LEN = 4;
+
+ default ClassifyAddDelTable createTable(final int nextTableIndex) {
+ return createTable(nextTableIndex, 1);
+ }
+
+ default ClassifyAddDelTable createTable(final int nextTableIndex, @Nonnegative final int numberOfSessions) {
+ final ClassifyAddDelTable request = new ClassifyAddDelTable();
+ request.isAdd = 1;
+ request.tableIndex = -1; // value not present
+ request.nbuckets = numberOfSessions;
+ request.nextTableIndex = nextTableIndex;
+
+
+ // TODO: HONEYCOMB-181 minimise memory used by classify tables (we create a lot of them to make ietf-acl model
+ // mapping more convenient):
+ // according to https://wiki.fd.io/view/VPP/Introduction_To_N-tuple_Classifiers#Creating_a_classifier_table,
+ // classify table needs 16*(1 + match_n_vectors) bytes, but this does not quite work,
+ // so setting 8K +1k*numberOfSessions for now
+ checkArgument(numberOfSessions>0, "negative numberOfSessions %s", numberOfSessions);
+ request.memorySize = TABLE_MEM_SIZE+1024*(numberOfSessions-1);
+ request.missNextIndex = -1; // value not set, but anyway it is ignored for tables in chain
+ return request;
+ }
+
+ default ClassifyAddDelSession createSession(@Nonnull final PacketHandling action, final int tableIndex) {
+ final ClassifyAddDelSession request = new ClassifyAddDelSession();
+ request.isAdd = 1;
+ request.tableIndex = tableIndex;
+ request.opaqueIndex = ~0; // value not used
+
+ if (action instanceof Permit) {
+ request.hitNextIndex = -1;
+ } // deny (0) is default value
+
+ return request;
+ }
+
+ default int getVlanTagsLen(final int vlanTags) {
+ return vlanTags * VLAN_TAG_LEN;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/IetfAclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/IetfAclWriter.java
new file mode 100644
index 000000000..df0b65c2e
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/IetfAclWriter.java
@@ -0,0 +1,47 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.List;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface IetfAclWriter {
+ default void write(@Nonnull final InstanceIdentifier<?> id, final int ifIndex, @Nonnull final List<Acl> acls,
+ final AccessLists.DefaultAction defaultAction, @Nullable final InterfaceMode mode,
+ @Nonnull final WriteContext writeContext, @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException {
+ write(id, ifIndex, acls, defaultAction, mode, writeContext, 0, mappingContext);
+ }
+
+ void write(@Nonnull final InstanceIdentifier<?> id, int ifIndex, @Nonnull final List<Acl> acls,
+ final AccessLists.DefaultAction defaultAction, @Nullable InterfaceMode mode,
+ @Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags,
+ @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException;
+
+ void deleteAcl(@Nonnull final InstanceIdentifier<?> id, int ifIndex, @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException;
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/Ip4AclTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/Ip4AclTranslator.java
new file mode 100644
index 000000000..c1bad0735
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/Ip4AclTranslator.java
@@ -0,0 +1,149 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import com.google.common.primitives.Ints;
+import io.fd.hc2vpp.common.translate.util.Ipv4Translator;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpHeaderFields;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpv4HeaderFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+
+interface Ip4AclTranslator extends Ipv4Translator {
+ int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6)
+ int DSCP_OFFSET = 15;
+ int DSCP_MASK = 0xfc;
+
+ int IP_PROTOCOL_OFFSET = ETHER_TYPE_OFFSET + 11;
+ int IP_PROTOCOL_MASK = 0xff;
+
+ int IP4_LEN = 4;
+ int IP4_MASK_BIT_LENGTH = 32;
+ int SRC_IP_OFFSET = ETHER_TYPE_OFFSET + 14;
+ int DST_IP_OFFSET = SRC_IP_OFFSET + IP4_LEN;
+ int SRC_PORT_OFFSET = DST_IP_OFFSET + IP4_LEN;
+ int DST_PORT_OFFSET = SRC_PORT_OFFSET + 2;
+
+ default boolean ip4Mask(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
+ final AclIpv4HeaderFields ip4, final ClassifyAddDelTable request) {
+ boolean aceIsEmpty = true;
+ if (InterfaceMode.L2.equals(mode)) {
+ // in L2 mode we need to match ether type
+ request.mask[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0xff;
+ request.mask[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xff;
+ }
+ if (header.getDscp() != null) {
+ aceIsEmpty = false;
+ request.mask[baseOffset + DSCP_OFFSET] = (byte) DSCP_MASK; // first 6 bits
+ }
+ if (header.getProtocol() != null) { // Internet Protocol number
+ aceIsEmpty = false;
+ request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK;
+ }
+ if (header.getSourcePortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ aceIsEmpty = false;
+ request.mask[baseOffset + SRC_PORT_OFFSET] = (byte) 0xff;
+ request.mask[baseOffset + SRC_PORT_OFFSET + 1] = (byte) 0xff;
+ }
+ if (header.getDestinationPortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ aceIsEmpty = false;
+ request.mask[baseOffset + DST_PORT_OFFSET] = (byte) 0xff;
+ request.mask[baseOffset + DST_PORT_OFFSET + 1] = (byte) 0xff;
+ }
+ if (ip4.getSourceIpv4Network() != null) {
+ aceIsEmpty = false;
+ System.arraycopy(Impl.toByteMask(ip4.getSourceIpv4Network()), 0, request.mask,
+ baseOffset + SRC_IP_OFFSET, IP4_LEN);
+ }
+ if (ip4.getDestinationIpv4Network() != null) {
+ aceIsEmpty = false;
+ System.arraycopy(Impl.toByteMask(ip4.getDestinationIpv4Network()), 0, request.mask,
+ baseOffset + DST_IP_OFFSET, IP4_LEN);
+ }
+ return aceIsEmpty;
+ }
+
+ default boolean ip4Match(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
+ final AclIpv4HeaderFields ip4, final Integer srcPort,
+ final Integer dstPort, final ClassifyAddDelSession request) {
+ boolean noMatch = true;
+ if (InterfaceMode.L2.equals(mode)) {
+ // match IP4 etherType (0x0800)
+ request.match[baseOffset + ETHER_TYPE_OFFSET] = 0x08;
+ request.match[baseOffset + ETHER_TYPE_OFFSET + 1] = 0x00;
+ }
+ if (header.getDscp() != null) {
+ noMatch = false;
+ request.match[baseOffset + DSCP_OFFSET] = (byte) (DSCP_MASK & (header.getDscp().getValue() << 2));
+ }
+ if (header.getProtocol() != null) { // Internet Protocol number
+ noMatch = false;
+ request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & header.getProtocol());
+ }
+ if (srcPort != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ noMatch = false;
+ request.match[baseOffset + SRC_PORT_OFFSET] = (byte) (0xff & srcPort >> 8);
+ request.match[baseOffset + SRC_PORT_OFFSET + 1] = (byte) (0xff & srcPort);
+ }
+ if (header.getDestinationPortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ noMatch = false;
+ request.match[baseOffset + DST_PORT_OFFSET] = (byte) (0xff & dstPort >> 8);
+ request.match[baseOffset + DST_PORT_OFFSET + 1] = (byte) (0xff & dstPort);
+ }
+ if (ip4.getSourceIpv4Network() != null) {
+ noMatch = false;
+ System.arraycopy(Impl.toMatchValue(ip4.getSourceIpv4Network()), 0, request.match,
+ baseOffset + SRC_IP_OFFSET, IP4_LEN);
+
+ }
+ if (ip4.getDestinationIpv4Network() != null) {
+ noMatch = false;
+ System.arraycopy(Impl.toMatchValue(ip4.getDestinationIpv4Network()), 0, request.match,
+ baseOffset + DST_IP_OFFSET, IP4_LEN);
+
+ }
+ return noMatch;
+ }
+
+ class Impl {
+ private static byte[] toByteMask(final int prefixLength) {
+ final long mask = ((1L << prefixLength) - 1) << (IP4_MASK_BIT_LENGTH - prefixLength);
+ return Ints.toByteArray((int) mask);
+ }
+
+ private static byte[] toByteMask(final Ipv4Prefix ipv4Prefix) {
+ final int prefixLength = Byte.valueOf(ipv4Prefix.getValue().split("/")[1]);
+ return toByteMask(prefixLength);
+ }
+
+ private static byte[] toMatchValue(final Ipv4Prefix ipv4Prefix) {
+ final String[] split = ipv4Prefix.getValue().split("/");
+ final byte[] addressBytes = Ipv4Translator.INSTANCE.ipv4AddressNoZoneToArray(split[0]);
+ final byte[] mask = Impl.toByteMask(Byte.valueOf(split[1]));
+ for (int i = 0; i < addressBytes.length; ++i) {
+ addressBytes[i] &= mask[i];
+ }
+ return addressBytes;
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/Ip6AclTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/Ip6AclTranslator.java
new file mode 100644
index 000000000..ec9bebe7e
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/Ip6AclTranslator.java
@@ -0,0 +1,182 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.BitSet;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpHeaderFields;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpv6HeaderFields;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+
+interface Ip6AclTranslator {
+
+ int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6)
+ int IP_VERSION_OFFSET = ETHER_TYPE_OFFSET + 2;
+ int DSCP_MASK1 = 0x0f;
+ int DSCP_MASK2 = 0xc0;
+ int IP_PROTOCOL_OFFSET = IP_VERSION_OFFSET + 6;
+ int IP_PROTOCOL_MASK = 0xff;
+ int IP6_LEN = 16;
+ int SRC_IP_OFFSET = IP_VERSION_OFFSET + 8;
+ int DST_IP_OFFSET = SRC_IP_OFFSET + IP6_LEN;
+ int SRC_PORT_OFFSET = DST_IP_OFFSET + IP6_LEN;
+ int DST_PORT_OFFSET = SRC_PORT_OFFSET + 2;
+
+ default boolean ip6Mask(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
+ final AclIpv6HeaderFields ip6, final ClassifyAddDelTable request) {
+ boolean aceIsEmpty = true;
+ if (InterfaceMode.L2.equals(mode)) {
+ // in L2 mode we need to match ether type
+ request.mask[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0xff;
+ request.mask[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xff;
+ }
+ if (header.getDscp() != null) {
+ aceIsEmpty = false;
+ // DCSP (bits 4-9 of IP6 header)
+ request.mask[baseOffset + IP_VERSION_OFFSET] |= DSCP_MASK1;
+ request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= DSCP_MASK2;
+ }
+ if (header.getProtocol() != null) { // Internet Protocol number
+ aceIsEmpty = false;
+ request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK;
+ }
+ if (ip6.getFlowLabel() != null) {
+ aceIsEmpty = false;
+ // bits 12-31
+ request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) 0x0f;
+ request.mask[baseOffset + IP_VERSION_OFFSET + 2] = (byte) 0xff;
+ request.mask[baseOffset + IP_VERSION_OFFSET + 3] = (byte) 0xff;
+ }
+ if (header.getSourcePortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ aceIsEmpty = false;
+ request.mask[baseOffset + SRC_PORT_OFFSET] = (byte) 0xff;
+ request.mask[baseOffset + SRC_PORT_OFFSET + 1] = (byte) 0xff;
+ }
+ if (header.getDestinationPortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ aceIsEmpty = false;
+ request.mask[baseOffset + DST_PORT_OFFSET] = (byte) 0xff;
+ request.mask[baseOffset + DST_PORT_OFFSET + 1] = (byte) 0xff;
+ }
+ if (ip6.getSourceIpv6Network() != null) {
+ aceIsEmpty = false;
+ final byte[] mask = Impl.toByteMask(ip6.getSourceIpv6Network());
+ System.arraycopy(mask, 0, request.mask, baseOffset + SRC_IP_OFFSET, mask.length);
+ }
+ if (ip6.getDestinationIpv6Network() != null) {
+ aceIsEmpty = false;
+ final byte[] mask = Impl.toByteMask(ip6.getDestinationIpv6Network());
+ System.arraycopy(mask, 0, request.mask, baseOffset + DST_IP_OFFSET, mask.length);
+ }
+ return aceIsEmpty;
+ }
+
+ default boolean ip6Match(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
+ final AclIpv6HeaderFields ip6, final Integer srcPort, final Integer dstPort, final ClassifyAddDelSession request) {
+ boolean noMatch = true;
+ if (InterfaceMode.L2.equals(mode)) {
+ // match IP6 etherType (0x86dd)
+ request.match[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0x86;
+ request.match[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xdd;
+ }
+ if (header.getDscp() != null) {
+ noMatch = false;
+ final int dcsp = header.getDscp().getValue();
+ // set bits 4-9 of IP6 header:
+ request.match[baseOffset + IP_VERSION_OFFSET] |= (byte) (DSCP_MASK1 & (dcsp >> 2));
+ request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (DSCP_MASK2 & (dcsp << 6));
+ }
+ if (header.getProtocol() != null) { // Internet Protocol number
+ noMatch = false;
+ request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & header.getProtocol());
+ }
+ if (ip6.getFlowLabel() != null) {
+ noMatch = false;
+ final int flowLabel = ip6.getFlowLabel().getValue().intValue();
+ // bits 12-31
+ request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (0x0f & (flowLabel >> 16));
+ request.match[baseOffset + IP_VERSION_OFFSET + 2] = (byte) (0xff & (flowLabel >> 8));
+ request.match[baseOffset + IP_VERSION_OFFSET + 3] = (byte) (0xff & flowLabel);
+ }
+ if (header.getSourcePortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ noMatch = false;
+ request.match[baseOffset + SRC_PORT_OFFSET] = (byte) (0xff & srcPort >> 8);
+ request.match[baseOffset + SRC_PORT_OFFSET + 1] = (byte) (0xff & srcPort);
+ }
+ if (header.getDestinationPortRange() != null) {
+ // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
+ noMatch = false;
+ request.match[baseOffset + DST_PORT_OFFSET] = (byte) (0xff & dstPort >> 8);
+ request.match[baseOffset + DST_PORT_OFFSET + 1] = (byte) (0xff & dstPort);
+ }
+ if (ip6.getSourceIpv6Network() != null) {
+ noMatch = false;
+ final byte[] match = Impl.toMatchValue(ip6.getSourceIpv6Network());
+ System.arraycopy(match, 0, request.match, baseOffset + SRC_IP_OFFSET, IP6_LEN);
+ }
+ if (ip6.getDestinationIpv6Network() != null) {
+ noMatch = false;
+ final byte[] match = Impl.toMatchValue(ip6.getDestinationIpv6Network());
+ System.arraycopy(match, 0, request.match, baseOffset + DST_IP_OFFSET, IP6_LEN);
+ }
+ return noMatch;
+ }
+
+ class Impl {
+ private static final int IP6_MASK_BIT_LENGTH = 128;
+
+ private static byte[] toByteMask(final int prefixLength) {
+ final BitSet mask = new BitSet(IP6_MASK_BIT_LENGTH);
+ mask.set(0, prefixLength, true);
+ if (prefixLength < IP6_MASK_BIT_LENGTH) {
+ mask.set(prefixLength, IP6_MASK_BIT_LENGTH, false);
+ }
+ return mask.toByteArray();
+ }
+
+ private static byte[] toByteMask(final Ipv6Prefix ipv6Prefix) {
+ final int prefixLength = Short.valueOf(ipv6Prefix.getValue().split("/")[1]);
+ return toByteMask(prefixLength);
+ }
+
+ private static byte[] toMatchValue(final Ipv6Prefix ipv6Prefix) {
+ final String[] split = ipv6Prefix.getValue().split("/");
+ final byte[] addressBytes;
+ try {
+ addressBytes = InetAddress.getByName(split[0]).getAddress();
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Invalid IP6 address", e);
+ }
+ final byte[] mask = toByteMask(Short.valueOf(split[1]));
+ int pos = 0;
+ for (; pos < mask.length; ++pos) {
+ addressBytes[pos] &= mask[pos];
+ }
+ // mask can be shorter that address, so we need to clear rest of the address:
+ for (; pos < addressBytes.length; ++pos) {
+ addressBytes[pos] = 0;
+ }
+ return addressBytes;
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/L2AclTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/L2AclTranslator.java
new file mode 100644
index 000000000..5a6807bba
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/L2AclTranslator.java
@@ -0,0 +1,90 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import io.fd.hc2vpp.common.translate.util.MacTranslator;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+
+interface L2AclTranslator extends MacTranslator {
+
+ default boolean destinationMacAddressMask(final MacAddress dstMask, final MacAddress dstAddress,
+ final ClassifyAddDelTable request) {
+ // destination-mac-address or destination-mac-address-mask is present =>
+ // ff:ff:ff:ff:ff:ff:00:00:00:00:00:00:00:00:00:00
+ if (dstMask != null) {
+ final List<String> parts = COLON_SPLITTER.splitToList(dstMask.getValue());
+ int i = 0;
+ for (String part : parts) {
+ request.mask[i++] = parseHexByte(part);
+ }
+ return false;
+ } else if (dstAddress != null) {
+ for (int i = 0; i < 6; ++i) {
+ request.mask[i] = (byte) 0xff;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ default boolean sourceMacAddressMask(final MacAddress srcMask, final MacAddress srcAddress,
+ final ClassifyAddDelTable request) {
+ // source-mac-address or source-mac-address-mask =>
+ // 00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:00:00:00:00
+ if (srcMask != null) {
+ final List<String> parts = COLON_SPLITTER.splitToList(srcMask.getValue());
+ int i = 6;
+ for (String part : parts) {
+ request.mask[i++] = parseHexByte(part);
+ }
+ return false;
+ } else if (srcAddress != null) {
+ for (int i = 6; i < 12; ++i) {
+ request.mask[i] = (byte) 0xff;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ default boolean destinationMacAddressMatch(final MacAddress dstAddress, final ClassifyAddDelSession request) {
+ if (dstAddress != null) {
+ final List<String> parts = COLON_SPLITTER.splitToList(dstAddress.getValue());
+ int i = 0;
+ for (String part : parts) {
+ request.match[i++] = parseHexByte(part);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ default boolean sourceMacAddressMatch(final MacAddress srcAddress, final ClassifyAddDelSession request) {
+ if (srcAddress != null) {
+ final List<String> parts = COLON_SPLITTER.splitToList(srcAddress.getValue());
+ int i = 6;
+ for (String part : parts) {
+ request.match[i++] = parseHexByte(part);
+ }
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/PortPair.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/PortPair.java
new file mode 100644
index 000000000..1630f58fd
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/common/PortPair.java
@@ -0,0 +1,126 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.common;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.BiFunction;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.DestinationPortRange;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRange;
+
+/**
+ * Utility that produces cartesian product out of src and dst port ranges (used to translate ranges into
+ * list of classify sessions).
+ */
+final class PortPair {
+ private final Integer src;
+ private final Integer dst;
+
+ PortPair(@Nullable final Integer src, @Nullable final Integer dst) {
+ this.src = src;
+ this.dst = dst;
+ }
+
+ Integer getSrc() {
+ return src;
+ }
+
+ Integer getDst() {
+ return dst;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + src + "," + dst + ")";
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final PortPair that = (PortPair) o;
+ if (!Objects.equals(src, that.src)) {
+ return false;
+ }
+ if (!Objects.equals(dst, that.dst)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(src, dst);
+ }
+
+ static List<PortPair> fromRange(final SourcePortRange srcRange,
+ final DestinationPortRange dstRange) {
+ final List<PortPair> result = new ArrayList<>();
+ if (srcRange == null && dstRange == null) {
+ result.add(new PortPair(null, null));
+ } else if (srcRange != null && dstRange == null) {
+ processSingleRange(result, srcRange.getLowerPort(), srcRange.getUpperPort(), PortPair::new);
+ } else if (srcRange == null && dstRange != null) {
+ processSingleRange(result, dstRange.getLowerPort(), dstRange.getUpperPort(),
+ (dst, src) -> new PortPair(src, dst));
+ } else {
+ processDoubleRange(result, srcRange, dstRange);
+ }
+ return result;
+ }
+
+ private static void processSingleRange(final List<PortPair> result,
+ final PortNumber lowerPort,
+ final PortNumber upperPort,
+ final BiFunction<Integer, Integer, PortPair> f) {
+ int low = lowerPort.getValue(); // mandatory
+ int hi = low;
+ if (upperPort != null) {
+ hi = upperPort.getValue();
+ }
+ for (; low <= hi; ++low) {
+ result.add(f.apply(low, null));
+ }
+ }
+
+ private static void processDoubleRange(final List<PortPair> result, final SourcePortRange srcRange,
+ final DestinationPortRange dstRange) {
+ int srcL = srcRange.getLowerPort().getValue();
+ int srcH = srcL;
+ if (srcRange.getUpperPort() != null) {
+ srcH = srcRange.getUpperPort().getValue();
+ }
+ int dstL = dstRange.getLowerPort().getValue();
+ int dstH = dstL;
+ if (dstRange.getUpperPort() != null) {
+ dstH = dstRange.getUpperPort().getValue();
+ }
+ for (int i=srcL; i <= srcH; ++i) {
+ for (int j=dstL; j <= dstH; ++j) {
+ result.add(new PortPair(i, j));
+ }
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/egress/EgressIetfAclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/egress/EgressIetfAclWriter.java
new file mode 100644
index 000000000..adb19e360
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/egress/EgressIetfAclWriter.java
@@ -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.hc2vpp.v3po.interfaces.acl.egress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.hc2vpp.v3po.interfaces.acl.common.AbstractIetfAclWriter;
+import io.fd.hc2vpp.v3po.interfaces.acl.common.AclTableContextManager;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.ClassifySetInterfaceL2Tables;
+import io.fd.vpp.jvpp.core.dto.ClassifySetInterfaceL2TablesReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class EgressIetfAclWriter extends AbstractIetfAclWriter {
+ private final AclTableContextManager aclCtx;
+
+ public EgressIetfAclWriter(@Nonnull final FutureJVppCore futureJVppCore, @Nonnull AclTableContextManager aclCtx) {
+ super(futureJVppCore);
+ this.aclCtx = checkNotNull(aclCtx, "aclCtx should not be null");
+ }
+
+ @Override
+ public void deleteAcl(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex,
+ @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException {
+ Optional<MappingEntry> optional = aclCtx.getEntry(swIfIndex, mappingContext);
+ checkState(optional.isPresent(), "Removing ACL id=%s, but acl mapping entry is not present", id);
+ final MappingEntry entry = optional.get();
+ unassignClassifyTables(id, swIfIndex);
+ removeClassifyTables(id, entry);
+ aclCtx.removeEntry(swIfIndex, mappingContext);
+ }
+
+ private void unassignClassifyTables(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex)
+ throws WriteFailedException {
+ final ClassifySetInterfaceL2Tables request = new ClassifySetInterfaceL2Tables();
+ request.swIfIndex = swIfIndex;
+ request.ip4TableIndex = NOT_DEFINED;
+ request.ip6TableIndex = NOT_DEFINED;
+ request.otherTableIndex = NOT_DEFINED;
+ request.isInput = 0; // egress
+ final CompletionStage<ClassifySetInterfaceL2TablesReply> cs = jvpp.classifySetInterfaceL2Tables(request);
+ getReplyForDelete(cs.toCompletableFuture(), id);
+ }
+
+ @Override
+ public void write(@Nonnull final InstanceIdentifier<?> id, int swIfIndex, @Nonnull final List<Acl> acls,
+ @Nonnull final AccessLists.DefaultAction defaultAction, @Nullable InterfaceMode mode,
+ @Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags,
+ @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException {
+ checkArgument(numberOfTags >= 0 && numberOfTags <= 2, "Number of vlan tags %s is not in [0,2] range");
+ checkArgument(InterfaceMode.L2.equals(mode), "Writing egress Acls is supported only in L2 mode");
+
+ final ClassifySetInterfaceL2Tables request = new ClassifySetInterfaceL2Tables();
+ request.isInput = 0; // egress
+ request.swIfIndex = swIfIndex;
+
+ // applied to packets according to their ether type
+ final List<Ace> ip4Aces = getACEs(acls, writeContext, (AbstractIetfAclWriter::appliesToIp4Path));
+ request.ip4TableIndex = writeAces(id, ip4Aces, defaultAction, mode, numberOfTags);
+ final List<Ace> ip6Aces = getACEs(acls, writeContext, (AbstractIetfAclWriter::appliesToIp6Path));
+ request.ip6TableIndex = writeAces(id, ip6Aces, defaultAction, mode, numberOfTags);
+ final List<Ace> aces = getACEs(acls, writeContext, EgressIetfAclWriter::isNotIpRule);
+ request.otherTableIndex = writeAces(id, aces, defaultAction, mode, numberOfTags);
+
+ final MappingEntry entry = new MappingEntryBuilder().setIndex(swIfIndex)
+ .setIp4TableId(request.ip4TableIndex)
+ .setIp6TableId(request.ip6TableIndex)
+ .setL2TableId(request.otherTableIndex)
+ .build();
+ aclCtx.addEntry(entry, mappingContext);
+
+ try {
+ getReplyForWrite(jvpp.classifySetInterfaceL2Tables(request).toCompletableFuture(), id);
+ } catch (WriteFailedException e) {
+ removeClassifyTables(id, entry);
+ throw e;
+ }
+ }
+
+ private static boolean isNotIpRule(final Ace ace) {
+ final Matches matches = ace.getMatches();
+ checkArgument(matches != null, "Incomplete ACE: %s", ace);
+ return matches.getAceType() instanceof AceEth;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/egress/IetfAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/egress/IetfAclCustomizer.java
new file mode 100644
index 000000000..3cef7a697
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/egress/IetfAclCustomizer.java
@@ -0,0 +1,85 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.egress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.acl.common.IetfAclWriter;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ietf.acl.Egress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class IetfAclCustomizer implements WriterCustomizer<Egress> {
+ private static final Logger LOG = LoggerFactory.getLogger(IetfAclCustomizer.class);
+ private final IetfAclWriter aclWriter;
+ private final NamingContext interfaceContext;
+
+ public IetfAclCustomizer(final IetfAclWriter aclWriter, final NamingContext interfaceContext) {
+ this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null");
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Egress> id, @Nonnull final Egress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext());
+ LOG.debug("Adding egress ACLs for interface={}(id={}): {}", ifName, ifIndex, dataAfter);
+
+ final AccessLists accessLists = dataAfter.getAccessLists();
+ checkArgument(accessLists != null && accessLists.getAcl() != null,
+ "ietf-acl container does not define acl list");
+
+ if (!InterfaceMode.L2.equals(accessLists.getMode())) {
+ LOG.debug("Writing egress Acls is supported only in L2 mode. Ignoring config: {}", dataAfter);
+ return;
+ }
+
+ aclWriter.write(id, ifIndex, accessLists.getAcl(), accessLists.getDefaultAction(), accessLists.getMode(),
+ writeContext, writeContext.getMappingContext());
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Egress> id, @Nonnull final Egress dataBefore,
+ @Nonnull final Egress dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("ACLs update: removing previously configured ACLs");
+ deleteCurrentAttributes(id, dataBefore, writeContext);
+ LOG.debug("ACLs update: adding updated ACLs");
+ writeCurrentAttributes(id, dataAfter, writeContext);
+ LOG.debug("ACLs update was successful");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Egress> id, @Nonnull final Egress dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext());
+ LOG.debug("Removing ACLs for interface={}(id={}): {}", ifName, ifIndex, dataBefore);
+ aclWriter.deleteAcl(id, ifIndex, writeContext.getMappingContext());
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/egress/SubInterfaceIetfAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/egress/SubInterfaceIetfAclCustomizer.java
new file mode 100644
index 000000000..3ea40436b
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/egress/SubInterfaceIetfAclCustomizer.java
@@ -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 io.fd.hc2vpp.v3po.interfaces.acl.egress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.getNumberOfTags;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.v3po.interfaces.acl.common.IetfAclWriter;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.ietf.acl.Egress;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SubInterfaceIetfAclCustomizer implements WriterCustomizer<Egress> {
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIetfAclCustomizer.class);
+ private final IetfAclWriter aclWriter;
+ private final NamingContext interfaceContext;
+
+ public SubInterfaceIetfAclCustomizer(final IetfAclWriter aclWriter, final NamingContext interfaceContext) {
+ this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null");
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ private String getSubInterfaceName(@Nonnull final InstanceIdentifier<Egress> id) {
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ return SubInterfaceUtils
+ .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Egress> id, @Nonnull final Egress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ LOG.debug("Adding IETF-ACL for sub-interface: {}(id={}): {}", subInterfaceName, subInterfaceIndex, dataAfter);
+
+ final AccessLists accessLists = dataAfter.getAccessLists();
+ checkArgument(accessLists != null && accessLists.getAcl() != null,
+ "ietf-acl container does not define acl list");
+
+ final Optional<SubInterface> subInterfaceOptional =
+ writeContext.readAfter(id.firstIdentifierOf(SubInterface.class));
+ checkState(subInterfaceOptional.isPresent(), "Could not read SubInterface data object for %s", id);
+ final SubInterface subInterface = subInterfaceOptional.get();
+
+ if (!InterfaceMode.L2.equals(accessLists.getMode())) {
+ LOG.debug("Writing egress Acls is supported only in L2 mode. Ignoring config: {}", dataAfter);
+ return;
+ }
+
+ aclWriter
+ .write(id, subInterfaceIndex, accessLists.getAcl(), accessLists.getDefaultAction(), accessLists.getMode(),
+ writeContext, getNumberOfTags(subInterface.getTags()), writeContext.getMappingContext());
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Egress> id, @Nonnull final Egress dataBefore,
+ @Nonnull final Egress dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Sub-interface ACLs update: removing previously configured ACLs");
+ deleteCurrentAttributes(id, dataBefore, writeContext);
+ LOG.debug("Sub-interface ACLs update: adding updated ACLs");
+ writeCurrentAttributes(id, dataAfter, writeContext);
+ LOG.debug("Sub-interface ACLs update was successful");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Egress> id, @Nonnull final Egress dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ LOG.debug("Removing ACLs for sub-interface={}(id={}): {}", subInterfaceName, subInterfaceIndex, dataBefore);
+ aclWriter.deleteAcl(id, subInterfaceIndex, writeContext.getMappingContext());
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/AclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/AclCustomizer.java
new file mode 100644
index 000000000..05233ce40
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/AclCustomizer.java
@@ -0,0 +1,83 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+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.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.acl.Ingress;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for enabling/disabling ingress ACLs on given interface based on low lever classfier model.
+ */
+public class AclCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Ingress>, AclWriter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final VppClassifierContextManager classifyTableContext;
+
+ public AclCustomizer(@Nonnull final FutureJVppCore vppApi, @Nonnull final NamingContext interfaceContext,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(vppApi);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ setAcl(true, id, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore,
+ @Nonnull final Ingress dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ throw new UnsupportedOperationException("Acl update is not supported. Please delete Acl container first.");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ setAcl(false, id, dataBefore, writeContext);
+ }
+
+ private void setAcl(final boolean isAdd, @Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress acl,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext());
+
+ LOG.debug("Setting ACL(isAdd={}) on interface={}(id={}): {}", isAdd, ifName, ifIndex, acl);
+
+ inputAclSetInterface(getFutureJVpp(), isAdd, id, acl, ifIndex, classifyTableContext,
+ writeContext.getMappingContext());
+ LOG.debug("Successfully set ACL(isAdd={}) on interface={}(id={}): {}", isAdd, ifName, ifIndex, acl);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/AclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/AclWriter.java
new file mode 100644
index 000000000..da74f0a8d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/AclWriter.java
@@ -0,0 +1,73 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.AclBaseAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.L2Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
+import io.fd.vpp.jvpp.core.dto.InputAclSetInterfaceReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+
+interface AclWriter extends ByteDataTranslator, JvppReplyConsumer {
+
+ default void inputAclSetInterface(@Nonnull final FutureJVppCore futureJVppCore, final boolean isAdd,
+ @Nonnull final InstanceIdentifier<?> id, @Nonnull final AclBaseAttributes acl,
+ @Nonnegative final int ifIndex,
+ @Nonnull final VppClassifierContextManager classifyTableContext,
+ @Nonnull final MappingContext mappingContext) throws WriteFailedException {
+ final InputAclSetInterface request = new InputAclSetInterface();
+ request.isAdd = booleanToByte(isAdd);
+ request.swIfIndex = ifIndex;
+ request.l2TableIndex = ~0; // skip
+ request.ip4TableIndex = ~0; // skip
+ request.ip6TableIndex = ~0; // skip
+
+ final L2Acl l2Acl = acl.getL2Acl();
+ if (l2Acl != null) {
+ final String tableName = checkNotNull(l2Acl.getClassifyTable(), "L2 classify table is null");
+ request.l2TableIndex = classifyTableContext.getTableIndex(tableName, mappingContext);
+ }
+ final Ip4Acl ip4Acl = acl.getIp4Acl();
+ if (ip4Acl != null) {
+ final String tableName = checkNotNull(ip4Acl.getClassifyTable(), "IPv4 classify table is null");
+ request.ip4TableIndex = classifyTableContext.getTableIndex(tableName, mappingContext);
+ }
+ final Ip6Acl ip6Acl = acl.getIp6Acl();
+ if (ip6Acl != null) {
+ final String tableName = checkNotNull(ip6Acl.getClassifyTable(), "IPv6 classify table is null");
+ request.ip6TableIndex = classifyTableContext.getTableIndex(tableName, mappingContext);
+ }
+
+ final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage =
+ futureJVppCore.inputAclSetInterface(request);
+
+ getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/IetfAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/IetfAclCustomizer.java
new file mode 100644
index 000000000..e4003fc9d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/IetfAclCustomizer.java
@@ -0,0 +1,89 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ietf.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for enabling/disabling ingress ACLs for given interface (as defined in ietf-acl model).
+ *
+ * The customizer assumes it owns classify table management for interfaces where ietf-acl container is present. Using
+ * low level classifier model or direct changes to classify tables in combination with ietf-acls are not supported and
+ * can result in unpredictable behaviour.
+ */
+public class IetfAclCustomizer implements WriterCustomizer<Ingress> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(IetfAclCustomizer.class);
+ private final IngressIetfAclWriter aclWriter;
+ private final NamingContext interfaceContext;
+
+ public IetfAclCustomizer(@Nonnull final IngressIetfAclWriter aclWriter,
+ @Nonnull final NamingContext interfaceContext) {
+ this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null");
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext());
+ LOG.debug("Adding ACLs for interface={}(id={}): {}", ifName, ifIndex, dataAfter);
+
+ final AccessLists accessLists = dataAfter.getAccessLists();
+ checkArgument(accessLists != null && accessLists.getAcl() != null,
+ "ietf-acl container does not define acl list");
+
+ aclWriter.write(id, ifIndex, accessLists.getAcl(), accessLists.getDefaultAction(), accessLists.getMode(),
+ writeContext, writeContext.getMappingContext());
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore, @Nonnull final Ingress dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("ACLs update: removing previously configured ACLs");
+ deleteCurrentAttributes(id, dataBefore, writeContext);
+ LOG.debug("ACLs update: adding updated ACLs");
+ writeCurrentAttributes(id, dataAfter, writeContext);
+ LOG.debug("ACLs update was successful");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifName = id.firstKeyOf(Interface.class).getName();
+ final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext());
+ LOG.debug("Removing ACLs for interface={}(id={}): {}", ifName, ifIndex, dataBefore);
+ aclWriter.deleteAcl(id, ifIndex, writeContext.getMappingContext());
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/IngressIetfAclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/IngressIetfAclWriter.java
new file mode 100644
index 000000000..022d21861
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/IngressIetfAclWriter.java
@@ -0,0 +1,118 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.v3po.interfaces.acl.common.AbstractIetfAclWriter;
+import io.fd.hc2vpp.v3po.interfaces.acl.common.AclTableContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
+import io.fd.vpp.jvpp.core.dto.InputAclSetInterfaceReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class IngressIetfAclWriter extends AbstractIetfAclWriter {
+ private final AclTableContextManager aclCtx;
+
+ public IngressIetfAclWriter(@Nonnull final FutureJVppCore futureJVppCore, @Nonnull AclTableContextManager aclCtx) {
+ super(futureJVppCore);
+ this.aclCtx = checkNotNull(aclCtx, "aclCtx should not be null");
+ }
+
+ @Override
+ public void deleteAcl(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex,
+ @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException {
+ Optional<MappingEntry> optional = aclCtx.getEntry(swIfIndex, mappingContext);
+ checkState(optional.isPresent(), "Removing ACL id=%s, but acl mapping entry is not present", id);
+ final MappingEntry entry = optional.get();
+ unassignClassifyTables(id, entry);
+ removeClassifyTables(id, entry);
+ aclCtx.removeEntry(swIfIndex, mappingContext);
+ }
+
+ private void unassignClassifyTables(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final MappingEntry entry)
+ throws WriteFailedException {
+ final InputAclSetInterface request = new InputAclSetInterface();
+ request.isAdd = 0;
+ request.swIfIndex = entry.getIndex();
+ request.l2TableIndex = entry.getL2TableId();
+ request.ip4TableIndex = entry.getIp4TableId();
+ request.ip6TableIndex = entry.getIp6TableId();
+ final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage =
+ jvpp.inputAclSetInterface(request);
+ getReplyForDelete(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id);
+ }
+
+ @Override
+ public void write(@Nonnull final InstanceIdentifier<?> id, int swIfIndex, @Nonnull final List<Acl> acls,
+ @Nonnull final AccessLists.DefaultAction defaultAction, @Nullable final InterfaceMode mode,
+ @Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags,
+ @Nonnull final MappingContext mappingContext)
+ throws WriteFailedException {
+ checkArgument(numberOfTags >= 0 && numberOfTags <= 2, "Number of vlan tags %s is not in [0,2] range");
+
+ final InputAclSetInterface request = new InputAclSetInterface();
+ request.isAdd = 1;
+ request.swIfIndex = swIfIndex;
+ request.l2TableIndex = NOT_DEFINED;
+ request.ip4TableIndex = NOT_DEFINED;
+ request.ip6TableIndex = NOT_DEFINED;
+
+ if (InterfaceMode.L2.equals(mode)) {
+ final List<Ace> aces = getACEs(acls, writeContext, ace -> true);
+ request.l2TableIndex = writeAces(id, aces, defaultAction, mode, numberOfTags);
+ } else {
+ final List<Ace> ip4Aces = getACEs(acls, writeContext, (AbstractIetfAclWriter::appliesToIp4Path));
+ request.ip4TableIndex = writeAces(id, ip4Aces, defaultAction, mode, numberOfTags);
+ final List<Ace> ip6Aces = getACEs(acls, writeContext, (AbstractIetfAclWriter::appliesToIp6Path));
+ request.ip6TableIndex = writeAces(id, ip6Aces, defaultAction, mode, numberOfTags);
+ }
+
+ final MappingEntry entry = new MappingEntryBuilder().setIndex(swIfIndex)
+ .setIp4TableId(request.ip4TableIndex)
+ .setIp6TableId(request.ip6TableIndex)
+ .setL2TableId(request.l2TableIndex)
+ .build();
+ aclCtx.addEntry(entry, mappingContext);
+
+ try {
+ getReplyForWrite(jvpp.inputAclSetInterface(request).toCompletableFuture(), id);
+ } catch (WriteFailedException e) {
+ removeClassifyTables(id, entry);
+ throw e;
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/SubInterfaceAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/SubInterfaceAclCustomizer.java
new file mode 100644
index 000000000..b0be5d71f
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/SubInterfaceAclCustomizer.java
@@ -0,0 +1,93 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+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.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.acl.Ingress;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for enabling/disabling ingress ACLs on given sub-interface.
+ */
+public class SubInterfaceAclCustomizer extends FutureJVppCustomizer
+ implements WriterCustomizer<Ingress>, AclWriter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final VppClassifierContextManager classifyTableContext;
+
+ public SubInterfaceAclCustomizer(@Nonnull final FutureJVppCore vppApi,
+ @Nonnull final NamingContext interfaceContext,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(vppApi);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ setAcl(true, id, dataAfter, writeContext);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore,
+ @Nonnull final Ingress dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ throw new UnsupportedOperationException("Acl update is not supported. Please delete Acl container first.");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ setAcl(false, id, dataBefore, writeContext);
+ }
+
+ private void setAcl(final boolean isAdd, @Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress acl,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ final String subInterfaceName = SubInterfaceUtils
+ .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+
+ LOG.debug("Setting ACL(isAdd={}) on sub-interface={}(id={}): {}",
+ isAdd, subInterfaceName, subInterfaceIndex, acl);
+ inputAclSetInterface(getFutureJVpp(), isAdd, id, acl, subInterfaceIndex, classifyTableContext,
+ writeContext.getMappingContext());
+ LOG.debug("Successfully set ACL(isAdd={}) on sub-interface={}(id={}): {}",
+ isAdd, subInterfaceName, subInterfaceIndex, acl);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizer.java
new file mode 100644
index 000000000..4f24906a1
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizer.java
@@ -0,0 +1,108 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.getNumberOfTags;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+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.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.ietf.acl.Ingress;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for enabling/disabling ingress ACLs for given sub-interface (as defined in ietf-acl model).
+ *
+ * The customizer assumes it owns classify table management for sub-interfaces where ietf-acl container is present.
+ * Using low level classifier model or direct changes to classify tables in combination with ietf-acls are not supported
+ * and can result in unpredictable behaviour.
+ */
+public class SubInterfaceIetfAclCustomizer implements WriterCustomizer<Ingress> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIetfAclCustomizer.class);
+ private final IngressIetfAclWriter aclWriter;
+ private final NamingContext interfaceContext;
+
+ public SubInterfaceIetfAclCustomizer(@Nonnull final IngressIetfAclWriter aclWriter,
+ @Nonnull final NamingContext interfaceContext) {
+ this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null");
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ private String getSubInterfaceName(@Nonnull final InstanceIdentifier<Ingress> id) {
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ return SubInterfaceUtils
+ .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ LOG.debug("Adding IETF-ACL for sub-interface: {}(id={}): {}", subInterfaceName, subInterfaceIndex, dataAfter);
+
+ final AccessLists accessLists = dataAfter.getAccessLists();
+ checkArgument(accessLists != null && accessLists.getAcl() != null,
+ "ietf-acl container does not define acl list");
+
+ final Optional<SubInterface> subInterfaceOptional =
+ writeContext.readAfter(id.firstIdentifierOf(SubInterface.class));
+ checkState(subInterfaceOptional.isPresent(), "Could not read SubInterface data object for %s", id);
+ final SubInterface subInterface = subInterfaceOptional.get();
+
+ aclWriter
+ .write(id, subInterfaceIndex, accessLists.getAcl(), accessLists.getDefaultAction(), accessLists.getMode(),
+ writeContext, getNumberOfTags(subInterface.getTags()), writeContext.getMappingContext());
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore, @Nonnull final Ingress dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Sub-interface ACLs update: removing previously configured ACLs");
+ deleteCurrentAttributes(id, dataBefore, writeContext);
+ LOG.debug("Sub-interface ACLs update: adding updated ACLs");
+ writeCurrentAttributes(id, dataAfter, writeContext);
+ LOG.debug("Sub-interface ACLs update was successful");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress dataBefore, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext());
+ LOG.debug("Removing ACLs for sub-interface={}(id={}): {}", subInterfaceName, subInterfaceIndex, dataBefore);
+ aclWriter.deleteAcl(id, subInterfaceIndex, writeContext.getMappingContext());
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4AddressCustomizer.java
new file mode 100644
index 000000000..6a6bb6c35
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4AddressCustomizer.java
@@ -0,0 +1,151 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.v3po.interfaces.ip.subnet.validation.SubnetValidationException;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.v3po.interfaces.ip.subnet.validation.SubnetValidator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+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.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for writing {@link Address}
+ */
+public class Ipv4AddressCustomizer extends FutureJVppCustomizer
+ implements ListWriterCustomizer<Address, AddressKey>, Ipv4Writer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final SubnetValidator subnetValidator;
+
+ Ipv4AddressCustomizer(@Nonnull final FutureJVppCore futureJVppCore, @Nonnull final NamingContext interfaceContext,
+ @Nonnull final SubnetValidator subnetValidator) {
+ super(futureJVppCore);
+ this.interfaceContext = checkNotNull(interfaceContext, "Interface context cannot be null");
+ this.subnetValidator = checkNotNull(subnetValidator, "Subnet validator cannot be null");
+ }
+
+ public Ipv4AddressCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext interfaceContext) {
+ this(futureJVppCore, interfaceContext, new SubnetValidator());
+ }
+
+ @Override
+ public void writeCurrentAttributes(InstanceIdentifier<Address> id, Address dataAfter, WriteContext writeContext)
+ throws WriteFailedException {
+
+ final String interfaceName = id.firstKeyOf(Interface.class).getName();
+ final int interfaceIndex = interfaceContext.getIndex(interfaceName, writeContext.getMappingContext());
+
+ // checks whether address is not from same subnet of some address already defined on this interface
+ try {
+
+ final InstanceIdentifier<Ipv4> parentId = RWUtils.cutId(id, InstanceIdentifier.create(Ipv4.class));
+ final Optional<Ipv4> ipv4Optional = writeContext.readAfter(parentId);
+
+ //no need to check isPresent() - we are inside of address customizer, therefore there must be Address data
+ //that is being processed by infrastructure
+
+ subnetValidator.checkNotAddingToSameSubnet(ipv4Optional.get().getAddress());
+ } catch (SubnetValidationException e) {
+ throw new WriteFailedException(id, e);
+ }
+
+ setAddress(true, id, interfaceName, interfaceIndex, 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 {
+
+ final String interfaceName = id.firstKeyOf(Interface.class).getName();
+ final int interfaceIndex = interfaceContext.getIndex(interfaceName, writeContext.getMappingContext());
+
+ setAddress(false, id, interfaceName, interfaceIndex, dataBefore, writeContext);
+ }
+
+ private void setAddress(boolean add, final InstanceIdentifier<Address> id, final String interfaceName,
+ final int interfaceIndex, final Address address,
+ final WriteContext writeContext) throws WriteFailedException {
+
+ 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 {
+ 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 {
+
+ 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);
+ }
+
+ 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 {
+ 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);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4Customizer.java
new file mode 100644
index 000000000..ff86331b1
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4Customizer.java
@@ -0,0 +1,56 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.ip;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Ipv4Customizer extends FutureJVppCustomizer implements WriterCustomizer<Ipv4> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4Customizer.class);
+
+ public Ipv4Customizer(final FutureJVppCore vppApi) {
+ super(vppApi);
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id,
+ @Nonnull final Ipv4 dataAfter, @Nonnull final WriteContext writeContext) {
+ LOG.debug("Handling Ipv4 leaves (mtu, forwarding) is not supported by VPP API. Ignoring configuration");
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id,
+ @Nonnull final Ipv4 dataBefore, @Nonnull final Ipv4 dataAfter,
+ @Nonnull final WriteContext writeContext) {
+ LOG.debug("Handling Ipv4 leaves (mtu, forwarding) is not supported by VPP API. Ignoring configuration");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id,
+ @Nonnull final Ipv4 dataBefore, @Nonnull final WriteContext writeContext) {
+ LOG.debug("Handling Ipv4 leaves (mtu, forwarding) is not supported by VPP API. Ignoring configuration");
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java
new file mode 100644
index 000000000..1a1c2d2c0
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java
@@ -0,0 +1,126 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.ip;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.AddressTranslator;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.IpNeighborAddDel;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+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.Neighbor;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.NeighborKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Customizer for writing {@link Neighbor} for {@link Ipv4}.
+ */
+public class Ipv4NeighbourCustomizer extends FutureJVppCustomizer
+ implements ListWriterCustomizer<Neighbor, NeighborKey>, ByteDataTranslator, AddressTranslator,
+ JvppReplyConsumer {
+
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4NeighbourCustomizer.class);
+ final NamingContext interfaceContext;
+
+ public Ipv4NeighbourCustomizer(final FutureJVppCore futureJVppCore, final NamingContext interfaceContext) {
+ super(futureJVppCore);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull InstanceIdentifier<Neighbor> id, @Nonnull Neighbor dataAfter,
+ @Nonnull WriteContext writeContext)
+ throws WriteFailedException {
+
+ checkNotNull(dataAfter, "Cannot write null neighbour");
+ checkArgument(id.firstKeyOf(Interface.class) != null, "No parent interface key found");
+
+ LOG.debug("Processing request for Neigbour write");
+ String interfaceName = id.firstKeyOf(Interface.class).getName();
+ MappingContext mappingContext = writeContext.getMappingContext();
+
+ checkState(interfaceContext.containsIndex(interfaceName, mappingContext),
+ "Mapping does not contains mapping for provider interface name ".concat(interfaceName));
+
+ LOG.debug("Parent interface index found");
+ addDelNeighbourAndReply(id, true,
+ interfaceContext.getIndex(interfaceName, mappingContext), dataAfter);
+ LOG.info("Neighbour successfully written");
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull InstanceIdentifier<Neighbor> id, @Nonnull Neighbor dataBefore,
+ @Nonnull Neighbor dataAfter,
+ @Nonnull WriteContext writeContext) throws WriteFailedException {
+ throw new UnsupportedOperationException("Operation not supported");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull InstanceIdentifier<Neighbor> id, @Nonnull Neighbor dataBefore,
+ @Nonnull WriteContext writeContext)
+ throws WriteFailedException {
+
+ checkNotNull(dataBefore, "Cannot delete null neighbour");
+ checkArgument(id.firstKeyOf(Interface.class) != null, "No parent interface key found");
+
+ LOG.debug("Processing request for Neigbour delete");
+ String interfaceName = id.firstKeyOf(Interface.class).getName();
+ MappingContext mappingContext = writeContext.getMappingContext();
+
+ checkState(interfaceContext.containsIndex(interfaceName, mappingContext),
+ "Mapping does not contains mapping for provider interface name %s", interfaceName);
+
+ LOG.debug("Parent interface[{}] index found", interfaceName);
+
+ addDelNeighbourAndReply(id, false,
+ interfaceContext.getIndex(interfaceName, mappingContext), dataBefore);
+ LOG.info("Neighbour {} successfully deleted", id);
+ }
+
+ private void addDelNeighbourAndReply(InstanceIdentifier<Neighbor> id, boolean add, int parentInterfaceIndex,
+ Neighbor data) throws WriteFailedException {
+
+ IpNeighborAddDel request = new IpNeighborAddDel();
+
+ request.isAdd = booleanToByte(add);
+ request.isIpv6 = 0;
+ request.isStatic = 1;
+ request.dstAddress = ipv4AddressNoZoneToArray(data.getIp());
+ request.macAddress = parseMac(data.getLinkLayerAddress().getValue());
+ request.swIfIndex = parentInterfaceIndex;
+
+ //TODO HONEYCOMB-182 if it is necessary for future use ,make adjustments to be able to set vrfid
+ //request.vrfId
+ getReplyForWrite(getFutureJVpp().ipNeighborAddDel(request).toCompletableFuture(), id);
+ }
+} \ No newline at end of file
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4Writer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4Writer.java
new file mode 100644
index 000000000..36e1800e1
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv4Writer.java
@@ -0,0 +1,108 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.ip;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.Ipv4Translator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceAddDelAddress;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceAddDelAddressReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+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;
+
+/**
+ * Utility class providing Ipv4 CUD support.
+ */
+public interface Ipv4Writer extends ByteDataTranslator, Ipv4Translator, JvppReplyConsumer {
+
+ int DOTTED_QUAD_MASK_LENGTH = 4;
+ int IPV4_ADDRESS_PART_BITS_COUNT = 8;
+ int NETMASK_PART_LIMIT = 256; // 2 power to 8
+
+ default void addDelAddress(@Nonnull final FutureJVppCore futureJVppCore, final boolean add,
+ final InstanceIdentifier<?> id,
+ @Nonnegative final int ifaceId,
+ @Nonnull final Ipv4AddressNoZone address, @Nonnegative final byte prefixLength)
+ throws WriteFailedException {
+ checkArgument(prefixLength > 0, "Invalid prefix length");
+ checkNotNull(address, "address should not be null");
+
+ final byte[] addressBytes = ipv4AddressNoZoneToArray(address);
+
+ final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage =
+ futureJVppCore.swInterfaceAddDelAddress(
+ getSwInterfaceAddDelAddressRequest(ifaceId, booleanToByte(add) /* isAdd */,
+ (byte) 0 /* isIpv6 */, (byte) 0 /* delAll */, prefixLength, addressBytes));
+
+ getReplyForWrite(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture(), id);
+ }
+
+ default 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
+ */
+ default 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/hc2vpp/v3po/interfaces/ip/Ipv6Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv6Customizer.java
new file mode 100644
index 000000000..85f190d83
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/Ipv6Customizer.java
@@ -0,0 +1,55 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.ip;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv6;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Ipv6Customizer extends FutureJVppCustomizer implements WriterCustomizer<Ipv6> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv6Customizer.class);
+
+ public Ipv6Customizer(final FutureJVppCore vppApi) {
+ super(vppApi);
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv6> id,
+ @Nonnull final Ipv6 dataAfter, @Nonnull final WriteContext writeContext) {
+ LOG.warn("Unsupported, ignoring configuration {}", dataAfter);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv6> id,
+ @Nonnull final Ipv6 dataBefore, @Nonnull final Ipv6 dataAfter,
+ @Nonnull final WriteContext writeContext) {
+ LOG.warn("Unsupported, ignoring configuration {}", dataAfter);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv6> id,
+ @Nonnull final Ipv6 dataBefore, @Nonnull final WriteContext writeContext) {
+ LOG.warn("Unsupported, ignoring configuration delete {}", id);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java
new file mode 100644
index 000000000..214ff36c4
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java
@@ -0,0 +1,131 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+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.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.ipv4.AddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.ipv4.address.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.ipv4.address.subnet.Netmask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLength;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Write customizer for sub-interface {@link Address}
+ */
+public class SubInterfaceIpv4AddressCustomizer extends FutureJVppCustomizer
+ implements ListWriterCustomizer<Address, AddressKey>, Ipv4Writer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIpv4AddressCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public SubInterfaceIpv4AddressCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJVppCore);
+ 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);
+ }
+
+ 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 {
+ 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 {
+
+ 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);
+ }
+
+ 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 {
+ 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);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/subnet/validation/SubnetValidationException.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/subnet/validation/SubnetValidationException.java
new file mode 100644
index 000000000..001923093
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/subnet/validation/SubnetValidationException.java
@@ -0,0 +1,50 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.ip.subnet.validation;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.apache.commons.lang3.StringUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address;
+
+/**
+ * Thrown as negative result of subnet validation
+ */
+public class SubnetValidationException extends Exception {
+
+ private SubnetValidationException(@Nonnull final String message) {
+ super(message);
+ }
+
+ public static SubnetValidationException forConflictingData(@Nonnull final Short prefix, @Nonnull Collection<Address> addresses) {
+ return new SubnetValidationException(
+ "Attempt to define multiple addresses for same subnet[prefixLen = " + prefixToString(prefix) + "], "
+ + "addresses : " + addressesToString(addresses));
+ }
+
+ private static String prefixToString(final Short prefix) {
+ return checkNotNull(prefix, "Cannot create " + SubnetValidationException.class.getName() + " for null prefix")
+ .toString();
+ }
+
+ private static String addressesToString(final Collection<Address> addresses) {
+ return StringUtils.join(checkNotNull(addresses,
+ "Cannot create " + SubnetValidationException.class.getName() + " for null address list"), " | ");
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/subnet/validation/SubnetValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/subnet/validation/SubnetValidator.java
new file mode 100644
index 000000000..c5b011e07
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/ip/subnet/validation/SubnetValidator.java
@@ -0,0 +1,80 @@
+/*
+ * 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.hc2vpp.v3po.interfaces.ip.subnet.validation;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import io.fd.hc2vpp.v3po.interfaces.ip.Ipv4Writer;
+import java.util.List;
+import javax.annotation.Nonnull;
+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.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;
+
+/**
+ * Validator for detecting if there is an attempt to assign multiple addresses from same subnet
+ */
+public class SubnetValidator implements Ipv4Writer {
+
+ /**
+ * Checks whether data provided for writing are not in collision with already existing data
+ */
+ public void checkNotAddingToSameSubnet(@Nonnull final List<Address> addresses)
+ throws SubnetValidationException {
+
+ final Multimap<Short, Address> prefixLengthRegister = Multimaps.index(addresses, toPrefixLength());
+ final int keySetSize = prefixLengthRegister.keySet().size();
+
+ if (keySetSize == 0 || keySetSize == addresses.size()) {
+ //this means that every key is unique(has only one value) or no addresses were prefix-length based ,so there is no conflict
+ return;
+ }
+
+ //finds conflicting prefix
+ final Short conflictingPrefix = prefixLengthRegister.keySet()
+ .stream()
+ .filter(a -> prefixLengthRegister.get(a).size() > 1)
+ .findFirst()
+ .get();
+
+ //and reports it with affected addresses
+ throw SubnetValidationException
+ .forConflictingData(conflictingPrefix, prefixLengthRegister.get(conflictingPrefix));
+ }
+
+ private Function<Address, Short> toPrefixLength() {
+ return (final Address address) -> {
+ final Subnet subnet = address.getSubnet();
+
+ if (subnet instanceof PrefixLength) {
+ return ((PrefixLength) subnet).getPrefixLength();
+ }
+
+ if (address.getSubnet() instanceof Netmask) {
+ return (short) getSubnetMaskLength(
+ checkNotNull(((Netmask) subnet).getNetmask(), "No netmask defined for %s", subnet)
+ .getValue());
+ }
+
+ throw new IllegalArgumentException("Unsupported subnet : " + subnet);
+ };
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/pbb/PbbRewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/pbb/PbbRewriteCustomizer.java
new file mode 100644
index 000000000..3e8d82399
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfaces/pbb/PbbRewriteCustomizer.java
@@ -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.hc2vpp.v3po.interfaces.pbb;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.MacTranslator;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.VppBaseCallException;
+import io.fd.vpp.jvpp.core.dto.L2InterfacePbbTagRewrite;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.TimeoutException;
+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.opendaylight.params.xml.ns.yang.vpp.pbb.rev161214.interfaces._interface.PbbRewrite;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class PbbRewriteCustomizer extends FutureJVppCustomizer
+ implements WriterCustomizer<PbbRewrite>, MacTranslator, JvppReplyConsumer {
+
+ private static final int OPERATION_DISABLE = 0;
+
+ private final NamingContext interfaceNamingContext;
+
+ public PbbRewriteCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext interfaceNamingContext) {
+ super(futureJVppCore);
+ this.interfaceNamingContext = checkNotNull(interfaceNamingContext, "Interface naming context cannot be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<PbbRewrite> id,
+ @Nonnull final PbbRewrite dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ try {
+ setPbbRewrite(id, dataAfter, writeContext, false);
+ } catch (TimeoutException | VppBaseCallException e) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<PbbRewrite> id,
+ @Nonnull final PbbRewrite dataBefore, @Nonnull final PbbRewrite dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ try {
+ setPbbRewrite(id, dataAfter, writeContext, false);
+ } catch (TimeoutException | VppBaseCallException e) {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<PbbRewrite> id,
+ @Nonnull final PbbRewrite dataBefore, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ try {
+ setPbbRewrite(id, dataBefore, writeContext, true);
+ } catch (TimeoutException | VppBaseCallException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void setPbbRewrite(final InstanceIdentifier<PbbRewrite> id, final PbbRewrite data,
+ final WriteContext writeContext, final boolean disable)
+ throws TimeoutException, VppBaseCallException {
+ final String interfaceName = checkNotNull(id.firstKeyOf(Interface.class), "Interface key not found").getName();
+
+ final L2InterfacePbbTagRewrite request = new L2InterfacePbbTagRewrite();
+
+ //checking all attributes in preconditions(pbb-rewrite is subcontainer, so there can't be mandatory statements)
+ request.swIfIndex = interfaceNamingContext.getIndex(interfaceName, writeContext.getMappingContext());
+ request.bDmac = parseMac(verifiedDestinationAddress(data));
+ request.bSmac = parseMac(verifiedSourceAddress(data));
+ request.bVlanid = verifiedBVlanId(data);
+ request.iSid = verifiedISid(data);
+ request.vtrOp = verifiedOperation(data, disable);
+
+ //not sure whats gonna happen to this attribute, so its left optional for now
+ if (data.getOuterTag() != null) {
+ request.outerTag = data.getOuterTag().shortValue();
+ }
+
+ getReply(getFutureJVpp().l2InterfacePbbTagRewrite(request).toCompletableFuture());
+ }
+
+ private String verifiedDestinationAddress(final PbbRewrite data) {
+ return checkNotNull(data.getDestinationAddress(), "Destination address cannot be null").getValue();
+ }
+
+ private String verifiedSourceAddress(final PbbRewrite data) {
+ return checkNotNull(data.getSourceAddress(), "Destination address cannot be null").getValue();
+ }
+
+ private byte verifiedBVlanId(final PbbRewrite data) {
+ return (byte) checkNotNull(data.getBVlanTagVlanId(), "BVlan id cannot be null").shortValue();
+ }
+
+ private int verifiedISid(final PbbRewrite data) {
+ return checkNotNull(data.getITagIsid(), "ISid cannot be null").intValue();
+ }
+
+ // if disabled ,then uses non-public allowed value 0, which is equal to operation disable
+ private int verifiedOperation(final PbbRewrite data, final boolean disable) {
+
+ return disable
+ ? OPERATION_DISABLE
+ : checkNotNull(data.getInterfaceOperation(), "Operation cannot be null").getIntValue();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/EthernetCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/EthernetCustomizer.java
new file mode 100644
index 000000000..33b71b1e4
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/EthernetCustomizer.java
@@ -0,0 +1,108 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDetails;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Ethernet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.EthernetBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class EthernetCustomizer extends FutureJVppCustomizer
+ implements InitializingReaderCustomizer<Ethernet, EthernetBuilder>, InterfaceDataTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(EthernetCustomizer.class);
+ private NamingContext interfaceContext;
+
+ public EthernetCustomizer(@Nonnull final FutureJVppCore jvpp,
+ @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder,
+ @Nonnull final Ethernet readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setEthernet(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public EthernetBuilder getBuilder(@Nonnull InstanceIdentifier<Ethernet> id) {
+ return new EthernetBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Ethernet> id,
+ @Nonnull final EthernetBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final SwInterfaceDetails iface = getVppInterfaceDetails(getFutureJVpp(), id, key.getName(),
+ interfaceContext.getIndex(key.getName(), ctx.getMappingContext()), ctx.getModificationCache(), LOG);
+
+ if (iface.linkMtu != 0) {
+ builder.setMtu((int) iface.linkMtu);
+ }
+
+ switch (iface.linkDuplex) {
+ case 1:
+ builder.setDuplex(Ethernet.Duplex.Half);
+ break;
+ case 2:
+ builder.setDuplex(Ethernet.Duplex.Full);
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Ethernet> init(
+ @Nonnull final InstanceIdentifier<Ethernet> id,
+ @Nonnull final Ethernet readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.EthernetBuilder()
+ .setMtu(readValue.getMtu())
+ .build());
+ }
+
+ private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Ethernet> getCfgId(
+ final InstanceIdentifier<Ethernet> id) {
+ return InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class))
+ .augmentation(VppInterfaceAugmentation.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Ethernet.class);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/GreCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/GreCustomizer.java
new file mode 100644
index 000000000..b31ab74d5
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/GreCustomizer.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016 Intel 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.hc2vpp.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.GreTunnelDetails;
+import io.fd.vpp.jvpp.core.dto.GreTunnelDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.GreTunnelDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.GreTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Gre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.GreBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GreCustomizer extends FutureJVppCustomizer
+ implements InitializingReaderCustomizer<Gre, GreBuilder>, InterfaceDataTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(GreCustomizer.class);
+ private NamingContext interfaceContext;
+
+ public GreCustomizer(@Nonnull final FutureJVppCore jvpp, @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> parentBuilder,
+ @Nonnull Gre readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setGre(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public GreBuilder getBuilder(@Nonnull InstanceIdentifier<Gre> id) {
+ return new GreBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Gre> id,
+ @Nonnull final GreBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+ if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, GreTunnel.class, LOG)) {
+ return;
+ }
+
+ LOG.debug("Reading attributes for gre tunnel: {}", key.getName());
+ // Dump just a single
+ final GreTunnelDump request = new GreTunnelDump();
+ request.swIfIndex = index;
+
+ final CompletionStage<GreTunnelDetailsReplyDump> swInterfaceGreDetailsReplyDumpCompletionStage =
+ getFutureJVpp().greTunnelDump(request);
+ final GreTunnelDetailsReplyDump reply =
+ getReplyForRead(swInterfaceGreDetailsReplyDumpCompletionStage.toCompletableFuture(), id);
+
+ // VPP keeps gre tunnel interfaces even after they were deleted (optimization)
+ // However there ar no longer any gre tunnel specific fields assigned to it and this call
+ // returns nothing
+ if (reply == null || reply.greTunnelDetails == null || reply.greTunnelDetails.isEmpty()) {
+ LOG.debug(
+ "Gre tunnel {}, id {} has no attributes assigned in VPP. Probably is a leftover interface placeholder" +
+ "after delete", key.getName(), index);
+ return;
+ }
+
+ checkState(reply.greTunnelDetails.size() == 1,
+ "Unexpected number of returned gre tunnels: {} for tunnel: {}", reply.greTunnelDetails,
+ key.getName());
+ LOG.trace("Gre tunnel: {} attributes returned from VPP: {}", key.getName(), reply);
+
+ final GreTunnelDetails swInterfaceGreDetails = reply.greTunnelDetails.get(0);
+ if (swInterfaceGreDetails.isIpv6 == 1) {
+ final Ipv6Address dstIpv6 =
+ new Ipv6Address(parseAddress(swInterfaceGreDetails.dstAddress).getHostAddress());
+ builder.setDst(new IpAddress(dstIpv6));
+ final Ipv6Address srcIpv6 =
+ new Ipv6Address(parseAddress(swInterfaceGreDetails.srcAddress).getHostAddress());
+ builder.setSrc(new IpAddress(srcIpv6));
+ } else {
+ final byte[] dstBytes = Arrays.copyOfRange(swInterfaceGreDetails.dstAddress, 0, 4);
+ final Ipv4Address dstIpv4 = new Ipv4Address(parseAddress(dstBytes).getHostAddress());
+ builder.setDst(new IpAddress(dstIpv4));
+ final byte[] srcBytes = Arrays.copyOfRange(swInterfaceGreDetails.srcAddress, 0, 4);
+ final Ipv4Address srcIpv4 = new Ipv4Address(parseAddress(srcBytes).getHostAddress());
+ builder.setSrc(new IpAddress(srcIpv4));
+ }
+ builder.setOuterFibId((long) swInterfaceGreDetails.outerFibId);
+ LOG.debug("Gre tunnel: {}, id: {} attributes read as: {}", key.getName(), index, builder);
+ }
+
+ @Nonnull
+ private static InetAddress parseAddress(@Nonnull final byte[] addr) {
+ try {
+ return InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Cannot create InetAddress from " + Arrays.toString(addr), e);
+ }
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Gre> init(
+ @Nonnull final InstanceIdentifier<Gre> id, @Nonnull final Gre readValue, @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.GreBuilder()
+ .setDst(readValue.getDst())
+ .setSrc(readValue.getSrc())
+ .setOuterFibId(readValue.getOuterFibId())
+ .build());
+ }
+
+ private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Gre> getCfgId(
+ final InstanceIdentifier<Gre> id) {
+ return InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class))
+ .augmentation(VppInterfaceAugmentation.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Gre.class);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterconnectionReadUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterconnectionReadUtils.java
new file mode 100644
index 000000000..3893d37a1
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterconnectionReadUtils.java
@@ -0,0 +1,125 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.BridgeDomainDetails;
+import io.fd.vpp.jvpp.core.dto.BridgeDomainDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.BridgeDomainDump;
+import io.fd.vpp.jvpp.core.dto.BridgeDomainSwIfDetails;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDetails;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.base.attributes.Interconnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.base.attributes.interconnection.BridgeBasedBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class providing Interconnection read support.
+ */
+final class InterconnectionReadUtils implements InterfaceDataTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterconnectionReadUtils.class);
+
+ private final FutureJVppCore futureJVppCore;
+ private final NamingContext interfaceContext;
+ private final NamingContext bridgeDomainContext;
+
+ InterconnectionReadUtils(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext interfaceContext,
+ @Nonnull final NamingContext bridgeDomainContext) {
+ this.futureJVppCore = requireNonNull(futureJVppCore, "futureJVppCore should not be null");
+ this.interfaceContext = requireNonNull(interfaceContext, "interfaceContext should not be null");
+ this.bridgeDomainContext = requireNonNull(bridgeDomainContext, "bridgeDomainContext should not be null");
+ }
+
+ @Nullable
+ Interconnection readInterconnection(@Nonnull final InstanceIdentifier<?> id, @Nonnull final String ifaceName,
+ @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ final int ifaceId = interfaceContext.getIndex(ifaceName, ctx.getMappingContext());
+
+ final SwInterfaceDetails iface = getVppInterfaceDetails(futureJVppCore, id, ifaceName,
+ ifaceId, ctx.getModificationCache(), LOG);
+ LOG.debug("Interface details for interface: {}, details: {}", ifaceName, iface);
+
+ final BridgeDomainDetailsReplyDump dumpReply = getDumpReply(id);
+ final Optional<BridgeDomainSwIfDetails> bdForInterface = getBridgeDomainForInterface(ifaceId, dumpReply);
+ if (bdForInterface.isPresent()) {
+ final BridgeDomainSwIfDetails bdSwIfDetails = bdForInterface.get();
+ final BridgeBasedBuilder bbBuilder = new BridgeBasedBuilder();
+ bbBuilder.setBridgeDomain(bridgeDomainContext.getName(bdSwIfDetails.bdId, ctx.getMappingContext()));
+
+ // Set BVI if the bridgeDomainDetails.bviSwIfIndex == current sw if index
+ final Optional<BridgeDomainDetails> bridgeDomainForInterface =
+ getBridgeDomainForInterface(dumpReply, bdForInterface.get().bdId);
+ // Since we already found an interface assigned to a bridge domain, the details for BD must be present
+ checkState(bridgeDomainForInterface.isPresent());
+ if (bridgeDomainForInterface.get().bviSwIfIndex == ifaceId) {
+ bbBuilder.setBridgedVirtualInterface(true);
+ } else {
+ bbBuilder.setBridgedVirtualInterface(false);
+ }
+
+ if (bdSwIfDetails.shg != 0) {
+ bbBuilder.setSplitHorizonGroup((short) bdSwIfDetails.shg);
+ }
+ return bbBuilder.build();
+ }
+ // TODO HONEYCOMB-190 is there a way to check if interconnection is XconnectBased?
+
+ return null;
+ }
+
+ private Optional<BridgeDomainSwIfDetails> getBridgeDomainForInterface(final int ifaceId,
+ final BridgeDomainDetailsReplyDump reply) {
+ if (null == reply || null == reply.bridgeDomainSwIfDetails || reply.bridgeDomainSwIfDetails.isEmpty()) {
+ return Optional.empty();
+ }
+ // interface can be added to only one BD only
+ return reply.bridgeDomainSwIfDetails.stream().filter(a -> a.swIfIndex == ifaceId).findFirst();
+ }
+
+ private Optional<BridgeDomainDetails> getBridgeDomainForInterface(final BridgeDomainDetailsReplyDump reply,
+ int bdId) {
+ return reply.bridgeDomainDetails.stream().filter(a -> a.bdId == bdId).findFirst();
+ }
+
+ private BridgeDomainDetailsReplyDump getDumpReply(@Nonnull final InstanceIdentifier<?> id)
+ throws ReadFailedException {
+ // We need to perform full bd dump, because there is no way
+ // to ask VPP for BD details given interface id/name (TODO HONEYCOMB-190 add it to vpp.api?)
+ // TODO HONEYCOMB-190 cache dump result
+ final BridgeDomainDump request = new BridgeDomainDump();
+ request.bdId = -1;
+
+ final CompletableFuture<BridgeDomainDetailsReplyDump> bdCompletableFuture =
+ futureJVppCore.bridgeDomainSwIfDump(request).toCompletableFuture();
+ return getReplyForRead(bdCompletableFuture, id);
+
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterfaceCustomizer.java
new file mode 100644
index 000000000..70bc0c62b
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterfaceCustomizer.java
@@ -0,0 +1,232 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import io.fd.hc2vpp.v3po.DisabledInterfacesManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingListReaderCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDetails;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading ietf-interfaces:interfaces-state/interface.
+ */
+public class InterfaceCustomizer extends FutureJVppCustomizer
+ implements InitializingListReaderCustomizer<Interface, InterfaceKey, InterfaceBuilder>, ByteDataTranslator,
+ InterfaceDataTranslator {
+
+ public static final String DUMPED_IFCS_CONTEXT_KEY =
+ InterfaceCustomizer.class.getName() + "dumpedInterfacesDuringGetAllIds";
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceCustomizer.class);
+ private final NamingContext interfaceNamingContext;
+ private final DisabledInterfacesManager interfaceDisableContext;
+
+ public InterfaceCustomizer(@Nonnull final FutureJVppCore jvpp,
+ @Nonnull final NamingContext interfaceNamingContext,
+ @Nonnull final DisabledInterfacesManager interfaceDisableContext) {
+ super(jvpp);
+ this.interfaceNamingContext = interfaceNamingContext;
+ this.interfaceDisableContext = interfaceDisableContext;
+ }
+
+ public static void cacheInterfaceDump(final @Nonnull ReadContext context, final SwInterfaceDetailsReplyDump ifaces) {
+ context.getModificationCache().put(DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream()
+ .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails)));
+ }
+
+ @Nonnull
+ @SuppressWarnings("unchecked")
+ public static Map<Integer, SwInterfaceDetails> getCachedInterfaceDump(@Nonnull final ModificationCache ctx) {
+ return ctx.get(DUMPED_IFCS_CONTEXT_KEY) == null
+ ? new HashMap<>()
+ // allow customizers to update the cache
+ : (Map<Integer, SwInterfaceDetails>) ctx.get(DUMPED_IFCS_CONTEXT_KEY);
+ }
+
+ private static boolean isRegularInterface(final SwInterfaceDetails iface) {
+ return iface.subId == 0;
+ }
+
+ @Nonnull
+ @Override
+ public InterfaceBuilder getBuilder(@Nonnull InstanceIdentifier<Interface> id) {
+ return new InterfaceBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull InstanceIdentifier<Interface> id, @Nonnull InterfaceBuilder builder,
+ @Nonnull ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading attributes for interface: {}", id);
+ final String ifaceName = id.firstKeyOf(id.getTargetType()).getName();
+
+ final int index = interfaceNamingContext.getIndex(ifaceName, ctx.getMappingContext());
+
+ // Ignore disabled interface (such as deleted VXLAN tunnels)
+ if (interfaceDisableContext.isInterfaceDisabled(index, ctx.getMappingContext())) {
+ LOG.debug("Skipping disabled interface: {}", id);
+ return;
+ }
+
+ // Pass cached details from getAllIds to getDetails to avoid additional dumps
+ final SwInterfaceDetails iface = getVppInterfaceDetails(getFutureJVpp(), id, ifaceName,
+ index, ctx.getModificationCache(), LOG);
+ LOG.debug("Interface details for interface: {}, details: {}", ifaceName, iface);
+
+ if (!isRegularInterface(iface)) {
+ LOG.debug("Interface: {} is a sub-interface. Ignoring read request.", ifaceName);
+ return;
+ }
+
+ builder.setName(ifaceName);
+ builder.setType(getInterfaceType(new String(iface.interfaceName).intern()));
+ builder.setIfIndex(vppIfIndexToYang(iface.swIfIndex));
+ builder.setAdminStatus(1 == iface.adminUpDown
+ ? AdminStatus.Up
+ : AdminStatus.Down);
+ builder.setOperStatus(1 == iface.linkUpDown
+ ? OperStatus.Up
+ : OperStatus.Down);
+ if (0 != iface.linkSpeed) {
+ builder.setSpeed(vppInterfaceSpeedToYang(iface.linkSpeed));
+ }
+ if (iface.l2AddressLength == 6) {
+ builder.setPhysAddress(new PhysAddress(vppPhysAddrToYang(iface.l2Address)));
+ }
+ LOG.trace("Base attributes read for interface: {} as: {}", ifaceName, builder);
+ }
+
+ @Nonnull
+ @Override
+ public List<InterfaceKey> getAllIds(@Nonnull final InstanceIdentifier<Interface> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ final List<InterfaceKey> interfacesKeys;
+ LOG.trace("Dumping all interfaces to get all IDs");
+
+ final SwInterfaceDump request = new SwInterfaceDump();
+ request.nameFilter = "".getBytes();
+ request.nameFilterValid = 0;
+
+ final CompletableFuture<SwInterfaceDetailsReplyDump> swInterfaceDetailsReplyDumpCompletableFuture =
+ getFutureJVpp().swInterfaceDump(request).toCompletableFuture();
+ final SwInterfaceDetailsReplyDump ifaces =
+ getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, id);
+
+ if (null == ifaces || null == ifaces.swInterfaceDetails) {
+ LOG.debug("No interfaces for :{} found in VPP", id);
+ return Collections.emptyList();
+ }
+
+ // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes
+ cacheInterfaceDump(context, ifaces);
+
+ final MappingContext mappingCtx = context.getMappingContext();
+ final Set<Integer> interfacesIdxs = ifaces.swInterfaceDetails.stream()
+ .filter(elt -> elt != null)
+ // Filter out disabled interfaces, dont read them
+ // This also prevents child readers in being invoked such as vxlan (which relies on disabling interfaces)
+ .filter(elt -> !interfaceDisableContext
+ .isInterfaceDisabled(elt.swIfIndex, mappingCtx))
+ .map((elt) -> {
+ // Store interface name from VPP in context if not yet present
+ if (!interfaceNamingContext.containsName(elt.swIfIndex, mappingCtx)) {
+ interfaceNamingContext.addName(elt.swIfIndex, toString(elt.interfaceName),
+ mappingCtx);
+ }
+ LOG.trace("Interface with name: {}, VPP name: {} and index: {} found in VPP",
+ interfaceNamingContext.getName(elt.swIfIndex, mappingCtx),
+ elt.interfaceName,
+ elt.swIfIndex);
+
+ return elt;
+ })
+ // filter out sub-interfaces
+ .filter(InterfaceCustomizer::isRegularInterface)
+ .map(elt -> elt.swIfIndex)
+ .collect(Collectors.toSet());
+
+ // Clean disabled interfaces list
+ interfaceDisableContext.getDisabledInterfaces(mappingCtx).stream()
+ // Find indices not currently in VPP
+ .filter(interfacesIdxs::contains)
+ // Remove from disabled list ... not disabled if not existing
+ .forEach(idx -> interfaceDisableContext.removeDisabledInterface(idx, mappingCtx));
+
+ // Transform indices to keys
+ interfacesKeys = interfacesIdxs.stream()
+ .map(index -> new InterfaceKey(interfaceNamingContext.getName(index, context.getMappingContext())))
+ .collect(Collectors.toList());
+
+ LOG.debug("Interfaces found in VPP: {}", interfacesKeys);
+ return interfacesKeys;
+ }
+
+ @Override
+ public void merge(@Nonnull final org.opendaylight.yangtools.concepts.Builder<? extends DataObject> builder,
+ @Nonnull final List<Interface> readData) {
+ ((InterfacesStateBuilder) builder).setInterface(readData);
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface> init(
+ @Nonnull final InstanceIdentifier<Interface> id, @Nonnull final Interface readValue, @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder()
+ .setName(readValue.getName())
+ .setType(readValue.getType())
+ .setEnabled(AdminStatus.Up.equals(readValue.getAdminStatus()))
+ // Not present in interfaces-state
+ // .setLinkUpDownTrapEnable()
+ .build());
+ }
+
+ public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface> getCfgId(
+ final InstanceIdentifier<Interface> id) {
+ return InstanceIdentifier.create(Interfaces.class).child(
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface.class,
+ new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey(
+ id.firstKeyOf(Interface.class).getName()));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterfaceDataTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterfaceDataTranslator.java
new file mode 100644
index 000000000..a0d292a4f
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/InterfaceDataTranslator.java
@@ -0,0 +1,287 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDetails;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.math.BigInteger;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.CompletionStage;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+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.yang.types.rev130715.Gauge64;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.GreTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.Loopback;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.Tap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VhostUser;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanGpeTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanTunnel;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+
+public interface InterfaceDataTranslator extends ByteDataTranslator, JvppReplyConsumer {
+
+ Gauge64 vppLinkSpeed0 = new Gauge64(BigInteger.ZERO);
+ Gauge64 vppLinkSpeed1 = new Gauge64(BigInteger.valueOf(10L * 1000000));
+ Gauge64 vppLinkSpeed2 = new Gauge64(BigInteger.valueOf(100L * 1000000));
+ Gauge64 vppLinkSpeed4 = new Gauge64(BigInteger.valueOf(1000L * 1000000));
+ Gauge64 vppLinkSpeed8 = new Gauge64(BigInteger.valueOf(10000L * 1000000));
+ Gauge64 vppLinkSpeed16 = new Gauge64(BigInteger.valueOf(40000L * 1000000));
+ Gauge64 vppLinkSpeed32 = new Gauge64(BigInteger.valueOf(100000L * 1000000));
+
+ char[] HEX_CHARS = "0123456789abcdef".toCharArray();
+
+ int PHYSICAL_ADDRESS_LENGTH = 6;
+
+ Collector<SwInterfaceDetails, ?, SwInterfaceDetails> SINGLE_ITEM_COLLECTOR =
+ RWUtils.singleItemCollector();
+
+ /**
+ * Convert VPP's link speed bitmask to Yang type. 1 = 10M, 2 = 100M, 4 = 1G, 8 = 10G, 16 = 40G, 32 = 100G
+ *
+ * @param vppLinkSpeed Link speed in bitmask format from VPP.
+ * @return Converted value from VPP link speed
+ */
+ default Gauge64 vppInterfaceSpeedToYang(byte vppLinkSpeed) {
+ switch (vppLinkSpeed) {
+ case 1:
+ return vppLinkSpeed1;
+ case 2:
+ return vppLinkSpeed2;
+ case 4:
+ return vppLinkSpeed4;
+ case 8:
+ return vppLinkSpeed8;
+ case 16:
+ return vppLinkSpeed16;
+ case 32:
+ return vppLinkSpeed32;
+ default:
+ return vppLinkSpeed0;
+ }
+ }
+
+ default void appendHexByte(final StringBuilder sb, final byte b) {
+ final int v = b & 0xFF;
+ sb.append(HEX_CHARS[v >>> 4]);
+ sb.append(HEX_CHARS[v & 15]);
+ }
+
+ /**
+ * Reads first 6 bytes of supplied byte array and converts to string as Yang dictates <p> Replace later with
+ * https://git.opendaylight.org/gerrit/#/c/34869/10/model/ietf/ietf-type- util/src/main/
+ * java/org/opendaylight/mdsal/model/ietf/util/AbstractIetfYangUtil.java
+ *
+ * @param vppPhysAddress byte array of bytes in big endian order, constructing the network IF physical address.
+ * @return String like "aa:bb:cc:dd:ee:ff"
+ * @throws NullPointerException if vppPhysAddress is null
+ * @throws IllegalArgumentException if vppPhysAddress.length < 6
+ */
+ default String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress) {
+ return vppPhysAddrToYang(vppPhysAddress, 0);
+ }
+
+ default String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress, final int startIndex) {
+ Objects.requireNonNull(vppPhysAddress, "Empty physical address bytes");
+ final int endIndex = startIndex + PHYSICAL_ADDRESS_LENGTH;
+ checkArgument(endIndex <= vppPhysAddress.length,
+ "Invalid physical address size (%s) for given startIndex (%s), expected >= %s", vppPhysAddress.length,
+ startIndex, endIndex);
+ return printHexBinary(vppPhysAddress, startIndex, endIndex);
+ }
+
+ default String printHexBinary(@Nonnull final byte[] bytes) {
+ Objects.requireNonNull(bytes, "bytes array should not be null");
+ return printHexBinary(bytes, 0, bytes.length);
+ }
+
+ default String printHexBinary(@Nonnull final byte[] bytes, final int startIndex, final int endIndex) {
+ StringBuilder str = new StringBuilder();
+
+ appendHexByte(str, bytes[startIndex]);
+ for (int i = startIndex + 1; i < endIndex; i++) {
+ str.append(":");
+ appendHexByte(str, bytes[i]);
+ }
+
+ return str.toString();
+ }
+
+ /**
+ * VPP's interface index is counted from 0, whereas ietf-interface's if-index is from 1. This function converts from
+ * VPP's interface index to YANG's interface index.
+ *
+ * @param vppIfIndex the sw interface index VPP reported.
+ * @return VPP's interface index incremented by one
+ */
+ default int vppIfIndexToYang(int vppIfIndex) {
+ return vppIfIndex + 1;
+ }
+
+ /**
+ * This function does the opposite of what {@link #vppIfIndexToYang(int)} does.
+ *
+ * @param yangIfIndex if-index from ietf-interfaces.
+ * @return VPP's representation of the if-index
+ */
+ default int yangIfIndexToVpp(int yangIfIndex) {
+ checkArgument(yangIfIndex >= 1, "YANG if-index has invalid value %s", yangIfIndex);
+ return yangIfIndex - 1;
+ }
+
+
+ /**
+ * Queries VPP for interface description given interface key.
+ *
+ * @param futureJVppCore VPP Java Future API
+ * @param id InstanceIdentifier, which is passed in ReadFailedException
+ * @param name interface name
+ * @param index VPP index of the interface
+ * @param ctx per-tx scope context containing cached dump with all the interfaces. If the cache is not
+ * available or outdated, another dump will be performed.
+ * @return SwInterfaceDetails DTO or null if interface was not found
+ * @throws IllegalArgumentException If interface cannot be found
+ * @throws ReadFailedException If read operation had failed
+ */
+ @Nonnull
+ default SwInterfaceDetails getVppInterfaceDetails(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final String name, final int index,
+ @Nonnull final ModificationCache ctx,
+ @Nonnull final Logger callerLogger)
+ throws ReadFailedException {
+ requireNonNull(futureJVppCore, "futureJVppCore should not be null");
+ requireNonNull(name, "name should not be null");
+ requireNonNull(ctx, "ctx should not be null");
+
+ final SwInterfaceDump request = new SwInterfaceDump();
+ request.nameFilter = name.getBytes();
+ request.nameFilterValid = 1;
+
+ final Map<Integer, SwInterfaceDetails> allInterfaces = InterfaceCustomizer.getCachedInterfaceDump(ctx);
+
+ // Returned cached if available
+ if (allInterfaces.containsKey(index)) {
+ return allInterfaces.get(index);
+ }
+
+ SwInterfaceDetailsReplyDump ifaces;
+
+ CompletionStage<SwInterfaceDetailsReplyDump> requestFuture = futureJVppCore.swInterfaceDump(request);
+ ifaces = getReplyForRead(requestFuture.toCompletableFuture(), id);
+ if (null == ifaces || null == ifaces.swInterfaceDetails || ifaces.swInterfaceDetails.isEmpty()) {
+ request.nameFilterValid = 0;
+
+ callerLogger.warn("VPP returned null instead of interface by key {} and its not cached", name);
+ callerLogger.warn("Iterating through all the interfaces to find interface: {}", name);
+
+ // Or else just perform full dump and do inefficient filtering
+ requestFuture = futureJVppCore.swInterfaceDump(request);
+ ifaces = getReplyForRead(requestFuture.toCompletableFuture(), id);
+
+ // Update the cache
+ allInterfaces.clear();
+ allInterfaces
+ .putAll(ifaces.swInterfaceDetails.stream().collect(Collectors.toMap(d -> d.swIfIndex, d -> d)));
+
+ if (allInterfaces.containsKey(index)) {
+ return allInterfaces.get(index);
+ }
+ throw new IllegalArgumentException("Unable to find interface " + name);
+ }
+
+ // SwInterfaceDump's name filter does prefix match, so we need additional filtering:
+ final SwInterfaceDetails iface =
+ ifaces.swInterfaceDetails.stream().filter(d -> d.swIfIndex == index).collect(SINGLE_ITEM_COLLECTOR);
+ allInterfaces.put(index, iface); // update the cache
+ return iface;
+ }
+
+ /**
+ * Determine interface type based on its VPP name (relying on VPP's interface naming conventions)
+ *
+ * @param interfaceName VPP generated interface name
+ * @return Interface type
+ */
+ @Nonnull
+ default Class<? extends InterfaceType> getInterfaceType(@Nonnull final String interfaceName) {
+ if (interfaceName.startsWith("tap")) {
+ return Tap.class;
+ }
+
+ if (interfaceName.startsWith("vxlan_gpe")) {
+ return VxlanGpeTunnel.class;
+ }
+
+ if (interfaceName.startsWith("vxlan")) {
+ return VxlanTunnel.class;
+ }
+
+ if (interfaceName.startsWith("gre")) {
+ return GreTunnel.class;
+ }
+
+ if (interfaceName.startsWith("VirtualEthernet")) {
+ return VhostUser.class;
+ }
+
+ if (interfaceName.startsWith("loop")) {
+ return Loopback.class;
+ }
+
+ return EthernetCsmacd.class;
+ }
+
+ /**
+ * Check interface type. Uses interface details from VPP to determine. Uses {@link
+ * #getVppInterfaceDetails(FutureJVppCore, InstanceIdentifier, String, int, ModificationCache, Logger)} internally
+ * so tries to utilize cache before asking VPP.
+ */
+ default boolean isInterfaceOfType(@Nonnull final FutureJVppCore jvpp,
+ @Nonnull final ModificationCache cache,
+ @Nonnull final InstanceIdentifier<?> id,
+ final int index,
+ @Nonnull final Class<? extends InterfaceType> ifcType,
+ @Nonnull final Logger callerLogger)
+ throws ReadFailedException {
+ final String name = id.firstKeyOf(Interface.class).getName();
+ final SwInterfaceDetails vppInterfaceDetails =
+ getVppInterfaceDetails(jvpp, id, name, index, cache, callerLogger);
+
+ return isInterfaceOfType(ifcType, vppInterfaceDetails);
+ }
+
+ default boolean isInterfaceOfType(final Class<? extends InterfaceType> ifcType,
+ final SwInterfaceDetails cachedDetails) {
+ return ifcType.equals(getInterfaceType(toString(cachedDetails.interfaceName)));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/L2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/L2Customizer.java
new file mode 100644
index 000000000..ed88370f5
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/L2Customizer.java
@@ -0,0 +1,116 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.L2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.base.attributes.Interconnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.base.attributes.interconnection.BridgeBased;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.base.attributes.interconnection.BridgeBasedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.base.attributes.interconnection.XconnectBased;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.base.attributes.interconnection.XconnectBasedBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading ietf-interfaces:interfaces-state/interface/iface_name/v3po:l2
+ */
+public class L2Customizer extends FutureJVppCustomizer implements InitializingReaderCustomizer<L2, L2Builder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(L2Customizer.class);
+ private final InterconnectionReadUtils icReadUtils;
+
+ public L2Customizer(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext interfaceContext,
+ @Nonnull final NamingContext bridgeDomainContext) {
+ super(futureJVppCore);
+ this.icReadUtils = new InterconnectionReadUtils(futureJVppCore, interfaceContext, bridgeDomainContext);
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final L2 readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setL2(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public L2Builder getBuilder(@Nonnull final InstanceIdentifier<L2> id) {
+ return new L2Builder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2Builder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+
+ LOG.debug("Reading attributes for L2: {}", id);
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final String ifaceName = key.getName();
+ builder.setInterconnection(icReadUtils.readInterconnection(id, ifaceName, ctx));
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.L2> init(
+ @Nonnull final InstanceIdentifier<L2> id,
+ @Nonnull final L2 readValue,
+ @Nonnull final ReadContext ctx) {
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.L2Builder
+ l2Builder =
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.L2Builder();
+
+ final Interconnection interconnection = readValue.getInterconnection();
+ if (interconnection != null) {
+ if (interconnection instanceof XconnectBased) {
+ final XconnectBasedBuilder xconnectBasedBuilder = new XconnectBasedBuilder();
+ xconnectBasedBuilder.setXconnectOutgoingInterface(
+ ((XconnectBased) interconnection).getXconnectOutgoingInterface());
+ l2Builder.setInterconnection(xconnectBasedBuilder.build());
+ } else if (interconnection instanceof BridgeBased) {
+ final BridgeBasedBuilder bridgeBasedBuilder = new BridgeBasedBuilder();
+ bridgeBasedBuilder.setBridgeDomain(((BridgeBased) interconnection).getBridgeDomain());
+ bridgeBasedBuilder
+ .setBridgedVirtualInterface(((BridgeBased) interconnection).isBridgedVirtualInterface());
+ bridgeBasedBuilder.setSplitHorizonGroup(((BridgeBased) interconnection).getSplitHorizonGroup());
+ l2Builder.setInterconnection(bridgeBasedBuilder.build());
+ }
+ }
+
+ return Initialized.create(getCfgId(id), l2Builder.build());
+ }
+
+ private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.L2> getCfgId(
+ final InstanceIdentifier<L2> id) {
+ return InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class))
+ .augmentation(VppInterfaceAugmentation.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.L2.class);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ProxyArpCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ProxyArpCustomizer.java
new file mode 100644
index 000000000..028e8e0d8
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ProxyArpCustomizer.java
@@ -0,0 +1,79 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.ProxyArp;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProxyArpCustomizer extends FutureJVppCustomizer
+ implements ReaderCustomizer<ProxyArp,
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.ProxyArpBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ProxyArpCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public ProxyArpCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) {
+ super(vppApi);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> parentBuilder,
+ @Nonnull org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214
+ .interfaces.state._interface.ProxyArp readValue) {
+
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setProxyArp(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state
+ ._interface.ProxyArpBuilder getBuilder(
+ @Nonnull InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight
+ .params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.ProxyArp> id) {
+
+ return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces
+ .state._interface.ProxyArpBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight
+ .params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.ProxyArp> id,
+ @Nonnull org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po
+ .rev161214.interfaces.state._interface.ProxyArpBuilder builder,
+ @Nonnull ReadContext ctx) throws ReadFailedException {
+
+ //TODO: VPP-225 Implement fully when VPP Proxy ARP read API is available + add initializing
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+ LOG.warn("Reading of ARP data not (yet) supported by VPP API");
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/RewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/RewriteCustomizer.java
new file mode 100644
index 000000000..6906ebc0c
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/RewriteCustomizer.java
@@ -0,0 +1,147 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.hc2vpp.common.translate.util.TagRewriteOperation;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qTagVlanType;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.Dot1qTagBuilder;
+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.rev161214._802dot1ad;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214._802dot1q;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.L2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.l2.Rewrite;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.l2.RewriteBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.tag.rewrite.PushTags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.tag.rewrite.PushTagsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.tag.rewrite.PushTagsKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDetails;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading vlan tag-rewrite configuration state form the VPP.
+ */
+public class RewriteCustomizer extends FutureJVppCustomizer
+ implements ReaderCustomizer<Rewrite, RewriteBuilder>, InterfaceDataTranslator {
+
+ // No initialization necessary since its parent Subinterface L2 customzier sets the entire subtree during
+ // initialization
+
+ private static final Logger LOG = LoggerFactory.getLogger(RewriteCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public RewriteCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJVppCore);
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder,
+ @Nonnull final Rewrite readValue) {
+ ((L2Builder) parentBuilder).setRewrite(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public RewriteBuilder getBuilder(@Nonnull final InstanceIdentifier<Rewrite> id) {
+ return new RewriteBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Rewrite> id,
+ @Nonnull final RewriteBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ LOG.debug("Reading attributes for sub interface: {}", subInterfaceName);
+
+ final SwInterfaceDetails iface = getVppInterfaceDetails(getFutureJVpp(), id, subInterfaceName,
+ interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()), ctx.getModificationCache(), LOG);
+ LOG.debug("VPP sub-interface details: {}", iface);
+
+ checkState(iface.subId != 0, "Interface returned by the VPP is not a sub-interface");
+
+ final TagRewriteOperation operation = TagRewriteOperation.get(iface.vtrOp);
+ if (TagRewriteOperation.disabled == operation) {
+ LOG.debug("Tag rewrite operation is disabled for ");
+ return;
+ }
+
+ builder.setVlanType(iface.vtrPushDot1Q == 1
+ ? _802dot1q.class
+ : _802dot1ad.class);
+
+ setPushTags(builder, iface);
+ setPopTags(builder, operation);
+ }
+
+ private static String getSubInterfaceName(final InstanceIdentifier<Rewrite> id) {
+ return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(),
+ Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier()));
+ }
+
+ private void setPopTags(final RewriteBuilder builder, final TagRewriteOperation operation) {
+ final byte numberOfTagsToPop = operation.getPopTags();
+ if (numberOfTagsToPop != 0) {
+ builder.setPopTags(Short.valueOf(numberOfTagsToPop));
+ }
+ }
+
+ private void setPushTags(final RewriteBuilder builder, final SwInterfaceDetails iface) {
+ final List<PushTags> tags = new ArrayList<>();
+ if (iface.vtrTag1 != 0) {
+ tags.add(buildTag((short) 0, SVlan.class, iface.vtrTag1));
+ }
+ if (iface.vtrTag2 != 0) {
+ tags.add(buildTag((short) 1, CVlan.class, iface.vtrTag2));
+ }
+ if (tags.size() > 0) {
+ builder.setPushTags(tags);
+ }
+ }
+
+ private PushTags buildTag(final short index, final Class<? extends Dot1qTagVlanType> tagType, final int vlanId) {
+ final PushTagsBuilder tag = new PushTagsBuilder();
+ tag.setIndex(index);
+ tag.setKey(new PushTagsKey(index));
+ final Dot1qTagBuilder dtag = new Dot1qTagBuilder();
+ dtag.setTagType(tagType);
+ dtag.setVlanId(new Dot1qVlanId(vlanId));
+ tag.setDot1qTag(dtag.build());
+ return tag.build();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/SubInterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/SubInterfaceCustomizer.java
new file mode 100644
index 000000000..9c13b382a
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/SubInterfaceCustomizer.java
@@ -0,0 +1,264 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingListReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDetails;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qTagVlanType;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag;
+import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTagBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.SubInterfaceStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.SubinterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.SubInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.SubInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.match.attributes.match.type.DefaultBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.match.attributes.match.type.UntaggedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.match.attributes.match.type.vlan.tagged.VlanTaggedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.Tags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.TagsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.tags.Tag;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.tags.TagBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.tags.TagKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading sub interfaces form the VPP.
+ */
+public class SubInterfaceCustomizer extends FutureJVppCustomizer
+ implements InitializingListReaderCustomizer<SubInterface, SubInterfaceKey, SubInterfaceBuilder>, ByteDataTranslator,
+ InterfaceDataTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceCustomizer.class);
+ private static final Dot1qTag.VlanId ANY_VLAN_ID = new Dot1qTag.VlanId(Dot1qTag.VlanId.Enumeration.Any);
+ private NamingContext interfaceContext;
+
+ public SubInterfaceCustomizer(@Nonnull final FutureJVppCore jvpp,
+ @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ private static String getSubInterfaceName(final InstanceIdentifier<SubInterface> id) {
+ return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(),
+ Math.toIntExact(id.firstKeyOf(id.getTargetType()).getIdentifier()));
+ }
+
+ private static Tag buildTag(final short index, final Class<? extends Dot1qTagVlanType> tagType,
+ final Dot1qTag.VlanId vlanId) {
+ TagBuilder tag = new TagBuilder();
+ tag.setIndex(index);
+ tag.setKey(new TagKey(index));
+ final Dot1qTagBuilder dtag = new Dot1qTagBuilder();
+ dtag.setTagType(tagType);
+ dtag.setVlanId(vlanId);
+ tag.setDot1qTag(dtag.build());
+ return tag.build();
+ }
+
+ private static Dot1qTag.VlanId buildVlanId(final short vlanId) {
+ // treat vlanId as unsigned value:
+ return new Dot1qTag.VlanId(new Dot1qVlanId(0xffff & vlanId));
+ }
+
+ @Nonnull
+ @Override
+ public List<SubInterfaceKey> getAllIds(@Nonnull final InstanceIdentifier<SubInterface> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ // Relying here that parent InterfaceCustomizer was invoked first (PREORDER)
+ // to fill in the context with initial ifc mapping
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final String ifaceName = key.getName();
+ final int ifaceId = interfaceContext.getIndex(ifaceName, context.getMappingContext());
+
+ // TODO HONEYCOMB-189 if we know that full dump was already performed we could use cache
+ // (checking if getCachedInterfaceDump() returns non empty map is not enough, because
+ // we could be part of particular iface state read
+ final SwInterfaceDump request = new SwInterfaceDump();
+ request.nameFilter = "".getBytes();
+ request.nameFilterValid = 0;
+
+ final CompletableFuture<SwInterfaceDetailsReplyDump> swInterfaceDetailsReplyDumpCompletableFuture =
+ getFutureJVpp().swInterfaceDump(request).toCompletableFuture();
+ final SwInterfaceDetailsReplyDump ifaces =
+ getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, id);
+
+ if (null == ifaces || null == ifaces.swInterfaceDetails) {
+ LOG.warn("Looking for sub-interfaces, but no interfaces found in VPP");
+ return Collections.emptyList();
+ }
+
+ // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes
+ context.getModificationCache()
+ .put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream()
+ .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails)));
+
+ final List<SubInterfaceKey> interfacesKeys = ifaces.swInterfaceDetails.stream()
+ .filter(elt -> elt != null)
+ // accept only sub-interfaces for current iface:
+ .filter(elt -> elt.subId != 0 && elt.supSwIfIndex == ifaceId)
+ .map(details -> new SubInterfaceKey(new Long(details.subId)))
+ .collect(Collectors.toList());
+
+ LOG.debug("Sub-interfaces of {} found in VPP: {}", ifaceName, interfacesKeys);
+ return interfacesKeys;
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<SubInterface> readData) {
+ ((SubInterfacesBuilder) builder).setSubInterface(readData);
+ }
+
+ @Nonnull
+ @Override
+ public SubInterfaceBuilder getBuilder(@Nonnull final InstanceIdentifier<SubInterface> id) {
+ return new SubInterfaceBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<SubInterface> id,
+ @Nonnull final SubInterfaceBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ final String subInterfaceName = getSubInterfaceName(id);
+ LOG.debug("Reading attributes for sub interface: {}", subInterfaceName);
+
+ final SwInterfaceDetails iface = getVppInterfaceDetails(getFutureJVpp(), id, subInterfaceName,
+ interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()), ctx.getModificationCache(), LOG);
+ LOG.debug("VPP sub-interface details: {}", iface);
+
+ checkState(iface.subId != 0, "Interface returned by the VPP is not a sub-interface");
+
+ builder.setIdentifier(Long.valueOf(iface.subId));
+ builder.setKey(new SubInterfaceKey(builder.getIdentifier()));
+
+ // sub-interface-base-attributes:
+ builder.setTags(readTags(iface));
+ builder.setMatch(readMatch(iface));
+
+ // sub-interface-operational-attributes:
+ builder.setAdminStatus(1 == iface.adminUpDown
+ ? SubInterfaceStatus.Up
+ : SubInterfaceStatus.Down);
+ builder.setOperStatus(1 == iface.linkUpDown
+ ? SubInterfaceStatus.Up
+ : SubInterfaceStatus.Down);
+ builder.setIfIndex(vppIfIndexToYang(iface.swIfIndex));
+ if (iface.l2AddressLength == 6) {
+ builder.setPhysAddress(new PhysAddress(vppPhysAddrToYang(iface.l2Address)));
+ }
+ if (0 != iface.linkSpeed) {
+ builder.setSpeed(vppInterfaceSpeedToYang(iface.linkSpeed));
+ }
+ }
+
+ private Tags readTags(final SwInterfaceDetails iface) {
+ final TagsBuilder tags = new TagsBuilder();
+ final List<Tag> list = new ArrayList<>();
+ if (iface.subNumberOfTags > 0) {
+ if (iface.subOuterVlanIdAny == 1) {
+ list.add(buildTag((short) 0, SVlan.class, ANY_VLAN_ID));
+ } else {
+ list.add(buildTag((short) 0, SVlan.class, buildVlanId(iface.subOuterVlanId)));
+ }
+ // inner tag (customer tag):
+ if (iface.subNumberOfTags == 2) {
+ if (iface.subInnerVlanIdAny == 1) {
+ list.add(buildTag((short) 1, CVlan.class, ANY_VLAN_ID));
+ } else {
+ list.add(buildTag((short) 1, CVlan.class, buildVlanId(iface.subInnerVlanId)));
+ }
+ }
+ }
+ tags.setTag(list);
+ return tags.build();
+ }
+
+ private Match readMatch(final SwInterfaceDetails iface) {
+ final MatchBuilder match = new MatchBuilder();
+ if (iface.subDefault == 1) {
+ match.setMatchType(new DefaultBuilder().build());
+ } else if (iface.subNumberOfTags == 0) {
+ match.setMatchType(new UntaggedBuilder().build());
+ } else {
+ final VlanTaggedBuilder tagged = new VlanTaggedBuilder();
+ tagged.setMatchExactTags(byteToBoolean(iface.subExactMatch));
+ match.setMatchType(
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.match.attributes.match.type.VlanTaggedBuilder()
+ .setVlanTagged(tagged.build()).build());
+ }
+ return match.build();
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface> init(
+ @Nonnull final InstanceIdentifier<SubInterface> id, @Nonnull final SubInterface readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterfaceBuilder()
+ .setEnabled(SubInterfaceStatus.Up.equals(readValue.getAdminStatus()))
+ .setIdentifier(readValue.getIdentifier())
+ .setMatch(readValue.getMatch())
+ .setTags(readValue.getTags())
+ .setVlanType(readValue.getVlanType())
+ .build());
+ }
+
+ public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface> getCfgId(
+ final InstanceIdentifier<SubInterface> id) {
+ return InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class))
+ .augmentation(SubinterfaceAugmentation.class)
+ .child(SubInterfaces.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface.class,
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterfaceKey(
+ id.firstKeyOf(SubInterface.class).getIdentifier()));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/SubInterfaceL2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/SubInterfaceL2Customizer.java
new file mode 100644
index 000000000..1b98b41ef
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/SubInterfaceL2Customizer.java
@@ -0,0 +1,93 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.getSubInterfaceName;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.L2Builder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading vlan sub interface L2 operational state
+ */
+public class SubInterfaceL2Customizer extends FutureJVppCustomizer
+ implements InitializingReaderCustomizer<L2, L2Builder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceL2Customizer.class);
+ private final InterconnectionReadUtils icReadUtils;
+
+ public SubInterfaceL2Customizer(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext interfaceContext,
+ @Nonnull final NamingContext bridgeDomainContext) {
+ super(futureJVppCore);
+ this.icReadUtils = new InterconnectionReadUtils(futureJVppCore, interfaceContext, bridgeDomainContext);
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final L2 readValue) {
+ ((SubInterfaceBuilder) parentBuilder).setL2(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public L2Builder getBuilder(@Nonnull final InstanceIdentifier<L2> id) {
+ return new L2Builder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2Builder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading attributes for sub-interface L2: {}", id);
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ final String subInterfaceName = getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+
+ builder.setInterconnection(icReadUtils.readInterconnection(id, subInterfaceName, ctx));
+ }
+
+ @Override
+ public Initialized<L2> init(
+ @Nonnull final InstanceIdentifier<L2> id,
+ @Nonnull final L2 readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id), readValue);
+ }
+
+ static InstanceIdentifier<L2> getCfgId(final InstanceIdentifier<L2> id) {
+ return SubInterfaceCustomizer.getCfgId(RWUtils.cutId(id, SubInterface.class))
+ .child(L2.class);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/TapCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/TapCustomizer.java
new file mode 100644
index 000000000..683450da3
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/TapCustomizer.java
@@ -0,0 +1,143 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceDetails;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceTapDetails;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceTapDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceTapDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletionStage;
+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.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Tap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.TapBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class TapCustomizer extends FutureJVppCustomizer
+ implements InitializingReaderCustomizer<Tap, TapBuilder>, InterfaceDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TapCustomizer.class);
+ public static final String DUMPED_TAPS_CONTEXT_KEY = TapCustomizer.class.getName() + "dumpedTapsDuringGetAllIds";
+ private NamingContext interfaceContext;
+
+ public TapCustomizer(@Nonnull final FutureJVppCore jvpp, @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> parentBuilder, @Nonnull Tap readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setTap(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public TapBuilder getBuilder(@Nonnull InstanceIdentifier<Tap> id) {
+ return new TapBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Tap> id,
+ @Nonnull final TapBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+ if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index,
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.Tap.class, LOG)) {
+ return;
+ }
+
+ LOG.debug("Reading attributes for tap interface: {}", key.getName());
+
+ @SuppressWarnings("unchecked")
+ Map<Integer, SwInterfaceTapDetails> mappedTaps =
+ (Map<Integer, SwInterfaceTapDetails>) ctx.getModificationCache().get(DUMPED_TAPS_CONTEXT_KEY);
+
+ if (mappedTaps == null) {
+ // Full Tap dump has to be performed here, no filter or anything is here to help so at least we cache it
+ final SwInterfaceTapDump request = new SwInterfaceTapDump();
+ final CompletionStage<SwInterfaceTapDetailsReplyDump> swInterfaceTapDetailsReplyDumpCompletionStage =
+ getFutureJVpp().swInterfaceTapDump(request);
+ final SwInterfaceTapDetailsReplyDump reply =
+ getReplyForRead(swInterfaceTapDetailsReplyDumpCompletionStage.toCompletableFuture(), id);
+
+ if (null == reply || null == reply.swInterfaceTapDetails) {
+ mappedTaps = Collections.emptyMap();
+ } else {
+ final List<SwInterfaceTapDetails> swInterfaceTapDetails = reply.swInterfaceTapDetails;
+ // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes
+ mappedTaps = swInterfaceTapDetails.stream()
+ .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails));
+ }
+
+ ctx.getModificationCache().put(DUMPED_TAPS_CONTEXT_KEY, mappedTaps);
+ }
+
+ final SwInterfaceTapDetails swInterfaceTapDetails = mappedTaps.get(index);
+ LOG.trace("Tap interface: {} attributes returned from VPP: {}", key.getName(), swInterfaceTapDetails);
+
+ builder.setTapName(toString(swInterfaceTapDetails.devName));
+ LOG.debug("Tap interface: {}, id: {} attributes read as: {}", key.getName(), index, builder);
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Tap> init(
+ @Nonnull final InstanceIdentifier<Tap> id, @Nonnull final Tap readValue, @Nonnull final ReadContext ctx) {
+ // The MAC address is set from interface details, those details are retrieved from cache
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+ final SwInterfaceDetails ifcDetails =
+ InterfaceCustomizer.getCachedInterfaceDump(ctx.getModificationCache()).get(index);
+
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.TapBuilder()
+ .setMac(new PhysAddress(vppPhysAddrToYang(ifcDetails.l2Address)))
+ .setTapName(readValue.getTapName())
+// tapBuilder.setDeviceInstance();
+ .build());
+ }
+
+ private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Tap> getCfgId(
+ final InstanceIdentifier<Tap> id) {
+ return InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class))
+ .augmentation(VppInterfaceAugmentation.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Tap.class);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/VhostUserCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/VhostUserCustomizer.java
new file mode 100644
index 000000000..6a918e842
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/VhostUserCustomizer.java
@@ -0,0 +1,154 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceVhostUserDetails;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceVhostUserDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceVhostUserDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletionStage;
+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.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VhostUserRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.VhostUser;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.VhostUserBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class VhostUserCustomizer extends FutureJVppCustomizer
+ implements InitializingReaderCustomizer<VhostUser, VhostUserBuilder>, InterfaceDataTranslator, JvppReplyConsumer {
+
+ public static final String DUMPED_VHOST_USERS_CONTEXT_KEY =
+ VhostUserCustomizer.class.getName() + "dumpedVhostUsersDuringGetAllIds";
+ private static final Logger LOG = LoggerFactory.getLogger(VhostUserCustomizer.class);
+ private NamingContext interfaceContext;
+
+ public VhostUserCustomizer(@Nonnull final FutureJVppCore jvpp, @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> parentBuilder, @Nonnull VhostUser readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVhostUser(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public VhostUserBuilder getBuilder(@Nonnull InstanceIdentifier<VhostUser> id) {
+ return new VhostUserBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VhostUser> id,
+ @Nonnull final VhostUserBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+ if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index,
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VhostUser.class,
+ LOG)) {
+ return;
+ }
+
+ LOG.debug("Reading attributes for vhpost user interface: {}", key.getName());
+
+ @SuppressWarnings("unchecked")
+ Map<Integer, SwInterfaceVhostUserDetails> mappedVhostUsers =
+ (Map<Integer, SwInterfaceVhostUserDetails>) ctx.getModificationCache()
+ .get(DUMPED_VHOST_USERS_CONTEXT_KEY);
+
+ if (mappedVhostUsers == null) {
+ // Full VhostUser dump has to be performed here, no filter or anything is here to help so at least we cache it
+ final SwInterfaceVhostUserDump request = new SwInterfaceVhostUserDump();
+ final CompletionStage<SwInterfaceVhostUserDetailsReplyDump>
+ swInterfaceVhostUserDetailsReplyDumpCompletionStage =
+ getFutureJVpp().swInterfaceVhostUserDump(request);
+ final SwInterfaceVhostUserDetailsReplyDump reply =
+ getReplyForRead(swInterfaceVhostUserDetailsReplyDumpCompletionStage.toCompletableFuture(), id);
+
+ if (null == reply || null == reply.swInterfaceVhostUserDetails) {
+ mappedVhostUsers = Collections.emptyMap();
+ } else {
+ final List<SwInterfaceVhostUserDetails> swInterfaceVhostUserDetails =
+ reply.swInterfaceVhostUserDetails;
+ // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes
+ mappedVhostUsers = swInterfaceVhostUserDetails.stream()
+ .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails));
+ }
+
+ ctx.getModificationCache().put(DUMPED_VHOST_USERS_CONTEXT_KEY, mappedVhostUsers);
+ }
+
+ // Relying here that parent InterfaceCustomizer was invoked first to fill in the context with initial ifc mapping
+ final SwInterfaceVhostUserDetails swInterfaceVhostUserDetails = mappedVhostUsers.get(index);
+ LOG.trace("Vhost user interface: {} attributes returned from VPP: {}", key.getName(),
+ swInterfaceVhostUserDetails);
+
+ builder.setRole(swInterfaceVhostUserDetails.isServer == 1
+ ? VhostUserRole.Server
+ : VhostUserRole.Client);
+ builder.setFeatures(BigInteger.valueOf(swInterfaceVhostUserDetails.features));
+ builder.setNumMemoryRegions((long) swInterfaceVhostUserDetails.numRegions);
+ builder.setSocket(toString(swInterfaceVhostUserDetails.sockFilename));
+ builder.setVirtioNetHdrSize((long) swInterfaceVhostUserDetails.virtioNetHdrSz);
+ // TODO: map error code to meaningful message after VPP-436 is done
+ builder.setConnectError(Integer.toString(swInterfaceVhostUserDetails.sockErrno));
+
+ LOG.debug("Vhost user interface: {}, id: {} attributes read as: {}", key.getName(), index, builder);
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VhostUser> init(
+ @Nonnull final InstanceIdentifier<VhostUser> id,
+ @Nonnull final VhostUser readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VhostUserBuilder()
+ .setRole(readValue.getRole())
+ .setSocket(readValue.getSocket())
+ .build());
+ }
+
+ private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VhostUser> getCfgId(
+ final InstanceIdentifier<VhostUser> id) {
+ return InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class))
+ .augmentation(VppInterfaceAugmentation.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VhostUser.class);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/VxlanCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/VxlanCustomizer.java
new file mode 100644
index 000000000..d3174e643
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/VxlanCustomizer.java
@@ -0,0 +1,162 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.VxlanTunnelDetails;
+import io.fd.vpp.jvpp.core.dto.VxlanTunnelDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.VxlanTunnelDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanVni;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.Vxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.VxlanBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VxlanCustomizer extends FutureJVppCustomizer
+ implements InitializingReaderCustomizer<Vxlan, VxlanBuilder>, InterfaceDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class);
+ private final NamingContext interfaceContext;
+
+ public VxlanCustomizer(@Nonnull final FutureJVppCore jvpp, @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> parentBuilder,
+ @Nonnull Vxlan readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVxlan(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public VxlanBuilder getBuilder(@Nonnull InstanceIdentifier<Vxlan> id) {
+ return new VxlanBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Vxlan> id,
+ @Nonnull final VxlanBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+ if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, VxlanTunnel.class, LOG)) {
+ return;
+ }
+
+ LOG.debug("Reading attributes for vxlan tunnel: {}", key.getName());
+ // Dump just a single
+ final VxlanTunnelDump request = new VxlanTunnelDump();
+ request.swIfIndex = index;
+
+ final CompletionStage<VxlanTunnelDetailsReplyDump> swInterfaceVxlanDetailsReplyDumpCompletionStage =
+ getFutureJVpp().vxlanTunnelDump(request);
+ final VxlanTunnelDetailsReplyDump reply =
+ getReplyForRead(swInterfaceVxlanDetailsReplyDumpCompletionStage.toCompletableFuture(), id);
+
+ // VPP keeps vxlan tunnel interfaces even after they were deleted (optimization)
+ // However there ar no longer any vxlan tunnel specific fields assigned to it and this call
+ // returns nothing
+ if (reply == null || reply.vxlanTunnelDetails == null || reply.vxlanTunnelDetails.isEmpty()) {
+ LOG.debug(
+ "Vxlan tunnel {}, id {} has no attributes assigned in VPP. Probably is a leftover interface placeholder" +
+ "after delete", key.getName(), index);
+ return;
+ }
+
+ checkState(reply.vxlanTunnelDetails.size() == 1,
+ "Unexpected number of returned vxlan tunnels: {} for tunnel: {}", reply.vxlanTunnelDetails,
+ key.getName());
+ LOG.trace("Vxlan tunnel: {} attributes returned from VPP: {}", key.getName(), reply);
+
+ final VxlanTunnelDetails swInterfaceVxlanDetails = reply.vxlanTunnelDetails.get(0);
+ if (swInterfaceVxlanDetails.isIpv6 == 1) {
+ final Ipv6Address dstIpv6 =
+ new Ipv6Address(parseAddress(swInterfaceVxlanDetails.dstAddress).getHostAddress());
+ builder.setDst(new IpAddress(dstIpv6));
+ final Ipv6Address srcIpv6 =
+ new Ipv6Address(parseAddress(swInterfaceVxlanDetails.srcAddress).getHostAddress());
+ builder.setSrc(new IpAddress(srcIpv6));
+ } else {
+ final byte[] dstBytes = Arrays.copyOfRange(swInterfaceVxlanDetails.dstAddress, 0, 4);
+ final Ipv4Address dstIpv4 = new Ipv4Address(parseAddress(dstBytes).getHostAddress());
+ builder.setDst(new IpAddress(dstIpv4));
+ final byte[] srcBytes = Arrays.copyOfRange(swInterfaceVxlanDetails.srcAddress, 0, 4);
+ final Ipv4Address srcIpv4 = new Ipv4Address(parseAddress(srcBytes).getHostAddress());
+ builder.setSrc(new IpAddress(srcIpv4));
+ }
+ builder.setEncapVrfId((long) swInterfaceVxlanDetails.encapVrfId);
+ builder.setVni(new VxlanVni((long) swInterfaceVxlanDetails.vni));
+ LOG.debug("Vxlan tunnel: {}, id: {} attributes read as: {}", key.getName(), index, builder);
+ }
+
+ @Nonnull
+ private static InetAddress parseAddress(@Nonnull final byte[] addr) {
+ try {
+ return InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Cannot create InetAddress from " + Arrays.toString(addr), e);
+ }
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Vxlan> init(
+ @Nonnull final InstanceIdentifier<Vxlan> id, @Nonnull final Vxlan readValue, @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VxlanBuilder()
+ .setDst(readValue.getDst())
+ .setSrc(readValue.getSrc())
+ .setEncapVrfId(readValue.getEncapVrfId())
+ .setVni(new VxlanVni(readValue.getVni()))
+ .build());
+ }
+
+ private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Vxlan> getCfgId(
+ final InstanceIdentifier<Vxlan> id) {
+ return InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class))
+ .augmentation(VppInterfaceAugmentation.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Vxlan.class);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/VxlanGpeCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/VxlanGpeCustomizer.java
new file mode 100644
index 000000000..b10fef3e8
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/VxlanGpeCustomizer.java
@@ -0,0 +1,168 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.VxlanGpeTunnelDetails;
+import io.fd.vpp.jvpp.core.dto.VxlanGpeTunnelDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.VxlanGpeTunnelDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanGpeNextProtocol;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanGpeTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanGpeVni;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.VxlanGpe;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.VxlanGpeBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VxlanGpeCustomizer extends FutureJVppCustomizer
+ implements InitializingReaderCustomizer<VxlanGpe, VxlanGpeBuilder>, InterfaceDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class);
+ private NamingContext interfaceContext;
+
+ public VxlanGpeCustomizer(@Nonnull final FutureJVppCore jvpp, @Nonnull final NamingContext interfaceContext) {
+ super(jvpp);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> parentBuilder,
+ @Nonnull VxlanGpe readValue) {
+ ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVxlanGpe(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public VxlanGpeBuilder getBuilder(@Nonnull InstanceIdentifier<VxlanGpe> id) {
+ return new VxlanGpeBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanGpe> id,
+ @Nonnull final VxlanGpeBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+
+ final InterfaceKey key = id.firstKeyOf(Interface.class);
+ final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+ if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, VxlanGpeTunnel.class, LOG)) {
+ return;
+ }
+
+ LOG.debug("Reading attributes for VxlanGpe tunnel: {}", key.getName());
+ // Dump just a single
+ final VxlanGpeTunnelDump request = new VxlanGpeTunnelDump();
+ request.swIfIndex = index;
+
+ final CompletionStage<VxlanGpeTunnelDetailsReplyDump> swInterfaceVxlanGpeDetailsReplyDumpCompletionStage =
+ getFutureJVpp().vxlanGpeTunnelDump(request);
+ final VxlanGpeTunnelDetailsReplyDump reply =
+ getReplyForRead(swInterfaceVxlanGpeDetailsReplyDumpCompletionStage.toCompletableFuture(),
+ id);
+
+ // VPP keeps VxlanGpe tunnel interfaces even after they were deleted (optimization)
+ // However there are no longer any VxlanGpe tunnel specific fields assigned to it and this call
+ // returns nothing
+ if (reply == null || reply.vxlanGpeTunnelDetails == null || reply.vxlanGpeTunnelDetails.isEmpty()) {
+ LOG.debug(
+ "VxlanGpe tunnel {}, id {} has no attributes assigned in VPP. Probably is a leftover interface placeholder" +
+ "after delete", key.getName(), index);
+ return;
+ }
+
+ checkState(reply.vxlanGpeTunnelDetails.size() == 1,
+ "Unexpected number of returned VxlanGpe tunnels: {} for tunnel: {}", reply.vxlanGpeTunnelDetails,
+ key.getName());
+ LOG.trace("VxlanGpe tunnel: {} attributes returned from VPP: {}", key.getName(), reply);
+
+ final VxlanGpeTunnelDetails swInterfaceVxlanGpeDetails = reply.vxlanGpeTunnelDetails.get(0);
+ if (swInterfaceVxlanGpeDetails.isIpv6 == 1) {
+ final Ipv6Address remote6 =
+ new Ipv6Address(parseAddress(swInterfaceVxlanGpeDetails.remote).getHostAddress());
+ builder.setRemote(new IpAddress(remote6));
+ final Ipv6Address local6 =
+ new Ipv6Address(parseAddress(swInterfaceVxlanGpeDetails.local).getHostAddress());
+ builder.setLocal(new IpAddress(local6));
+ } else {
+ final byte[] dstBytes = Arrays.copyOfRange(swInterfaceVxlanGpeDetails.remote, 0, 4);
+ final Ipv4Address remote4 = new Ipv4Address(parseAddress(dstBytes).getHostAddress());
+ builder.setRemote(new IpAddress(remote4));
+ final byte[] srcBytes = Arrays.copyOfRange(swInterfaceVxlanGpeDetails.local, 0, 4);
+ final Ipv4Address local4 = new Ipv4Address(parseAddress(srcBytes).getHostAddress());
+ builder.setLocal(new IpAddress(local4));
+ }
+ builder.setVni(new VxlanGpeVni((long) swInterfaceVxlanGpeDetails.vni));
+ builder.setNextProtocol(VxlanGpeNextProtocol.forValue(swInterfaceVxlanGpeDetails.protocol));
+ builder.setEncapVrfId((long) swInterfaceVxlanGpeDetails.encapVrfId);
+ builder.setDecapVrfId((long) swInterfaceVxlanGpeDetails.decapVrfId);
+ LOG.debug("VxlanGpe tunnel: {}, id: {} attributes read as: {}", key.getName(), index, builder);
+ }
+
+ @Nonnull
+ private static InetAddress parseAddress(@Nonnull final byte[] addr) {
+ try {
+ return InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Cannot create InetAddress from " + Arrays.toString(addr), e);
+ }
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VxlanGpe> init(
+ @Nonnull final InstanceIdentifier<VxlanGpe> id, @Nonnull final VxlanGpe readValue, @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VxlanGpeBuilder()
+ .setLocal(readValue.getLocal())
+ .setRemote(readValue.getRemote())
+ .setVni(new VxlanGpeVni(readValue.getVni()))
+ .setNextProtocol(readValue.getNextProtocol())
+ .setEncapVrfId(readValue.getEncapVrfId())
+ .setDecapVrfId(readValue.getDecapVrfId())
+ .build());
+ }
+
+ private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VxlanGpe> getCfgId(
+ final InstanceIdentifier<VxlanGpe> id) {
+ return InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class))
+ .augmentation(VppInterfaceAugmentation.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VxlanGpe.class);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/acl/ingress/AclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/acl/ingress/AclCustomizer.java
new file mode 100644
index 000000000..713868d2e
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/acl/ingress/AclCustomizer.java
@@ -0,0 +1,118 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.v3po.interfacesstate.InterfaceCustomizer;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterface;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterfaceReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces.state._interface.acl.IngressBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading ingress ACLs enabled on given interface.
+ */
+public class AclCustomizer extends FutureJVppCustomizer
+ implements InitializingReaderCustomizer<Ingress, IngressBuilder>, AclReader, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final VppClassifierContextManager classifyTableContext;
+
+ public AclCustomizer(@Nonnull final FutureJVppCore jvpp, @Nonnull final NamingContext interfaceContext,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(jvpp);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Ingress readValue) {
+ ((AclBuilder) parentBuilder).setIngress(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public IngressBuilder getBuilder(@Nonnull final InstanceIdentifier<Ingress> id) {
+ return new IngressBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final IngressBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading attributes for interface ACL: {}", id);
+ final InterfaceKey interfaceKey = id.firstKeyOf(Interface.class);
+ checkArgument(interfaceKey != null, "No parent interface key found");
+
+ final ClassifyTableByInterface request = new ClassifyTableByInterface();
+ request.swIfIndex = interfaceContext.getIndex(interfaceKey.getName(), ctx.getMappingContext());
+
+ final ClassifyTableByInterfaceReply reply =
+ getReplyForRead(getFutureJVpp().classifyTableByInterface(request).toCompletableFuture(), id);
+
+ builder.setL2Acl(readL2Acl(reply.l2TableId, classifyTableContext, ctx.getMappingContext()));
+ builder.setIp4Acl(readIp4Acl(reply.ip4TableId, classifyTableContext, ctx.getMappingContext()));
+ builder.setIp6Acl(readIp6Acl(reply.ip6TableId, classifyTableContext, ctx.getMappingContext()));
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for ACL {} successfully read: {}", id, builder.build());
+ }
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.acl.Ingress> init(
+ @Nonnull final InstanceIdentifier<Ingress> id, @Nonnull final Ingress readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.acl.IngressBuilder()
+ .setL2Acl(readValue.getL2Acl())
+ .setIp4Acl(readValue.getIp4Acl())
+ .setIp6Acl(readValue.getIp6Acl())
+ .build());
+ }
+
+ private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.acl.Ingress> getCfgId(
+ final InstanceIdentifier<Ingress> id) {
+ return InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class))
+ .augmentation(VppInterfaceAugmentation.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Acl.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.acl.Ingress.class);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/acl/ingress/AclReader.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/acl/ingress/AclReader.java
new file mode 100644
index 000000000..8f1b428b9
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/acl/ingress/AclReader.java
@@ -0,0 +1,60 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate.acl.ingress;
+
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip4AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip6AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.L2Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.L2AclBuilder;
+
+interface AclReader {
+
+ @Nonnull
+ default L2Acl readL2Acl(final int l2TableId, @Nonnull final VppClassifierContextManager classifyTableContext,
+ @Nonnull final MappingContext mappingContext) {
+ if (l2TableId == ~0) {
+ return null;
+ }
+ return new L2AclBuilder()
+ .setClassifyTable(classifyTableContext.getTableName(l2TableId, mappingContext)).build();
+ }
+
+ @Nonnull
+ default Ip4Acl readIp4Acl(final int ip4TableId, @Nonnull final VppClassifierContextManager classifyTableContext,
+ @Nonnull final MappingContext mappingContext) {
+ if (ip4TableId == ~0) {
+ return null;
+ }
+ return new Ip4AclBuilder()
+ .setClassifyTable(classifyTableContext.getTableName(ip4TableId, mappingContext)).build();
+ }
+
+ @Nonnull
+ default Ip6Acl readIp6Acl(final int ip6TableId, @Nonnull final VppClassifierContextManager classifyTableContext,
+ @Nonnull final MappingContext mappingContext) {
+ if (ip6TableId == ~0) {
+ return null;
+ }
+ return new Ip6AclBuilder()
+ .setClassifyTable(classifyTableContext.getTableName(ip6TableId, mappingContext)).build();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/acl/ingress/SubInterfaceAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/acl/ingress/SubInterfaceAclCustomizer.java
new file mode 100644
index 000000000..4190619b8
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/acl/ingress/SubInterfaceAclCustomizer.java
@@ -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.hc2vpp.v3po.interfacesstate.acl.ingress;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.getSubInterfaceName;
+
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.v3po.interfacesstate.SubInterfaceCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterface;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterfaceReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.acl.Ingress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.acl.IngressBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for reading ingress ACLs enabled on given sub-interface.
+ */
+public class SubInterfaceAclCustomizer extends FutureJVppCustomizer
+ implements InitializingReaderCustomizer<Ingress, IngressBuilder>, AclReader, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class);
+ private final NamingContext interfaceContext;
+ private final VppClassifierContextManager classifyTableContext;
+
+ public SubInterfaceAclCustomizer(@Nonnull final FutureJVppCore jvpp, @Nonnull final NamingContext interfaceContext,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(jvpp);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Ingress readValue) {
+ ((AclBuilder) parentBuilder).setIngress(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public IngressBuilder getBuilder(@Nonnull final InstanceIdentifier<Ingress> id) {
+ return new IngressBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final IngressBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading attributes for sub-interface ACL: {}", id);
+ final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class);
+ checkArgument(parentInterfacekey != null, "No parent interface key found");
+ final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class);
+ checkArgument(subInterfacekey != null, "No sub-interface key found");
+ final String subInterfaceName =
+ getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue());
+
+ final ClassifyTableByInterface request = new ClassifyTableByInterface();
+ request.swIfIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext());
+
+ final ClassifyTableByInterfaceReply reply =
+ getReplyForRead(getFutureJVpp().classifyTableByInterface(request).toCompletableFuture(), id);
+
+ builder.setL2Acl(readL2Acl(reply.l2TableId, classifyTableContext, ctx.getMappingContext()));
+ builder.setIp4Acl(readIp4Acl(reply.ip4TableId, classifyTableContext, ctx.getMappingContext()));
+ builder.setIp6Acl(readIp6Acl(reply.ip6TableId, classifyTableContext, ctx.getMappingContext()));
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for ACL {} successfully read: {}", id, builder.build());
+ }
+ }
+
+ @Override
+ public Initialized<Ingress> init(
+ @Nonnull final InstanceIdentifier<Ingress> id,
+ @Nonnull final Ingress readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id), readValue);
+ }
+
+ static InstanceIdentifier<Ingress> getCfgId(
+ final InstanceIdentifier<Ingress> id) {
+ return SubInterfaceCustomizer.getCfgId(RWUtils.cutId(id, SubInterface.class))
+ .child(Acl.class)
+ .child(Ingress.class);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java
new file mode 100644
index 000000000..4a577ae60
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java
@@ -0,0 +1,166 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingListReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.IdentifierCacheKeyFactory;
+import io.fd.hc2vpp.v3po.interfacesstate.InterfaceCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.ip.dump.params.AddressDumpParams;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.IpAddressDetails;
+import io.fd.vpp.jvpp.core.dto.IpAddressDetailsReplyDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+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.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1;
+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.Subnet;
+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;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Read customizer for interface Ipv4 addresses.
+ */
+public class Ipv4AddressCustomizer extends FutureJVppCustomizer
+ implements InitializingListReaderCustomizer<Address, AddressKey, AddressBuilder>, Ipv4Reader {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class);
+ private static final String CACHE_KEY = Ipv4AddressCustomizer.class.getName();
+
+ private final NamingContext interfaceContext;
+ private final DumpCacheManager<IpAddressDetailsReplyDump, AddressDumpParams> dumpManager;
+
+ public Ipv4AddressCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJVppCore);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.dumpManager =
+ new DumpCacheManager.DumpCacheManagerBuilder<IpAddressDetailsReplyDump, AddressDumpParams>()
+ .withExecutor(createExecutor(futureJVppCore))
+ // Key needs to contain interface ID to distinguish dumps between interfaces
+ .withCacheKeyFactory(new IdentifierCacheKeyFactory(ImmutableSet.of(Interface.class)))
+ .build();
+ }
+
+ @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 interface address: {}", id);
+
+ final String interfaceName = id.firstKeyOf(Interface.class).getName();
+ final int interfaceIndex = interfaceContext.getIndex(interfaceName, ctx.getMappingContext());
+ final Optional<IpAddressDetailsReplyDump> dumpOptional =
+ dumpManager.getDump(id, ctx.getModificationCache(), new AddressDumpParams(interfaceIndex, false));
+
+ if (!dumpOptional.isPresent() || dumpOptional.get().ipAddressDetails.isEmpty()) {
+ return;
+ }
+ final Optional<IpAddressDetails> ipAddressDetails =
+ findIpAddressDetailsByIp(dumpOptional, id.firstKeyOf(Address.class).getIp());
+
+ if (ipAddressDetails.isPresent()) {
+ final IpAddressDetails detail = ipAddressDetails.get();
+ builder.setIp(arrayToIpv4AddressNoZone(detail.ip))
+ .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 ctx)
+ throws ReadFailedException {
+ 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 =
+ dumpManager.getDump(id, ctx.getModificationCache(), new AddressDumpParams(interfaceIndex, false));
+
+ return getAllIpv4AddressIds(dumpOptional, AddressKey::new);
+ }
+
+ @Override
+ public void merge(@Nonnull Builder<? extends DataObject> builder, @Nonnull List<Address> readData) {
+ ((Ipv4Builder) builder).setAddress(readData);
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address> init(
+ @Nonnull final InstanceIdentifier<Address> id, @Nonnull final Address readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder()
+ .setIp(readValue.getIp())
+ .setSubnet(getSubnet(readValue))
+ .build());
+ }
+
+ private static Subnet getSubnet(final Address address) {
+ final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.Subnet
+ subnet = address.getSubnet();
+
+ // Only prefix length supported
+ Preconditions.checkArgument(
+ subnet instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLength);
+
+ return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder()
+ .setPrefixLength(
+ ((org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLength) subnet)
+ .getPrefixLength()).build();
+ }
+
+ static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address> getCfgId(
+ final InstanceIdentifier<Address> id) {
+ return InterfaceCustomizer.getCfgId(RWUtils.cutId(id, Interface.class))
+ .augmentation(Interface1.class)
+ .child(Ipv4.class)
+ .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address.class,
+ new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressKey(id.firstKeyOf(Address.class).getIp()));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4Customizer.java
new file mode 100644
index 000000000..316f8ec47
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4Customizer.java
@@ -0,0 +1,59 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate.ip;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder;
+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.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Ipv4Customizer extends FutureJVppCustomizer implements ReaderCustomizer<Ipv4, Ipv4Builder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4Customizer.class);
+
+ public Ipv4Customizer(@Nonnull final FutureJVppCore futureJVppCore) {
+ super(futureJVppCore);
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Ipv4 readValue) {
+ ((Interface2Builder) parentBuilder).setIpv4(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public Ipv4Builder getBuilder(@Nonnull final InstanceIdentifier<Ipv4> id) {
+ return new Ipv4Builder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id, @Nonnull final Ipv4Builder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading Ipv4 leaves (mtu, forwarding) is not supported by VPP API");
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java
new file mode 100644
index 000000000..a32f8f20c
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java
@@ -0,0 +1,73 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate.ip;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Collections;
+import java.util.List;
+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.Neighbor;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.NeighborBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.NeighborKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Operational data read operation customizer for {@link Neighbor}<br>
+ * Currently not supported in jvpp, so this is only dummy implementation<br>
+ */
+public class Ipv4NeighbourCustomizer extends FutureJVppCustomizer
+ implements ListReaderCustomizer<Neighbor, NeighborKey, NeighborBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv4NeighbourCustomizer.class);
+
+ public Ipv4NeighbourCustomizer(FutureJVppCore futureJVppCore) {
+ super(futureJVppCore);
+ }
+
+ @Override
+ public NeighborBuilder getBuilder(InstanceIdentifier<Neighbor> id) {
+ return new NeighborBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(InstanceIdentifier<Neighbor> id, NeighborBuilder builder, ReadContext ctx)
+ throws ReadFailedException {
+ //TODO - not supported, implement https://jira.fd.io/browse/VPP-164 first + implement init
+ LOG.warn("Operation not supported");
+ }
+
+ @Override
+ public List<NeighborKey> getAllIds(InstanceIdentifier<Neighbor> id, ReadContext context)
+ throws ReadFailedException {
+ //TODO - not supported, implement https://jira.fd.io/browse/VPP-164 first
+ LOG.warn("Operation not supported,returning empty List");
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void merge(Builder<? extends DataObject> builder, List<Neighbor> readData) {
+ ((Ipv4Builder) builder).setNeighbor(readData);
+ }
+} \ No newline at end of file
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4Reader.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4Reader.java
new file mode 100644
index 000000000..729ca097d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv4Reader.java
@@ -0,0 +1,84 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.hc2vpp.v3po.interfacesstate.ip.dump.params.AddressDumpParams;
+import io.fd.hc2vpp.common.translate.util.Ipv4Translator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.vpp.jvpp.core.dto.IpAddressDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+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 io.fd.vpp.jvpp.core.dto.IpAddressDetails;
+import io.fd.vpp.jvpp.core.dto.IpAddressDetailsReplyDump;
+
+/**
+ * Utility class providing Ipv4 read support.
+ */
+interface Ipv4Reader extends Ipv4Translator, JvppReplyConsumer {
+
+ @Nonnull
+ default <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(arrayToIpv4AddressNoZone(detail.ip)))
+ .collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ default 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(arrayToIpv4AddressNoZone(singleDetail.ip)))
+ .collect(RWUtils.singleItemCollector()));
+ }
+ return Optional.absent();
+ }
+
+ default EntityDumpExecutor<IpAddressDetailsReplyDump, AddressDumpParams> createExecutor(
+ @Nonnull final FutureJVppCore vppApi) {
+ return (identifier, params) -> {
+ checkNotNull(params, "Address dump params cannot be null");
+
+ final IpAddressDump dumpRequest = new IpAddressDump();
+ dumpRequest.isIpv6 = booleanToByte(params.isIpv6());
+ dumpRequest.swIfIndex = params.getInterfaceIndex();
+
+ return getReplyForRead(vppApi.ipAddressDump(dumpRequest).toCompletableFuture(), identifier);
+ };
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv6Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv6Customizer.java
new file mode 100644
index 000000000..97f223a8c
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/Ipv6Customizer.java
@@ -0,0 +1,66 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate.ip;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6Builder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+
+public class Ipv6Customizer extends FutureJVppCustomizer implements ReaderCustomizer<Ipv6, Ipv6Builder> {
+
+ private final NamingContext interfaceContext;
+
+ public Ipv6Customizer(@Nonnull final FutureJVppCore futureJVppCore, final NamingContext interfaceContext) {
+ super(futureJVppCore);
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Ipv6 readValue) {
+ ((Interface2Builder) parentBuilder).setIpv6(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public Ipv6Builder getBuilder(@Nonnull final InstanceIdentifier<Ipv6> id) {
+ return new Ipv6Builder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv6> id, @Nonnull final Ipv6Builder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ // TODO HONEYCOMB-102 implement + init
+// final IpAddressDump dumpRequest = new IpAddressDump();
+// dumpRequest.isIpv6 = 1;
+// dumpRequest.swIfIndex = interfaceContext.getIndex(id.firstKeyOf(Interface.class).getName(),
+// ctx.getMappingContext());
+// final CompletionStage<IpAddressDetailsReplyDump> addressDumpFuture = getFutureJVpp().
+// ipAddressDump(dumpRequest);
+// final IpAddressDetailsReplyDump reply = TranslateUtils.getReply(addressDumpFuture.toCompletableFuture());
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java
new file mode 100644
index 000000000..eee49799b
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java
@@ -0,0 +1,143 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate.ip;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import io.fd.hc2vpp.v3po.interfacesstate.SubInterfaceCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.ip.dump.params.AddressDumpParams;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingListReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.IdentifierCacheKeyFactory;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.vpp.jvpp.core.dto.IpAddressDetails;
+import io.fd.vpp.jvpp.core.dto.IpAddressDetailsReplyDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+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.rev161214.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.ipv4.AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.ipv4.AddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Read customizer for sub-interface Ipv4 addresses.
+ */
+public class SubInterfaceIpv4AddressCustomizer extends FutureJVppCustomizer
+ implements InitializingListReaderCustomizer<Address, AddressKey, AddressBuilder>, Ipv4Reader {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIpv4AddressCustomizer.class);
+
+ private final NamingContext interfaceContext;
+ private final DumpCacheManager<IpAddressDetailsReplyDump, AddressDumpParams> dumpManager;
+
+ public SubInterfaceIpv4AddressCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJVppCore);
+ this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
+ this.dumpManager = new DumpCacheManager.DumpCacheManagerBuilder<IpAddressDetailsReplyDump, AddressDumpParams>()
+ .withExecutor(createExecutor(futureJVppCore))
+ //same as with ipv4 addresses for interfaces, these must have cache scope of their parent sub-interface
+ .withCacheKeyFactory(new IdentifierCacheKeyFactory(ImmutableSet.of(SubInterface.class)))
+ .build();
+ }
+
+ @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 = dumpManager
+ .getDump(id, ctx.getModificationCache(), new AddressDumpParams(subInterfaceIndex, false));
+
+ final Optional<IpAddressDetails> ipAddressDetails =
+ findIpAddressDetailsByIp(dumpOptional, id.firstKeyOf(Address.class).getIp());
+
+ if (ipAddressDetails.isPresent()) {
+ final IpAddressDetails detail = ipAddressDetails.get();
+ builder.setIp(arrayToIpv4AddressNoZone(detail.ip));
+ builder.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 = dumpManager
+ .getDump(id, ctx.getModificationCache(), new AddressDumpParams(subInterfaceIndex, false));
+
+ 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()));
+ }
+
+ @Override
+ public Initialized<Address> init(
+ @Nonnull final InstanceIdentifier<Address> id, @Nonnull final Address readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id), readValue);
+ }
+
+ private InstanceIdentifier<Address> getCfgId(final InstanceIdentifier<Address> id) {
+ return SubInterfaceCustomizer.getCfgId(RWUtils.cutId(id, SubInterface.class))
+ .child(Ipv4.class)
+ .child(Address.class, new AddressKey(id.firstKeyOf(Address.class)));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/dump/params/AddressDumpParams.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/dump/params/AddressDumpParams.java
new file mode 100644
index 000000000..cb80893be
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/ip/dump/params/AddressDumpParams.java
@@ -0,0 +1,44 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate.ip.dump.params;
+
+public class AddressDumpParams {
+
+ private final int interfaceIndex;
+ private final boolean isIpv6;
+
+ public AddressDumpParams(final int interfaceIndex, final boolean isIpv6) {
+ this.interfaceIndex = interfaceIndex;
+ this.isIpv6 = isIpv6;
+ }
+
+ public int getInterfaceIndex() {
+ return interfaceIndex;
+ }
+
+ public boolean isIpv6() {
+ return isIpv6;
+ }
+
+ @Override
+ public String toString() {
+ return "AddressDumpParams{" +
+ "interfaceIndex=" + interfaceIndex +
+ ", isIpv6=" + isIpv6 +
+ '}';
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/pbb/PbbRewriteStateCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/pbb/PbbRewriteStateCustomizer.java
new file mode 100644
index 000000000..4d560a55b
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/interfacesstate/pbb/PbbRewriteStateCustomizer.java
@@ -0,0 +1,57 @@
+/*
+ * 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.hc2vpp.v3po.interfacesstate.pbb;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.pbb.rev161214.PbbRewriteStateInterfaceAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.pbb.rev161214.interfaces.state._interface.PbbRewriteState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.pbb.rev161214.interfaces.state._interface.PbbRewriteStateBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class PbbRewriteStateCustomizer extends FutureJVppCustomizer
+ implements ReaderCustomizer<PbbRewriteState, PbbRewriteStateBuilder> {
+
+ public PbbRewriteStateCustomizer(@Nonnull final FutureJVppCore futureJVppCore) {
+ super(futureJVppCore);
+ }
+
+ @Nonnull
+ @Override
+ public PbbRewriteStateBuilder getBuilder(@Nonnull final InstanceIdentifier<PbbRewriteState> id) {
+ return new PbbRewriteStateBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<PbbRewriteState> id,
+ @Nonnull final PbbRewriteStateBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ //TODO implement read after https://jira.fd.io/browse/VPP-468 + init
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder,
+ @Nonnull final PbbRewriteState readValue) {
+ ((PbbRewriteStateInterfaceAugmentationBuilder) parentBuilder).setPbbRewriteState(readValue);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/notification/InterfaceChangeNotificationProducer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/notification/InterfaceChangeNotificationProducer.java
new file mode 100644
index 000000000..f7a159de7
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/notification/InterfaceChangeNotificationProducer.java
@@ -0,0 +1,163 @@
+/*
+ * 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.hc2vpp.v3po.notification;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.honeycomb.notification.ManagedNotificationProducer;
+import io.fd.honeycomb.notification.NotificationCollector;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.TimeoutException;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.InterfaceDeleted;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.InterfaceDeletedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.InterfaceNameOrIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.InterfaceStateChange;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.InterfaceStateChangeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.InterfaceStatus;
+import org.opendaylight.yangtools.yang.binding.Notification;
+import io.fd.vpp.jvpp.VppBaseCallException;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceSetFlagsNotification;
+import io.fd.vpp.jvpp.core.dto.WantInterfaceEvents;
+import io.fd.vpp.jvpp.core.dto.WantInterfaceEventsReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Notification producer for interface events. It starts interface notification stream and for every
+ * received notification, it transforms it into its BA equivalent and pushes into HC's notification collector.
+ */
+@NotThreadSafe
+public final class InterfaceChangeNotificationProducer implements ManagedNotificationProducer, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceChangeNotificationProducer.class);
+
+ private final FutureJVppCore jvpp;
+ private final NamingContext interfaceContext;
+ private final MappingContext mappingContext;
+ @Nullable
+ private AutoCloseable notificationListenerReg;
+
+ @Inject
+ public InterfaceChangeNotificationProducer(@Nonnull final FutureJVppCore jvpp,
+ @Named("interface-context") @Nonnull final NamingContext interfaceContext,
+ @Named("honeycomb-context") @Nonnull final MappingContext mappingContext) {
+ this.jvpp = jvpp;
+ this.interfaceContext = interfaceContext;
+ this.mappingContext = mappingContext;
+ }
+
+ @Override
+ public void start(final NotificationCollector collector) {
+ LOG.trace("Starting interface notifications");
+ enableDisableIfcNotifications(1);
+ LOG.debug("Interface notifications started successfully");
+ notificationListenerReg = jvpp.getNotificationRegistry().registerSwInterfaceSetFlagsNotificationCallback(
+ swInterfaceSetFlagsNotification -> {
+ LOG.trace("Interface notification received: {}", swInterfaceSetFlagsNotification);
+ // TODO HONEYCOMB-166 this should be lazy
+ collector.onNotification(transformNotification(swInterfaceSetFlagsNotification));
+ }
+ );
+ }
+
+ private Notification transformNotification(final SwInterfaceSetFlagsNotification swInterfaceSetFlagsNotification) {
+ if (swInterfaceSetFlagsNotification.deleted == 1) {
+ return new InterfaceDeletedBuilder().setName(getIfcName(swInterfaceSetFlagsNotification)).build();
+ } else {
+ return new InterfaceStateChangeBuilder()
+ .setName(getIfcName(swInterfaceSetFlagsNotification))
+ .setAdminStatus(swInterfaceSetFlagsNotification.adminUpDown == 1
+ ? InterfaceStatus.Up
+ : InterfaceStatus.Down)
+ .setOperStatus(swInterfaceSetFlagsNotification.linkUpDown == 1
+ ? InterfaceStatus.Up
+ : InterfaceStatus.Down)
+ .build();
+ }
+ }
+
+ /**
+ * Get mapped name for the interface. Best effort only! The mapping might not yet be stored in context
+ * data tree (write transaction is still in progress and context changes have not been committed yet, or
+ * VPP sends the notification before it returns create request(that would store mapping)).
+ * <p/>
+ * In case mapping is not available, index is used as name.
+ */
+ private InterfaceNameOrIndex getIfcName(final SwInterfaceSetFlagsNotification swInterfaceSetFlagsNotification) {
+ final Optional<String> optionalName =
+ interfaceContext.getNameIfPresent(swInterfaceSetFlagsNotification.swIfIndex, mappingContext);
+ return optionalName.isPresent()
+ ? new InterfaceNameOrIndex(optionalName.get())
+ : new InterfaceNameOrIndex((long) swInterfaceSetFlagsNotification.swIfIndex);
+ }
+
+ @Override
+ public void stop() {
+ LOG.trace("Stopping interface notifications");
+ enableDisableIfcNotifications(0);
+ LOG.debug("Interface notifications stopped successfully");
+ try {
+ if (notificationListenerReg != null) {
+ notificationListenerReg.close();
+ }
+ } catch (Exception e) {
+ LOG.warn("Unable to properly close notification registration: {}", notificationListenerReg, e);
+ }
+ }
+
+ private void enableDisableIfcNotifications(int enableDisable) {
+ final WantInterfaceEvents wantInterfaceEvents = new WantInterfaceEvents();
+ wantInterfaceEvents.pid = 1;
+ wantInterfaceEvents.enableDisable = enableDisable;
+ final CompletionStage<WantInterfaceEventsReply> wantInterfaceEventsReplyCompletionStage;
+ try {
+ wantInterfaceEventsReplyCompletionStage = jvpp.wantInterfaceEvents(wantInterfaceEvents);
+ getReply(wantInterfaceEventsReplyCompletionStage.toCompletableFuture());
+ } catch (VppBaseCallException | TimeoutException e) {
+ LOG.warn("Unable to {} interface notifications", enableDisable == 1
+ ? "enable"
+ : "disable", e);
+ throw new IllegalStateException("Unable to control interface notifications", e);
+ }
+ }
+
+ @Nonnull
+ @Override
+ public Collection<Class<? extends Notification>> getNotificationTypes() {
+ final ArrayList<Class<? extends Notification>> classes = Lists.newArrayList();
+ classes.add(InterfaceStateChange.class);
+ classes.add(InterfaceDeleted.class);
+ return classes;
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.trace("Closing interface notifications producer");
+ stop();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/util/SubInterfaceUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/util/SubInterfaceUtils.java
new file mode 100644
index 000000000..cb4e11af5
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/util/SubInterfaceUtils.java
@@ -0,0 +1,52 @@
+/*
+ * 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.hc2vpp.v3po.util;
+
+import java.util.List;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.Tags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.tags.Tag;
+
+public final class SubInterfaceUtils {
+
+ private SubInterfaceUtils() {
+ throw new UnsupportedOperationException("Utility class cannot be instantiated.");
+ }
+
+ public static String getSubInterfaceName(final String superIfName, final int subIfaceId) {
+ return String.format("%s.%d", superIfName, subIfaceId);
+ }
+
+ /**
+ * Returns number of sub-interface tags.
+ *
+ * @param tags data object that represents sub-interface tags
+ * @return number of sub interface tags
+ */
+ @Nonnegative
+ public static int getNumberOfTags(@Nullable final Tags tags) {
+ if (tags == null) {
+ return 0;
+ }
+ final List<Tag> tagList = tags.getTag();
+ if (tagList == null) {
+ return 0;
+ }
+ return tagList.size();
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vpp/ArpTerminationTableEntryCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vpp/ArpTerminationTableEntryCustomizer.java
new file mode 100644
index 000000000..e7c1dea3d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vpp/ArpTerminationTableEntryCustomizer.java
@@ -0,0 +1,118 @@
+/*
+ * 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.hc2vpp.v3po.vpp;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.AddressTranslator;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.BdIpMacAddDel;
+import io.fd.vpp.jvpp.core.dto.BdIpMacAddDelReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.bridge.domain.attributes.arp.termination.table.ArpTerminationTableEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.bridge.domain.attributes.arp.termination.table.ArpTerminationTableEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer Customizer responsible for ARP termination table management.<br> Sends {@code bd_ip_mac_add_del} message to
+ * VPP.<br> Equivalent of invoking {@code vppctl set bridge-domain arp term} command.
+ */
+public class ArpTerminationTableEntryCustomizer extends FutureJVppCustomizer
+ implements ListWriterCustomizer<ArpTerminationTableEntry, ArpTerminationTableEntryKey>, ByteDataTranslator,
+ AddressTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ArpTerminationTableEntryCustomizer.class);
+
+ private final NamingContext bdContext;
+
+ public ArpTerminationTableEntryCustomizer(@Nonnull final FutureJVppCore futureJvpp,
+ @Nonnull final NamingContext bdContext) {
+ super(futureJvpp);
+ this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<ArpTerminationTableEntry> id,
+ @Nonnull final ArpTerminationTableEntry dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Creating ARP termination table entry: {} {}", id, dataAfter);
+ bdIpMacAddDel(id, dataAfter, writeContext, true);
+ LOG.debug("L2 ARP termination table entry created successfully: {} {}", id, dataAfter);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<ArpTerminationTableEntry> id,
+ @Nonnull final ArpTerminationTableEntry dataBefore,
+ @Nonnull final ArpTerminationTableEntry dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ throw new UnsupportedOperationException(
+ "ARP termination table entry update is not supported. It has to be deleted and then created.");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<ArpTerminationTableEntry> id,
+ @Nonnull final ArpTerminationTableEntry dataBefore,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Deleting ARP termination table entry entry: {} {}", id, dataBefore);
+ bdIpMacAddDel(id, dataBefore, writeContext, false);
+ LOG.debug("ARP termination table entry deleted successfully: {} {}", id, dataBefore);
+ }
+
+ private void bdIpMacAddDel(@Nonnull final InstanceIdentifier<ArpTerminationTableEntry> id,
+ @Nonnull final ArpTerminationTableEntry entry,
+ final WriteContext writeContext, boolean isAdd) throws WriteFailedException {
+ final String bdName = id.firstKeyOf(BridgeDomain.class).getName();
+ final int bdId = bdContext.getIndex(bdName, writeContext.getMappingContext());
+
+ final BdIpMacAddDel request = createRequest(entry, bdId, isAdd);
+ LOG.debug("Sending l2FibAddDel request: {}", request);
+ final CompletionStage<BdIpMacAddDelReply> replyCompletionStage =
+ getFutureJVpp().bdIpMacAddDel(request);
+
+ getReplyForWrite(replyCompletionStage.toCompletableFuture(), id);
+ }
+
+ private BdIpMacAddDel createRequest(final ArpTerminationTableEntry entry, final int bdId, boolean isAdd) {
+ final BdIpMacAddDel request = new BdIpMacAddDel();
+ request.bdId = bdId;
+ request.isAdd = booleanToByte(isAdd);
+ request.macAddress = parseMac(entry.getPhysAddress().getValue());
+
+ final IpAddress ipAddress = entry.getIpAddress();
+ if (ipAddress.getIpv6Address() != null) {
+ // FIXME: HONEYCOMB-187 vpp does not support ipv6 in arp-termination table (based on analysis of l2_bd.c)
+ throw new UnsupportedOperationException("IPv6 address for ARP termination table is not supported yet");
+ }
+
+ request.ipAddress = ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(ipAddress.getIpv4Address()));
+ return request;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vpp/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vpp/BridgeDomainCustomizer.java
new file mode 100644
index 000000000..b4b86264b
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vpp/BridgeDomainCustomizer.java
@@ -0,0 +1,137 @@
+/*
+ * 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.hc2vpp.v3po.vpp;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Preconditions;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.BridgeDomainAddDel;
+import io.fd.vpp.jvpp.core.dto.BridgeDomainAddDelReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.bridge.domains.BridgeDomainKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BridgeDomainCustomizer
+ extends FutureJVppCustomizer
+ implements ListWriterCustomizer<BridgeDomain, BridgeDomainKey>, ByteDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class);
+
+ private static final byte ADD_OR_UPDATE_BD = (byte) 1;
+ private final NamingContext bdContext;
+ @GuardedBy("this")
+ private int bridgeDomainIndexCounter = 1;
+
+ public BridgeDomainCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext bdContext) {
+ super(futureJVppCore);
+ this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null");
+ }
+
+ private BridgeDomainAddDelReply addOrUpdateBridgeDomain(@Nonnull final InstanceIdentifier<BridgeDomain> id,
+ final int bdId, @Nonnull final BridgeDomain bd)
+ throws WriteFailedException {
+ final BridgeDomainAddDelReply reply;
+ final BridgeDomainAddDel request = new BridgeDomainAddDel();
+ request.bdId = bdId;
+ request.flood = booleanToByte(bd.isFlood());
+ request.forward = booleanToByte(bd.isForward());
+ request.learn = booleanToByte(bd.isLearn());
+ request.uuFlood = booleanToByte(bd.isUnknownUnicastFlood());
+ request.arpTerm = booleanToByte(bd.isArpTermination());
+ request.isAdd = ADD_OR_UPDATE_BD;
+
+ reply = getReplyForWrite(getFutureJVpp().bridgeDomainAddDel(request).toCompletableFuture(), id);
+ LOG.debug("Bridge domain {} (id={}) add/update successful", bd.getName(), bdId);
+ return reply;
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<BridgeDomain> id,
+ @Nonnull final BridgeDomain dataBefore,
+ @Nonnull final WriteContext ctx)
+ throws WriteFailedException {
+ LOG.debug("writeCurrentAttributes: id={}, current={}, ctx={}", id, dataBefore, ctx);
+ final String bdName = dataBefore.getName();
+
+ // Invoke 1. check index, 2. increase index 3. create ND 4. store mapping in a synchronized block to prevent
+ // race conditions in case of concurrent invocation
+ synchronized (this) {
+ int index;
+ if (bdContext.containsIndex(bdName, ctx.getMappingContext())) {
+ index = bdContext.getIndex(bdName, ctx.getMappingContext());
+ } else {
+ // Critical section due to bridgeDomainIndexCounter read and write access
+ // TODO HONEYCOMB-199 move this "get next available index" into naming context or an adapter
+ // or a dedicated object
+
+ // Use counter to assign bridge domain index, but still check naming context if it's not taken there
+ while (bdContext.containsName(bridgeDomainIndexCounter, ctx.getMappingContext())) {
+ bridgeDomainIndexCounter++;
+ }
+ index = bridgeDomainIndexCounter;
+ }
+ addOrUpdateBridgeDomain(id, index, dataBefore);
+ bdContext.addName(index, bdName, ctx.getMappingContext());
+ }
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<BridgeDomain> id,
+ @Nonnull final BridgeDomain dataBefore,
+ @Nonnull final WriteContext ctx)
+ throws WriteFailedException {
+ LOG.debug("deleteCurrentAttributes: id={}, dataBefore={}, ctx={}", id, dataBefore, ctx);
+ final String bdName = id.firstKeyOf(BridgeDomain.class).getName();
+ int bdId = bdContext.getIndex(bdName, ctx.getMappingContext());
+
+ final BridgeDomainAddDel request = new BridgeDomainAddDel();
+ request.bdId = bdId;
+
+ getReplyForWrite(getFutureJVpp().bridgeDomainAddDel(request).toCompletableFuture(), id);
+ LOG.debug("Bridge domain {} (id={}) deleted successfully", bdName, bdId);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<BridgeDomain> id,
+ @Nonnull final BridgeDomain dataBefore, @Nonnull final BridgeDomain dataAfter,
+ @Nonnull final WriteContext ctx)
+ throws WriteFailedException {
+ LOG.debug("updateCurrentAttributes: id={}, dataBefore={}, dataAfter={}, ctx={}", id, dataBefore, dataAfter,
+ ctx);
+
+ final String bdName = checkNotNull(dataAfter.getName());
+ checkArgument(bdName.equals(dataBefore.getName()),
+ "BridgeDomain name changed. It should be deleted and then created.");
+
+ addOrUpdateBridgeDomain(id, bdContext.getIndex(bdName, ctx.getMappingContext()), dataAfter);
+ }
+
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vpp/L2FibEntryCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vpp/L2FibEntryCustomizer.java
new file mode 100644
index 000000000..6328555a3
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vpp/L2FibEntryCustomizer.java
@@ -0,0 +1,129 @@
+/*
+ * 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.hc2vpp.v3po.vpp;
+
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.Longs;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.MacTranslator;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.L2FibAddDel;
+import io.fd.vpp.jvpp.core.dto.L2FibAddDelReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.L2FibFilter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.fib.attributes.l2.fib.table.L2FibEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.fib.attributes.l2.fib.table.L2FibEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer Customizer responsible for L2 FIB create/delete operations.<br> Sends {@code l2_fib_add_del} message to
+ * VPP.<br> Equivalent of invoking {@code vppctl l2fib add/del} command.
+ */
+public class L2FibEntryCustomizer extends FutureJVppCustomizer
+ implements ListWriterCustomizer<L2FibEntry, L2FibEntryKey>, ByteDataTranslator, MacTranslator,
+ JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(L2FibEntryCustomizer.class);
+
+ private final NamingContext bdContext;
+ private final NamingContext interfaceContext;
+
+ public L2FibEntryCustomizer(@Nonnull final FutureJVppCore futureJVppCore, @Nonnull final NamingContext bdContext,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJVppCore);
+ this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null");
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<L2FibEntry> id,
+ @Nonnull final L2FibEntry dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ LOG.debug("Creating L2 FIB entry: {} {}", id, dataAfter);
+ l2FibAddDel(id, dataAfter, writeContext, true);
+ LOG.debug("L2 FIB entry created successfully: {} {}", id, dataAfter);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<L2FibEntry> id,
+ @Nonnull final L2FibEntry dataBefore, @Nonnull final L2FibEntry dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ throw new UnsupportedOperationException(
+ "L2 FIB entry update is not supported. It has to be deleted and then created.");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<L2FibEntry> id,
+ @Nonnull final L2FibEntry dataBefore, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+
+ LOG.debug("Deleting L2 FIB entry: {} {}", id, dataBefore);
+ l2FibAddDel(id, dataBefore, writeContext, false);
+ LOG.debug("L2 FIB entry deleted successfully: {} {}", id, dataBefore);
+ }
+
+ private void l2FibAddDel(@Nonnull final InstanceIdentifier<L2FibEntry> id, @Nonnull final L2FibEntry entry,
+ final WriteContext writeContext, boolean isAdd) throws WriteFailedException {
+ final String bdName = id.firstKeyOf(BridgeDomain.class).getName();
+ final int bdId = bdContext.getIndex(bdName, writeContext.getMappingContext());
+
+ int swIfIndex = -1;
+ final String swIfName = entry.getOutgoingInterface();
+ if (swIfName != null) {
+ swIfIndex = interfaceContext.getIndex(swIfName, writeContext.getMappingContext());
+ }
+
+ final L2FibAddDel l2FibRequest = createL2FibRequest(entry, bdId, swIfIndex, isAdd);
+ LOG.debug("Sending l2FibAddDel request: {}", l2FibRequest);
+ final CompletionStage<L2FibAddDelReply> l2FibAddDelReplyCompletionStage =
+ getFutureJVpp().l2FibAddDel(l2FibRequest);
+
+ getReplyForWrite(l2FibAddDelReplyCompletionStage.toCompletableFuture(), id);
+ }
+
+ private L2FibAddDel createL2FibRequest(final L2FibEntry entry, final int bdId, final int swIfIndex, boolean isAdd) {
+ final L2FibAddDel request = new L2FibAddDel();
+ request.mac = macToLong(entry.getPhysAddress().getValue());
+ request.bdId = bdId;
+ request.swIfIndex = swIfIndex;
+ request.isAdd = booleanToByte(isAdd);
+ if (isAdd) {
+ request.staticMac = booleanToByte(entry.isStaticConfig());
+ request.filterMac = booleanToByte(L2FibFilter.class == entry.getAction());
+ }
+ return request;
+ }
+
+ // mac address is string of the form: 11:22:33:44:55:66
+ // but VPP expects long value in the format 11:22:33:44:55:66:XX:XX
+ private long macToLong(final String macAddress) {
+ final byte[] mac = parseMac(macAddress);
+ return Longs.fromBytes(mac[0], mac[1], mac[2], mac[3],
+ mac[4], mac[5], (byte) 0, (byte) 0);
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifySessionReader.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifySessionReader.java
new file mode 100644
index 000000000..daaa88c56
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifySessionReader.java
@@ -0,0 +1,207 @@
+/*
+ * 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.hc2vpp.v3po.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Optional;
+import com.google.common.primitives.UnsignedInts;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.InterfaceDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.vpp.jvpp.core.dto.ClassifySessionDetails;
+import io.fd.vpp.jvpp.core.dto.ClassifySessionDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.ClassifySessionDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.xml.bind.DatatypeConverter;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.OpaqueIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySessionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySessionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTableKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Reader customizer responsible for classify session read.<br> to VPP.<br> Equivalent to invoking {@code vppctl show
+ * class table verbose} command.
+ */
+public class ClassifySessionReader extends FutureJVppCustomizer
+ implements ListReaderCustomizer<ClassifySession, ClassifySessionKey, ClassifySessionBuilder>,
+ InterfaceDataTranslator, VppNodeReader, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionReader.class);
+ static final String CACHE_KEY = ClassifySessionReader.class.getName();
+
+ private final VppClassifierContextManager classifyTableContext;
+
+ public ClassifySessionReader(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(futureJVppCore);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<ClassifySession> readData) {
+ ((ClassifyTableBuilder) builder).setClassifySession(readData);
+ }
+
+ @Nonnull
+ @Override
+ public ClassifySessionBuilder getBuilder(@Nonnull final InstanceIdentifier<ClassifySession> id) {
+ return new ClassifySessionBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySessionBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ LOG.debug("Reading attributes for classify session: {}", id);
+
+ final ClassifySessionKey key = id.firstKeyOf(ClassifySession.class);
+ checkArgument(key != null, "could not find ClassifySession key in {}", id);
+
+ final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx);
+ final byte[] match = DatatypeConverter.parseHexBinary(key.getMatch().getValue().replace(":", ""));
+ final Optional<ClassifySessionDetails> classifySession =
+ findClassifySessionDetailsByMatch(classifySessionDump, match);
+
+ if (classifySession.isPresent()) {
+ final ClassifySessionDetails detail = classifySession.get();
+ builder.setHitNext(
+ readVppNode(detail.tableId, detail.hitNextIndex, classifyTableContext, ctx.getMappingContext(), LOG)
+ .get());
+ if (detail.opaqueIndex != ~0) {
+ // value is specified:
+ builder.setOpaqueIndex(readOpaqueIndex(detail.tableId, detail.opaqueIndex, ctx.getMappingContext()));
+ }
+ builder.setAdvance(detail.advance);
+ builder.setMatch(key.getMatch());
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for classify session {} successfully read: {}", id, builder.build());
+ }
+ }
+ }
+
+ private OpaqueIndex readOpaqueIndex(final int tableIndex, final int opaqueIndex, final MappingContext ctx) {
+ // We first try to map the value to a vpp node, if that fails, simply wrap the u32 value
+ // TODO: HONEYCOMB-118 the approach might fail if the opaqueIndex contains small value that collides
+ // with some of the adjacent nodes
+
+ final Optional<VppNode> node = readVppNode(tableIndex, opaqueIndex, classifyTableContext, ctx, LOG);
+ if (node.isPresent()) {
+ return new OpaqueIndex(node.get());
+ } else {
+ return new OpaqueIndex(UnsignedInts.toLong(opaqueIndex));
+ }
+ }
+
+ @Nullable
+ private ClassifySessionDetailsReplyDump dumpClassifySessions(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class);
+ checkArgument(tableKey != null, "could not find ClassifyTable key in {}", id);
+
+ final String cacheKey = CACHE_KEY + tableKey;
+
+ ClassifySessionDetailsReplyDump classifySessionDump =
+ (ClassifySessionDetailsReplyDump) ctx.getModificationCache().get(cacheKey);
+ if (classifySessionDump != null) {
+ LOG.debug("Classify sessions is present in cache: {}", cacheKey);
+ return classifySessionDump;
+ }
+
+ final String tableName = tableKey.getName();
+ checkState(classifyTableContext.containsTable(tableName, ctx.getMappingContext()),
+ "Reading classify sessions for table {}, but table index could not be found in the classify table context",
+ tableName);
+ final int tableId = classifyTableContext.getTableIndex(tableName, ctx.getMappingContext());
+ LOG.debug("Dumping classify sessions for classify table id={}", tableId);
+
+
+ final ClassifySessionDump dumpRequest = new ClassifySessionDump();
+ dumpRequest.tableId = tableId;
+ final int timeOut = 30; // there can be many session with current ietf-acl implementation (could be probably
+ // removed after fixing HONEYCOMB-247)
+ classifySessionDump =
+ getReplyForRead(getFutureJVpp().classifySessionDump(dumpRequest).toCompletableFuture(), id, timeOut);
+
+ if (classifySessionDump != null) {
+ // update the cache:
+ ctx.getModificationCache().put(cacheKey, classifySessionDump);
+ }
+
+ return classifySessionDump;
+ }
+
+ private static Optional<ClassifySessionDetails> findClassifySessionDetailsByMatch(
+ @Nullable final ClassifySessionDetailsReplyDump classifySessionDump, @Nonnull final byte[] match) {
+ if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) {
+ final List<ClassifySessionDetails> details = classifySessionDump.classifySessionDetails;
+ final List<ClassifySessionDetails> filteredSessions = details.stream()
+ .filter(singleDetail -> Arrays.equals(singleDetail.match, match)).collect(Collectors.toList());
+ if (filteredSessions.isEmpty()) {
+ return Optional.absent();
+ } else if (filteredSessions.size() == 1) {
+ return Optional.of(filteredSessions.get(0));
+ } else {
+ throw new IllegalStateException(String.format(
+ "Found %d classify sessions witch given match. Single session expected.",
+ filteredSessions.size()));
+ }
+ }
+ return Optional.absent();
+ }
+
+ @Nonnull
+ @Override
+ public List<ClassifySessionKey> getAllIds(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("Reading list of keys for classify sessions: {}", id);
+
+ final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx);
+ if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) {
+ return classifySessionDump.classifySessionDetails.stream()
+ .map(detail -> new ClassifySessionKey(new HexString(printHexBinary(detail.match))))
+ .collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifySessionWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifySessionWriter.java
new file mode 100644
index 000000000..4e1a51265
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifySessionWriter.java
@@ -0,0 +1,165 @@
+/*
+ * 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.hc2vpp.v3po.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.xml.bind.DatatypeConverter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.OpaqueIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySession;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.classify.table.base.attributes.ClassifySessionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.VppBaseCallException;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSessionReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer customizer responsible for classify session create/delete.<br> Sends {@code classify_add_del_session} message
+ * to VPP.<br> Equivalent to invoking {@code vppctl classify table} command.
+ */
+public class ClassifySessionWriter extends VppNodeWriter
+ implements ListWriterCustomizer<ClassifySession, ClassifySessionKey>, ByteDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionWriter.class);
+ private final VppClassifierContextManager classifyTableContext;
+
+ public ClassifySessionWriter(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(futureJVppCore);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Creating classify session: iid={} dataAfter={}", id, dataAfter);
+ try {
+ classifyAddDelSession(true, id, dataAfter, writeContext);
+ LOG.debug("Successfully created classify session: iid={} dataAfter={}", id, dataAfter);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession dataBefore,
+ @Nonnull final ClassifySession dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ throw new UnsupportedOperationException("Classify session update is not supported");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Removing classify session: iid={} dataBefore={}", id, dataBefore);
+ try {
+ classifyAddDelSession(false, id, dataBefore, writeContext);
+ LOG.debug("Successfully removed classify session: iid={} dataBefore={}", id, dataBefore);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private void classifyAddDelSession(final boolean isAdd, @Nonnull final InstanceIdentifier<ClassifySession> id,
+ @Nonnull final ClassifySession classifySession,
+ @Nonnull final WriteContext writeContext)
+ throws VppBaseCallException, WriteFailedException {
+ final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class);
+ checkArgument(tableKey != null, "could not find classify table key in {}", id);
+
+ final String tableName = tableKey.getName();
+ checkState(classifyTableContext.containsTable(tableName, writeContext.getMappingContext()),
+ "Could not find classify table index for {} in the classify table context", tableName);
+ final int tableIndex = classifyTableContext.getTableIndex(tableName, writeContext.getMappingContext());
+
+ final ClassifyTable classifyTable =
+ getClassifyTable(writeContext, id.firstIdentifierOf(ClassifyTable.class), isAdd);
+ final int hitNextIndex = getNodeIndex(classifySession.getHitNext(), classifyTable, classifyTableContext,
+ writeContext.getMappingContext(), id);
+ final int opaqueIndex =
+ getOpaqueIndex(classifySession.getOpaqueIndex(), classifyTable, writeContext.getMappingContext(), id);
+
+ final CompletionStage<ClassifyAddDelSessionReply> createClassifyTableReplyCompletionStage = getFutureJVpp()
+ .classifyAddDelSession(
+ getClassifyAddDelSessionRequest(isAdd, classifySession, tableIndex, hitNextIndex, opaqueIndex));
+
+ getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
+ }
+
+ private ClassifyTable getClassifyTable(final WriteContext writeContext,
+ @Nonnull final InstanceIdentifier<ClassifyTable> id,
+ final boolean isAdd) {
+ final Optional<ClassifyTable> classifyTable;
+ if (isAdd) {
+ classifyTable = writeContext.readAfter(id);
+ } else {
+ classifyTable = writeContext.readBefore(id);
+ }
+ return classifyTable.get();
+ }
+
+ private ClassifyAddDelSession getClassifyAddDelSessionRequest(final boolean isAdd,
+ @Nonnull final ClassifySession classifySession,
+ final int tableIndex,
+ final int hitNextIndex,
+ final int opaqueIndex) {
+ ClassifyAddDelSession request = new ClassifyAddDelSession();
+ request.isAdd = booleanToByte(isAdd);
+ request.tableIndex = tableIndex;
+ request.hitNextIndex = hitNextIndex;
+ request.opaqueIndex = opaqueIndex;
+
+ // default 0:
+ request.advance = classifySession.getAdvance();
+
+ request.match = DatatypeConverter.parseHexBinary(classifySession.getMatch().getValue().replace(":", ""));
+ return request;
+ }
+
+ private int getOpaqueIndex(@Nullable final OpaqueIndex opaqueIndex, final ClassifyTable classifyTable,
+ final MappingContext ctx, final InstanceIdentifier<ClassifySession> id)
+ throws VppBaseCallException, WriteFailedException {
+ if (opaqueIndex == null) {
+ return ~0; // value not specified
+ }
+ if (opaqueIndex.getUint32() != null) {
+ return opaqueIndex.getUint32().intValue();
+ } else {
+ return getNodeIndex(opaqueIndex.getVppNode(), classifyTable, classifyTableContext, ctx, id);
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifyTableReader.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifyTableReader.java
new file mode 100644
index 000000000..fba5fb694
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifyTableReader.java
@@ -0,0 +1,171 @@
+/*
+ * 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.hc2vpp.v3po.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import com.google.common.primitives.UnsignedInts;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingListReaderCustomizer;
+import io.fd.hc2vpp.v3po.interfacesstate.InterfaceDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.MacTranslator;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableIds;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableIdsReply;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableInfo;
+import io.fd.vpp.jvpp.core.dto.ClassifyTableInfoReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Arrays;
+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.yang.types.rev130715.HexString;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppClassifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppClassifierStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.state.ClassifyTableKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Reader customizer responsible for classify table read.<br> to VPP.<br> Equivalent to invoking {@code vppctl show
+ * class table} command.
+ */
+public class ClassifyTableReader extends FutureJVppCustomizer
+ implements InitializingListReaderCustomizer<ClassifyTable, ClassifyTableKey, ClassifyTableBuilder>, VppNodeReader,
+ MacTranslator, InterfaceDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableReader.class);
+ private final VppClassifierContextManager classifyTableContext;
+
+ public ClassifyTableReader(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(futureJVppCore);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<ClassifyTable> readData) {
+ ((VppClassifierStateBuilder) builder).setClassifyTable(readData);
+ }
+
+ @Nonnull
+ @Override
+ public ClassifyTableBuilder getBuilder(@Nonnull final InstanceIdentifier<ClassifyTable> id) {
+ return new ClassifyTableBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTableBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ LOG.debug("Reading attributes for classify table: {}", id);
+
+ final ClassifyTableKey key = id.firstKeyOf(ClassifyTable.class);
+ checkArgument(key != null, "could not find ClassifyTable key in {}", id);
+ final ClassifyTableInfo request = new ClassifyTableInfo();
+
+ final String tableName = key.getName();
+ if (!classifyTableContext.containsTable(tableName, ctx.getMappingContext())) {
+ LOG.debug("Could not find classify table {} in the naming context", tableName);
+ return;
+ }
+ request.tableId = classifyTableContext.getTableIndex(tableName, ctx.getMappingContext());
+
+
+ final ClassifyTableInfoReply reply =
+ getReplyForRead(getFutureJVpp().classifyTableInfo(request).toCompletableFuture(), id);
+
+ // mandatory values:
+ builder.setName(tableName);
+ builder.setKey(key);
+ builder.setNbuckets(UnsignedInts.toLong(reply.nbuckets));
+ builder.setSkipNVectors(UnsignedInts.toLong(reply.skipNVectors));
+
+ // optional value read from context
+ final Optional<String> tableBaseNode =
+ classifyTableContext.getTableBaseNode(tableName, ctx.getMappingContext());
+ if (tableBaseNode.isPresent()) {
+ builder.setClassifierNode(new VppNodeName(tableBaseNode.get()));
+ }
+
+ builder.setMissNext(
+ readVppNode(reply.tableId, reply.missNextIndex, classifyTableContext, ctx.getMappingContext(), LOG)
+ .get());
+ builder.setMask(new HexString(printHexBinary(reply.mask)));
+ builder.setActiveSessions(UnsignedInts.toLong(reply.activeSessions));
+
+ if (reply.nextTableIndex != ~0) {
+ // next table index is present:
+ builder.setNextTable(classifyTableContext.getTableName(reply.nextTableIndex, ctx.getMappingContext()));
+ }
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Attributes for classify table {} successfully read: {}", id, builder.build());
+ }
+ }
+
+ @Nonnull
+ @Override
+ public List<ClassifyTableKey> getAllIds(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ LOG.debug("Reading list of keys for classify tables: {}", id);
+
+ final ClassifyTableIdsReply classifyTableIdsReply =
+ getReplyForRead(getFutureJVpp().classifyTableIds(new ClassifyTableIds()).toCompletableFuture(),
+ id);
+ if (classifyTableIdsReply.ids != null) {
+ return Arrays.stream(classifyTableIdsReply.ids).mapToObj(i -> {
+ final String tableName = classifyTableContext.getTableName(i, context.getMappingContext());
+ LOG.trace("Classify table with name: {} and index: {} found in VPP", tableName, i);
+ return new ClassifyTableKey(tableName);
+ }).collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable> init(
+ @Nonnull final InstanceIdentifier<ClassifyTable> id, @Nonnull final ClassifyTable readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTableBuilder(readValue)
+ .setName(readValue.getName())
+ .build());
+ }
+
+ static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable> getCfgId(
+ final InstanceIdentifier<ClassifyTable> id) {
+ return InstanceIdentifier.create(VppClassifier.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable.class,
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTableKey(id.firstKeyOf(ClassifyTable.class).getName()));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifyTableWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifyTableWriter.java
new file mode 100644
index 000000000..62b6a2142
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/ClassifyTableWriter.java
@@ -0,0 +1,149 @@
+/*
+ * 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.hc2vpp.v3po.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import javax.xml.bind.DatatypeConverter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTableKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import io.fd.vpp.jvpp.VppBaseCallException;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTableReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer customizer responsible for classify table create/delete. <br> Sends {@code classify_add_del_table} message to
+ * VPP.<br> Equivalent to invoking {@code vppctl classify table} command.
+ */
+public class ClassifyTableWriter extends VppNodeWriter
+ implements ListWriterCustomizer<ClassifyTable, ClassifyTableKey>, ByteDataTranslator, JvppReplyConsumer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableWriter.class);
+ private final VppClassifierContextManager classifyTableContext;
+
+ public ClassifyTableWriter(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final VppClassifierContextManager classifyTableContext) {
+ super(futureJVppCore);
+ this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.debug("Creating classify table: iid={} dataAfter={}", id, dataAfter);
+ try {
+ final int newTableIndex =
+ classifyAddDelTable(true, id, dataAfter, ~0 /* value not present */,
+ writeContext.getMappingContext());
+
+ // Add classify table name <-> vpp index mapping to the naming context:
+ classifyTableContext.addTable(newTableIndex, dataAfter.getName(), dataAfter.getClassifierNode(),
+ writeContext.getMappingContext());
+ LOG.debug("Successfully created classify table(id={]): iid={} dataAfter={}", newTableIndex, id, dataAfter);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable dataBefore, @Nonnull final ClassifyTable dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ throw new UnsupportedOperationException("Classify table update is not supported");
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.debug("Removing classify table: iid={} dataBefore={}", id, dataBefore);
+ final String tableName = dataBefore.getName();
+ checkState(classifyTableContext.containsTable(tableName, writeContext.getMappingContext()),
+ "Removing classify table {}, but index could not be found in the classify table context", tableName);
+
+ final int tableIndex = classifyTableContext.getTableIndex(tableName, writeContext.getMappingContext());
+ try {
+ classifyAddDelTable(false, id, dataBefore, tableIndex, writeContext.getMappingContext());
+
+ // Remove deleted interface from interface context:
+ classifyTableContext.removeTable(dataBefore.getName(), writeContext.getMappingContext());
+ LOG.debug("Successfully removed classify table(id={]): iid={} dataAfter={}", tableIndex, id, dataBefore);
+ } catch (VppBaseCallException e) {
+ throw new WriteFailedException.DeleteFailedException(id, e);
+ }
+ }
+
+ private int classifyAddDelTable(final boolean isAdd, @Nonnull final InstanceIdentifier<ClassifyTable> id,
+ @Nonnull final ClassifyTable table, final int tableId, final MappingContext ctx)
+ throws VppBaseCallException, WriteFailedException {
+
+ final int missNextIndex =
+ getNodeIndex(table.getMissNext(), table, classifyTableContext, ctx, id);
+
+ final CompletionStage<ClassifyAddDelTableReply> createClassifyTableReplyCompletionStage =
+ getFutureJVpp()
+ .classifyAddDelTable(getClassifyAddDelTableRequest(isAdd, tableId, table, missNextIndex, ctx));
+
+ final ClassifyAddDelTableReply reply =
+ getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
+ return reply.newTableIndex;
+ }
+
+ private ClassifyAddDelTable getClassifyAddDelTableRequest(final boolean isAdd, final int tableIndex,
+ @Nonnull final ClassifyTable table,
+ final int missNextIndex,
+ @Nonnull final MappingContext ctx) {
+ final ClassifyAddDelTable request = new ClassifyAddDelTable();
+ request.isAdd = booleanToByte(isAdd);
+ request.tableIndex = tableIndex;
+
+ // mandatory, all u32 values are permitted:
+ request.nbuckets = table.getNbuckets().intValue();
+ request.memorySize = table.getMemorySize().intValue();
+ request.skipNVectors = table.getSkipNVectors().intValue();
+
+ // mandatory
+ request.missNextIndex = missNextIndex;
+
+ final String nextTable = table.getNextTable();
+ if (isAdd && nextTable != null) {
+ request.nextTableIndex = classifyTableContext.getTableIndex(nextTable, ctx);
+ } else {
+ request.nextTableIndex = ~0; // value not specified
+ }
+ request.mask = DatatypeConverter.parseHexBinary(table.getMask().getValue().replace(":", ""));
+ checkArgument(request.mask.length % 16 == 0, "Number of mask bytes must be multiple of 16.");
+ request.matchNVectors = request.mask.length / 16;
+
+ return request;
+ }
+} \ No newline at end of file
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppClassifierContextManager.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppClassifierContextManager.java
new file mode 100644
index 000000000..c06ef2700
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppClassifierContextManager.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.v3po.vppclassifier;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNodeName;
+
+/**
+ * Manages metadata for vpp-classifier
+ */
+public interface VppClassifierContextManager {
+
+ /**
+ * Creates metadata for classify table.
+ *
+ * @param id classify table index
+ * @param name classify table name
+ * @param classifierNode name of VPP node the table is defined for
+ * @param ctx mapping context providing context data for current transaction
+ */
+ void addTable(final int id, @Nonnull final String name, @Nullable final VppNodeName classifierNode,
+ @Nonnull final MappingContext ctx);
+
+ /**
+ * Check whether metadata for given classify table metadata is present.
+ *
+ * @param name classify table name
+ * @param ctx mapping context providing context data for current transaction
+ * @return true if present, false otherwise
+ */
+ boolean containsTable(@Nonnull String name, @Nonnull final MappingContext ctx);
+
+ /**
+ * Returns classify table index associated with the given name.
+ *
+ * @param name classify table name
+ * @param ctx mapping context providing context data for current transaction
+ * @return integer index value matching supplied classify table name
+ * @throws IllegalArgumentException if classify table was not found
+ */
+ int getTableIndex(@Nonnull final String name, @Nonnull final MappingContext ctx);
+
+ /**
+ * Retrieves classify table name for given id. If not present, artificial name will be generated.
+ *
+ * @param id classify table index
+ * @param ctx mapping context providing context data for current transaction
+ * @return classify table name matching supplied index
+ */
+ String getTableName(final int id, @Nonnull final MappingContext ctx);
+
+ /**
+ * Returns name of the base vpp node associated with the classify table.
+ *
+ * @param name classify table name
+ * @param ctx mapping context providing context data for current transaction
+ * @return name of VPP node the table is defined for
+ */
+ Optional<String> getTableBaseNode(final String name, @Nonnull final MappingContext ctx);
+
+ /**
+ * Removes classify table metadata from current context.
+ *
+ * @param name classify table name
+ * @param ctx mapping context providing context data for current transaction
+ */
+ void removeTable(@Nonnull final String name, @Nonnull final MappingContext ctx);
+
+ /**
+ * Adds relative node index to node name mapping for given classify table.
+ *
+ * @param tableName classify table name
+ * @param nodeIndex index of a vpp node, relative to table's base node
+ * @param nodeName name of a vpp node
+ * @param ctx mapping context providing context data for current transaction
+ */
+ void addNodeName(@Nonnull String tableName, final int nodeIndex, @Nonnull final String nodeName,
+ @Nonnull final MappingContext ctx);
+
+ /**
+ * Retrieves node name associated with the given classify table and node index.
+ *
+ * @param tableIndex classify table index
+ * @param nodeIndex relative index of a vpp node
+ * @param ctx mapping context providing context data for current transaction
+ * @return name of vpp node
+ */
+ Optional<String> getNodeName(final int tableIndex, final int nodeIndex, @Nonnull final MappingContext ctx);
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppClassifierContextManagerImpl.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppClassifierContextManagerImpl.java
new file mode 100644
index 000000000..2255c78a7
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppClassifierContextManagerImpl.java
@@ -0,0 +1,181 @@
+/*
+ * 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.hc2vpp.v3po.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.inject.Inject;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.honeycomb.translate.util.read.BindingBrokerReader;
+import java.util.List;
+import java.util.stream.Collector;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.inject.Named;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.VppClassifierContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.VppClassifierContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.ClassifyTableContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.ClassifyTableContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.ClassifyTableContextKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.classify.table.context.NodeContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.classify.table.context.NodeContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev160909.vpp.classifier.context.classify.table.context.NodeContextKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+/**
+ * Facade on top of {@link MappingContext} that manages {@link ClassifyTableContext}.
+ */
+public final class VppClassifierContextManagerImpl implements VppClassifierContextManager {
+ private static final Collector<ClassifyTableContext, ?, ClassifyTableContext> SINGLE_ITEM_COLLECTOR =
+ RWUtils.singleItemCollector();
+
+ @VisibleForTesting
+ static final InstanceIdentifier<VppClassifierContext>
+ VPP_CLASSIFIER_CONTEXT_IID = KeyedInstanceIdentifier.create(VppClassifierContext.class);
+ private final String artificialNamePrefix;
+
+ /**
+ * Creates new VppClassifierContextManagerImpl.
+ *
+ * @param artificialNamePrefix artificial name to be used to generate names for classify tables without existing
+ * metadata
+ */
+ public VppClassifierContextManagerImpl(@Nonnull final String artificialNamePrefix) {
+ this.artificialNamePrefix =
+ Preconditions.checkNotNull(artificialNamePrefix, "artificialNamePrefix should not be null");
+ }
+
+ private KeyedInstanceIdentifier<ClassifyTableContext, ClassifyTableContextKey> getMappingIid(final String name) {
+ return VPP_CLASSIFIER_CONTEXT_IID.child(ClassifyTableContext.class, new ClassifyTableContextKey(name));
+ }
+
+ @Override
+ public void addTable(final int id, @Nonnull final String name, @Nullable final VppNodeName classifierNode,
+ @Nonnull final MappingContext ctx) {
+ final KeyedInstanceIdentifier<ClassifyTableContext, ClassifyTableContextKey> mappingIid = getMappingIid(name);
+ final ClassifyTableContextBuilder tableCtx = new ClassifyTableContextBuilder().setIndex(id).setName(name);
+ if (classifierNode != null) {
+ tableCtx.setClassifierNodeName(classifierNode.getValue());
+ }
+ ctx.put(mappingIid, tableCtx.build());
+ }
+
+ @Override
+ public boolean containsTable(@Nonnull final String name, @Nonnull final MappingContext ctx) {
+ final Optional<ClassifyTableContext> read = ctx.read(getMappingIid(name));
+ return read.isPresent();
+ }
+
+ @Override
+ public int getTableIndex(@Nonnull final String name, @Nonnull final MappingContext ctx) {
+ final Optional<ClassifyTableContext> read = ctx.read(getMappingIid(name));
+ checkArgument(read.isPresent(), "No mapping stored for name: %s", name);
+ return read.get().getIndex();
+ }
+
+ @Override
+ public String getTableName(final int id, @Nonnull final MappingContext ctx) {
+ if (!containsName(id, ctx)) {
+ final String artificialName = getArtificialName(id);
+ addTable(id, artificialName, null, ctx);
+ }
+
+ final Optional<VppClassifierContext> read = ctx.read(VPP_CLASSIFIER_CONTEXT_IID);
+ checkState(read.isPresent(), "VppClassifierContext for index: %s is not present. But should be", id);
+
+ return read.get().getClassifyTableContext().stream()
+ .filter(t -> t.getIndex().equals(id))
+ .collect(SINGLE_ITEM_COLLECTOR).getName();
+ }
+
+ private boolean containsName(final int index, @Nonnull final MappingContext mappingContext) {
+ final Optional<VppClassifierContext> read = mappingContext.read(VPP_CLASSIFIER_CONTEXT_IID);
+ return read.isPresent()
+ ? read.get().getClassifyTableContext().stream().anyMatch(t -> t.getIndex().equals(index))
+ : false;
+ }
+
+ @Override
+ public Optional<String> getTableBaseNode(@Nonnull final String name, @Nonnull final MappingContext ctx) {
+ final Optional<ClassifyTableContext> read = ctx.read(getMappingIid(name));
+ if (read.isPresent()) {
+ return Optional.fromNullable(read.get().getClassifierNodeName());
+ }
+ return Optional.absent();
+ }
+
+ @Override
+ public void removeTable(@Nonnull final String name, @Nonnull final MappingContext ctx) {
+ ctx.delete(getMappingIid(name));
+ }
+
+ @Override
+ public void addNodeName(@Nonnull final String tableName, final int nodeIndex,
+ @Nonnull final String nodeName,
+ @Nonnull final MappingContext ctx) {
+ final KeyedInstanceIdentifier<NodeContext, NodeContextKey> iid =
+ getMappingIid(tableName).child(NodeContext.class, new NodeContextKey(nodeName));
+ ctx.put(iid, new NodeContextBuilder().setName(nodeName).setIndex(nodeIndex).build());
+ }
+
+ @Override
+ public Optional<String> getNodeName(final int tableIndex, final int nodeIndex, @Nonnull final MappingContext ctx) {
+ if (!containsName(tableIndex, ctx)) {
+ return Optional.absent();
+ }
+ final String tableName = getTableName(tableIndex, ctx);
+ final Optional<ClassifyTableContext> tableCtx = ctx.read(getMappingIid(tableName));
+ final List<NodeContext> nodeContext = tableCtx.get().getNodeContext();
+ if (nodeContext == null) {
+ return Optional.absent();
+ }
+ return Optional.fromNullable(nodeContext.stream()
+ .filter(n -> n.getIndex().equals(nodeIndex))
+ .findFirst()
+ .map(nodes -> nodes.getName())
+ .orElse(null));
+ }
+
+ private String getArtificialName(final int index) {
+ return artificialNamePrefix + index;
+ }
+
+ public static final class ContextsReaderFactory implements ReaderFactory {
+
+ @Inject
+ @Named("honeycomb-context")
+ private DataBroker contextBindingBrokerDependency;
+
+ @Override
+ public void init(final ModifiableReaderRegistryBuilder registry) {
+ registry.add(new BindingBrokerReader<>(VPP_CLASSIFIER_CONTEXT_IID,
+ contextBindingBrokerDependency,
+ LogicalDatastoreType.OPERATIONAL, VppClassifierContextBuilder.class));
+ }
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppNodeReader.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppNodeReader.java
new file mode 100644
index 000000000..c25a4572c
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppNodeReader.java
@@ -0,0 +1,45 @@
+/*
+ * 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.hc2vpp.v3po.vppclassifier;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.PacketHandlingAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNodeName;
+import org.slf4j.Logger;
+
+interface VppNodeReader {
+
+ /**
+ * Converts vpp node index to YANG representation of vpp node.
+ *
+ * @param nodeIndex index of vpp node treated as signed integer.
+ * @return vpp node representation
+ */
+ default Optional<VppNode> readVppNode(final int tableIndex, final int nodeIndex,
+ @Nonnull final VppClassifierContextManager vppClassifierContextManager,
+ @Nonnull final MappingContext ctx, @Nonnull final Logger log) {
+ final PacketHandlingAction action = PacketHandlingAction.forValue(nodeIndex);
+ if (action == null) {
+ return vppClassifierContextManager.getNodeName(tableIndex, nodeIndex, ctx)
+ .transform(nodeName -> new VppNode(new VppNodeName(nodeName)));
+ }
+ return Optional.of(new VppNode(action));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppNodeWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppNodeWriter.java
new file mode 100644
index 000000000..dd0b2d5ec
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppclassifier/VppNodeWriter.java
@@ -0,0 +1,79 @@
+/*
+ * 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.hc2vpp.v3po.vppclassifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.VppBaseCallException;
+import io.fd.vpp.jvpp.core.dto.GetNextIndex;
+import io.fd.vpp.jvpp.core.dto.GetNextIndexReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.VppNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev161214.vpp.classifier.ClassifyTable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+abstract class VppNodeWriter extends FutureJVppCustomizer implements JvppReplyConsumer {
+
+ protected VppNodeWriter(@Nonnull final FutureJVppCore futureJvpp) {
+ super(futureJvpp);
+ }
+
+ protected int getNodeIndex(@Nonnull final VppNode node, @Nonnull final ClassifyTable classifyTable,
+ @Nonnull final VppClassifierContextManager vppClassifierContextManager,
+ @Nonnull final MappingContext ctx, @Nonnull final InstanceIdentifier<?> id)
+ throws VppBaseCallException, WriteFailedException {
+ if (node.getPacketHandlingAction() != null) {
+ return node.getPacketHandlingAction().getIntValue();
+ } else {
+ return nodeNameToIndex(classifyTable, node.getVppNodeName().getValue(), vppClassifierContextManager, ctx,
+ id);
+ }
+ }
+
+ private int nodeNameToIndex(@Nonnull final ClassifyTable classifyTable, @Nonnull final String nextNodeName,
+ @Nonnull final VppClassifierContextManager vppClassifierContextManager,
+ @Nonnull final MappingContext ctx, @Nonnull final InstanceIdentifier<?> id)
+ throws WriteFailedException {
+ checkArgument(classifyTable != null && classifyTable.getClassifierNode() != null,
+ "to use relative node names, table classifier node needs to be provided");
+ final GetNextIndex request = new GetNextIndex();
+ request.nodeName = classifyTable.getClassifierNode().getValue().getBytes();
+ request.nextName = nextNodeName.getBytes();
+ final CompletionStage<GetNextIndexReply> getNextIndexCompletionStage =
+ getFutureJVpp().getNextIndex(request);
+
+ final GetNextIndexReply reply;
+ try {
+ reply = getReplyForRead(getNextIndexCompletionStage.toCompletableFuture(), id);
+
+ // vpp does not provide relative node index to node name conversion (https://jira.fd.io/browse/VPP-219)
+ // as a workaround we need to add mapping to vpp-classfier-context
+ vppClassifierContextManager.addNodeName(classifyTable.getName(), reply.nextIndex, nextNodeName, ctx);
+ } catch (ReadFailedException e) {
+ throw new WriteFailedException(id, String.format("Failed to get node index for %s relative to %s",
+ nextNodeName, classifyTable.getClassifierNode()), e);
+ }
+ return reply.nextIndex;
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppstate/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppstate/BridgeDomainCustomizer.java
new file mode 100644
index 000000000..e6f3bbb49
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppstate/BridgeDomainCustomizer.java
@@ -0,0 +1,181 @@
+/*
+ * 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.hc2vpp.v3po.vppstate;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingListReaderCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.BridgeDomainDetails;
+import io.fd.vpp.jvpp.core.dto.BridgeDomainDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.BridgeDomainDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.Vpp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.BridgeDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.BridgeDomainsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.bridge.domains.BridgeDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.bridge.domains.BridgeDomainKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class BridgeDomainCustomizer extends FutureJVppCustomizer
+ implements InitializingListReaderCustomizer<BridgeDomain, BridgeDomainKey, BridgeDomainBuilder>, ByteDataTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class);
+ private final NamingContext bdContext;
+
+ public BridgeDomainCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+ @Nonnull final NamingContext bdContext) {
+ super(futureJVppCore);
+ this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null");
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<BridgeDomain> id,
+ @Nonnull final BridgeDomainBuilder builder, @Nonnull final ReadContext context)
+ throws ReadFailedException {
+ LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: id={}, builderbuilder={}, context={}",
+ id, builder, context);
+
+ final BridgeDomainKey key = id.firstKeyOf(id.getTargetType());
+ LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: key={}", key);
+
+ final int bdId = bdContext.getIndex(key.getName(), context.getMappingContext());
+ LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: bdId={}", bdId);
+
+ BridgeDomainDetailsReplyDump reply;
+ BridgeDomainDetails bridgeDomainDetails;
+ final BridgeDomainDump request = new BridgeDomainDump();
+ request.bdId = bdContext.getIndex(key.getName(), context.getMappingContext());
+ try {
+ reply = getFutureJVpp().bridgeDomainDump(request).toCompletableFuture().get();
+ bridgeDomainDetails = Iterables.getOnlyElement(reply.bridgeDomainDetails);
+ } catch (Exception e) {
+ LOG.debug("Unable to read bridge domain: {}", key.getName(), e);
+ return;
+ }
+
+ logBridgeDomainDetails(bridgeDomainDetails);
+
+ builder.setName(key.getName());
+ builder.setArpTermination(byteToBoolean(bridgeDomainDetails.arpTerm));
+ builder.setFlood(byteToBoolean(bridgeDomainDetails.flood));
+ builder.setForward(byteToBoolean(bridgeDomainDetails.forward));
+ builder.setLearn(byteToBoolean(bridgeDomainDetails.learn));
+ builder.setUnknownUnicastFlood(byteToBoolean(bridgeDomainDetails.uuFlood));
+ }
+
+ private void logBridgeDomainDetails(final BridgeDomainDetails bridgeDomainDetails) {
+ LOG.debug("bridgeDomainDetails={}", bridgeDomainDetails);
+ if (bridgeDomainDetails != null) {
+ LOG.debug("bridgeDomainDetails.arpTerm={}", bridgeDomainDetails.arpTerm);
+ LOG.debug("bridgeDomainDetails.bdId={}", bridgeDomainDetails.bdId);
+ LOG.debug("bridgeDomainDetails.bviSwIfIndex={}", bridgeDomainDetails.bviSwIfIndex);
+ LOG.debug("bridgeDomainDetails.flood={}", bridgeDomainDetails.flood);
+ LOG.debug("bridgeDomainDetails.forward={}", bridgeDomainDetails.forward);
+ LOG.debug("bridgeDomainDetails.learn={}", bridgeDomainDetails.learn);
+ LOG.debug("bridgeDomainDetails.nSwIfs={}", bridgeDomainDetails.nSwIfs);
+ LOG.debug("bridgeDomainDetails.uuFlood={}", bridgeDomainDetails.uuFlood);
+ }
+ }
+
+ @Nonnull
+ @Override
+ public BridgeDomainBuilder getBuilder(@Nonnull final InstanceIdentifier<BridgeDomain> id) {
+ return new BridgeDomainBuilder();
+ }
+
+ @Nonnull
+ @Override
+ public List<BridgeDomainKey> getAllIds(@Nonnull final InstanceIdentifier<BridgeDomain> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ final BridgeDomainDump request = new BridgeDomainDump();
+ request.bdId = -1; // dump call
+
+ BridgeDomainDetailsReplyDump reply;
+ try {
+ reply = getFutureJVpp().bridgeDomainDump(request).toCompletableFuture().get();
+ } catch (Exception e) {
+ throw new ReadFailedException(id, e);
+ }
+
+ if (reply == null || reply.bridgeDomainDetails == null) {
+ return Collections.emptyList();
+ }
+
+ final int bIdsLength = reply.bridgeDomainDetails.size();
+ LOG.debug("vppstate.BridgeDomainCustomizer.getAllIds: bIds.length={}", bIdsLength);
+ if (bIdsLength == 0) {
+ // No bridge domains
+ return Collections.emptyList();
+ }
+
+ final List<BridgeDomainKey> allIds = new ArrayList<>(bIdsLength);
+ for (BridgeDomainDetails detail : reply.bridgeDomainDetails) {
+ logBridgeDomainDetails(detail);
+
+ final String bName = bdContext.getName(detail.bdId, context.getMappingContext());
+ LOG.debug("vppstate.BridgeDomainCustomizer.getAllIds: bName={}", bName);
+ allIds.add(new BridgeDomainKey(bName));
+ }
+
+ return allIds;
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<BridgeDomain> readData) {
+ ((BridgeDomainsBuilder) builder).setBridgeDomain(readData);
+ }
+
+ @Override
+ public Initialized<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.bridge.domains.BridgeDomain> init(
+ @Nonnull final InstanceIdentifier<BridgeDomain> id,
+ @Nonnull final BridgeDomain readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.bridge.domains.BridgeDomainBuilder()
+ .setName(readValue.getName())
+ .setLearn(readValue.isLearn())
+ .setUnknownUnicastFlood(readValue.isUnknownUnicastFlood())
+ .setArpTermination(readValue.isArpTermination())
+ .setFlood(readValue.isFlood())
+ .setForward(readValue.isForward())
+ .build());
+ }
+
+ static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.bridge.domains.BridgeDomain> getCfgId(
+ final InstanceIdentifier<BridgeDomain> id) {
+ return InstanceIdentifier.create(Vpp.class).child(BridgeDomains.class).child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.bridge.domains.BridgeDomain.class,
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.bridge.domains.BridgeDomainKey(
+ id.firstKeyOf(BridgeDomain.class).getName()));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppstate/L2FibEntryCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppstate/L2FibEntryCustomizer.java
new file mode 100644
index 000000000..2605293c5
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppstate/L2FibEntryCustomizer.java
@@ -0,0 +1,165 @@
+/*
+ * 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.hc2vpp.v3po.vppstate;
+
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.Longs;
+import io.fd.hc2vpp.v3po.interfacesstate.InterfaceDataTranslator;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingListReaderCustomizer;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.vpp.jvpp.core.dto.L2FibTableDump;
+import io.fd.vpp.jvpp.core.dto.L2FibTableEntry;
+import io.fd.vpp.jvpp.core.dto.L2FibTableEntryReplyDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.L2FibFilter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.L2FibForward;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.fib.attributes.L2FibTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.fib.attributes.L2FibTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.fib.attributes.l2.fib.table.L2FibEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.fib.attributes.l2.fib.table.L2FibEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.bridge.domains.BridgeDomainKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class L2FibEntryCustomizer extends FutureJVppCustomizer
+ implements InitializingListReaderCustomizer<L2FibEntry, L2FibEntryKey, L2FibEntryBuilder>, ByteDataTranslator,
+ InterfaceDataTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(L2FibEntryCustomizer.class);
+
+ private static final Collector<L2FibTableEntry, ?, L2FibTableEntry> SINGLE_ITEM_COLLECTOR =
+ RWUtils.singleItemCollector();
+
+ private final NamingContext bdContext;
+ private final NamingContext interfaceContext;
+
+ public L2FibEntryCustomizer(@Nonnull final FutureJVppCore futureJVppCore, @Nonnull final NamingContext bdContext,
+ @Nonnull final NamingContext interfaceContext) {
+ super(futureJVppCore);
+ this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null");
+ this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<L2FibEntry> id,
+ @Nonnull final L2FibEntryBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+
+ final L2FibEntryKey key = id.firstKeyOf(id.getTargetType());
+ final BridgeDomainKey bridgeDomainKey = id.firstKeyOf(BridgeDomain.class);
+ final int bdId = bdContext.getIndex(bridgeDomainKey.getName(), ctx.getMappingContext());
+ LOG.debug("Reading L2 FIB entry: key={}. bridgeDomainKey={}, bdId={}", key, bridgeDomainKey, bdId);
+
+ try {
+ // TODO HONEYCOMB-186 use cached l2FibTable
+ final L2FibTableEntry entry = dumpL2Fibs(id, bdId).stream().filter(e -> key.getPhysAddress()
+ .equals(new PhysAddress(vppPhysAddrToYang(Longs.toByteArray(e.mac), 2))))
+ .collect(SINGLE_ITEM_COLLECTOR);
+
+ builder.setAction(byteToBoolean(entry.filterMac)
+ ? L2FibFilter.class
+ : L2FibForward.class);
+ builder.setBridgedVirtualInterface(byteToBoolean(entry.bviMac));
+
+ if (entry.swIfIndex != -1) {
+ builder.setOutgoingInterface(interfaceContext.getName(entry.swIfIndex, ctx.getMappingContext()));
+ }
+ builder.setStaticConfig(byteToBoolean(entry.staticMac));
+ builder.setPhysAddress(key.getPhysAddress());
+ builder.setKey(key);
+ } catch (Exception e) {
+ throw new ReadFailedException(id, e);
+ }
+ }
+
+ @Nonnull
+ private List<L2FibTableEntry> dumpL2Fibs(final InstanceIdentifier<L2FibEntry> id, final int bdId)
+ throws ReadFailedException {
+ final L2FibTableDump l2FibRequest = new L2FibTableDump();
+ l2FibRequest.bdId = bdId;
+
+ final CompletableFuture<L2FibTableEntryReplyDump> l2FibTableDumpCompletableFuture =
+ getFutureJVpp().l2FibTableDump(l2FibRequest).toCompletableFuture();
+
+ final L2FibTableEntryReplyDump dump = getReplyForRead(l2FibTableDumpCompletableFuture, id);
+
+ if (null == dump || null == dump.l2FibTableEntry) {
+ return Collections.emptyList();
+ } else {
+ return dump.l2FibTableEntry;
+ }
+ }
+
+ @Nonnull
+ @Override
+ public List<L2FibEntryKey> getAllIds(@Nonnull final InstanceIdentifier<L2FibEntry> id,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ final BridgeDomainKey bridgeDomainKey = id.firstKeyOf(BridgeDomain.class);
+ final int bdId = bdContext.getIndex(bridgeDomainKey.getName(), ctx.getMappingContext());
+
+ LOG.debug("Reading L2 FIB for bridge domain {} (bdId={})", bridgeDomainKey, bdId);
+ return dumpL2Fibs(id, bdId).stream()
+ .map(entry -> new L2FibEntryKey(
+ new PhysAddress(vppPhysAddrToYang(Longs.toByteArray(entry.mac), 2))))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<L2FibEntry> readData) {
+ ((L2FibTableBuilder) builder).setL2FibEntry(readData);
+ }
+
+ @Nonnull
+ @Override
+ public L2FibEntryBuilder getBuilder(@Nonnull final InstanceIdentifier<L2FibEntry> id) {
+ return new L2FibEntryBuilder();
+ }
+
+ @Override
+ public Initialized<L2FibEntry> init(
+ @Nonnull final InstanceIdentifier<L2FibEntry> id,
+ @Nonnull final L2FibEntry readValue,
+ @Nonnull final ReadContext ctx) {
+ return Initialized.create(getCfgId(id),
+ // Convert operational object to config. VPP does not support setting BVI (see v3po.yang)
+ new L2FibEntryBuilder(readValue).setBridgedVirtualInterface(null).build());
+ }
+
+ static InstanceIdentifier<L2FibEntry> getCfgId(
+ final @Nonnull InstanceIdentifier<L2FibEntry> id) {
+ return BridgeDomainCustomizer.getCfgId(RWUtils.cutId(id, BridgeDomain.class)).child(
+ L2FibTable.class).child(L2FibEntry.class, new L2FibEntryKey(id.firstKeyOf(L2FibEntry.class)));
+ }
+}
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppstate/VersionCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppstate/VersionCustomizer.java
new file mode 100644
index 000000000..3f69c98df
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/vppstate/VersionCustomizer.java
@@ -0,0 +1,82 @@
+/*
+ * 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.hc2vpp.v3po.vppstate;
+
+import com.google.common.primitives.UnsignedInts;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.vpp.jvpp.core.dto.ShowVersion;
+import io.fd.vpp.jvpp.core.dto.ShowVersionReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import io.fd.vpp.jvpp.dto.ControlPing;
+import io.fd.vpp.jvpp.dto.ControlPingReply;
+import io.fd.vpp.jvpp.dto.JVppReply;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.Version;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.VersionBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class VersionCustomizer
+ extends FutureJVppCustomizer
+ implements ReaderCustomizer<Version, VersionBuilder>, ByteDataTranslator, JvppReplyConsumer {
+
+ public VersionCustomizer(@Nonnull final FutureJVppCore futureJVppCore) {
+ super(futureJVppCore);
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Version readValue) {
+ ((VppStateBuilder) parentBuilder).setVersion(readValue);
+ }
+
+ @Nonnull
+ @Override
+ public VersionBuilder getBuilder(@Nonnull InstanceIdentifier<Version> id) {
+ return new VersionBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Version> id, @Nonnull final VersionBuilder builder,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+
+ // Execute with timeout
+ final CompletionStage<ShowVersionReply> showVersionFuture = getFutureJVpp().showVersion(new ShowVersion());
+ final ShowVersionReply reply = getReplyForRead(showVersionFuture.toCompletableFuture(), id);
+
+ builder.setBranch(toString(reply.version));
+ builder.setName(toString(reply.program));
+ builder.setBuildDate(toString(reply.buildDate));
+ builder.setBuildDirectory(toString(reply.buildDirectory));
+ builder.setPid(getPid(id));
+ }
+
+ private Long getPid(@Nonnull final InstanceIdentifier<Version> id) throws ReadFailedException {
+ final CompletionStage<JVppReply<ControlPing>> request = getFutureJVpp().send(new ControlPing());
+ final ControlPingReply reply = (ControlPingReply)getReplyForRead(request.toCompletableFuture(), id);
+ return UnsignedInts.toLong(reply.vpePid);
+ }
+
+
+}