diff options
Diffstat (limited to 'v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces')
21 files changed, 2688 insertions, 0 deletions
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); + } + } +} |