diff options
author | 2016-07-29 16:27:12 +0200 | |
---|---|---|
committer | 2016-07-29 16:32:17 +0200 | |
commit | 599944605bb0ad58b30eca8a5723609f8dc2cada (patch) | |
tree | a2300f3d1f197e5c64ab2ae37d8d3d06d591bd26 /v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate | |
parent | 81c9cdfa5a9e91b91d73a6a2b20cff8b612d7de3 (diff) |
HONEYCOMB-130: Rename infra packages(remove vpp/v3po)
Change-Id: Ic5b90e397e3743623d01b206bc60bc5c7df6b981
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate')
57 files changed, 7299 insertions, 0 deletions
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java new file mode 100644 index 000000000..1d58bd18d --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.initializers; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import io.fd.honeycomb.data.init.AbstractDataTreeConverter; +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.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.InterfacesBuilder; +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.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; +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.interfaces.rev140508.interfaces.state.Interface.AdminStatus; +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.Interface1Builder; +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.interfaces._interface.Ipv4Builder; +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.NeighborBuilder; +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.PrefixLengthBuilder; +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.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeVni; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.AclBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.EthernetBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.TapBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUserBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Ethernet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Tap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUser; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBased; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBased; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBasedBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Initializes ietf-interfaces config data based on operational state + */ +public class InterfacesInitializer extends AbstractDataTreeConverter<InterfacesState, Interfaces> { + private static final Logger LOG = LoggerFactory.getLogger(InterfacesInitializer.class); + + public InterfacesInitializer(@Nonnull final DataBroker bindingDataBroker) { + super(bindingDataBroker, InstanceIdentifier.create(InterfacesState.class), + InstanceIdentifier.create(Interfaces.class)); + } + + @Override + protected Interfaces convert(final InterfacesState operationalData) { + LOG.debug("InterfacesInitializer.convert()"); + InterfacesBuilder interfacesBuilder = new InterfacesBuilder(); + interfacesBuilder + .setInterface(Lists.transform(operationalData.getInterface(), InterfacesInitializer::initialize)); + return interfacesBuilder.build(); + } + + // FIXME https://jira.fd.io/browse/HONEYCOMB-73 this kind of initialization/transformation is bad + // There is no relation to readers, it cannot be extended (readers can) and its hard to keep in sync with readers + + // TODO add IP v4/ v6 initializer + + private static Interface initialize( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input) { + InterfaceBuilder builder = new InterfaceBuilder(); + builder.setKey(new InterfaceKey(input.getKey().getName())); + builder.setName(input.getName()); + builder.setType(input.getType()); + builder.setEnabled(AdminStatus.Up.equals(input.getAdminStatus())); + // builder.setLinkUpDownTrapEnable(); TODO not present in interfaces-state + + initializeVppInterfaceStateAugmentation(input, builder); + SubInterfaceInitializationUtils.initializeSubinterfaceStateAugmentation(input, builder); + initializeIetfIpAugmentation(input, builder); + + return builder.build(); + } + + private static void initializeVppInterfaceStateAugmentation( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input, + final InterfaceBuilder builder) { + final VppInterfaceStateAugmentation vppIfcAugmentation = + input.getAugmentation(VppInterfaceStateAugmentation.class); + if (vppIfcAugmentation != null) { + final VppInterfaceAugmentationBuilder augmentBuilder = new VppInterfaceAugmentationBuilder(); + builder.setDescription(vppIfcAugmentation.getDescription()); + + final Vxlan vxlan = vppIfcAugmentation.getVxlan(); + if (vxlan != null) { + setVxlan(augmentBuilder, vxlan); + } + + final VxlanGpe vxlanGpe = vppIfcAugmentation.getVxlanGpe(); + if (vxlanGpe != null) { + setVxlanGpe(augmentBuilder, vxlanGpe); + } + + final Tap tap = vppIfcAugmentation.getTap(); + if (tap != null) { + setTap(input, augmentBuilder, tap); + } + + final VhostUser vhostUser = vppIfcAugmentation.getVhostUser(); + if (vhostUser != null) { + setVhostUser(augmentBuilder, vhostUser); + } + + final L2 l2 = vppIfcAugmentation.getL2(); + if (l2 != null) { + setL2(augmentBuilder, l2); + } + + final Ethernet ethernet = vppIfcAugmentation.getEthernet(); + if (ethernet != null) { + setEthernet(augmentBuilder, ethernet); + } + + final Acl acl = vppIfcAugmentation.getAcl(); + if (acl != null) { + setAcl(augmentBuilder, acl); + } + + // TODO set routing, not present in interface-state + + builder.addAugmentation(VppInterfaceAugmentation.class, augmentBuilder.build()); + } + } + + private static void initializeIetfIpAugmentation( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input, + final InterfaceBuilder builder) { + final Interface2 ietfIpAugmentation = input.getAugmentation(Interface2.class); + if (ietfIpAugmentation != null) { + final Interface1Builder augmentBuilder = new Interface1Builder(); + + final Ipv4 ipv4 = ietfIpAugmentation.getIpv4(); + if (ipv4 != null) { + final List<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address> + collect = + ipv4.getAddress().stream() + .map( + address -> new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder() + .setIp(address.getIp()) + .setSubnet(getSubnet(address)) + .build()) + .collect(Collectors.toList()); + + final List<Neighbor> neighbors = ipv4.getNeighbor().stream() + .map(neighbor -> new NeighborBuilder().setIp(neighbor.getIp()) + .setLinkLayerAddress(neighbor.getLinkLayerAddress()).build()) + .collect(Collectors.toList()); + + augmentBuilder.setIpv4(new Ipv4Builder().setAddress(collect).setNeighbor(neighbors).build()); + } + + // TODO ipv6 + + builder.addAugmentation(Interface1.class, augmentBuilder.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(); + + // TODO 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 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(); + } + + private static void setEthernet(final VppInterfaceAugmentationBuilder augmentBuilder, final Ethernet ethernet) { + final EthernetBuilder ethernetBuilder = new EthernetBuilder(); + ethernetBuilder.setMtu(ethernet.getMtu()); + augmentBuilder.setEthernet(ethernetBuilder.build()); + } + + private static void setAcl(final VppInterfaceAugmentationBuilder augmentBuilder, final Acl acl) { + final AclBuilder aclBuilder = new AclBuilder(); + aclBuilder.setL2Acl(acl.getL2Acl()); + aclBuilder.setIp4Acl(acl.getIp4Acl()); + aclBuilder.setIp6Acl(acl.getIp6Acl()); + augmentBuilder.setAcl(aclBuilder.build()); + } + + private static void setL2(final VppInterfaceAugmentationBuilder augmentBuilder, final L2 l2) { + final L2Builder l2Builder = new L2Builder(); + + final Interconnection interconnection = l2.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()); + } + } + + augmentBuilder.setL2(l2Builder.build()); + } + + private static void setVhostUser(final VppInterfaceAugmentationBuilder augmentBuilder, final VhostUser vhostUser) { + final VhostUserBuilder vhostUserBuilder = new VhostUserBuilder(); + vhostUserBuilder.setRole(vhostUser.getRole()); + vhostUserBuilder.setSocket(vhostUser.getSocket()); + augmentBuilder.setVhostUser(vhostUserBuilder.build()); + } + + private static void setTap( + final @Nonnull org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input, + final VppInterfaceAugmentationBuilder augmentBuilder, + final Tap tap) { + final TapBuilder tapBuilder = new TapBuilder(); + tapBuilder.setMac(input.getPhysAddress()); + tapBuilder.setTapName(tap.getTapName()); +// tapBuilder.setDeviceInstance(); + augmentBuilder.setTap(tapBuilder.build()); + } + + private static void setVxlan(final VppInterfaceAugmentationBuilder augmentBuilder, final Vxlan vxlan) { + final VxlanBuilder vxlanBuilder = new VxlanBuilder(); + vxlanBuilder.setDst(vxlan.getDst()); + vxlanBuilder.setSrc(vxlan.getSrc()); + vxlanBuilder.setEncapVrfId(vxlan.getEncapVrfId()); + vxlanBuilder.setVni(new VxlanVni(vxlan.getVni())); + augmentBuilder.setVxlan(vxlanBuilder.build()); + } + + private static void setVxlanGpe(final VppInterfaceAugmentationBuilder augmentBuilder, final VxlanGpe vxlanGpe) { + final VxlanGpeBuilder vxlanGpeBuilder = new VxlanGpeBuilder(); + vxlanGpeBuilder.setLocal(vxlanGpe.getLocal()); + vxlanGpeBuilder.setRemote(vxlanGpe.getRemote()); + vxlanGpeBuilder.setVni(new VxlanGpeVni(vxlanGpe.getVni())); + vxlanGpeBuilder.setNextProtocol(vxlanGpe.getNextProtocol()); + vxlanGpeBuilder.setEncapVrfId(vxlanGpe.getEncapVrfId()); + vxlanGpeBuilder.setDecapVrfId(vxlanGpe.getDecapVrfId()); + augmentBuilder.setVxlanGpe(vxlanGpeBuilder.build()); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/SubInterfaceInitializationUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/SubInterfaceInitializationUtils.java new file mode 100644 index 000000000..7acc75bcd --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/SubInterfaceInitializationUtils.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.honeycomb.translate.v3po.initializers; + +import com.google.common.collect.Lists; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubInterfaceStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceStateAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfaces; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.AclBuilder; + +/** + * Utility class for sub interface initialization + */ +final class SubInterfaceInitializationUtils { + + private SubInterfaceInitializationUtils() { + throw new UnsupportedOperationException("Utility class cannot be instantiated"); + } + + static void initializeSubinterfaceStateAugmentation( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input, + final InterfaceBuilder builder) { + final SubinterfaceStateAugmentation subIfcAugmentation = + input.getAugmentation(SubinterfaceStateAugmentation.class); + if (subIfcAugmentation != null) { + final SubinterfaceAugmentationBuilder augmentBuilder = new SubinterfaceAugmentationBuilder(); + + final SubInterfaces subInterfaces = subIfcAugmentation.getSubInterfaces(); + if (subInterfaces != null) { + setSubInterfaces(augmentBuilder, subInterfaces); + } + + builder.addAugmentation(SubinterfaceAugmentation.class, augmentBuilder.build()); + } + } + + private static void setSubInterfaces(final SubinterfaceAugmentationBuilder augmentBuilder, + final SubInterfaces operationalData) { + + final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfacesBuilder + subInterfacesCfgBuilder = + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfacesBuilder(); + subInterfacesCfgBuilder.setSubInterface(Lists.transform(operationalData.getSubInterface(), + SubInterfaceInitializationUtils::convertSubInterface)); + augmentBuilder.setSubInterfaces(subInterfacesCfgBuilder.build()); + } + + private static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface convertSubInterface( + final SubInterface operationalData) { + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceBuilder subInterfaceCfgBuilder = + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceBuilder(); + + subInterfaceCfgBuilder.setEnabled(SubInterfaceStatus.Up.equals(operationalData.getAdminStatus())); + subInterfaceCfgBuilder.setIdentifier(operationalData.getIdentifier()); + subInterfaceCfgBuilder.setKey(new SubInterfaceKey(operationalData.getIdentifier())); + subInterfaceCfgBuilder.setL2(operationalData.getL2()); + subInterfaceCfgBuilder.setMatch(operationalData.getMatch()); + subInterfaceCfgBuilder.setTags(operationalData.getTags()); + subInterfaceCfgBuilder.setVlanType(operationalData.getVlanType()); + subInterfaceCfgBuilder.setIpv4(operationalData.getIpv4()); + subInterfaceCfgBuilder.setIpv6(operationalData.getIpv6()); + + if (operationalData.getAcl() != null) { + final AclBuilder aclBuilder = new AclBuilder(); + aclBuilder.setL2Acl(operationalData.getAcl().getL2Acl()); + aclBuilder.setIp4Acl(operationalData.getAcl().getIp4Acl()); + aclBuilder.setIp6Acl(operationalData.getAcl().getIp6Acl()); + subInterfaceCfgBuilder.setAcl(aclBuilder.build()); + } + + return subInterfaceCfgBuilder.build(); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppClasifierInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppClasifierInitializer.java new file mode 100644 index 000000000..42d1c59dc --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppClasifierInitializer.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.initializers; + +import io.fd.honeycomb.data.init.AbstractDataTreeConverter; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Initializes vpp-classfier node in config data tree based on operational state. + */ +public class VppClasifierInitializer extends AbstractDataTreeConverter<VppClassifierState, VppClassifier> { + private static final InstanceIdentifier<VppClassifierState> OPER_ID = + InstanceIdentifier.create(VppClassifierState.class); + private static final InstanceIdentifier<VppClassifier> CFG_ID = InstanceIdentifier.create(VppClassifier.class); + + public VppClasifierInitializer(@Nonnull final DataBroker bindingDataBroker) { + super(bindingDataBroker, OPER_ID, CFG_ID); + } + + @Override + protected VppClassifier convert(final VppClassifierState operationalData) { + final VppClassifierBuilder builder = new VppClassifierBuilder(); + builder.setClassifyTable(operationalData.getClassifyTable().stream() + .map(oper -> new ClassifyTableBuilder(oper).setName(oper.getName()).build()) + .collect(Collectors.toList())); + return builder.build(); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializer.java new file mode 100644 index 000000000..370de347b --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializer.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.initializers; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import io.fd.honeycomb.data.init.AbstractDataTreeConverter; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomainsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Initializes vpp node in config data tree based on operational state. + */ +public class VppInitializer extends AbstractDataTreeConverter<VppState, Vpp> { + private static final Logger LOG = LoggerFactory.getLogger(VppInitializer.class); + + public VppInitializer(@Nonnull final DataBroker bindingDataBroker) { + super(bindingDataBroker, InstanceIdentifier.create(VppState.class), InstanceIdentifier.create(Vpp.class)); + } + + // TODO move to v3po2vpp + + @Override + protected Vpp convert(final VppState operationalData) { + LOG.debug("VppInitializer.convert()"); + + VppBuilder vppBuilder = new VppBuilder(); + BridgeDomainsBuilder bdsBuilder = new BridgeDomainsBuilder(); + bdsBuilder.setBridgeDomain(Lists.transform(operationalData.getBridgeDomains().getBridgeDomain(), CONVERT_BD)); + vppBuilder.setBridgeDomains(bdsBuilder.build()); + return vppBuilder.build(); + } + + private static final Function<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain, BridgeDomain> + CONVERT_BD = + new Function<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain, BridgeDomain>() { + @Nullable + @Override + public BridgeDomain apply( + @Nullable final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain input) { + final BridgeDomainBuilder builder = new BridgeDomainBuilder(); + builder.setLearn(input.isLearn()); + builder.setUnknownUnicastFlood(input.isUnknownUnicastFlood()); + builder.setArpTermination(input.isArpTermination()); + builder.setFlood(input.isFlood()); + builder.setForward(input.isForward()); + builder.setKey(new BridgeDomainKey(input.getKey().getName())); + builder.setName(input.getName()); + setL2FibTable(builder, input.getL2FibTable()); + return builder.build(); + } + }; + + private static void setL2FibTable(@Nonnull final BridgeDomainBuilder builder, + @Nullable final L2FibTable l2FibTable) { + if (l2FibTable == null) { + return; + } + final L2FibTableBuilder tableBuilder = new L2FibTableBuilder() + .setL2FibEntry( + l2FibTable.getL2FibEntry().stream() + // Convert operational object to config. VPP does not support setting BVI (see v3po.yang) + .map(oper -> new L2FibEntryBuilder(oper).setBridgedVirtualInterface(null).build()) + .collect(Collectors.toList())); + builder.setL2FibTable(tableBuilder.build()); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizer.java new file mode 100644 index 000000000..c292073e3 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizer.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.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.rev150105.interfaces._interface.Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for enabling/disabling ACLs on given interface. + */ +public class AclCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Acl>, AclWriter { + + private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class); + private final NamingContext interfaceContext; + private final NamingContext classifyTableContext; + + public AclCustomizer(@Nonnull final FutureJVpp vppApi, @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext 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<Acl> id, @Nonnull final Acl dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + try { + setAcl(true, id, dataAfter, writeContext); + } catch (VppBaseCallException e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore, + @Nonnull final Acl 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<Acl> id, @Nonnull final Acl dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + try { + setAcl(false, id, dataBefore, writeContext); + } catch (VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void setAcl(final boolean isAdd, @Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl, + @Nonnull final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + 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/honeycomb/translate/v3po/interfaces/AclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclWriter.java new file mode 100644 index 000000000..1d538ac3f --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclWriter.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.honeycomb.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.AclBaseAttributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.InputAclSetInterface; +import org.openvpp.jvpp.dto.InputAclSetInterfaceReply; +import org.openvpp.jvpp.future.FutureJVpp; + +interface AclWriter { + + default void inputAclSetInterface(@Nonnull final FutureJVpp futureJvpp, final boolean isAdd, + @Nonnull final InstanceIdentifier<?> id, @Nonnull final AclBaseAttributes acl, + @Nonnegative final int ifIndex, @Nonnull final NamingContext classifyTableContext, + @Nonnull final MappingContext mappingContext) + throws VppBaseCallException, WriteTimeoutException { + 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.getIndex(tableName, mappingContext); + } + final Ip4Acl ip4Acl = acl.getIp4Acl(); + if (ip4Acl != null) { + final String tableName = checkNotNull(ip4Acl.getClassifyTable(), "IPv4 classify table is null"); + request.ip4TableIndex = classifyTableContext.getIndex(tableName, mappingContext); + } + final Ip6Acl ip6Acl = acl.getIp6Acl(); + if (ip6Acl != null) { + final String tableName = checkNotNull(ip6Acl.getClassifyTable(), "IPv6 classify table is null"); + request.ip6TableIndex = classifyTableContext.getIndex(tableName, mappingContext); + } + + final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage = + futureJvpp.inputAclSetInterface(request); + + TranslateUtils.getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/EthernetCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/EthernetCustomizer.java new file mode 100644 index 000000000..2dd0dbd00 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/EthernetCustomizer.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces; + +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.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.rev150105.interfaces._interface.Ethernet; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +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 FutureJVpp vppApi) { + super(vppApi); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ethernet> id, + @Nonnull final Ethernet dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + // TODO + 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) { + // TODO + LOG.warn("Unsupported, ignoring configuration {}", dataAfter); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ethernet> id, + @Nonnull final Ethernet dataBefore, @Nonnull final WriteContext writeContext) { + // TODO + LOG.warn("Unsupported, ignoring configuration delete {}", id); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterconnectionWriteUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterconnectionWriteUtils.java new file mode 100644 index 000000000..ecaaa4717 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterconnectionWriteUtils.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; + +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBased; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBased; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceSetL2Bridge; +import org.openvpp.jvpp.dto.SwInterfaceSetL2BridgeReply; +import org.openvpp.jvpp.dto.SwInterfaceSetL2Xconnect; +import org.openvpp.jvpp.dto.SwInterfaceSetL2XconnectReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class providing Interconnection CUD support. + */ +final class InterconnectionWriteUtils { + + private static final Logger LOG = LoggerFactory.getLogger(InterconnectionWriteUtils.class); + + private final FutureJVpp futureJvpp; + private final NamingContext interfaceContext; + private final NamingContext bridgeDomainContext; + + InterconnectionWriteUtils(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext bridgeDomainContext) { + this.futureJvpp = requireNonNull(futureJvpp, "futureJvpp 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 { + try { + 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 { + // FIXME how does choice extensibility work + // FIXME it is not even possible to create a dedicated customizer for Interconnection, since it's not a DataObject + // FIXME we might need a choice customizer + // THis choice is already from augment, so its probably not possible to augment augmented choice + LOG.error("Unable to handle Interconnection of type {}", ic.getClass()); + throw new WriteFailedException(id, "Unable to handle Interconnection of type " + ic.getClass()); + } + } catch (VppBaseCallException e) { + LOG.warn("Failed to update bridge/xconnect based interconnection flags for: {}, interconnection: {}", + ifcName, ic); + throw new WriteFailedException(id, "Unable to handle Interconnection of type " + ic.getClass(), e); + } + } + + void deleteInterconnection(final InstanceIdentifier<? extends DataObject> id, final int swIfIndex, + final String ifcName, final Interconnection ic, final WriteContext writeContext) + throws WriteFailedException { + try { + 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()); + } + } catch (VppBaseCallException e) { + LOG.warn("Failed to delete bridge/xconnect based interconnection flags for: {}, interconnection: {}", + ifcName, ic); + throw new WriteFailedException(id, "Unable to delete Interconnection of type " + ic.getClass(), e); + } + } + + private void setBridgeBasedL2(final InstanceIdentifier<? extends DataObject> id, final int swIfIndex, + final String ifcName, final BridgeBased bb, + final WriteContext writeContext, final byte enabled) + throws VppBaseCallException, WriteTimeoutException { + 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 = futureJvpp + .swInterfaceSetL2Bridge(getL2BridgeRequest(swIfIndex, bdId, shg, bvi, enabled)); + TranslateUtils.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 VppBaseCallException, WriteTimeoutException { + 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 = + futureJvpp + .swInterfaceSetL2Xconnect(getL2XConnectRequest(swIfIndex, outSwIfIndex, enabled)); + TranslateUtils.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/honeycomb/translate/v3po/interfaces/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizer.java new file mode 100644 index 000000000..1bad2cdca --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizer.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +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.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceSetFlags; +import org.openvpp.jvpp.dto.SwInterfaceSetFlagsReply; +import org.openvpp.jvpp.future.FutureJVpp; +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> { + + private static final Logger LOG = LoggerFactory.getLogger(InterfaceCustomizer.class); + private final NamingContext interfaceContext; + + public InterfaceCustomizer(final FutureJVpp 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 { + + try { + setInterface(id, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Update of VppInterfaceAugment failed", e); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Interface> id, + @Nonnull final Interface dataBefore, + @Nonnull final Interface dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + + try { + updateInterface(id, dataBefore, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Update of VppInterfaceAugment failed", e); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Interface> id, + @Nonnull final Interface dataBefore, + @Nonnull final WriteContext writeContext) { + + // TODO Handle deletes + } + + private void setInterface(final InstanceIdentifier<Interface> id, final Interface swIf, + final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + 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 VppBaseCallException, WriteTimeoutException { + + 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 VppBaseCallException, WriteTimeoutException { + 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 VppBaseCallException, WriteTimeoutException { + final CompletionStage<SwInterfaceSetFlagsReply> swInterfaceSetFlagsReplyFuture = getFutureJVpp().swInterfaceSetFlags( + getSwInterfaceSetFlagsInput(swIfIndex, enabled, (byte) 0 /* deleted */)); + + LOG.debug("Updating interface flags for: {}, index: {}, enabled: {}", swIfName, swIfIndex, enabled); + + TranslateUtils.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/honeycomb/translate/v3po/interfaces/L2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/L2Customizer.java new file mode 100644 index 000000000..881c82b53 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/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.honeycomb.translate.v3po.interfaces; + +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.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.rev150105.interfaces._interface.L2; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +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 FutureJVpp 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()); + // TODO handle update properly (if possible) + 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/honeycomb/translate/v3po/interfaces/RewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizer.java new file mode 100644 index 000000000..86af47709 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizer.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.honeycomb.translate.v3po.interfaces; + +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +import io.fd.honeycomb.translate.v3po.util.TagRewriteOperation; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.List; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +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.rev150527._802dot1q; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.RewriteBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTags; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewrite; +import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; +import org.openvpp.jvpp.future.FutureJVpp; +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> { + + private static final Logger LOG = LoggerFactory.getLogger(RewriteCustomizer.class); + private final NamingContext interfaceContext; + + public RewriteCustomizer(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + 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); + try { + setTagRewrite(id, subifName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to write interface {}(id=): {}", subifName, writeContext, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + 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 VppBaseCallException, WriteTimeoutException { + 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)); + + TranslateUtils.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: {}", ReflectionToStringBuilder.toString(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); + try { + setTagRewrite(id, subifName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to update interface {}(id=): {}", subifName, writeContext, dataAfter); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Rewrite> id, + @Nonnull final Rewrite dataBefore, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String subifName = getSubInterfaceName(id); + try { + 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); + } catch (VppBaseCallException e) { + LOG.warn("Failed to delete interface {}(id=): {}", subifName, writeContext, dataBefore); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizer.java new file mode 100644 index 000000000..fe7b7263e --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizer.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.honeycomb.translate.v3po.interfaces; + +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +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.rev150105.interfaces._interface.Routing; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceSetTable; +import org.openvpp.jvpp.dto.SwInterfaceSetTableReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RoutingCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Routing> { + + private static final Logger LOG = LoggerFactory.getLogger(RoutingCustomizer.class); + private final NamingContext interfaceContext; + + public RoutingCustomizer(final FutureJVpp 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(); + try { + setRouting(id, ifName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to set routing for interface: {}, {}, vxlan: {}", ifName, writeContext, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @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(); + try { + // TODO handle updates properly + setRouting(id, ifName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to update routing for interface: {}, {}, vxlan: {}", ifName, writeContext, dataAfter); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> id, + @Nonnull final Routing dataBefore, @Nonnull final WriteContext writeContext) { + // TODO implement delete + } + + private void setRouting(final InstanceIdentifier<Routing> id, final String name, final Routing rt, + final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException { + final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext()); + LOG.debug("Setting routing for interface: {}, {}. Routing: {}", name, swIfc, rt); + + int vrfId = (rt != null) + ? rt.getVrfId().intValue() + : 0; + + if (vrfId != 0) { + final CompletionStage<SwInterfaceSetTableReply> swInterfaceSetTableReplyCompletionStage = + getFutureJVpp().swInterfaceSetTable(getInterfaceSetTableRequest(swIfc, (byte) 0, /* isIpv6 */ vrfId)); + TranslateUtils.getReplyForWrite(swInterfaceSetTableReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Routing set successfully for interface: {}, {}, routing: {}", name, swIfc, rt); + } + } + + 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/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.java new file mode 100644 index 000000000..45b2a480d --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.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.honeycomb.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +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.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for enabling/disabling ACLs on given sub-interface. + */ +public class SubInterfaceAclCustomizer extends FutureJVppCustomizer + implements WriterCustomizer<Acl>, AclWriter { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class); + private final NamingContext interfaceContext; + private final NamingContext classifyTableContext; + + public SubInterfaceAclCustomizer(@Nonnull final FutureJVpp vppApi, @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext 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<Acl> id, @Nonnull final Acl dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + try { + setAcl(true, id, dataAfter, writeContext); + } catch (VppBaseCallException e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore, + @Nonnull final Acl 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<Acl> id, @Nonnull final Acl dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + try { + setAcl(false, id, dataBefore, writeContext); + } catch (VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void setAcl(final boolean isAdd, @Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl, + @Nonnull final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + 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/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizer.java new file mode 100644 index 000000000..6af19cb89 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizer.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.List; +import java.util.Objects; +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.rev150527._802dot1ad; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.MatchType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.Default; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.vlan.tagged.VlanTagged; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Tags; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.Tag; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.CreateSubif; +import org.openvpp.jvpp.dto.CreateSubifReply; +import org.openvpp.jvpp.dto.SwInterfaceSetFlags; +import org.openvpp.jvpp.dto.SwInterfaceSetFlagsReply; +import org.openvpp.jvpp.future.FutureJVpp; +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> { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceCustomizer.class); + private final NamingContext interfaceContext; + + public SubInterfaceCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + 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(); + try { + createSubInterface(id, superIfName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to create sub interface for: {}, subInterface: {}", superIfName, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + private void createSubInterface(final InstanceIdentifier<SubInterface> id, @Nonnull final String superIfName, + @Nonnull final SubInterface subInterface, + final WriteContext writeContext) throws VppBaseCallException, + WriteTimeoutException { + final int superIfIndex = interfaceContext.getIndex(superIfName, writeContext.getMappingContext()); + final CompletionStage<CreateSubifReply> createSubifReplyCompletionStage = + getFutureJVpp().createSubif(getCreateSubifRequest(subInterface, superIfIndex)); + + final CreateSubifReply reply = + TranslateUtils.getReplyForWrite(createSubifReplyCompletionStage.toCompletableFuture(), id); + + 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 add validation + CreateSubif request = new CreateSubif(); + request.subId = Math.toIntExact(subInterface.getIdentifier().intValue()); + request.swIfIndex = swIfIndex; + + final int numberOfTags = getNumberOfTags(subInterface); + 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()); + + final MatchType matchType = subInterface.getMatch().getMatchType(); // todo match should be mandatory + 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 int getNumberOfTags(@Nonnull final SubInterface subInterface) { + final Tags tags = subInterface.getTags(); + if (tags == null) { + return 0; + } + final List<Tag> tagList = tags.getTag(); + if (tagList == null) { + return 0; + } + return tagList.size(); + } + + 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 { + if (Objects.equals(dataBefore.isEnabled(), dataAfter.isEnabled())) { + LOG.debug("No state update will be performed. Ignoring config"); + return; // TODO shouldn't we throw exception here (if there will be dedicated L2 customizer)? + } + final String subIfaceName = getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), + Math.toIntExact(dataAfter.getIdentifier())); + try { + setInterfaceState(id, interfaceContext.getIndex(subIfaceName, writeContext.getMappingContext()), + booleanToByte(dataAfter.isEnabled())); + } catch (VppBaseCallException e) { + LOG.warn("Failed to update interface state for: interface if={}, enabled: {}", + subIfaceName, booleanToByte(dataAfter.isEnabled())); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + private void setInterfaceState(final InstanceIdentifier<SubInterface> id, final int swIfIndex, final byte enabled) + throws VppBaseCallException, WriteTimeoutException { + 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 = + TranslateUtils.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/honeycomb/translate/v3po/interfaces/SubInterfaceL2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceL2Customizer.java new file mode 100644 index 000000000..b420e73e3 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/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.honeycomb.translate.v3po.interfaces; + +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +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.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +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 FutureJVpp 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()); + // TODO handle update properly (if possible) + 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/honeycomb/translate/v3po/interfaces/TapCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizer.java new file mode 100644 index 000000000..b90e2c304 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizer.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces; + +import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteFailedException; +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.rev150105.interfaces._interface.Tap; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.TapConnect; +import org.openvpp.jvpp.dto.TapConnectReply; +import org.openvpp.jvpp.dto.TapDelete; +import org.openvpp.jvpp.dto.TapDeleteReply; +import org.openvpp.jvpp.dto.TapModify; +import org.openvpp.jvpp.dto.TapModifyReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TapCustomizer extends AbstractInterfaceTypeCustomizer<Tap> { + + private static final Logger LOG = LoggerFactory.getLogger(TapCustomizer.class); + private final NamingContext interfaceContext; + + public TapCustomizer(final FutureJVpp 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.rev150105.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(); + try { + createTap(id, ifcName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to set tap interface: {}, tap: {}", ifcName, dataAfter, e); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @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); + } + + try { + modifyTap(id, ifcName, index, dataAfter); + } catch (VppBaseCallException e) { + LOG.warn("Failed to set tap interface: {}, tap: {}", ifcName, dataAfter, e); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + @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); + } + + try { + deleteTap(id, ifcName, index, dataBefore, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to delete tap interface: {}, tap: {}", ifcName, dataBefore.getTapName(), e); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void createTap(final InstanceIdentifier<Tap> id, final String swIfName, final Tap tap, + final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Setting tap interface: {}. Tap: {}", swIfName, tap); + final CompletionStage<TapConnectReply> tapConnectFuture = + getFutureJVpp().tapConnect(getTapConnectRequest(tap.getTapName(), tap.getMac(), tap.getDeviceInstance())); + final TapConnectReply reply = + TranslateUtils.getReplyForWrite(tapConnectFuture.toCompletableFuture(), id); + 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 tap) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Modifying tap interface: {}. Tap: {}", swIfName, tap); + final CompletionStage<TapModifyReply> vxlanAddDelTunnelReplyCompletionStage = + getFutureJVpp().tapModify(getTapModifyRequest(tap.getTapName(), index, tap.getMac(), tap.getDeviceInstance())); + TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Tap modified successfully for: {}, tap: {}", swIfName, tap); + } + + private void deleteTap(final InstanceIdentifier<Tap> id, final String swIfName, final int index, + final Tap dataBefore, + final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Deleting tap interface: {}. Tap: {}", swIfName, dataBefore); + final CompletionStage<TapDeleteReply> vxlanAddDelTunnelReplyCompletionStage = + getFutureJVpp().tapDelete(getTapDeleteRequest(index)); + TranslateUtils.getReplyForWrite(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 = TranslateUtils.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 = TranslateUtils.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/honeycomb/translate/v3po/interfaces/VhostUserCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizer.java new file mode 100644 index 000000000..6f30b41c5 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizer.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteFailedException; +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.rev150105.VhostUserRole; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.CreateVhostUserIf; +import org.openvpp.jvpp.dto.CreateVhostUserIfReply; +import org.openvpp.jvpp.dto.DeleteVhostUserIf; +import org.openvpp.jvpp.dto.DeleteVhostUserIfReply; +import org.openvpp.jvpp.dto.ModifyVhostUserIf; +import org.openvpp.jvpp.dto.ModifyVhostUserIfReply; +import org.openvpp.jvpp.future.FutureJVpp; +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> { + + private static final Logger LOG = LoggerFactory.getLogger(VhostUserCustomizer.class); + private final NamingContext interfaceContext; + + public VhostUserCustomizer(@Nonnull final FutureJVpp 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.rev150105.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(); + try { + createVhostUserIf(id, swIfName, dataAfter, writeContext); + } catch (VppBaseCallException | IllegalInterfaceTypeException e) { + LOG.debug("Failed to create vhost user interface: {}, vhostUser: {}", swIfName, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + private void createVhostUserIf(final InstanceIdentifier<VhostUser> id, final String swIfName, + final VhostUser vhostUser, final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Creating vhost user interface: name={}, vhostUser={}", swIfName, vhostUser); + + final CompletionStage<CreateVhostUserIfReply> createVhostUserIfReplyCompletionStage = + getFutureJVpp().createVhostUserIf(getCreateVhostUserIfRequest(vhostUser)); + final CreateVhostUserIfReply reply = + TranslateUtils.getReplyForWrite(createVhostUserIfReplyCompletionStage.toCompletableFuture(), id); + 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 = TranslateUtils.booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole())); + request.sockFilename = vhostUser.getSocket().getBytes(); + request.renumber = 0; // TODO + request.customDevInstance = 0; // TODO + 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(); + try { + modifyVhostUserIf(id, swIfName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to update vhost user interface: {}, vhostUser: {}", swIfName, dataAfter); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + private void modifyVhostUserIf(final InstanceIdentifier<VhostUser> id, final String swIfName, + final VhostUser vhostUser, final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Updating vhost user interface: name={}, vhostUser={}", swIfName, vhostUser); + final CompletionStage<ModifyVhostUserIfReply> modifyVhostUserIfReplyCompletionStage = + getFutureJVpp() + .modifyVhostUserIf(getModifyVhostUserIfRequest(vhostUser, interfaceContext.getIndex(swIfName, writeContext.getMappingContext()))); + + TranslateUtils.getReplyForWrite(modifyVhostUserIfReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Vhost user interface updated successfully for: {}, vhostUser: {}", swIfName, vhostUser); + } + + private ModifyVhostUserIf getModifyVhostUserIfRequest(final VhostUser vhostUser, final int swIfIndex) { + ModifyVhostUserIf request = new ModifyVhostUserIf(); + request.isServer = TranslateUtils.booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole())); + request.sockFilename = vhostUser.getSocket().getBytes(); + request.renumber = 0; // TODO + request.customDevInstance = 0; // TODO + 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(); + try { + deleteVhostUserIf(id, swIfName, dataBefore, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to delete vhost user interface: {}, vhostUser: {}", swIfName, dataBefore); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void deleteVhostUserIf(final InstanceIdentifier<VhostUser> id, final String swIfName, + final VhostUser vhostUser, final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Deleting vhost user interface: name={}, vhostUser={}", swIfName, vhostUser); + final CompletionStage<DeleteVhostUserIfReply> deleteVhostUserIfReplyCompletionStage = + getFutureJVpp().deleteVhostUserIf(getDeleteVhostUserIfRequest(interfaceContext.getIndex(swIfName, writeContext.getMappingContext()))); + + TranslateUtils.getReplyForWrite(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/honeycomb/translate/v3po/interfaces/VxlanCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizer.java new file mode 100644 index 000000000..5b424449d --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizer.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.net.InetAddresses; +import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteFailedException; +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.rev150105.VxlanTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.VxlanAddDelTunnel; +import org.openvpp.jvpp.dto.VxlanAddDelTunnelReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// TODO extract common code from all Interface type specific writer customizers into a superclass +public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer<Vxlan> { + + private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class); + private final NamingContext interfaceContext; + + public VxlanCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @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(); + try { + createVxlanTunnel(id, swIfName, dataAfter, writeContext); + } catch (VppBaseCallException | IllegalInterfaceTypeException e) { + LOG.debug("Failed to set vxlan tunnel for interface: {}, vxlan: {}", swIfName, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @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(); + try { + deleteVxlanTunnel(id, swIfName, dataBefore, writeContext); + } catch (VppBaseCallException e) { + LOG.debug("Failed to delete vxlan tunnel for interface: {}, vxlan: {}", swIfName, dataBefore); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void createVxlanTunnel(final InstanceIdentifier<Vxlan> id, final String swIfName, final Vxlan vxlan, + final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException { + 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 = + TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Vxlan tunnel set successfully for: {}, vxlan: {}", swIfName, vxlan); + if(interfaceContext.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 = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext()); + LOG.debug("Removing updated mapping of a vxlan tunnel, id: {}, former name: {}, new name: {}", + reply.swIfIndex, formerName, swIfName); + interfaceContext.removeName(formerName, writeContext.getMappingContext()); + } + // Add new interface to our interface context + interfaceContext.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 VppBaseCallException, WriteTimeoutException { + 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)); + + TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Vxlan tunnel deleted successfully for: {}, vxlan: {}", swIfName, vxlan); + // Remove interface from our interface context + interfaceContext.removeName(swIfName, writeContext.getMappingContext()); + } + + 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/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizer.java new file mode 100644 index 000000000..95ed55570 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizer.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.net.InetAddresses; +import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +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.rev150105.VxlanGpeTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpe; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.VxlanGpeAddDelTunnel; +import org.openvpp.jvpp.dto.VxlanGpeAddDelTunnelReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VxlanGpeCustomizer extends AbstractInterfaceTypeCustomizer<VxlanGpe> { + + private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class); + private final NamingContext interfaceContext; + + public VxlanGpeCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @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(); + try { + createVxlanGpeTunnel(id, swIfName, dataAfter, writeContext); + } catch (VppBaseCallException | IllegalInterfaceTypeException e) { + LOG.warn("Failed to set VxlanGpe tunnel for interface: {}, VxlanGpe: {}", swIfName, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @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(); + try { + deleteVxlanGpeTunnel(id, swIfName, dataBefore, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to delete VxlanGpe tunnel for interface: {}, VxlanGpe: {}", swIfName, dataBefore); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void createVxlanGpeTunnel(final InstanceIdentifier<VxlanGpe> id, final String swIfName, + final VxlanGpe vxlanGpe, final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + final byte isIpv6 = (byte) (isIpv6(vxlanGpe) ? 1 : 0); + final InetAddress Local = InetAddresses.forString(getAddressString(vxlanGpe.getLocal())); + final InetAddress Remote = InetAddresses.forString(getAddressString(vxlanGpe.getRemote())); + + 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 = + TranslateUtils.getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("VxlanGpe tunnel set successfully for: {}, VxlanGpe: {}", swIfName, vxlanGpe); + if(interfaceContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) { + final String formerName = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext()); + LOG.debug("Removing updated mapping of a vxlan-gpe 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 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 VppBaseCallException, WriteTimeoutException { + final byte isIpv6 = (byte) (isIpv6(VxlanGpe) ? 1 : 0); + final InetAddress local = InetAddresses.forString(getAddressString(VxlanGpe.getLocal())); + final InetAddress remote = InetAddresses.forString(getAddressString(VxlanGpe.getRemote())); + + 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)); + + TranslateUtils.getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("VxlanGpe tunnel deleted successfully for: {}, VxlanGpe: {}", swIfName, VxlanGpe); + // Remove interface from our interface context + interfaceContext.removeName(swIfName, writeContext.getMappingContext()); + } + + 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/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java new file mode 100644 index 000000000..74d546d65 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.ip; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.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.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.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for writing {@link Address} + */ +public class Ipv4AddressCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer<Address, AddressKey> { + + private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class); + private final NamingContext interfaceContext; + + public Ipv4AddressCustomizer(FutureJVpp futureJvpp, NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = interfaceContext; + } + + @Override + public void writeCurrentAttributes(InstanceIdentifier<Address> id, Address dataAfter, WriteContext writeContext) + throws WriteFailedException { + setAddress(true, id, dataAfter, writeContext); + } + + @Override + public void updateCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, Address dataAfter, + WriteContext writeContext) throws WriteFailedException { + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, + new UnsupportedOperationException("Operation not supported")); + } + + @Override + public void deleteCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, WriteContext writeContext) + throws WriteFailedException { + setAddress(false, id, dataBefore, writeContext); + } + + private void setAddress(boolean add, final InstanceIdentifier<Address> id, final Address address, + final WriteContext writeContext) throws WriteFailedException { + + final String interfaceName = id.firstKeyOf(Interface.class).getName(); + final int interfaceIndex = interfaceContext.getIndex(interfaceName, writeContext.getMappingContext()); + + Subnet subnet = address.getSubnet(); + + if (subnet instanceof PrefixLength) { + setPrefixLengthSubnet(add, id, interfaceName, interfaceIndex, address, (PrefixLength) subnet); + } else if (subnet instanceof Netmask) { + setNetmaskSubnet(add, id, interfaceName, interfaceIndex, address, (Netmask) subnet); + } else { + // FIXME how does choice extensibility work + // FIXME it is not even possible to create a dedicated + // customizer for Interconnection, since it's not a DataObject + // FIXME we might need a choice customizer + // THis choice is already from augment, so its probably not + // possible to augment augmented choice + LOG.error("Unable to handle subnet of type {}", subnet.getClass()); + throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass()); + } + } + + private void setNetmaskSubnet(final boolean add, @Nonnull final InstanceIdentifier<Address> id, + @Nonnull final String interfaceName, final int interfaceIndex, + @Nonnull final Address address, @Nonnull final Netmask subnet) + throws WriteFailedException { + try { + LOG.debug("Setting Subnet(subnet-mask) for interface: {}(id={}). Subnet: {}, address: {}", + interfaceName, interfaceIndex, subnet, address); + + final DottedQuad netmask = subnet.getNetmask(); + checkNotNull(netmask, "netmask value should not be null"); + + final byte subnetLength = Ipv4WriteUtils.getSubnetMaskLength(netmask.getValue()); + Ipv4WriteUtils.addDelAddress(getFutureJVpp(), add, id, interfaceIndex, address.getIp(), subnetLength); + } catch (VppBaseCallException e) { + LOG.warn("Failed to set Subnet(subnet-mask) for interface: {}(id={}). Subnet: {}, address: {}", + interfaceName, interfaceIndex, subnet, address); + throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); + } + } + + private void setPrefixLengthSubnet(final boolean add, @Nonnull final InstanceIdentifier<Address> id, + @Nonnull final String interfaceName, final int interfaceIndex, + @Nonnull final Address address, @Nonnull final PrefixLength subnet) + throws WriteFailedException { + try { + LOG.debug("Setting Subnet(prefix-length) for interface: {}(id={}). Subnet: {}, address: {}", + interfaceName, interfaceIndex, subnet, address); + + Ipv4WriteUtils.addDelAddress(getFutureJVpp(), add, id, interfaceIndex, address.getIp(), + subnet.getPrefixLength().byteValue()); + + LOG.debug("Subnet(prefix-length) set successfully for interface: {}(id={}). Subnet: {}, address: {}", + interfaceName, interfaceIndex, subnet, address); + } catch (VppBaseCallException e) { + LOG.warn("Failed to set Subnet(prefix-length) for interface: {}(id={}). Subnet: {}, address: {}", + interfaceName, interfaceIndex, subnet, address); + throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4Customizer.java new file mode 100644 index 000000000..c956794ac --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4Customizer.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.ip; + +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.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.ip.rev140616.interfaces._interface.Ipv4; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +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); + private final NamingContext interfaceContext; + + public Ipv4Customizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id, + @Nonnull final Ipv4 dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifcName = id.firstKeyOf(Interface.class).getName(); + setIpv4(id, ifcName, dataAfter, writeContext); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id, + @Nonnull final Ipv4 dataBefore, @Nonnull final Ipv4 dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifcName = id.firstKeyOf(Interface.class).getName(); + + // TODO handle update in a better way + setIpv4(id, ifcName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id, + @Nonnull final Ipv4 dataBefore, @Nonnull final WriteContext writeContext) { + // TODO implement delete + } + + private void setIpv4(final InstanceIdentifier<Ipv4> id, final String name, final Ipv4 ipv4, + final WriteContext writeContext) + throws WriteFailedException { + final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext()); + + LOG.warn("Ignoring Ipv4 leaf nodes (create/update is not supported)"); + // TODO add support for enabled leaf + // TODO add support for forwarding leaf + // TODO add support for mtu leaf + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java new file mode 100644 index 000000000..edd49f2f5 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.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.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +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.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.IpNeighborAddDel; +import org.openvpp.jvpp.future.FutureJVpp; +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> { + + + private static final Logger LOG = LoggerFactory.getLogger(Ipv4NeighbourCustomizer.class); + final NamingContext interfaceContext; + + public Ipv4NeighbourCustomizer(final FutureJVpp futureJvpp, final NamingContext interfaceContext) { + super(futureJvpp); + 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"); + try { + addDelNeighbourAndReply(id, true, + interfaceContext.getIndex(interfaceName, mappingContext), dataAfter); + LOG.info("Neighbour successfully written"); + } catch (VppBaseCallException e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @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); + try { + addDelNeighbourAndReply(id, false, + interfaceContext.getIndex(interfaceName, mappingContext), dataBefore); + LOG.info("Neighbour {} successfully deleted", id); + } catch (VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void addDelNeighbourAndReply(InstanceIdentifier<Neighbor> id, boolean add, int parentInterfaceIndex, + Neighbor data) + throws VppBaseCallException, WriteTimeoutException { + + IpNeighborAddDel request = new IpNeighborAddDel(); + + request.isAdd = TranslateUtils.booleanToByte(add); + request.isIpv6 = 0; + request.isStatic = 1; + request.dstAddress = TranslateUtils.ipv4AddressNoZoneToArray(data.getIp()); + request.macAddress = TranslateUtils.parseMac(data.getLinkLayerAddress().getValue()); + request.swIfIndex = parentInterfaceIndex; + + //TODO if it is necessary for future use ,make adjustments to be able to set vrfid + //request.vrfId + TranslateUtils.getReplyForWrite(getFutureJVpp().ipNeighborAddDel(request).toCompletableFuture(), id); + } +}
\ No newline at end of file diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4WriteUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4WriteUtils.java new file mode 100644 index 000000000..3aeb2dfaf --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4WriteUtils.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.ip; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress; +import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply; +import org.openvpp.jvpp.future.FutureJVpp; + +/** + * Utility class providing Ipv4 CUD support. + */ +// TODO replace with interface with default methods or abstract class +final class Ipv4WriteUtils { + + private static final int DOTTED_QUAD_MASK_LENGTH = 4; + private static final int IPV4_ADDRESS_PART_BITS_COUNT = 8; + private static final int NETMASK_PART_LIMIT = 256; // 2 power to 8 + + private Ipv4WriteUtils() { + throw new UnsupportedOperationException("This utility class cannot be instantiated"); + } + + static void addDelAddress(@Nonnull final FutureJVpp futureJvpp, final boolean add, final InstanceIdentifier<?> id, + @Nonnegative final int ifaceId, + @Nonnull final Ipv4AddressNoZone address, @Nonnegative final byte prefixLength) + throws VppBaseCallException, WriteTimeoutException { + checkArgument(prefixLength > 0, "Invalid prefix length"); + checkNotNull(address, "address should not be null"); + + final byte[] addressBytes = TranslateUtils.ipv4AddressNoZoneToArray(address); + + final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage = + futureJvpp.swInterfaceAddDelAddress( + getSwInterfaceAddDelAddressRequest(ifaceId, TranslateUtils.booleanToByte(add) /* isAdd */, + (byte) 0 /* isIpv6 */, (byte) 0 /* delAll */, prefixLength, addressBytes)); + + TranslateUtils.getReplyForWrite(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture(), id); + } + + static SwInterfaceAddDelAddress getSwInterfaceAddDelAddressRequest(final int swIfc, final byte isAdd, + final byte ipv6, final byte deleteAll, + final byte length, final byte[] addr) { + final SwInterfaceAddDelAddress swInterfaceAddDelAddress = new SwInterfaceAddDelAddress(); + swInterfaceAddDelAddress.swIfIndex = swIfc; + swInterfaceAddDelAddress.isAdd = isAdd; + swInterfaceAddDelAddress.isIpv6 = ipv6; + swInterfaceAddDelAddress.delAll = deleteAll; + swInterfaceAddDelAddress.address = addr; + swInterfaceAddDelAddress.addressLength = length; + return swInterfaceAddDelAddress; + } + + /** + * Returns the prefix size in bits of the specified subnet mask. Example: For the subnet mask 255.255.255.128 it + * returns 25 while for 255.0.0.0 it returns 8. If the passed subnetMask array is not complete or contains not only + * leading ones, IllegalArgumentExpression is thrown + * + * @param mask the subnet mask in dot notation 255.255.255.255 + * @return the prefix length as number of bits + */ + static byte getSubnetMaskLength(final String mask) { + String[] maskParts = mask.split("\\."); + + checkArgument(maskParts.length == DOTTED_QUAD_MASK_LENGTH, + "Network mask %s is not in Quad Dotted Decimal notation!", mask); + + long maskAsNumber = 0; + for (int i = 0; i < DOTTED_QUAD_MASK_LENGTH; i++) { + maskAsNumber <<= IPV4_ADDRESS_PART_BITS_COUNT; + int value = Integer.parseInt(maskParts[i]); + checkArgument(value < NETMASK_PART_LIMIT, "Network mask %s contains invalid number(s) over 255!", mask); + checkArgument(value >= 0, "Network mask %s contains invalid negative number(s)!", mask); + maskAsNumber += value; + } + + String bits = Long.toBinaryString(maskAsNumber); + checkArgument(bits.length() == IPV4_ADDRESS_PART_BITS_COUNT * DOTTED_QUAD_MASK_LENGTH, + "Incorrect network mask %s", mask); + final int leadingOnes = bits.indexOf('0'); + checkArgument(leadingOnes != -1, "Broadcast address %s is not allowed!", mask); + checkArgument(bits.substring(leadingOnes).indexOf('1') == -1, + "Non-contiguous network mask %s is not allowed!", mask); + return (byte) leadingOnes; + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv6Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv6Customizer.java new file mode 100644 index 000000000..1e3a3e747 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv6Customizer.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.honeycomb.translate.v3po.interfaces.ip; + +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +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 org.openvpp.jvpp.future.FutureJVpp; +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 FutureJVpp vppApi) { + super(vppApi); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv6> id, + @Nonnull final Ipv6 dataAfter, @Nonnull final WriteContext writeContext) { + // TODO + 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); + // TODO + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java new file mode 100644 index 000000000..700139704 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.ip; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.Subnet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.Netmask; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLength; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Write customizer for sub-interface {@link Address} + */ +public class SubInterfaceIpv4AddressCustomizer extends FutureJVppCustomizer + implements ListWriterCustomizer<Address, AddressKey> { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIpv4AddressCustomizer.class); + private final NamingContext interfaceContext; + + public SubInterfaceIpv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = checkNotNull(interfaceContext, "interface context should not be null"); + } + + @Override + public void writeCurrentAttributes(InstanceIdentifier<Address> id, Address dataAfter, WriteContext writeContext) + throws WriteFailedException { + setAddress(true, id, dataAfter, writeContext); + } + + @Override + public void updateCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, Address dataAfter, + WriteContext writeContext) throws WriteFailedException { + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, + new UnsupportedOperationException("Operation not supported")); + } + + @Override + public void deleteCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, WriteContext writeContext) + throws WriteFailedException { + setAddress(false, id, dataBefore, writeContext); + } + + private void setAddress(boolean add, final InstanceIdentifier<Address> id, final Address address, + final WriteContext writeContext) throws WriteFailedException { + + final String interfaceName = id.firstKeyOf(Interface.class).getName(); + final String subInterfaceName = getSubInterfaceName(id); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); + + Subnet subnet = address.getSubnet(); + + if (subnet instanceof PrefixLength) { + setPrefixLengthSubnet(add, id, interfaceName, subInterfaceIndex, address, (PrefixLength) subnet); + } else if (subnet instanceof Netmask) { + setNetmaskSubnet(add, id, interfaceName, subInterfaceIndex, address, (Netmask) subnet); + } else { + // FIXME how does choice extensibility work + // FIXME it is not even possible to create a dedicated + // customizer for Interconnection, since it's not a DataObject + // FIXME we might need a choice customizer + // THis choice is already from augment, so its probably not + // possible to augment augmented choice + LOG.error("Unable to handle subnet of type {}", subnet.getClass()); + throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass()); + } + } + + private String getSubInterfaceName(@Nonnull final InstanceIdentifier<Address> id) { + final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); + final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); + return SubInterfaceUtils + .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); + } + + private void setNetmaskSubnet(final boolean add, @Nonnull final InstanceIdentifier<Address> id, + @Nonnull final String subInterfaceName, final int subInterfaceIndex, + @Nonnull final Address address, @Nonnull final Netmask subnet) + throws WriteFailedException { + try { + LOG.debug("Setting Subnet(subnet-mask) for sub-interface: {}(id={}). Subnet: {}, address: {}", + subInterfaceName, subInterfaceIndex, subnet, address); + + final DottedQuad netmask = subnet.getNetmask(); + checkNotNull(netmask, "netmask value should not be null"); + + final byte subnetLength = Ipv4WriteUtils.getSubnetMaskLength(netmask.getValue()); + Ipv4WriteUtils.addDelAddress(getFutureJVpp(), add, id, subInterfaceIndex, address.getIp(), subnetLength); + + } catch (VppBaseCallException e) { + LOG.warn("Failed to set Subnet(subnet-mask) for sub-interface: {}(id={}). Subnet: {}, address: {}", + subInterfaceName, subInterfaceIndex, subnet, address); + throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); + } + } + + private void setPrefixLengthSubnet(final boolean add, @Nonnull final InstanceIdentifier<Address> id, + @Nonnull final String subInterfaceName, final int subInterfaceIndex, + @Nonnull final Address address, @Nonnull final PrefixLength subnet) + throws WriteFailedException { + try { + LOG.debug("Setting Subnet(prefix-length) for sub-interface: {}(id={}). Subnet: {}, address: {}", + subInterfaceName, subInterfaceIndex, subnet, address); + + Ipv4WriteUtils.addDelAddress(getFutureJVpp(), add, id, subInterfaceIndex, address.getIp(), + subnet.getPrefixLength().byteValue()); + + LOG.debug("Subnet(prefix-length) set successfully for sub-interface: {}(id={}). Subnet: {}, address: {}", + subInterfaceName, subInterfaceIndex, subnet, address); + } catch (VppBaseCallException e) { + LOG.warn("Failed to set Subnet(prefix-length) for sub-interface: {}(id={}). Subnet: {}, address: {}", + subInterfaceName, subInterfaceIndex, subnet, address); + throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizer.java new file mode 100644 index 000000000..1b76a0382 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizer.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import 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.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.AclBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifyTableByInterface; +import org.openvpp.jvpp.dto.ClassifyTableByInterfaceReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for reading ACLs enabled on given interface. + */ +public class AclCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer<Acl, AclBuilder>, AclReader { + + private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class); + private final NamingContext interfaceContext; + private final NamingContext classifyTableContext; + + public AclCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext 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 Acl readValue) { + ((VppInterfaceStateAugmentationBuilder) parentBuilder).setAcl(readValue); + } + + @Nonnull + @Override + public AclBuilder getBuilder(@Nonnull final InstanceIdentifier<Acl> id) { + return new AclBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final AclBuilder 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()); + try { + final ClassifyTableByInterfaceReply reply = TranslateUtils + .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()); + } + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclReader.java new file mode 100644 index 000000000..c64c096a8 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/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.honeycomb.translate.v3po.interfacesstate; + +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4AclBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6AclBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2AclBuilder; + +interface AclReader { + + @Nonnull + default L2Acl readL2Acl(final int l2TableId, @Nonnull final NamingContext classifyTableContext, + @Nonnull final MappingContext mappingContext) { + if (l2TableId == ~0) { + return null; + } + return new L2AclBuilder() + .setClassifyTable(classifyTableContext.getName(l2TableId, mappingContext)).build(); + } + + @Nonnull + default Ip4Acl readIp4Acl(final int ip4TableId, @Nonnull final NamingContext classifyTableContext, + @Nonnull final MappingContext mappingContext) { + if (ip4TableId == ~0) { + return null; + } + return new Ip4AclBuilder() + .setClassifyTable(classifyTableContext.getName(ip4TableId, mappingContext)).build(); + } + + @Nonnull + default Ip6Acl readIp6Acl(final int ip6TableId, @Nonnull final NamingContext classifyTableContext, + @Nonnull final MappingContext mappingContext) { + if (ip6TableId == ~0) { + return null; + } + return new Ip6AclBuilder() + .setClassifyTable(classifyTableContext.getName(ip6TableId, mappingContext)).build(); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/EthernetCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/EthernetCustomizer.java new file mode 100644 index 000000000..30d3f6482 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/EthernetCustomizer.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfacesstate; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.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.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Ethernet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.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.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class EthernetCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer<Ethernet, EthernetBuilder> { + + private static final Logger LOG = LoggerFactory.getLogger(EthernetCustomizer.class); + private NamingContext interfaceContext; + + public EthernetCustomizer(@Nonnull final FutureJVpp 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 = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, key.getName(), + interfaceContext.getIndex(key.getName(), ctx.getMappingContext()), ctx.getModificationCache()); + + 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; + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterconnectionReadUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterconnectionReadUtils.java new file mode 100644 index 000000000..c01d27a2d --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterconnectionReadUtils.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.honeycomb.translate.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.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +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.rev150105.l2.base.attributes.Interconnection; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.BridgeDomainDetails; +import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump; +import org.openvpp.jvpp.dto.BridgeDomainDump; +import org.openvpp.jvpp.dto.BridgeDomainSwIfDetails; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class providing Interconnection read support. + */ +// FIXME this should be customizer, but it is not possible because Interconnection is not a DataObject +final class InterconnectionReadUtils { + + private static final Logger LOG = LoggerFactory.getLogger(InterconnectionReadUtils.class); + + private final FutureJVpp futureJvpp; + private final NamingContext interfaceContext; + private final NamingContext bridgeDomainContext; + + InterconnectionReadUtils(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext bridgeDomainContext) { + this.futureJvpp = requireNonNull(futureJvpp, "futureJvpp 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 = InterfaceUtils.getVppInterfaceDetails(futureJvpp, id, ifaceName, + ifaceId, ctx.getModificationCache()); + 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 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 { + try { + // We need to perform full bd dump, because there is no way + // to ask VPP for BD details given interface id/name (TODO add it to vpp.api?) + // TODO cache dump result + final BridgeDomainDump request = new BridgeDomainDump(); + request.bdId = -1; + + final CompletableFuture<BridgeDomainDetailsReplyDump> bdCompletableFuture = + futureJvpp.bridgeDomainSwIfDump(request).toCompletableFuture(); + return TranslateUtils.getReplyForRead(bdCompletableFuture, id); + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizer.java new file mode 100644 index 000000000..082b68559 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizer.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfacesstate; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +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.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.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump; +import org.openvpp.jvpp.dto.SwInterfaceDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for reading ietf-interfaces:interfaces-state/interface. + */ +public class InterfaceCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer<Interface, InterfaceKey, InterfaceBuilder> { + + private static final Logger LOG = LoggerFactory.getLogger(InterfaceCustomizer.class); + public static final String DUMPED_IFCS_CONTEXT_KEY = + InterfaceCustomizer.class.getName() + "dumpedInterfacesDuringGetAllIds"; + + private final NamingContext interfaceContext; + + public InterfaceCustomizer(@Nonnull final FutureJVpp jvpp, final NamingContext interfaceContext) { + super(jvpp); + this.interfaceContext = interfaceContext; + } + + @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(); + + // Pass cached details from getAllIds to getDetails to avoid additional dumps + final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, ifaceName, + interfaceContext.getIndex(ifaceName, ctx.getMappingContext()), ctx.getModificationCache()); + 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(InterfaceUtils.getInterfaceType(new String(iface.interfaceName).intern())); + builder.setIfIndex(InterfaceUtils.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(InterfaceUtils.vppInterfaceSpeedToYang(iface.linkSpeed)); + } + if (iface.l2AddressLength == 6) { + builder.setPhysAddress(new PhysAddress(InterfaceUtils.vppPhysAddrToYang(iface.l2Address))); + } + LOG.trace("Base attributes read for interface: {} as: {}", ifaceName, builder); + } + + @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); + } + + @Nonnull + @Override + public List<InterfaceKey> getAllIds(@Nonnull final InstanceIdentifier<Interface> id, + @Nonnull final ReadContext context) throws ReadFailedException { + try { + 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 = + TranslateUtils.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 + context.getModificationCache().put(DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream() + .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails))); + + interfacesKeys = ifaces.swInterfaceDetails.stream() + .filter(elt -> elt != null) + .map((elt) -> { + // Store interface name from VPP in context if not yet present + if (!interfaceContext.containsName(elt.swIfIndex, context.getMappingContext())) { + interfaceContext.addName(elt.swIfIndex, TranslateUtils.toString(elt.interfaceName), + context.getMappingContext()); + } + LOG.trace("Interface with name: {}, VPP name: {} and index: {} found in VPP", + interfaceContext.getName(elt.swIfIndex, context.getMappingContext()), elt.interfaceName, + elt.swIfIndex); + + return elt; + }) + .filter(InterfaceCustomizer::isRegularInterface) // filter out sub-interfaces + .map((elt) -> new InterfaceKey(interfaceContext.getName(elt.swIfIndex, context.getMappingContext()))) + .collect(Collectors.toList()); + + LOG.debug("Interfaces found in VPP: {}", interfacesKeys); + return interfacesKeys; + } catch (VppBaseCallException e) { + LOG.warn("getAllIds for id :{} failed with exception ", id, e); + throw new ReadFailedException(id, e); + } + } + + private static boolean isRegularInterface(final SwInterfaceDetails iface) { + return iface.subId == 0; + } + + @Override + public void merge(@Nonnull final org.opendaylight.yangtools.concepts.Builder<? extends DataObject> builder, + @Nonnull final List<Interface> readData) { + ((InterfacesStateBuilder) builder).setInterface(readData); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java new file mode 100644 index 000000000..b7c1e518a --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.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.honeycomb.translate.v3po.util.TranslateUtils; +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.rev150105.Tap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump; +import org.openvpp.jvpp.dto.SwInterfaceDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class InterfaceUtils { + private static final Logger LOG = LoggerFactory.getLogger(InterfaceUtils.class); + + private static final Gauge64 vppLinkSpeed0 = new Gauge64(BigInteger.ZERO); + private static final Gauge64 vppLinkSpeed1 = new Gauge64(BigInteger.valueOf(10L * 1000000)); + private static final Gauge64 vppLinkSpeed2 = new Gauge64(BigInteger.valueOf(100L * 1000000)); + private static final Gauge64 vppLinkSpeed4 = new Gauge64(BigInteger.valueOf(1000L * 1000000)); + private static final Gauge64 vppLinkSpeed8 = new Gauge64(BigInteger.valueOf(10000L * 1000000)); + private static final Gauge64 vppLinkSpeed16 = new Gauge64(BigInteger.valueOf(40000L * 1000000)); + private static final Gauge64 vppLinkSpeed32 = new Gauge64(BigInteger.valueOf(100000L * 1000000)); + + private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray(); + + private static final int PHYSICAL_ADDRESS_LENGTH = 6; + + private static final Collector<SwInterfaceDetails, ?, SwInterfaceDetails> SINGLE_ITEM_COLLECTOR = + RWUtils.singleItemCollector(); + + private InterfaceUtils() { + throw new UnsupportedOperationException("This utility class cannot be instantiated"); + } + + /** + * 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 + */ + public static 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; + } + } + + private static final 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]); + } + + // TODO rename and move to V3poUtils + + /** + * 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 + */ + public static String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress) { + return vppPhysAddrToYang(vppPhysAddress, 0); + } + + public static 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); + } + + public static String printHexBinary(@Nonnull final byte[] bytes) { + Objects.requireNonNull(bytes, "bytes array should not be null"); + return printHexBinary(bytes, 0, bytes.length); + } + + private static 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 + */ + public static 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 + */ + public static 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 futureJvpp 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 + public static SwInterfaceDetails getVppInterfaceDetails(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final InstanceIdentifier<?> id, + @Nonnull final String name, final int index, + @Nonnull final ModificationCache ctx) + throws ReadFailedException { + requireNonNull(futureJvpp, "futureJvpp 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; + try { + CompletionStage<SwInterfaceDetailsReplyDump> requestFuture = futureJvpp.swInterfaceDump(request); + ifaces = TranslateUtils.getReplyForRead(requestFuture.toCompletableFuture(), id); + if (null == ifaces || null == ifaces.swInterfaceDetails || ifaces.swInterfaceDetails.isEmpty()) { + request.nameFilterValid = 0; + + LOG.warn("VPP returned null instead of interface by key {} and its not cached", name); + LOG.warn("Iterating through all the interfaces to find interface: {}", name); + + // Or else just perform full dump and do inefficient filtering + requestFuture = futureJvpp.swInterfaceDump(request); + ifaces = TranslateUtils.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); + } + } catch (VppBaseCallException e) { + LOG.warn("getVppInterfaceDetails for id :{} and name :{} failed with exception :", id, name, e); + throw new ReadFailedException(id, e); + } + + // 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 + public static 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("VirtualEthernet")) { + return VhostUser.class; + } + + return EthernetCsmacd.class; + } + + /** + * Check interface type. Uses interface details from VPP to determine. Uses {@link + * #getVppInterfaceDetails(FutureJVpp, InstanceIdentifier, String, int, ModificationCache)} internally so tries to + * utilize cache before asking VPP. + */ + static boolean isInterfaceOfType(@Nonnull final FutureJVpp jvpp, + @Nonnull final ModificationCache cache, + @Nonnull final InstanceIdentifier<?> id, + final int index, + @Nonnull final Class<? extends InterfaceType> ifcType) throws ReadFailedException { + final String name = id.firstKeyOf(Interface.class).getName(); + final SwInterfaceDetails vppInterfaceDetails = + getVppInterfaceDetails(jvpp, id, name, index, cache); + + return isInterfaceOfType(ifcType, vppInterfaceDetails); + } + + static boolean isInterfaceOfType(final Class<? extends InterfaceType> ifcType, + final SwInterfaceDetails cachedDetails) { + return ifcType.equals(getInterfaceType(TranslateUtils.toString(cachedDetails.interfaceName))); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2Customizer.java new file mode 100644 index 000000000..4e18c9804 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2Customizer.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.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.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +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.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2Builder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nonnull; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Customizer for reading ietf-interfaces:interfaces-state/interface/iface_name/v3po:l2 + */ +public class L2Customizer extends FutureJVppCustomizer implements ReaderCustomizer<L2, L2Builder> { + + private static final Logger LOG = LoggerFactory.getLogger(L2Customizer.class); + private final InterconnectionReadUtils icReadUtils; + + public L2Customizer(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext bridgeDomainContext) { + super(futureJvpp); + this.icReadUtils = new InterconnectionReadUtils(futureJvpp, 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)); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizer.java new file mode 100644 index 000000000..87bd1b25b --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizer.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.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.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +import io.fd.honeycomb.translate.v3po.util.TagRewriteOperation; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +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.rev150527._802dot1ad; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1q; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.RewriteBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTags; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTagsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTagsKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.future.FutureJVpp; +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> { + + private static final Logger LOG = LoggerFactory.getLogger(RewriteCustomizer.class); + private final NamingContext interfaceContext; + + public RewriteCustomizer(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + 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 = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, subInterfaceName, + interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()), ctx.getModificationCache()); + LOG.debug("VPP sub-interface details: {}", ReflectionToStringBuilder.toString(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/honeycomb/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java new file mode 100644 index 000000000..8c46a6a09 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import 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.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.AclBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifyTableByInterface; +import org.openvpp.jvpp.dto.ClassifyTableByInterfaceReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for reading ACLs enabled on given sub-interface. + */ +public class SubInterfaceAclCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer<Acl, AclBuilder>, AclReader { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class); + private final NamingContext interfaceContext; + private final NamingContext classifyTableContext; + + public SubInterfaceAclCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext 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 Acl readValue) { + ((SubInterfaceBuilder) parentBuilder).setAcl(readValue); + } + + @Nonnull + @Override + public AclBuilder getBuilder(@Nonnull final InstanceIdentifier<Acl> id) { + return new AclBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final AclBuilder 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()); + try { + final ClassifyTableByInterfaceReply reply = TranslateUtils + .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()); + } + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizer.java new file mode 100644 index 000000000..108a07a2c --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizer.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.byteToBoolean; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +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.apache.commons.lang3.builder.ReflectionToStringBuilder; +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.rev150527.SubInterfaceStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfacesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.DefaultBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.UntaggedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.vlan.tagged.VlanTaggedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Tags; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.TagsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.Tag; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.TagBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.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.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump; +import org.openvpp.jvpp.dto.SwInterfaceDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for reading sub interfaces form the VPP. + */ +public class SubInterfaceCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer<SubInterface, SubInterfaceKey, SubInterfaceBuilder> { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceCustomizer.class); + private NamingContext interfaceContext; + private static final Dot1qTag.VlanId ANY_VLAN_ID = new Dot1qTag.VlanId(Dot1qTag.VlanId.Enumeration.Any); + + public SubInterfaceCustomizer(@Nonnull final FutureJVpp jvpp, + @Nonnull final NamingContext interfaceContext) { + super(jvpp); + this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Nonnull + @Override + public List<SubInterfaceKey> getAllIds(@Nonnull final InstanceIdentifier<SubInterface> id, + @Nonnull final ReadContext context) throws ReadFailedException { + try { + // 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 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 = + TranslateUtils.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; + } catch (VppBaseCallException e) { + throw new ReadFailedException(id,e); + } + } + + @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 = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, subInterfaceName, + interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()), ctx.getModificationCache()); + LOG.debug("VPP sub-interface details: {}", ReflectionToStringBuilder.toString(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(InterfaceUtils.vppIfIndexToYang(iface.swIfIndex)); + if (iface.l2AddressLength == 6) { + builder.setPhysAddress(new PhysAddress(InterfaceUtils.vppPhysAddrToYang(iface.l2Address))); + } + if (0 != iface.linkSpeed) { + builder.setSpeed(InterfaceUtils.vppInterfaceSpeedToYang(iface.linkSpeed)); + } + } + + private static String getSubInterfaceName(final InstanceIdentifier<SubInterface> id) { + return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), + Math.toIntExact(id.firstKeyOf(id.getTargetType()).getIdentifier())); + } + + 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 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)); + } + + 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.rev150527.match.attributes.match.type.VlanTaggedBuilder() + .setVlanTagged(tagged.build()).build()); + } + return match.build(); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java new file mode 100644 index 000000000..4855915bb --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfacesstate; + +import static io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.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.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2Builder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for reading vlan sub interface L2 operational state + */ +public class SubInterfaceL2Customizer extends FutureJVppCustomizer implements ReaderCustomizer<L2, L2Builder> { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceL2Customizer.class); + private final InterconnectionReadUtils icReadUtils; + + public SubInterfaceL2Customizer(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext bridgeDomainContext) { + super(futureJvpp); + this.icReadUtils = new InterconnectionReadUtils(futureJvpp, 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)); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/TapCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/TapCustomizer.java new file mode 100644 index 000000000..992912a63 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/TapCustomizer.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.honeycomb.translate.v3po.interfacesstate; + +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType; + +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.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +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.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Tap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.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.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceTapDetails; +import org.openvpp.jvpp.dto.SwInterfaceTapDetailsReplyDump; +import org.openvpp.jvpp.dto.SwInterfaceTapDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class TapCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer<Tap, TapBuilder> { + + 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 FutureJVpp 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 { + try { + 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.rev150105.Tap.class)) { + 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 = + TranslateUtils.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(TranslateUtils.toString(swInterfaceTapDetails.devName)); + LOG.debug("Tap interface: {}, id: {} attributes read as: {}", key.getName(), index, builder); + } catch (VppBaseCallException e) { + LOG.warn("Failed to readCurrentAttributes for: {}", id, e); + throw new ReadFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VhostUserCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VhostUserCustomizer.java new file mode 100644 index 000000000..a9bf069b2 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VhostUserCustomizer.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.honeycomb.translate.v3po.interfacesstate; + +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import 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.rev150105.VhostUserRole; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUser; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUserBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceVhostUserDetails; +import org.openvpp.jvpp.dto.SwInterfaceVhostUserDetailsReplyDump; +import org.openvpp.jvpp.dto.SwInterfaceVhostUserDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class VhostUserCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer<VhostUser, VhostUserBuilder> { + + private static final Logger LOG = LoggerFactory.getLogger(VhostUserCustomizer.class); + public static final String DUMPED_VHOST_USERS_CONTEXT_KEY = VhostUserCustomizer.class.getName() + "dumpedVhostUsersDuringGetAllIds"; + private NamingContext interfaceContext; + + public VhostUserCustomizer(@Nonnull final FutureJVpp 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 { + try { + 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.rev150105.VhostUser.class)) { + 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 = + TranslateUtils.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(TranslateUtils.toString(swInterfaceVhostUserDetails.sockFilename)); + builder.setVirtioNetHdrSize((long) swInterfaceVhostUserDetails.virtioNetHdrSz); + builder.setConnectError(Integer.toString(swInterfaceVhostUserDetails.sockErrno)); + + LOG.debug("Vhost user interface: {}, id: {} attributes read as: {}", key.getName(), index, builder); + } catch (VppBaseCallException e) { + LOG.warn("Failed to readCurrentAttributes for: {}", id, e); + throw new ReadFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizer.java new file mode 100644 index 000000000..450c75709 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizer.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType; + +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.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +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.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.VxlanTunnelDetails; +import org.openvpp.jvpp.dto.VxlanTunnelDetailsReplyDump; +import org.openvpp.jvpp.dto.VxlanTunnelDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VxlanCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer<Vxlan, VxlanBuilder> { + + private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class); + private final NamingContext interfaceContext; + + public VxlanCustomizer(@Nonnull final FutureJVpp 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 { + try { + 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)) { + 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 = + TranslateUtils.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); + } catch (VppBaseCallException e) { + LOG.warn("Failed to readCurrentAttributes for: {}", id); + throw new ReadFailedException( id, e ); + } + } + + @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); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizer.java new file mode 100644 index 000000000..6763aaf60 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizer.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import 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.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeNextProtocol; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeVni; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.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.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.VxlanGpeTunnelDetails; +import org.openvpp.jvpp.dto.VxlanGpeTunnelDetailsReplyDump; +import org.openvpp.jvpp.dto.VxlanGpeTunnelDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VxlanGpeCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer<VxlanGpe, VxlanGpeBuilder> { + + private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class); + private NamingContext interfaceContext; + + public VxlanGpeCustomizer(@Nonnull final FutureJVpp 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 { + try { + 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)) { + 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 = + TranslateUtils.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); + } catch (VppBaseCallException e) { + LOG.warn("Failed to readCurrentAttributes for: {}", id); + throw new ReadFailedException( id, e ); + } + } + + @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); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java new file mode 100644 index 000000000..b4b656c52 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfacesstate.ip; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.dumpAddresses; +import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.findIpAddressDetailsByIp; +import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.getAllIpv4AddressIds; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.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.openvpp.jvpp.dto.IpAddressDetails; +import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Read customizer for interface Ipv4 addresses. + */ +public class Ipv4AddressCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer<Address, AddressKey, AddressBuilder> { + + private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class); + + private final NamingContext interfaceContext; + + public Ipv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + @Nonnull + public AddressBuilder getBuilder(@Nonnull InstanceIdentifier<Address> id) { + return new AddressBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull InstanceIdentifier<Address> id, @Nonnull AddressBuilder builder, + @Nonnull ReadContext ctx) + throws ReadFailedException { + LOG.debug("Reading attributes for interface address: {}", id); + + final String interfaceName = id.firstKeyOf(Interface.class).getName(); + final int interfaceIndex = interfaceContext.getIndex(interfaceName, ctx.getMappingContext()); + final Optional<IpAddressDetailsReplyDump> dumpOptional = + dumpAddresses(getFutureJVpp(), id, interfaceName, interfaceIndex, ctx); + + final Optional<IpAddressDetails> ipAddressDetails = + findIpAddressDetailsByIp(dumpOptional, id.firstKeyOf(Address.class).getIp()); + + if (ipAddressDetails.isPresent()) { + final IpAddressDetails detail = ipAddressDetails.get(); + builder.setIp(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip)) + .setSubnet(new PrefixLengthBuilder().setPrefixLength(Short.valueOf(detail.prefixLength)).build()); + + if (LOG.isDebugEnabled()) { + LOG.debug("Attributes for {} 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 = + dumpAddresses(getFutureJVpp(), id, interfaceName, interfaceIndex, ctx); + + return getAllIpv4AddressIds(dumpOptional, AddressKey::new); + } + + @Override + public void merge(@Nonnull Builder<? extends DataObject> builder, @Nonnull List<Address> readData) { + ((Ipv4Builder) builder).setAddress(readData); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4Customizer.java new file mode 100644 index 000000000..6b890f343 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4Customizer.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.honeycomb.translate.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.honeycomb.translate.v3po.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 org.openvpp.jvpp.future.FutureJVpp; +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 FutureJVpp futureJvpp) { + super(futureJvpp); + } + + @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 { + //TODO add reading of isForwarding flag when there is dump for it + LOG.warn("Operation not supported"); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java new file mode 100644 index 000000000..3b04c5614 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/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.honeycomb.translate.v3po.interfacesstate.ip; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +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.openvpp.jvpp.future.FutureJVpp; +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(FutureJVpp futureJvpp) { + super(futureJvpp); + } + + @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 + 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/honeycomb/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java new file mode 100644 index 000000000..56ad73c9b --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.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.honeycomb.translate.v3po.interfacesstate.ip; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.ReadTimeoutException; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.IpAddressDetails; +import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump; +import org.openvpp.jvpp.dto.IpAddressDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class providing Ipv4 read support. + */ +final class Ipv4ReadUtils { + + static final String CACHE_KEY = Ipv4ReadUtils.class.getName(); + private static final Logger LOG = LoggerFactory.getLogger(Ipv4ReadUtils.class); + + private Ipv4ReadUtils() { + throw new UnsupportedOperationException("This utility class cannot be instantiated"); + } + + // Many VPP APIs do not provide get operation for single item. Dump requests for all items are used instead. + // To improve HC performance, caching dump requests is a common pattern. + // TODO: use more generic caching implementation, once provided + static Optional<IpAddressDetailsReplyDump> dumpAddresses(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final InstanceIdentifier<?> id, + @Nonnull final String interfaceName, + final int interfaceIndex, @Nonnull final ReadContext ctx) + throws ReadFailedException { + + final String cacheKey = CACHE_KEY + interfaceName; + Optional<IpAddressDetailsReplyDump> dumpFromCache = dumpAddressFromCache(cacheKey, ctx.getModificationCache()); + + if (dumpFromCache.isPresent()) { + return dumpFromCache; + } + + Optional<IpAddressDetailsReplyDump> dumpFromOperational; + try { + dumpFromOperational = dumpAddressFromOperationalData(futureJvpp, id, interfaceIndex); + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + + if (dumpFromOperational.isPresent()) { + ctx.getModificationCache().put(cacheKey, dumpFromOperational.get()); + } + + return dumpFromOperational; + } + + private static Optional<IpAddressDetailsReplyDump> dumpAddressFromCache(@Nonnull final String cacheKey, + @Nonnull final ModificationCache cache) { + LOG.debug("Retrieving Ipv4 addresses from cache for {}", cacheKey); + return Optional.fromNullable((IpAddressDetailsReplyDump) cache.get(cacheKey)); + } + + private static Optional<IpAddressDetailsReplyDump> dumpAddressFromOperationalData( + @Nonnull final FutureJVpp futureJvpp, @Nonnull final InstanceIdentifier<?> id, final int interfaceIndex) + throws VppBaseCallException, ReadTimeoutException { + LOG.debug("Dumping Ipv4 addresses for interface id={}", interfaceIndex); + final IpAddressDump dumpRequest = new IpAddressDump(); + dumpRequest.isIpv6 = 0; + dumpRequest.swIfIndex = interfaceIndex; + return Optional.fromNullable( + TranslateUtils.getReplyForRead(futureJvpp.ipAddressDump(dumpRequest).toCompletableFuture(), id)); + } + + @Nonnull static <T extends Identifier> List<T> getAllIpv4AddressIds( + final Optional<IpAddressDetailsReplyDump> dumpOptional, + @Nonnull final Function<Ipv4AddressNoZone, T> keyConstructor) { + if (dumpOptional.isPresent() && dumpOptional.get().ipAddressDetails != null) { + return dumpOptional.get().ipAddressDetails.stream() + .map(detail -> keyConstructor.apply(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip))) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + static Optional<IpAddressDetails> findIpAddressDetailsByIp( + final Optional<IpAddressDetailsReplyDump> dump, + @Nonnull final Ipv4AddressNoZone ip) { + checkNotNull(ip, "ip address should not be null"); + + if (dump.isPresent() && dump.get().ipAddressDetails != null) { + final List<IpAddressDetails> details = dump.get().ipAddressDetails; + + return Optional.of(details.stream() + .filter(singleDetail -> ip.equals(TranslateUtils.arrayToIpv4AddressNoZone(singleDetail.ip))) + .collect(RWUtils.singleItemCollector())); + } + return Optional.absent(); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv6Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv6Customizer.java new file mode 100644 index 000000000..b71cca0bb --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv6Customizer.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.honeycomb.translate.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.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.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 org.openvpp.jvpp.future.FutureJVpp; + +public class Ipv6Customizer extends FutureJVppCustomizer implements ReaderCustomizer<Ipv6, Ipv6Builder> { + + private final NamingContext interfaceContext; + + public Ipv6Customizer(@Nonnull final FutureJVpp futureJvpp, final NamingContext interfaceContext) { + super(futureJvpp); + 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 implement +// 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); + // TODO consider extracting customizer for address +// final IpAddressDetailsReplyDump reply = TranslateUtils.getReply(addressDumpFuture.toCompletableFuture()); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java new file mode 100644 index 000000000..c5fa6ee8e --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.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.honeycomb.translate.v3po.interfacesstate.ip; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.dumpAddresses; +import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.findIpAddressDetailsByIp; +import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.getAllIpv4AddressIds; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLengthBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.IpAddressDetails; +import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Read customizer for sub-interface Ipv4 addresses. + */ +public class SubInterfaceIpv4AddressCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer<Address, AddressKey, AddressBuilder> { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIpv4AddressCustomizer.class); + + private final NamingContext interfaceContext; + + public SubInterfaceIpv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + @Nonnull + public AddressBuilder getBuilder(@Nonnull InstanceIdentifier<Address> id) { + return new AddressBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull InstanceIdentifier<Address> id, @Nonnull AddressBuilder builder, + @Nonnull ReadContext ctx) + throws ReadFailedException { + LOG.debug("Reading attributes for sub-interface address: {}", id); + + final String subInterfaceName = getSubInterfaceName(id); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()); + final Optional<IpAddressDetailsReplyDump> dumpOptional = + dumpAddresses(getFutureJVpp(), id, subInterfaceName, subInterfaceIndex, ctx); + + final Optional<IpAddressDetails> ipAddressDetails = + findIpAddressDetailsByIp(dumpOptional, id.firstKeyOf(Address.class).getIp()); + + if (ipAddressDetails.isPresent()) { + final IpAddressDetails detail = ipAddressDetails.get(); + builder.setIp(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip)) + .setSubnet(new PrefixLengthBuilder().setPrefixLength(Short.valueOf(detail.prefixLength)).build()); + + if (LOG.isDebugEnabled()) { + LOG.debug("Attributes for {} sub-interface (id={}) address {} successfully read: {}", + subInterfaceName, subInterfaceIndex, id, builder.build()); + } + } + } + + @Override + public List<AddressKey> getAllIds(@Nonnull InstanceIdentifier<Address> id, @Nonnull ReadContext ctx) + throws ReadFailedException { + LOG.debug("Reading list of keys for sub-interface addresses: {}", id); + + final String subInterfaceName = getSubInterfaceName(id); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()); + final Optional<IpAddressDetailsReplyDump> dumpOptional = + dumpAddresses(getFutureJVpp(), id, subInterfaceName, subInterfaceIndex, ctx); + + return getAllIpv4AddressIds(dumpOptional, AddressKey::new); + } + + @Override + public void merge(@Nonnull Builder<? extends DataObject> builder, @Nonnull List<Address> readData) { + ((Ipv4Builder) builder).setAddress(readData); + } + + private static String getSubInterfaceName(@Nonnull final InstanceIdentifier<Address> id) { + return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), + Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier())); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducer.java new file mode 100644 index 000000000..1c60ef609 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducer.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.fd.honeycomb.translate.v3po.notification; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import io.fd.honeycomb.notification.ManagedNotificationProducer; +import io.fd.honeycomb.notification.NotificationCollector; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +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.rev150105.InterfaceDeleted; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceDeletedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceNameOrIndex; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStateChange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStateChangeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStatus; +import org.opendaylight.yangtools.yang.binding.Notification; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceSetFlagsNotification; +import org.openvpp.jvpp.dto.WantInterfaceEvents; +import org.openvpp.jvpp.dto.WantInterfaceEventsReply; +import org.openvpp.jvpp.future.FutureJVpp; +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 { + + private static final Logger LOG = LoggerFactory.getLogger(InterfaceChangeNotificationProducer.class); + + private final FutureJVpp jvpp; + private final NamingContext interfaceContext; + private final MappingContext mappingContext; + @Nullable + private AutoCloseable notificationListenerReg; + + public InterfaceChangeNotificationProducer(@Nonnull final FutureJVpp jvpp, + @Nonnull final NamingContext interfaceContext, + @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 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. TODO inconsistent behavior, maybe just use indices ? + */ + 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); + TranslateUtils.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/honeycomb/translate/v3po/vpp/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizer.java new file mode 100644 index 000000000..d148bc20c --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizer.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.vpp; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.BridgeDomainAddDel; +import org.openvpp.jvpp.dto.BridgeDomainAddDelReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BridgeDomainCustomizer + extends FutureJVppCustomizer + implements ListWriterCustomizer<BridgeDomain, BridgeDomainKey> { + + private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class); + + private static final byte ADD_OR_UPDATE_BD = (byte) 1; + private final NamingContext bdContext; + + public BridgeDomainCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext bdContext) { + super(futureJvpp); + 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 VppBaseCallException, WriteTimeoutException { + 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 = TranslateUtils.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(); + + try { + int index; + if (bdContext.containsIndex(bdName, ctx.getMappingContext())) { + index = bdContext.getIndex(bdName, ctx.getMappingContext()); + } else { + // FIXME we need the bd index to be returned by VPP or we should have a counter field + // (maybe in context similar to artificial name) + // Here we assign the next available ID from bdContext's perspective + index = 1; + while (bdContext.containsName(index, ctx.getMappingContext())) { + index++; + } + } + addOrUpdateBridgeDomain(id, index, dataBefore); + bdContext.addName(index, bdName, ctx.getMappingContext()); + } catch (VppBaseCallException e) { + LOG.warn("Failed to create bridge domain", e); + throw new WriteFailedException.CreateFailedException(id, dataBefore, e); + } + } + + @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()); + try { + + final BridgeDomainAddDel request = new BridgeDomainAddDel(); + request.bdId = bdId; + + TranslateUtils.getReplyForWrite(getFutureJVpp().bridgeDomainAddDel(request).toCompletableFuture(), id); + LOG.debug("Bridge domain {} (id={}) deleted successfully", bdName, bdId); + } catch (VppBaseCallException e) { + LOG.warn("Bridge domain {} (id={}) delete failed", bdName, bdId); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + @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."); + + try { + addOrUpdateBridgeDomain(id, bdContext.getIndex(bdName, ctx.getMappingContext()), dataAfter); + } catch (VppBaseCallException e) { + LOG.warn("Failed to create bridge domain", e); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizer.java new file mode 100644 index 000000000..0e4b90a56 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizer.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.vpp; + +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.parseMac; + +import com.google.common.base.Preconditions; +import com.google.common.primitives.Longs; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibFilter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.L2FibAddDel; +import org.openvpp.jvpp.dto.L2FibAddDelReply; +import org.openvpp.jvpp.future.FutureJVpp; +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> { + + private static final Logger LOG = LoggerFactory.getLogger(L2FibEntryCustomizer.class); + + private final NamingContext bdContext; + private final NamingContext interfaceContext; + + public L2FibEntryCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext bdContext, + @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + 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 { + try { + LOG.debug("Creating L2 FIB entry: {} {}", id, dataAfter); + l2FibAddDel(id, dataAfter, writeContext, true); + LOG.debug("L2 FIB entry created successfully: {} {}", id, dataAfter); + } catch (VppBaseCallException e) { + LOG.warn("Failed to create L2 FIB entry: {} {}", id, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @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 { + try { + LOG.debug("Deleting L2 FIB entry: {} {}", id, dataBefore); + l2FibAddDel(id, dataBefore, writeContext, false); + LOG.debug("L2 FIB entry deleted successfully: {} {}", id, dataBefore); + } catch (VppBaseCallException e) { + LOG.warn("Failed to delete L2 FIB entry: {} {}", id, dataBefore); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void l2FibAddDel(@Nonnull final InstanceIdentifier<L2FibEntry> id, @Nonnull final L2FibEntry entry, + final WriteContext writeContext, boolean isAdd) + throws VppBaseCallException, WriteTimeoutException { + 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: {}", ReflectionToStringBuilder.toString(l2FibRequest)); + final CompletionStage<L2FibAddDelReply> l2FibAddDelReplyCompletionStage = + getFutureJVpp().l2FibAddDel(l2FibRequest); + + TranslateUtils.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 static 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/honeycomb/translate/v3po/vppclassifier/ClassifySessionReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReader.java new file mode 100644 index 000000000..8027968f1 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReader.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.vppclassifier; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.printHexBinary; + +import com.google.common.base.Optional; +import com.google.common.primitives.UnsignedInts; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Arrays; +import java.util.Collections; +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.rev150603.OpaqueIndex; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifySessionDetails; +import org.openvpp.jvpp.dto.ClassifySessionDetailsReplyDump; +import org.openvpp.jvpp.dto.ClassifySessionDump; +import org.openvpp.jvpp.future.FutureJVpp; +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>, VppNodeReader { + + private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionReader.class); + static final String CACHE_KEY = ClassifySessionReader.class.getName(); + + private final NamingContext classifyTableContext; + + public ClassifySessionReader(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext classifyTableContext) { + super(futureJvpp); + 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.hitNextIndex, LOG)); + if (detail.opaqueIndex != ~0) { + // value is specified: + builder.setOpaqueIndex(readOpaqueIndex(detail.opaqueIndex)); + } + 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 opaqueIndex) { + // We first try to map the value to a vpp node, if that fails, simply wrap the u32 value + // FIXME: the approach might fail if the opaqueIndex contains small value that collides + // with some of the adjacent nodes + final VppNode node = readVppNode(opaqueIndex, LOG); + if (node != null) { + return new OpaqueIndex(node); + } 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.containsIndex(tableName, ctx.getMappingContext()), + "Reading classify sessions for table {}, but table index could not be found in the classify table context", + tableName); + final int tableId = classifyTableContext.getIndex(tableName, ctx.getMappingContext()); + LOG.debug("Dumping classify sessions for classify table id={}", tableId); + + try { + final ClassifySessionDump dumpRequest = new ClassifySessionDump(); + dumpRequest.tableId = tableId; + classifySessionDump = TranslateUtils + .getReplyForRead(getFutureJVpp().classifySessionDump(dumpRequest).toCompletableFuture(), id); + + // update the cache: + ctx.getModificationCache().put(cacheKey, classifySessionDump); + return classifySessionDump; + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } + + 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/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriter.java new file mode 100644 index 000000000..5c00903ae --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriter.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.honeycomb.translate.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 static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.write.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.rev150603.OpaqueIndex; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifyAddDelSession; +import org.openvpp.jvpp.dto.ClassifyAddDelSessionReply; +import org.openvpp.jvpp.future.FutureJVpp; +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 FutureJVppCustomizer + implements ListWriterCustomizer<ClassifySession, ClassifySessionKey> { + + private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionWriter.class); + private final NamingContext classifyTableContext; + + public ClassifySessionWriter(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext classifyTableContext) { + super(futureJvpp); + 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, WriteTimeoutException { + final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class); + checkArgument(tableKey != null, "could not find classify table key in {}", id); + + final String tableName = tableKey.getName(); + checkState(classifyTableContext.containsIndex(tableName, writeContext.getMappingContext()), + "Could not find classify table index for {} in the classify table context", tableName); + final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext()); + + final CompletionStage<ClassifyAddDelSessionReply> createClassifyTableReplyCompletionStage = getFutureJVpp() + .classifyAddDelSession( + getClassifyAddDelSessionRequest(isAdd, tableIndex, classifySession)); + + TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id); + } + + private static ClassifyAddDelSession getClassifyAddDelSessionRequest(final boolean isAdd, final int tableIndex, + @Nonnull final ClassifySession classifySession) { + ClassifyAddDelSession request = new ClassifyAddDelSession(); + request.isAdd = booleanToByte(isAdd); + request.tableIndex = tableIndex; + + // mandatory: + // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed + request.hitNextIndex = classifySession.getHitNext().getPacketHandlingAction().getIntValue(); + + if (classifySession.getOpaqueIndex() != null) { + request.opaqueIndex = getOpaqueIndexValue(classifySession.getOpaqueIndex()); + } else { + request.opaqueIndex = ~0; // value not specified + } + + // default 0: + request.advance = classifySession.getAdvance(); + + request.match = DatatypeConverter.parseHexBinary(classifySession.getMatch().getValue().replace(":", "")); + return request; + } + + private static int getOpaqueIndexValue(@Nonnull final OpaqueIndex opaqueIndex) { + if (opaqueIndex.getUint32() != null) { + return opaqueIndex.getUint32().intValue(); + } else { + // TODO: implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed + return opaqueIndex.getVppNode().getPacketHandlingAction().getIntValue(); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReader.java new file mode 100644 index 000000000..6ad7b2151 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReader.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.honeycomb.translate.v3po.vppclassifier; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.printHexBinary; + +import com.google.common.primitives.UnsignedInts; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Arrays; +import java.util.Collections; +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.rev150603.VppClassifierStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifyTableIds; +import org.openvpp.jvpp.dto.ClassifyTableIdsReply; +import org.openvpp.jvpp.dto.ClassifyTableInfo; +import org.openvpp.jvpp.dto.ClassifyTableInfoReply; +import org.openvpp.jvpp.future.FutureJVpp; +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 ListReaderCustomizer<ClassifyTable, ClassifyTableKey, ClassifyTableBuilder>, VppNodeReader { + + private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableReader.class); + private final NamingContext classifyTableContext; + + public ClassifyTableReader(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext classifyTableContext) { + super(futureJvpp); + 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.containsIndex(tableName, ctx.getMappingContext())) { + LOG.debug("Could not find classify table {} in the naming context", tableName); + return; + } + request.tableId = classifyTableContext.getIndex(tableName, ctx.getMappingContext()); + + try { + final ClassifyTableInfoReply reply = + TranslateUtils.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)); + + + builder.setMissNext(readVppNode(reply.missNextIndex, LOG)); + builder.setMask(new HexString(printHexBinary(reply.mask))); + builder.setActiveSessions(UnsignedInts.toLong(reply.activeSessions)); + + if (reply.nextTableIndex != ~0) { + // next table index is present: + builder.setNextTable(classifyTableContext.getName(reply.nextTableIndex, ctx.getMappingContext())); + } + + if (LOG.isTraceEnabled()) { + LOG.trace("Attributes for classify table {} successfully read: {}", id, builder.build()); + } + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } + + @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); + try { + final ClassifyTableIdsReply classifyTableIdsReply = TranslateUtils + .getReplyForRead(getFutureJVpp().classifyTableIds(new ClassifyTableIds()).toCompletableFuture(), id); + if (classifyTableIdsReply.ids != null) { + return Arrays.stream(classifyTableIdsReply.ids).mapToObj(i -> { + final String tableName = classifyTableContext.getName(i, context.getMappingContext()); + LOG.trace("Classify table with name: {} and index: {} found in VPP", tableName, i); + return new ClassifyTableKey(tableName); + }).collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriter.java new file mode 100644 index 000000000..12680b9cf --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriter.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.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 static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import javax.xml.bind.DatatypeConverter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifyAddDelTable; +import org.openvpp.jvpp.dto.ClassifyAddDelTableReply; +import org.openvpp.jvpp.future.FutureJVpp; +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 FutureJVppCustomizer + implements ListWriterCustomizer<ClassifyTable, ClassifyTableKey> { + + private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableWriter.class); + private final NamingContext classifyTableContext; + + public ClassifyTableWriter(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext classifyTableContext) { + super(futureJvpp); + 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.addName(newTableIndex, dataAfter.getName(), 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.containsIndex(tableName, writeContext.getMappingContext()), + "Removing classify table {}, but index could not be found in the classify table context", tableName); + + final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext()); + try { + classifyAddDelTable(false, id, dataBefore, tableIndex, writeContext.getMappingContext()); + + // Remove deleted interface from interface context: + classifyTableContext.removeName(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, WriteTimeoutException { + final CompletionStage<ClassifyAddDelTableReply> createClassifyTableReplyCompletionStage = + getFutureJVpp().classifyAddDelTable(getClassifyAddDelTableRequest(isAdd, tableId, table, ctx)); + + final ClassifyAddDelTableReply reply = + TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id); + return reply.newTableIndex; + + } + + private ClassifyAddDelTable getClassifyAddDelTableRequest(final boolean isAdd, final int tableIndex, + @Nonnull final ClassifyTable table, + @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 + // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed + request.missNextIndex = table.getMissNext().getPacketHandlingAction().getIntValue(); + + final String nextTable = table.getNextTable(); + if (isAdd && nextTable != null) { + request.nextTableIndex = classifyTableContext.getIndex(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/honeycomb/translate/v3po/vppclassifier/VppNodeReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeReader.java new file mode 100644 index 000000000..6061b8672 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeReader.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.vppclassifier; + +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode; +import org.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 VppNode readVppNode(final int nodeIndex, @Nonnull final Logger log) { + final PacketHandlingAction action = PacketHandlingAction.forValue(nodeIndex); + if (action == null) { + // TODO: implement node index to name conversion after https://jira.fd.io/browse/VPP-203 is fixed + log.debug("VPP node index {} cannot be mapped to PacketHandlingAction", nodeIndex); + return null; + } + return new VppNode(action); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizer.java new file mode 100644 index 000000000..e8cfe3978 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizer.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.honeycomb.translate.v3po.vppstate; + +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.byteToBoolean; + +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.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +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.rev150105.vpp.state.BridgeDomainsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.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.openvpp.jvpp.dto.BridgeDomainDetails; +import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump; +import org.openvpp.jvpp.dto.BridgeDomainDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class BridgeDomainCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer<BridgeDomain, BridgeDomainKey, BridgeDomainBuilder> { + + private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class); + private final NamingContext bdContext; + + public BridgeDomainCustomizer(@Nonnull final FutureJVpp futureJVpp, @Nonnull final NamingContext bdContext) { + super(futureJVpp); + 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) { + final BridgeDomainDump request = new BridgeDomainDump(); + request.bdId = -1; // dump call + + BridgeDomainDetailsReplyDump reply; + try { + reply = getFutureJVpp().bridgeDomainDump(request).toCompletableFuture().get(); + } catch (Exception e) { + throw new IllegalStateException("Bridge domain dump failed", e); // TODO ReadFailedException? + } + + 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); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizer.java new file mode 100644 index 000000000..a6ecafd72 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizer.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.honeycomb.translate.v3po.vppstate; + +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.vppPhysAddrToYang; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.byteToBoolean; + +import com.google.common.base.Preconditions; +import com.google.common.primitives.Longs; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.ReadTimeoutException; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +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.rev150105.L2FibFilter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibForward; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.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.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.L2FibTableDump; +import org.openvpp.jvpp.dto.L2FibTableEntry; +import org.openvpp.jvpp.dto.L2FibTableEntryReplyDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class L2FibEntryCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer<L2FibEntry, L2FibEntryKey, L2FibEntryBuilder> { + + 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 FutureJVpp futureJVpp, @Nonnull final NamingContext bdContext, + @Nonnull final NamingContext interfaceContext) { + super(futureJVpp); + 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 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 VppBaseCallException, ReadTimeoutException { + final L2FibTableDump l2FibRequest = new L2FibTableDump(); + l2FibRequest.bdId = bdId; + + final CompletableFuture<L2FibTableEntryReplyDump> l2FibTableDumpCompletableFuture = + getFutureJVpp().l2FibTableDump(l2FibRequest).toCompletableFuture(); + + final L2FibTableEntryReplyDump dump = TranslateUtils.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); + try { + return dumpL2Fibs(id, bdId).stream() + .map(entry -> new L2FibEntryKey( + new PhysAddress(vppPhysAddrToYang(Longs.toByteArray(entry.mac), 2)))) + .collect(Collectors.toList()); + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } + + @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(); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizer.java new file mode 100644 index 000000000..7eaf2ec80 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizer.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.honeycomb.translate.v3po.vppstate; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ShowVersion; +import org.openvpp.jvpp.dto.ShowVersionReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public final class VersionCustomizer + extends FutureJVppCustomizer + implements ReaderCustomizer<Version, VersionBuilder> { + + /** + * Default timeout for executing version read + */ + private static final int DEFAULT_TIMEOUT_IN_SECONDS = 30; + + public VersionCustomizer(@Nonnull final FutureJVpp futureJVpp) { + super(futureJVpp); + } + + @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 InstanceIdentifier<Version> id, @Nonnull final VersionBuilder builder, + @Nonnull final ReadContext context) throws ReadFailedException { + try { + // Execute with timeout + final CompletionStage<ShowVersionReply> showVersionFuture = getFutureJVpp().showVersion(new ShowVersion()); + final ShowVersionReply reply = TranslateUtils.getReplyForRead(showVersionFuture.toCompletableFuture(), id, + DEFAULT_TIMEOUT_IN_SECONDS); + + builder.setBranch(TranslateUtils.toString(reply.version)); + builder.setName(TranslateUtils.toString(reply.program)); + builder.setBuildDate(TranslateUtils.toString(reply.buildDate)); + builder.setBuildDirectory(TranslateUtils.toString(reply.buildDirectory)); + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } + +} |