From 5543345d32514bfa38292a5080e57b915e39ea1d Mon Sep 17 00:00:00 2001 From: Michal Cmarada Date: Mon, 27 May 2019 13:54:02 +0200 Subject: HC2VPP-411: remove deprecated interface-state - new ietf-interfaces obsoletes interfaces-state container, only interfaces container should be used from now on. Change-Id: Ifb24611a3dca987bdf6b029d32e01d9b1f479fe8 Signed-off-by: Michal Cmarada --- .../v3po/write/AbstractUnnumberedCustomizer.java | 80 ++++++++ .../fd/hc2vpp/v3po/write/AfPacketCustomizer.java | 119 +++++++++++ .../io/fd/hc2vpp/v3po/write/AfPacketValidator.java | 79 +++++++ .../fd/hc2vpp/v3po/write/EthernetCustomizer.java | 90 ++++++++ .../io/fd/hc2vpp/v3po/write/EthernetValidator.java | 48 +++++ .../io/fd/hc2vpp/v3po/write/GreCustomizer.java | 147 +++++++++++++ .../java/io/fd/hc2vpp/v3po/write/GreValidator.java | 72 +++++++ .../v3po/write/InterconnectionWriteUtils.java | 159 +++++++++++++++ .../fd/hc2vpp/v3po/write/InterfaceCustomizer.java | 124 +++++++++++ .../v3po/write/InterfaceRoutingCustomizer.java | 61 ++++++ .../v3po/write/InterfaceRoutingValidator.java | 118 +++++++++++ .../v3po/write/InterfaceUnnumberedCustomizer.java | 56 +++++ .../v3po/write/InterfaceUnnumberedValidator.java | 55 +++++ .../fd/hc2vpp/v3po/write/InterfaceValidator.java | 74 +++++++ .../v3po/write/InterfacesStatisticsCustomizer.java | 67 ++++++ .../v3po/write/InterfacesStatisticsValidator.java | 55 +++++ .../java/io/fd/hc2vpp/v3po/write/L2Customizer.java | 89 ++++++++ .../java/io/fd/hc2vpp/v3po/write/L2Validator.java | 58 ++++++ .../fd/hc2vpp/v3po/write/LoopbackCustomizer.java | 104 ++++++++++ .../io/fd/hc2vpp/v3po/write/LoopbackValidator.java | 55 +++++ .../io/fd/hc2vpp/v3po/write/RewriteCustomizer.java | 135 ++++++++++++ .../io/fd/hc2vpp/v3po/write/RewriteValidator.java | 55 +++++ .../io/fd/hc2vpp/v3po/write/RoutingCustomizer.java | 95 +++++++++ .../hc2vpp/v3po/write/SubInterfaceCustomizer.java | 193 ++++++++++++++++++ .../v3po/write/SubInterfaceL2Customizer.java | 100 +++++++++ .../hc2vpp/v3po/write/SubInterfaceL2Validator.java | 58 ++++++ .../v3po/write/SubInterfaceRoutingCustomizer.java | 57 ++++++ .../v3po/write/SubInterfaceRoutingValidator.java | 110 ++++++++++ .../write/SubInterfaceUnnumberedCustomizer.java | 57 ++++++ .../write/SubInterfaceUnnumberedValidator.java | 55 +++++ .../hc2vpp/v3po/write/SubInterfaceValidator.java | 62 ++++++ .../io/fd/hc2vpp/v3po/write/TapV2Customizer.java | 227 +++++++++++++++++++++ .../io/fd/hc2vpp/v3po/write/TapV2Validator.java | 55 +++++ .../fd/hc2vpp/v3po/write/VhostUserCustomizer.java | 169 +++++++++++++++ .../fd/hc2vpp/v3po/write/VhostUserValidator.java | 55 +++++ .../io/fd/hc2vpp/v3po/write/VxlanCustomizer.java | 181 ++++++++++++++++ .../fd/hc2vpp/v3po/write/VxlanGpeCustomizer.java | 164 +++++++++++++++ .../io/fd/hc2vpp/v3po/write/VxlanGpeValidator.java | 78 +++++++ .../io/fd/hc2vpp/v3po/write/VxlanValidator.java | 79 +++++++ .../v3po/write/pbb/PbbRewriteCustomizer.java | 111 ++++++++++ .../hc2vpp/v3po/write/pbb/PbbRewriteValidator.java | 82 ++++++++ .../write/span/MirroredInterfaceCustomizer.java | 118 +++++++++++ .../write/span/MirroredInterfaceValidator.java | 79 +++++++ 43 files changed, 4085 insertions(+) create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/AbstractUnnumberedCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/AfPacketCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/AfPacketValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/EthernetCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/EthernetValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/GreCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/GreValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterconnectionWriteUtils.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceRoutingCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceRoutingValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceUnnumberedCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceUnnumberedValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfacesStatisticsCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfacesStatisticsValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/L2Customizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/L2Validator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/LoopbackCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/LoopbackValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/RewriteCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/RewriteValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/RoutingCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceL2Customizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceL2Validator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceRoutingCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceRoutingValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceUnnumberedCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceUnnumberedValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/TapV2Customizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/TapV2Validator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VhostUserCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VhostUserValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanGpeCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanGpeValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/pbb/PbbRewriteCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/pbb/PbbRewriteValidator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/span/MirroredInterfaceCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/span/MirroredInterfaceValidator.java (limited to 'v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write') diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/AbstractUnnumberedCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/AbstractUnnumberedCustomizer.java new file mode 100644 index 000000000..15b4be75b --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/AbstractUnnumberedCustomizer.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.SwInterfaceSetUnnumbered; +import io.fd.jvpp.core.future.FutureJVppCore; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.unnumbered.interfaces.rev180103.unnumbered.config.attributes.Unnumbered; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +abstract class AbstractUnnumberedCustomizer extends FutureJVppCustomizer implements WriterCustomizer, + JvppReplyConsumer, ByteDataTranslator { + private static final Logger LOG = LoggerFactory.getLogger(AbstractUnnumberedCustomizer.class); + + private final NamingContext interfaceContext; + + protected AbstractUnnumberedCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final NamingContext interfaceContext) { + super(futureJVppCore); + this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + protected void setUnnumbered(@Nonnull final InstanceIdentifier id, + @Nonnull final String unnumberedIfcName, + @Nonnull final Unnumbered data, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final int unnumberedIfcId = interfaceContext.getIndex(unnumberedIfcName, writeContext.getMappingContext()); + final int targetId = interfaceContext.getIndex(data.getUse(), writeContext.getMappingContext()); + final SwInterfaceSetUnnumbered request = getUnnumberedAddDelRequest(targetId, unnumberedIfcId, true); + getReplyForWrite(getFutureJVpp().swInterfaceSetUnnumbered(request).toCompletableFuture(), id); + LOG.debug("The {}(id={}) interface unnumbered flag was set: {}", unnumberedIfcName, unnumberedIfcId, data); + } + + protected void disableUnnumbered(@Nonnull final InstanceIdentifier id, + @Nonnull final String unnumberedIfcName, + @Nonnull final Unnumbered data, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final int unnumberedIfcId = interfaceContext.getIndex(unnumberedIfcName, writeContext.getMappingContext()); + final int targetId = interfaceContext.getIndex(data.getUse(), writeContext.getMappingContext()); + final SwInterfaceSetUnnumbered request = getUnnumberedAddDelRequest(targetId, unnumberedIfcId, false); + getReplyForWrite(getFutureJVpp().swInterfaceSetUnnumbered(request).toCompletableFuture(), id); + LOG.debug("The {}(id={}) interface unnumbered flag was unset: {}", unnumberedIfcName, unnumberedIfcId, data); + } + + private SwInterfaceSetUnnumbered getUnnumberedAddDelRequest(final int targetId, final int unnumberedIfcId, + final Boolean isAdd) { + final SwInterfaceSetUnnumbered request = new SwInterfaceSetUnnumbered(); + request.swIfIndex = targetId; + request.unnumberedSwIfIndex = unnumberedIfcId; + request.isAdd = booleanToByte(isAdd); + return request; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/AfPacketCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/AfPacketCustomizer.java new file mode 100644 index 000000000..f8e658216 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/AfPacketCustomizer.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2018 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.MacTranslator; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.AfPacketCreate; +import io.fd.jvpp.core.dto.AfPacketCreateReply; +import io.fd.jvpp.core.dto.AfPacketDelete; +import io.fd.jvpp.core.dto.AfPacketDeleteReply; +import io.fd.jvpp.core.future.FutureJVppCore; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.AfPacket; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AfPacketCustomizer extends AbstractInterfaceTypeCustomizer + implements MacTranslator, JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(AfPacketCustomizer.class); + private final NamingContext interfaceContext; + + public AfPacketCustomizer(@Nonnull final FutureJVppCore vppApi, @Nonnull final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + protected Class getExpectedInterfaceType() { + return org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.AfPacket.class; + } + + @Override + protected final void writeInterface(@Nonnull final InstanceIdentifier id, + @Nonnull final AfPacket dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + final int swIfIndex = createAfPacketIfc(id, swIfName, dataAfter); + + // Add new interface to our interface context + interfaceContext.addName(swIfIndex, swIfName, writeContext.getMappingContext()); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final AfPacket dataBefore, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + deleteAfPacketIfc(id, swIfName, dataBefore); + + // Remove interface from interface context + interfaceContext.removeName(swIfName, writeContext.getMappingContext()); + } + + private int createAfPacketIfc(final InstanceIdentifier id, final String swIfName, final AfPacket afPacket) + throws WriteFailedException { + LOG.debug("Creating af_packet interface {}: {}", swIfName, afPacket); + final CompletionStage createAfPacketIfReplyCompletionStage = + getFutureJVpp().afPacketCreate(getCreateRequest(afPacket)); + final AfPacketCreateReply reply = + getReplyForCreate(createAfPacketIfReplyCompletionStage.toCompletableFuture(), id, afPacket); + LOG.debug("Af_packet interface {} created successfully: {}", swIfName, afPacket); + return reply.swIfIndex; + } + + private AfPacketCreate getCreateRequest(@Nonnull final AfPacket afPacket) { + final AfPacketCreate request = new AfPacketCreate(); + request.hostIfName = afPacket.getHostInterfaceName().getBytes(StandardCharsets.UTF_8); + final PhysAddress mac = afPacket.getMac(); + if (mac == null) { + request.useRandomHwAddr = 1; + request.hwAddr = new byte[6]; + } else { + request.useRandomHwAddr = 0; + request.hwAddr = parseMac(mac.getValue()); + } + return request; + } + + private void deleteAfPacketIfc(final InstanceIdentifier id, final String swIfName, + final AfPacket afPacket) throws WriteFailedException { + LOG.debug("Deleting af_packet interface {}: {}", swIfName, afPacket); + final CompletionStage deleteAfPacketIfReplyCompletionStage = + getFutureJVpp().afPacketDelete(getDeleteRequest(afPacket)); + + getReplyForDelete(deleteAfPacketIfReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Af_packet interface {} deleted successfully: {}", swIfName, afPacket); + } + + private AfPacketDelete getDeleteRequest(@Nonnull final AfPacket afPacket) { + final AfPacketDelete request = new AfPacketDelete(); + request.hostIfName = afPacket.getHostInterfaceName().getBytes(StandardCharsets.UTF_8); + return request; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/AfPacketValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/AfPacketValidator.java new file mode 100644 index 000000000..392875190 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/AfPacketValidator.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException.CreateValidationFailedException; +import io.fd.honeycomb.translate.write.DataValidationFailedException.DeleteValidationFailedException; +import io.fd.honeycomb.translate.write.DataValidationFailedException.UpdateValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import java.nio.charset.StandardCharsets; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.AfPacket; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class AfPacketValidator implements Validator { + + public AfPacketValidator(@Nonnull final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final AfPacket dataAfter, + @Nonnull final WriteContext writeContext) + throws CreateValidationFailedException { + try { + validateAfPacket(dataAfter); + } catch (Exception e) { + throw new CreateValidationFailedException(id, dataAfter, e); + } + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final AfPacket dataBefore, + @Nonnull final AfPacket dataAfter, @Nonnull final WriteContext writeContext) + throws UpdateValidationFailedException { + try { + validateAfPacket(dataAfter); + } catch (Exception e) { + throw new UpdateValidationFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final AfPacket dataBefore, + @Nonnull final WriteContext writeContext) + throws DeleteValidationFailedException { + try { + validateAfPacket(dataBefore); + } catch (Exception e) { + throw new DeleteValidationFailedException(id, e); + } + } + + private void validateAfPacket(final AfPacket data) { + checkNotNull(data.getHostInterfaceName(), "host-interface-name is mandatory for af-packet interface"); + byte[] hostIfName = data.getHostInterfaceName().getBytes(StandardCharsets.UTF_8); + checkArgument(hostIfName.length <= 64, + "Interface name for af_packet interface should not be longer than 64 bytes, but was %s", + hostIfName.length); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/EthernetCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/EthernetCustomizer.java new file mode 100644 index 000000000..029f6f308 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/EthernetCustomizer.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.HwInterfaceSetMtu; +import io.fd.jvpp.core.future.FutureJVppCore; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.Ethernet; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev180703.EthernetCsmacd; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EthernetCustomizer extends AbstractInterfaceTypeCustomizer implements JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(EthernetCustomizer.class); + private final NamingContext interfaceContext; + + public EthernetCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + protected Class getExpectedInterfaceType() { + return EthernetCsmacd.class; + } + + @Override + public void writeInterface(@Nonnull final InstanceIdentifier id, + @Nonnull final Ethernet dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + setEthernetAttributes(id, dataAfter, writeContext); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Ethernet dataBefore, @Nonnull final Ethernet dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + setEthernetAttributes(id, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Ethernet dataBefore, @Nonnull final WriteContext writeContext) + throws WriteFailedException.DeleteFailedException { + throw new WriteFailedException.DeleteFailedException(id, + new UnsupportedOperationException("Removing ethernet container is not supported")); + } + + private void setEthernetAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Ethernet dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String name = id.firstKeyOf(Interface.class).getName(); + final int index = interfaceContext.getIndex(name, writeContext.getMappingContext()); + LOG.debug("Setting Ethernet attributes for interface: {}, {}. Ethernet: {}", name, index, dataAfter); + + // Set the physical payload MTU. I.e. not including L2 overhead. + // Setting the hardware MTU will program the NIC. + // Setting MTU for software interfaces is currently not supported (TODO: HC2VPP-355). + // More details: + // https://git.fd.io/vpp/tree/src/vnet/MTU.md + final HwInterfaceSetMtu request = new HwInterfaceSetMtu(); + request.swIfIndex = index; + request.mtu = dataAfter.getMtu().shortValue(); + getReplyForWrite(getFutureJVpp().hwInterfaceSetMtu(request).toCompletableFuture(), id); + LOG.debug("Ethernet attributes set successfully for: {}, {}. Ethernet: {}", name, index, dataAfter); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/EthernetValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/EthernetValidator.java new file mode 100644 index 000000000..ebdd17346 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/EthernetValidator.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.Ethernet; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class EthernetValidator implements Validator { + + public EthernetValidator(final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final Ethernet dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + checkNotNull(dataAfter.getMtu(), "MTU cannot be null"); + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final Ethernet dataBefore, + @Nonnull final Ethernet dataAfter, @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + checkNotNull(dataAfter.getMtu(), "MTU cannot be null"); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/GreCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/GreCustomizer.java new file mode 100644 index 000000000..adb7e2401 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/GreCustomizer.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016 Intel and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer; +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.GreTunnelAddDel; +import io.fd.jvpp.core.dto.GreTunnelAddDelReply; +import io.fd.jvpp.core.future.FutureJVppCore; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.GreTunnel; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.Gre; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GreCustomizer extends AbstractInterfaceTypeCustomizer implements JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(GreCustomizer.class); + private final NamingContext interfaceContext; + + public GreCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + private static GreTunnelAddDel getGreTunnelRequest(final byte isAdd, final IpAddressNoZone srcAddr, + final IpAddressNoZone dstAddr, final int outerFibId, + final byte isIpv6) { + final GreTunnelAddDel greTunnelAddDel = new GreTunnelAddDel(); + greTunnelAddDel.isAdd = isAdd; + greTunnelAddDel.tunnel = new io.fd.jvpp.core.types.GreTunnel(); + if (isIpv6==0) { + greTunnelAddDel.tunnel.src = + AddressTranslator.INSTANCE.ipv4AddressNoZoneToAddress(srcAddr.getIpv4AddressNoZone()); + greTunnelAddDel.tunnel.dst = + AddressTranslator.INSTANCE.ipv4AddressNoZoneToAddress(dstAddr.getIpv4AddressNoZone()); + } else { + greTunnelAddDel.tunnel.src = + AddressTranslator.INSTANCE.ipv6AddressToAddress(srcAddr.getIpv6AddressNoZone()); + greTunnelAddDel.tunnel.dst = + AddressTranslator.INSTANCE.ipv6AddressToAddress(dstAddr.getIpv6AddressNoZone()); + } + greTunnelAddDel.tunnel.outerFibId = outerFibId; + greTunnelAddDel.tunnel.isIpv6 = isIpv6; + return greTunnelAddDel; + } + + @Override + protected Class getExpectedInterfaceType() { + return GreTunnel.class; + } + + @Override + protected final void writeInterface(@Nonnull final InstanceIdentifier id, @Nonnull final Gre dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + + createGreTunnel(id, swIfName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Gre dataBefore, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + deleteGreTunnel(id, swIfName, dataBefore, writeContext); + } + + private void createGreTunnel(final InstanceIdentifier id, final String swIfName, final Gre gre, + final WriteContext writeContext) throws WriteFailedException { + final byte isIpv6 = (byte) (isIpv6(gre) + ? 1 + : 0); + int outerFibId = gre.getOuterFibId().intValue(); + + LOG.debug("Setting gre tunnel for interface: {}. Gre: {}", swIfName, gre); + final CompletionStage greAddDelTunnelReplyCompletionStage = + getFutureJVpp().greTunnelAddDel(getGreTunnelRequest((byte) 1 /* is add */, gre.getSrc(), + gre.getDst(), outerFibId, isIpv6)); + + final GreTunnelAddDelReply reply = + getReplyForCreate(greAddDelTunnelReplyCompletionStage.toCompletableFuture(), id, gre); + LOG.debug("Gre tunnel set successfully for: {}, gre: {}", swIfName, gre); + if (interfaceContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) { + // VPP keeps gre tunnels present even after they are delete(reserving ID for next tunnel) + // This may cause inconsistencies in mapping context when configuring tunnels like this: + // 1. Add tunnel 2. Delete tunnel 3. Read interfaces (reserved mapping e.g. gre_tunnel0 -> 6 + // will get into mapping context) 4. Add tunnel (this will add another mapping with the same + // reserved ID and context is invalid) + // That's why a check has to be performed here removing mapping gre_tunnel0 -> 6 mapping and storing + // new name for that ID + final String formerName = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext()); + LOG.debug("Removing updated mapping of a gre tunnel, id: {}, former name: {}, new name: {}", + reply.swIfIndex, formerName, swIfName); + interfaceContext.removeName(formerName, writeContext.getMappingContext()); + } + // Add new interface to our interface context + interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); + } + + private boolean isIpv6(final Gre gre) { + return gre.getSrc().getIpv4AddressNoZone() == null; + } + + private void deleteGreTunnel(final InstanceIdentifier id, final String swIfName, final Gre gre, + final WriteContext writeContext) throws WriteFailedException { + final byte isIpv6 = (byte) (isIpv6(gre) + ? 1 + : 0); + + int outerFibId = gre.getOuterFibId().intValue(); + + LOG.debug("Deleting gre tunnel for interface: {}. Gre: {}", swIfName, gre); + final CompletionStage greAddDelTunnelReplyCompletionStage = + getFutureJVpp().greTunnelAddDel(getGreTunnelRequest((byte) 0 /* is add */, gre.getSrc(), + gre.getDst(), outerFibId, isIpv6)); + + getReplyForDelete(greAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Gre tunnel deleted successfully for: {}, gre: {}", swIfName, gre); + // Remove interface from our interface context + interfaceContext.removeName(swIfName, writeContext.getMappingContext()); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/GreValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/GreValidator.java new file mode 100644 index 000000000..df487fde8 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/GreValidator.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.Gre; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class GreValidator implements Validator { + + public GreValidator(final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final Gre dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + try { + validateGre(dataAfter); + } catch (Exception e) { + throw new DataValidationFailedException.CreateValidationFailedException(id, dataAfter, e); + } + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final Gre dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + try { + validateGre(dataBefore); + } catch (Exception e) { + throw new DataValidationFailedException.DeleteValidationFailedException(id, e); + } + } + + private void validateGre(final Gre data) { + checkNotNull(data.getOuterFibId(), "Outer Fib ID cannot be null"); + checkNotNull(data.getSrc(), "Source cannot be null"); + checkNotNull(data.getDst(), "Destination cannot be null"); + if (data.getSrc().getIpv4AddressNoZone() == null) { + checkArgument(data.getDst().getIpv4AddressNoZone() == null, "Inconsistent ip addresses: %s, %s", + data.getSrc(), + data.getDst()); + } else { + checkArgument(data.getDst().getIpv6AddressNoZone() == null, "Inconsistent ip addresses: %s, %s", + data.getSrc(), + data.getDst()); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterconnectionWriteUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterconnectionWriteUtils.java new file mode 100644 index 000000000..b93168496 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterconnectionWriteUtils.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; + +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.SwInterfaceSetL2Bridge; +import io.fd.jvpp.core.dto.SwInterfaceSetL2BridgeReply; +import io.fd.jvpp.core.dto.SwInterfaceSetL2Xconnect; +import io.fd.jvpp.core.dto.SwInterfaceSetL2XconnectReply; +import io.fd.jvpp.core.future.FutureJVppCore; +import io.fd.jvpp.core.types.L2PortType; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.l2.config.attributes.Interconnection; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.l2.config.attributes.interconnection.BridgeBased; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.l2.config.attributes.interconnection.XconnectBased; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class providing Interconnection CUD support. + */ +final class InterconnectionWriteUtils implements JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(InterconnectionWriteUtils.class); + + private final FutureJVppCore futureJVppCore; + private final NamingContext interfaceContext; + private final NamingContext bridgeDomainContext; + + InterconnectionWriteUtils(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext bridgeDomainContext) { + this.futureJVppCore = requireNonNull(futureJVppCore, "futureJVppCore should not be null"); + this.interfaceContext = requireNonNull(interfaceContext, "interfaceContext should not be null"); + this.bridgeDomainContext = requireNonNull(bridgeDomainContext, "bridgeDomainContext should not be null"); + } + + void setInterconnection(final InstanceIdentifier id, final int swIfIndex, + final String ifcName, final Interconnection ic, final WriteContext writeContext) + throws WriteFailedException { + + if (ic == null) { // TODO in case of update we should delete interconnection + LOG.trace("Interconnection is not set. Skipping"); + } else if (ic instanceof XconnectBased) { + setXconnectBasedL2(id, swIfIndex, ifcName, (XconnectBased) ic, writeContext, (byte) 1 /*enable*/); + } else if (ic instanceof BridgeBased) { + setBridgeBasedL2(id, swIfIndex, ifcName, (BridgeBased) ic, writeContext, (byte) 1 /*enable*/); + } else { + // Choices&cases are not data objects, so they cannot have a dedicated Reader/Writer + // This choice is already from augment, so its not possible to augment augmented choice + LOG.error("Unable to handle Interconnection of type {}", ic.getClass()); + throw new WriteFailedException(id, "Unable to handle Interconnection of type " + ic.getClass()); + } + } + + void deleteInterconnection(final InstanceIdentifier id, final int swIfIndex, + final String ifcName, final Interconnection ic, final WriteContext writeContext) + throws WriteFailedException { + + if (ic == null) { // TODO in case of update we should delete interconnection + LOG.trace("Interconnection is not set. Skipping"); + } else if (ic instanceof XconnectBased) { + setXconnectBasedL2(id, swIfIndex, ifcName, (XconnectBased) ic, writeContext, (byte) 0 /*disable*/); + } else if (ic instanceof BridgeBased) { + setBridgeBasedL2(id, swIfIndex, ifcName, (BridgeBased) ic, writeContext, (byte) 0 /*disable*/); + } else { + LOG.error("Unable to delete Interconnection of type {}", ic.getClass()); + throw new WriteFailedException(id, "Unable to delete Interconnection of type " + ic.getClass()); + } + } + + private void setBridgeBasedL2(final InstanceIdentifier id, final int swIfIndex, + final String ifcName, final BridgeBased bb, + final WriteContext writeContext, final byte enabled) throws WriteFailedException { + LOG.debug("Setting bridge based interconnection(bridge-domain={}) for interface: {}", bb.getBridgeDomain(), + ifcName); + + String bdName = bb.getBridgeDomain(); + + int bdId = bridgeDomainContext.getIndex(bdName, writeContext.getMappingContext()); + checkArgument(bdId > 0, "Unable to set Interconnection for Interface: %s, bridge domain: %s does not exist", + ifcName, bdName); + + byte shg = 0; + if (bb.getSplitHorizonGroup() != null) { + shg = bb.getSplitHorizonGroup().byteValue(); + } + + final CompletionStage swInterfaceSetL2BridgeReplyCompletionStage = futureJVppCore + .swInterfaceSetL2Bridge(getL2BridgeRequest(swIfIndex, bdId, shg, bb.isBridgedVirtualInterface(), enabled)); + getReplyForWrite(swInterfaceSetL2BridgeReplyCompletionStage.toCompletableFuture(), id); + + LOG.debug("Bridge based interconnection updated successfully for: {}, interconnection: {}", ifcName, bb); + } + + private SwInterfaceSetL2Bridge getL2BridgeRequest(final int swIfIndex, final int bdId, final byte shg, + final Boolean bvi, final byte enabled) { + final SwInterfaceSetL2Bridge swInterfaceSetL2Bridge = new SwInterfaceSetL2Bridge(); + swInterfaceSetL2Bridge.rxSwIfIndex = swIfIndex; + swInterfaceSetL2Bridge.bdId = bdId; + swInterfaceSetL2Bridge.shg = shg; + + // TODO HC2VPP-389: add support for unknown unicast type + swInterfaceSetL2Bridge.portType = bvi ? L2PortType.L2_API_PORT_TYPE_BVI : L2PortType.L2_API_PORT_TYPE_NORMAL; + swInterfaceSetL2Bridge.enable = enabled; + return swInterfaceSetL2Bridge; + } + + private void setXconnectBasedL2(final InstanceIdentifier id, final int swIfIndex, + final String ifcName, final XconnectBased ic, + final WriteContext writeContext, final byte enabled) throws WriteFailedException { + String outSwIfName = ic.getXconnectOutgoingInterface(); + LOG.debug("Setting xconnect based interconnection(outgoing ifc={}) for interface: {}", outSwIfName, ifcName); + + int outSwIfIndex = interfaceContext.getIndex(outSwIfName, writeContext.getMappingContext()); + checkArgument(outSwIfIndex > 0, + "Unable to set Interconnection for Interface: %s, outgoing interface: %s does not exist", + ifcName, outSwIfIndex); + + final CompletionStage swInterfaceSetL2XconnectReplyCompletionStage = + futureJVppCore + .swInterfaceSetL2Xconnect(getL2XConnectRequest(swIfIndex, outSwIfIndex, enabled)); + getReplyForWrite(swInterfaceSetL2XconnectReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Xconnect based interconnection updated successfully for: {}, interconnection: {}", ifcName, ic); + } + + private SwInterfaceSetL2Xconnect getL2XConnectRequest(final int rxIfc, final int txIfc, + final byte enabled) { + + final SwInterfaceSetL2Xconnect swInterfaceSetL2Xconnect = new SwInterfaceSetL2Xconnect(); + swInterfaceSetL2Xconnect.enable = enabled; + swInterfaceSetL2Xconnect.rxSwIfIndex = rxIfc; + swInterfaceSetL2Xconnect.txSwIfIndex = txIfc; + return swInterfaceSetL2Xconnect; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceCustomizer.java new file mode 100644 index 000000000..147575bb1 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceCustomizer.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.SwInterfaceSetFlags; +import io.fd.jvpp.core.dto.SwInterfaceSetFlagsReply; +import io.fd.jvpp.core.future.FutureJVppCore; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.InterfaceKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Ietf interface write customizer that only caches interface objects for child writers + */ +public class InterfaceCustomizer extends FutureJVppCustomizer + implements ListWriterCustomizer, JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(InterfaceCustomizer.class); + private static final String LOCAL0_NAME = "local0"; + + private final NamingContext interfaceContext; + + public InterfaceCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Interface dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + + setInterface(id, dataAfter, writeContext); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Interface dataBefore, + @Nonnull final Interface dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + updateInterface(id, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Interface dataBefore, + @Nonnull final WriteContext writeContext) + throws WriteFailedException.DeleteFailedException { + // Special handling for local0 interface (HC2VPP-308): + if (LOCAL0_NAME.equals(dataBefore.getName())) { + throw new WriteFailedException.DeleteFailedException(id, + new UnsupportedOperationException("Removing " + LOCAL0_NAME + " interface is not supported")); + } + // For other interfaces, delegate delete to customizers for specific interface types (e.g. VXLan, Tap). + } + + private void setInterface(final InstanceIdentifier id, final Interface swIf, + final WriteContext writeContext) throws WriteFailedException { + LOG.debug("Setting interface: {} to: {}", id, swIf); + setInterfaceAttributes(id, swIf, swIf.getName(), writeContext); + } + + private void setInterfaceAttributes(final InstanceIdentifier id, final Interface swIf, + final String swIfName, final WriteContext writeContext) + throws WriteFailedException { + + setInterfaceFlags(id, swIfName, interfaceContext.getIndex(swIfName, writeContext.getMappingContext()), + swIf.isEnabled() + ? (byte) 1 + : (byte) 0); + } + + private void updateInterface(final InstanceIdentifier id, + final Interface dataAfter, final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Updating interface:{} to: {}", id, dataAfter); + setInterfaceAttributes(id, dataAfter, dataAfter.getName(), writeContext); + } + + private void setInterfaceFlags(final InstanceIdentifier id, final String swIfName, final int swIfIndex, + final byte enabled) throws WriteFailedException { + final CompletionStage swInterfaceSetFlagsReplyFuture = + getFutureJVpp().swInterfaceSetFlags(getSwInterfaceSetFlagsInput(swIfIndex, enabled)); + + LOG.debug("Updating interface flags for: {}, index: {}, enabled: {}", swIfName, swIfIndex, enabled); + + getReplyForWrite(swInterfaceSetFlagsReplyFuture.toCompletableFuture(), id); + LOG.debug("Interface flags updated successfully for: {}, index: {}, enabled: {}", + swIfName, swIfIndex, enabled); + } + + private SwInterfaceSetFlags getSwInterfaceSetFlagsInput(final int swIfIndex, final byte enabled) { + final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags(); + swInterfaceSetFlags.swIfIndex = swIfIndex; + swInterfaceSetFlags.adminUpDown = enabled; + return swInterfaceSetFlags; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceRoutingCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceRoutingCustomizer.java new file mode 100644 index 000000000..51d15e348 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceRoutingCustomizer.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.future.FutureJVppCore; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.Routing; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class InterfaceRoutingCustomizer extends RoutingCustomizer + implements WriterCustomizer { + + public InterfaceRoutingCustomizer(@Nonnull final FutureJVppCore vppApi, + @Nonnull final NamingContext interfaceContext) { + super(vppApi, interfaceContext); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Routing dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifName = id.firstKeyOf(Interface.class).getName(); + setRouting(id, ifName, dataAfter, writeContext); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Routing dataBefore, @Nonnull final Routing dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifName = id.firstKeyOf(Interface.class).getName(); + setRouting(id, ifName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Routing dataBefore, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifName = id.firstKeyOf(Interface.class).getName(); + disableRouting(id, ifName, writeContext); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceRoutingValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceRoutingValidator.java new file mode 100644 index 000000000..608bda3fa --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceRoutingValidator.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2019 PANTHEON.tech. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +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.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.write.DataValidationFailedException.CreateValidationFailedException; +import io.fd.honeycomb.translate.write.DataValidationFailedException.DeleteValidationFailedException; +import io.fd.honeycomb.translate.write.DataValidationFailedException.UpdateValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import java.util.List; +import java.util.Optional; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.RoutingBaseAttributes; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.Routing; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev180222.Interface1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev180222.interfaces._interface.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev180222.interfaces._interface.Ipv6; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class InterfaceRoutingValidator implements Validator { + + public InterfaceRoutingValidator(@Nonnull final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final Routing dataAfter, + @Nonnull final WriteContext writeContext) + throws CreateValidationFailedException { + try { + checkVrfIds(dataAfter); + checkInterfaceAddressConf(id, writeContext, true); + } catch (Exception e) { + throw new CreateValidationFailedException(id, dataAfter, e); + } + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final Routing dataBefore, + @Nonnull final Routing dataAfter, @Nonnull final WriteContext writeContext) + throws UpdateValidationFailedException { + try { + checkVrfIds(dataAfter); + checkInterfaceAddressConf(id, writeContext, true); + } catch (Exception e) { + throw new UpdateValidationFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final Routing dataBefore, + @Nonnull final WriteContext writeContext) + throws DeleteValidationFailedException { + try { + checkVrfIds(dataBefore); + checkInterfaceAddressConf(id, writeContext, false); + } catch (Exception e) { + throw new DeleteValidationFailedException(id, e); + } + } + + private void checkVrfIds(final RoutingBaseAttributes data) { + checkArgument(data.getIpv4VrfId() != null || data.getIpv6VrfId() != null, "No vrf-id given"); + } + + private void checkInterfaceAddressConf(@Nonnull final InstanceIdentifier id, + @Nonnull final WriteContext ctx, + boolean checkBefore) { + checkState(isAddressNotPresentForInterface(id, ctx, checkBefore), + "Cannot change routing configuration, if address is present for interface"); + } + + /** + * Returns true if interface does not have v4/v6 addresses configured + */ + private boolean isAddressNotPresentForInterface(@Nonnull final InstanceIdentifier id, + @Nonnull final WriteContext ctx, + boolean checkBefore) { + final Optional interfaceData = checkBefore + ? ctx.readBefore(RWUtils.cutId(id, Interface.class)) + : ctx.readAfter(RWUtils.cutId(id, Interface.class)); + + if (interfaceData.isPresent()) { + final java.util.Optional augData = java.util.Optional.of(interfaceData.get()) + .map(iface -> iface.augmentation(Interface1.class)); + + final boolean v4NotPresent = + augData.map(Interface1::getIpv4).map(Ipv4::getAddress).map(List::isEmpty).orElse(true); + + final boolean v6NotPresent = + augData.map(Interface1::getIpv6).map(Ipv6::getAddress).map(List::isEmpty).orElse(true); + + return v4NotPresent && v6NotPresent; + } + return true; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceUnnumberedCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceUnnumberedCustomizer.java new file mode 100644 index 000000000..a6eada50a --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceUnnumberedCustomizer.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.future.FutureJVppCore; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.unnumbered.interfaces.rev180103.unnumbered.config.attributes.Unnumbered; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public final class InterfaceUnnumberedCustomizer extends AbstractUnnumberedCustomizer { + + public InterfaceUnnumberedCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final NamingContext interfaceContext) { + super(futureJVppCore, interfaceContext); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Unnumbered dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + setUnnumbered(id, id.firstKeyOf(Interface.class).getName(), dataAfter, writeContext); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Unnumbered dataBefore, @Nonnull final Unnumbered dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + setUnnumbered(id, id.firstKeyOf(Interface.class).getName(), dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Unnumbered dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + disableUnnumbered(id, id.firstKeyOf(Interface.class).getName(), dataBefore, writeContext); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceUnnumberedValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceUnnumberedValidator.java new file mode 100644 index 000000000..19f115119 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceUnnumberedValidator.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.unnumbered.interfaces.rev180103.unnumbered.config.attributes.Unnumbered; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class InterfaceUnnumberedValidator implements Validator { + + public InterfaceUnnumberedValidator(final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final Unnumbered dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + checkNotNull(dataAfter.getUse(), "Use cannot be null"); + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final Unnumbered dataBefore, + @Nonnull final Unnumbered dataAfter, @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + checkNotNull(dataAfter.getUse(), "Use cannot be null"); + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final Unnumbered dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + checkNotNull(dataBefore.getUse(), "Use cannot be null"); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceValidator.java new file mode 100644 index 000000000..59acbd7af --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfaceValidator.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException.CreateValidationFailedException; +import io.fd.honeycomb.translate.write.DataValidationFailedException.DeleteValidationFailedException; +import io.fd.honeycomb.translate.write.DataValidationFailedException.UpdateValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class InterfaceValidator implements Validator { + + public InterfaceValidator(final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final Interface dataAfter, + @Nonnull final WriteContext writeContext) + throws CreateValidationFailedException { + try { + checkInterface(dataAfter); + } catch (Exception e) { + throw new CreateValidationFailedException(id, dataAfter, e); + } + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final Interface dataBefore, + @Nonnull final Interface dataAfter, @Nonnull final WriteContext writeContext) + throws UpdateValidationFailedException { + try { + checkInterface(dataAfter); + } catch (Exception e) { + throw new UpdateValidationFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final Interface dataBefore, + @Nonnull final WriteContext writeContext) + throws DeleteValidationFailedException { + try { + checkInterface(dataBefore); + } catch (Exception e) { + throw new DeleteValidationFailedException(id, e); + } + } + + private void checkInterface(final Interface data) { + checkNotNull(data.isEnabled(), "Enabled tag cannot be null"); + checkNotNull(data.getName(), "Name cannot be null"); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfacesStatisticsCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfacesStatisticsCustomizer.java new file mode 100644 index 000000000..ca22aa5ea --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfacesStatisticsCustomizer.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019 PANTHEON.tech. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.v3po.read.cache.InterfaceStatisticsManager; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces.Statistics; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class InterfacesStatisticsCustomizer implements WriterCustomizer { + + private final InterfaceStatisticsManager statisticsManager; + + public InterfacesStatisticsCustomizer(final InterfaceStatisticsManager statisticsManager) { + this.statisticsManager = statisticsManager; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier instanceIdentifier, + @Nonnull final Statistics statisticsCollection, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + enableDisableStatistics(statisticsCollection); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Statistics dataBefore, + @Nonnull final Statistics dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + enableDisableStatistics(dataAfter); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier instanceIdentifier, + @Nonnull final Statistics statisticsCollection, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + statisticsManager.disableStatistics(); + } + + private void enableDisableStatistics(final Statistics statsCollect) { + if (statsCollect != null) { + if (statsCollect.isEnabled()) { + statisticsManager.enableStatistics(); + return; + } + } + statisticsManager.disableStatistics(); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfacesStatisticsValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfacesStatisticsValidator.java new file mode 100644 index 000000000..06c532842 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/InterfacesStatisticsValidator.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 PANTHEON.tech. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.v3po.read.cache.InterfaceStatisticsManager; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces.Statistics; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class InterfacesStatisticsValidator implements Validator { + + public InterfacesStatisticsValidator(final InterfaceStatisticsManager statisticsManager) { + checkNotNull(statisticsManager, "Statistics Collection Manager should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final Statistics dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + // there is nothing to validate yet + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final Statistics dataBefore, + @Nonnull final Statistics dataAfter, @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + // there is nothing to validate yet + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final Statistics dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + // there is nothing to validate yet + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/L2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/L2Customizer.java new file mode 100644 index 000000000..cbceea36f --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/L2Customizer.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.future.FutureJVppCore; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.L2; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class L2Customizer extends FutureJVppCustomizer implements WriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(L2Customizer.class); + private final NamingContext interfaceContext; + private final InterconnectionWriteUtils icWriteUtils; + + public L2Customizer(final FutureJVppCore vppApi, final NamingContext interfaceContext, + final NamingContext bridgeDomainContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + this.icWriteUtils = new InterconnectionWriteUtils(vppApi, interfaceContext, bridgeDomainContext); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier 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 id, @Nonnull final L2 dataBefore, + @Nonnull final L2 dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + + final String ifcName = id.firstKeyOf(Interface.class).getName(); + final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext()); + // No update, again calling set + setL2(id, swIfc, ifcName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier 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 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 id, final int swIfIndex, final String ifcName, final L2 l2Before, + final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Deleting L2 for interface: {}", ifcName); + // Nothing besides interconnection here + icWriteUtils.deleteInterconnection(id, swIfIndex, ifcName, l2Before.getInterconnection(), writeContext); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/L2Validator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/L2Validator.java new file mode 100644 index 000000000..1dedf3817 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/L2Validator.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.L2; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class L2Validator implements Validator { + + public L2Validator(final NamingContext interfaceContext, + final NamingContext bridgeDomainContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + checkNotNull(bridgeDomainContext, "bridgeDomainContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + // there is nothing to validate yet + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataBefore, + @Nonnull final L2 dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + // there is nothing to validate yet + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + // there is nothing to validate yet + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/LoopbackCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/LoopbackCustomizer.java new file mode 100644 index 000000000..0be934598 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/LoopbackCustomizer.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.MacTranslator; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.CreateLoopback; +import io.fd.jvpp.core.dto.CreateLoopbackReply; +import io.fd.jvpp.core.dto.DeleteLoopback; +import io.fd.jvpp.core.future.FutureJVppCore; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.Loopback; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class LoopbackCustomizer extends AbstractInterfaceTypeCustomizer + implements MacTranslator, JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(LoopbackCustomizer.class); + private final NamingContext interfaceContext; + + public LoopbackCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + protected Class getExpectedInterfaceType() { + return org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.Loopback.class; + } + + @Override + protected final void writeInterface(@Nonnull final InstanceIdentifier id, @Nonnull final Loopback dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifcName = id.firstKeyOf(Interface.class).getName(); + createLoopback(id, ifcName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Loopback dataBefore, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifcName = id.firstKeyOf(Interface.class).getName(); + + final int index; + try { + index = interfaceContext.getIndex(ifcName, writeContext.getMappingContext()); + } catch (IllegalArgumentException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + + deleteLoopback(id, ifcName, index, dataBefore, writeContext); + } + + private void createLoopback(final InstanceIdentifier id, final String swIfName, final Loopback loopback, + final WriteContext writeContext) throws WriteFailedException { + LOG.debug("Setting loopback interface: {}. Loopback: {}", swIfName, loopback); + + final CreateLoopback createLoopback = new CreateLoopback(); + if (loopback.getMac() != null) { + createLoopback.macAddress = parseMac(loopback.getMac().getValue()); + } + final CreateLoopbackReply reply = + getReplyForCreate(getFutureJVpp().createLoopback(createLoopback).toCompletableFuture(), id, loopback); + + LOG.debug("Loopback set successfully for: {}, loopback: {}", swIfName, loopback); + // Add new interface to our interface context + interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); + } + + private void deleteLoopback(final InstanceIdentifier id, final String swIfName, final int index, + final Loopback dataBefore, final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Deleting loopback interface: {}. Loopback: {}", swIfName, dataBefore); + final DeleteLoopback deleteLoopback = new DeleteLoopback(); + deleteLoopback.swIfIndex = index; + getReplyForDelete(getFutureJVpp().deleteLoopback(deleteLoopback).toCompletableFuture(), id); + LOG.debug("Loopback deleted successfully for: {}, loopback: {}", swIfName, dataBefore); + // Remove deleted interface from interface context + interfaceContext.removeName(swIfName, writeContext.getMappingContext()); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/LoopbackValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/LoopbackValidator.java new file mode 100644 index 000000000..af6126bfb --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/LoopbackValidator.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.Loopback; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class LoopbackValidator implements Validator { + + public LoopbackValidator(final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final Loopback dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + // there is nothing to validate yet + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final Loopback dataBefore, + @Nonnull final Loopback dataAfter, @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + // there is nothing to validate yet + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final Loopback dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + // there is nothing to validate yet + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/RewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/RewriteCustomizer.java new file mode 100644 index 000000000..15eb7b0b4 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/RewriteCustomizer.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.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.common.translate.util.TagRewriteOperation; +import io.fd.hc2vpp.v3po.util.SubInterfaceUtils; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.L2InterfaceVlanTagRewrite; +import io.fd.jvpp.core.dto.L2InterfaceVlanTagRewriteReply; +import io.fd.jvpp.core.future.FutureJVppCore; +import java.util.List; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319._802dot1q; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.rewrite.attributes.Rewrite; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.rewrite.attributes.RewriteBuilder; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.tag.rewrite.PushTags; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writer Customizer responsible for vlan tag rewrite.
Sends {@code l2_interface_vlan_tag_rewrite} message to + * VPP.
Equivalent of invoking {@code vppctl set interface l2 tag-rewrite} command. + */ +public class RewriteCustomizer extends FutureJVppCustomizer + implements WriterCustomizer, ByteDataTranslator, JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(RewriteCustomizer.class); + private final NamingContext interfaceContext; + + public RewriteCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final NamingContext interfaceContext) { + super(futureJVppCore); + this.interfaceContext = interfaceContext; + } + + @Override + public void writeCurrentAttributes(final InstanceIdentifier id, final Rewrite dataAfter, + final WriteContext writeContext) + throws WriteFailedException { + final String subifName = getSubInterfaceName(id); + setTagRewrite(id, subifName, dataAfter, writeContext); + } + + private static String getSubInterfaceName(final InstanceIdentifier id) { + return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), + Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier())); + } + + private void setTagRewrite(final InstanceIdentifier id, final String ifname, final Rewrite rewrite, + final WriteContext writeContext) throws WriteFailedException { + final int swIfIndex = interfaceContext.getIndex(ifname, writeContext.getMappingContext()); + LOG.debug("Setting tag rewrite for interface {}(id=): {}", ifname, swIfIndex, rewrite); + + final CompletionStage replyCompletionStage = + getFutureJVpp().l2InterfaceVlanTagRewrite(getTagRewriteRequest(swIfIndex, rewrite)); + + getReplyForWrite(replyCompletionStage.toCompletableFuture(), id); + LOG.debug("Tag rewrite for interface {}(id=) set successfully: {}", ifname, swIfIndex, rewrite); + } + + private L2InterfaceVlanTagRewrite getTagRewriteRequest(final int swIfIndex, final Rewrite rewrite) { + final L2InterfaceVlanTagRewrite request = new L2InterfaceVlanTagRewrite(); + request.swIfIndex = swIfIndex; + request.pushDot1Q = booleanToByte(_802dot1q.class == rewrite.getVlanType()); + + final List pushTags = rewrite.getPushTags(); + final Short popTags = rewrite.getPopTags(); + + final int numberOfTagsToPop = popTags == null + ? 0 + : popTags.intValue(); + final int numberOfTagsToPush = pushTags == null + ? 0 + : pushTags.size(); + + request.vtrOp = TagRewriteOperation.get(numberOfTagsToPop, numberOfTagsToPush).ordinal(); + + if (numberOfTagsToPush > 0) { + for (final PushTags tag : pushTags) { + if (tag.getIndex() == 0) { + request.tag1 = tag.getDot1qTag().getVlanId().getValue(); + } else { + request.tag2 = tag.getDot1qTag().getVlanId().getValue(); + } + } + } + + LOG.debug("Generated tag rewrite request: {}", request); + return request; + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Rewrite dataBefore, + @Nonnull final Rewrite dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String subifName = getSubInterfaceName(id); + setTagRewrite(id, subifName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Rewrite dataBefore, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String subifName = getSubInterfaceName(id); + + LOG.debug("Disabling tag rewrite for interface {}", subifName); + final Rewrite rewrite = new RewriteBuilder().build(); // rewrite without push and pops will cause delete + setTagRewrite(id, subifName, rewrite, writeContext); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/RewriteValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/RewriteValidator.java new file mode 100644 index 000000000..a16bbafc4 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/RewriteValidator.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.rewrite.attributes.Rewrite; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class RewriteValidator implements Validator { + + public RewriteValidator(@Nonnull final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final Rewrite dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + // there is nothing to validate yet + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final Rewrite dataBefore, + @Nonnull final Rewrite dataAfter, @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + // there is nothing to validate yet + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final Rewrite dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + // there is nothing to validate yet + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/RoutingCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/RoutingCustomizer.java new file mode 100644 index 000000000..b28b6e3c9 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/RoutingCustomizer.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkArgument; + +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.SwInterfaceSetTable; +import io.fd.jvpp.core.dto.SwInterfaceSetTableReply; +import io.fd.jvpp.core.future.FutureJVppCore; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.RoutingBaseAttributes; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.fib.table.management.rev180521.VniReference; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +abstract class RoutingCustomizer extends FutureJVppCustomizer implements JvppReplyConsumer, ByteDataTranslator { + private static final Logger LOG = LoggerFactory.getLogger(RoutingCustomizer.class); + protected final NamingContext interfaceContext; + + protected RoutingCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final NamingContext interfaceContext) { + super(futureJVppCore); + this.interfaceContext = interfaceContext; + } + + protected void setRouting(@Nonnull final InstanceIdentifier id, + @Nonnull final String name, + @Nonnull final RoutingBaseAttributes rt, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext()); + LOG.debug("Setting routing for interface: {}, {}. Routing: {}", name, swIfc, rt); + checkArgument(rt.getIpv4VrfId() != null || rt.getIpv6VrfId() != null, "No vrf-id given"); + + setVrfId(id, swIfc, rt.getIpv4VrfId(), false); + setVrfId(id, swIfc, rt.getIpv6VrfId(), true); + + LOG.debug("Routing set successfully for interface: {}, {}, routing: {}", name, swIfc, rt); + } + + private void setVrfId(final InstanceIdentifier id, final int swIfc, + final VniReference vniRef, boolean isIp6) + throws WriteFailedException { + if (vniRef == null || vniRef.getValue() == null) { + return; + } + final CompletionStage cs = getFutureJVpp().swInterfaceSetTable( + getInterfaceSetTableRequest(swIfc, booleanToByte(isIp6), vniRef.getValue().intValue())); + getReplyForWrite(cs.toCompletableFuture(), id); + } + + /** + * In this case, there is no such thing as delete routing,only thing that can be done is to disable it by setting + * default value 0 + */ + void disableRouting(final InstanceIdentifier id, final String name, + final WriteContext writeContext) throws WriteFailedException { + final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext()); + LOG.debug("Disabling routing for interface: {}, {}.", name, swIfc); + + getReplyForDelete(getFutureJVpp() + .swInterfaceSetTable(getInterfaceSetTableRequest(swIfc, (byte) 0, 0)).toCompletableFuture(), id); + LOG.debug("Routing for interface: {}, {} successfully disabled", name, swIfc); + + } + + private SwInterfaceSetTable getInterfaceSetTableRequest(final int swIfc, final byte isIpv6, final int vrfId) { + final SwInterfaceSetTable swInterfaceSetTable = new SwInterfaceSetTable(); + swInterfaceSetTable.isIpv6 = isIpv6; + swInterfaceSetTable.swIfIndex = swIfc; + swInterfaceSetTable.vrfId = vrfId; + return swInterfaceSetTable; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceCustomizer.java new file mode 100644 index 000000000..65d7de55e --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceCustomizer.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkState; +import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.getNumberOfTags; +import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.getSubInterfaceName; + +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.CreateSubif; +import io.fd.jvpp.core.dto.CreateSubifReply; +import io.fd.jvpp.core.dto.SwInterfaceSetFlags; +import io.fd.jvpp.core.dto.SwInterfaceSetFlagsReply; +import io.fd.jvpp.core.future.FutureJVppCore; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319._802dot1ad; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.match.attributes.MatchType; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.match.attributes.match.type.Default; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.match.attributes.match.type.VlanTagged; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.sub._interface.base.attributes.tags.Tag; +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.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writer Customizer responsible for sub interface creation.
Sends {@code create_subif} message to VPP.
+ * Equivalent of invoking {@code vppclt create subif} command. + */ +public class SubInterfaceCustomizer extends FutureJVppCustomizer + implements ListWriterCustomizer, ByteDataTranslator, JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceCustomizer.class); + private final NamingContext interfaceContext; + + public SubInterfaceCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final NamingContext interfaceContext) { + super(futureJVppCore); + this.interfaceContext = interfaceContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final SubInterface dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String superIfName = id.firstKeyOf(Interface.class).getName(); + createSubInterface(id, superIfName, dataAfter, writeContext); + } + + private void createSubInterface(final InstanceIdentifier id, @Nonnull final String superIfName, + @Nonnull final SubInterface subInterface, final WriteContext writeContext) + throws WriteFailedException { + final int superIfIndex = interfaceContext.getIndex(superIfName, writeContext.getMappingContext()); + final CompletionStage createSubifReplyCompletionStage = + getFutureJVpp().createSubif(getCreateSubifRequest(subInterface, superIfIndex)); + + final CreateSubifReply reply = + getReplyForCreate(createSubifReplyCompletionStage.toCompletableFuture(), id, subInterface); + + setInterfaceState(id, reply.swIfIndex, booleanToByte(subInterface.isEnabled())); + interfaceContext.addName(reply.swIfIndex, + getSubInterfaceName(superIfName, Math.toIntExact(subInterface.getIdentifier())), + writeContext.getMappingContext()); + LOG.debug("Sub interface created successfully for: {}, subInterface: {}", superIfName, subInterface); + } + + private CreateSubif getCreateSubifRequest(@Nonnull final SubInterface subInterface, final int swIfIndex) { + // TODO HONEYCOMB-183 add validation + CreateSubif request = new CreateSubif(); + request.subId = Math.toIntExact(subInterface.getIdentifier().intValue()); + request.swIfIndex = swIfIndex; + + final int numberOfTags = getNumberOfTags(subInterface.getTags()); + switch (numberOfTags) { + case 0: + request.noTags = 1; + break; + case 1: + request.oneTag = 1; + break; + case 2: + request.twoTags = 1; + break; + } + request.dot1Ad = booleanToByte(_802dot1ad.class == subInterface.getVlanType()); + + // TODO HONEYCOMB-183 match should be mandatory + final MatchType matchType = subInterface.getMatch().getMatchType(); + request.exactMatch = booleanToByte( + matchType instanceof VlanTagged + && ((VlanTagged) matchType).getVlanTagged().isMatchExactTags() + ); + request.defaultSub = booleanToByte(matchType instanceof Default); + if (numberOfTags > 0) { + for (final Tag tag : subInterface.getTags().getTag()) { + if (tag.getIndex() == 0) { + setOuterTag(request, tag); + } else if (tag.getIndex() == 1) { + setInnerTag(request, tag); + } + } + } + return request; + } + + private void setOuterTag(final CreateSubif request, final Tag outerTag) { + checkState(SVlan.class == outerTag.getDot1qTag().getTagType(), "Service Tag expected at index 0"); + final Dot1qTag.VlanId vlanId = outerTag.getDot1qTag().getVlanId(); + + request.outerVlanId = dot1qVlanIdToShort(vlanId.getDot1qVlanId()); + request.outerVlanIdAny = booleanToByte(Dot1qTag.VlanId.Enumeration.Any.equals(vlanId.getEnumeration())); + } + + private void setInnerTag(final CreateSubif request, final Tag innerTag) { + checkState(CVlan.class == innerTag.getDot1qTag().getTagType(), "Customer Tag expected at index 1"); + final Dot1qTag.VlanId vlanId = innerTag.getDot1qTag().getVlanId(); + + request.innerVlanId = dot1qVlanIdToShort(vlanId.getDot1qVlanId()); + request.innerVlanIdAny = booleanToByte(Dot1qTag.VlanId.Enumeration.Any.equals(vlanId.getEnumeration())); + } + + private static short dot1qVlanIdToShort(@Nullable Dot1qVlanId dot1qVlanId) { + if (dot1qVlanId == null) { + return 0; // tell VPP that optional argument is missing + } else { + return dot1qVlanId.getValue().shortValue(); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final SubInterface dataBefore, @Nonnull final SubInterface dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String subIfaceName = getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), + Math.toIntExact(dataAfter.getIdentifier())); + setInterfaceState(id, interfaceContext.getIndex(subIfaceName, writeContext.getMappingContext()), + booleanToByte(dataAfter.isEnabled())); + } + + private void setInterfaceState(final InstanceIdentifier id, final int swIfIndex, final byte enabled) + throws WriteFailedException { + final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags(); + swInterfaceSetFlags.swIfIndex = swIfIndex; + swInterfaceSetFlags.adminUpDown = enabled; + + final CompletionStage swInterfaceSetFlagsReplyFuture = + getFutureJVpp().swInterfaceSetFlags(swInterfaceSetFlags); + + LOG.debug("Updating interface state for interface if={}, enabled: {}", swIfIndex, enabled); + + SwInterfaceSetFlagsReply reply = + getReplyForWrite(swInterfaceSetFlagsReplyFuture.toCompletableFuture(), id); + LOG.debug("Interface state updated successfully for interface index: {}, enabled: {}, ctxId: {}", + swIfIndex, enabled, reply.context); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final SubInterface dataBefore, + @Nonnull final WriteContext writeContext) + throws WriteFailedException.DeleteFailedException { + throw new UnsupportedOperationException("Sub interface delete is not supported"); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceL2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceL2Customizer.java new file mode 100644 index 000000000..091713c26 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceL2Customizer.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.v3po.util.SubInterfaceUtils; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.future.FutureJVppCore; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.sub._interface.l2.config.attributes.L2; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.InterfaceKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for writing vlan sub interface l2 configuration + */ +public class SubInterfaceL2Customizer extends FutureJVppCustomizer implements WriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceL2Customizer.class); + private final NamingContext interfaceContext; + private final InterconnectionWriteUtils icWriterUtils; + + public SubInterfaceL2Customizer(final FutureJVppCore vppApi, final NamingContext interfaceContext, + final NamingContext bridgeDomainContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + this.icWriterUtils = new InterconnectionWriteUtils(vppApi, interfaceContext, bridgeDomainContext); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier 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 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 id, @Nonnull final L2 dataBefore, + @Nonnull final L2 dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + + final String subInterfaceName = getSubInterfaceName(id); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); + // Setting L2 to new values + setL2(id, subInterfaceIndex, subInterfaceName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier 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 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 id, final int swIfIndex, final String ifcName, final L2 l2Before, + final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Deleting L2 for sub-interface: {}", ifcName); + icWriterUtils.deleteInterconnection(id, swIfIndex, ifcName, l2Before.getInterconnection(), writeContext); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceL2Validator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceL2Validator.java new file mode 100644 index 000000000..713a80d30 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceL2Validator.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.sub._interface.l2.config.attributes.L2; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class SubInterfaceL2Validator implements Validator { + + public SubInterfaceL2Validator(final NamingContext interfaceContext, + final NamingContext bridgeDomainContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + checkNotNull(bridgeDomainContext, "bridgeDomainContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + // there is nothing to validate yet + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataBefore, + @Nonnull final L2 dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + // there is nothing to validate yet + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + // there is nothing to validate yet + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceRoutingCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceRoutingCustomizer.java new file mode 100644 index 000000000..6fe3c3c01 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceRoutingCustomizer.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.subInterfaceFullNameConfig; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.future.FutureJVppCore; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.sub._interface.routing.attributes.Routing; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class SubInterfaceRoutingCustomizer extends RoutingCustomizer implements WriterCustomizer { + + public SubInterfaceRoutingCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final NamingContext interfaceContext) { + super(futureJVppCore, interfaceContext); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier instanceIdentifier, + @Nonnull final Routing routing, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + setRouting(instanceIdentifier, subInterfaceFullNameConfig(instanceIdentifier), routing, writeContext); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier instanceIdentifier, + @Nonnull final Routing routing, @Nonnull final Routing d1, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + setRouting(instanceIdentifier, subInterfaceFullNameConfig(instanceIdentifier), routing, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier instanceIdentifier, + @Nonnull final Routing routing, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + disableRouting(instanceIdentifier, subInterfaceFullNameConfig(instanceIdentifier), writeContext); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceRoutingValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceRoutingValidator.java new file mode 100644 index 000000000..e769409bd --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceRoutingValidator.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.write.DataValidationFailedException.CreateValidationFailedException; +import io.fd.honeycomb.translate.write.DataValidationFailedException.DeleteValidationFailedException; +import io.fd.honeycomb.translate.write.DataValidationFailedException.UpdateValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import java.util.List; +import java.util.Optional; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.sub._interface.ip4.attributes.Ipv4; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.sub._interface.ip6.attributes.Ipv6; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.sub._interface.routing.attributes.Routing; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class SubInterfaceRoutingValidator implements Validator { + + public SubInterfaceRoutingValidator(@Nonnull final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final Routing dataAfter, + @Nonnull final WriteContext writeContext) + throws CreateValidationFailedException { + try { + checkInterfaceAddressConf(id, writeContext, true); + } catch (Exception e) { + throw new CreateValidationFailedException(id, dataAfter, e); + } + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final Routing dataBefore, + @Nonnull final Routing dataAfter, @Nonnull final WriteContext writeContext) + throws UpdateValidationFailedException { + try { + checkInterfaceAddressConf(id, writeContext, true); + } catch (Exception e) { + throw new UpdateValidationFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final Routing dataBefore, + @Nonnull final WriteContext writeContext) + throws DeleteValidationFailedException { + try { + checkInterfaceAddressConf(id, writeContext, false); + } catch (Exception e) { + throw new DeleteValidationFailedException(id, e); + } + } + + private void checkInterfaceAddressConf(@Nonnull final InstanceIdentifier id, + @Nonnull final WriteContext ctx, + boolean checkBefore) { + checkState(isAddressNotPresentForSubInterface(id, ctx, checkBefore), + "Cannot change routing configuration, if address is present for sub-interface"); + } + + /** + * Returns true if interface does not have v4/v6 addresses configured + */ + private boolean isAddressNotPresentForSubInterface(@Nonnull final InstanceIdentifier id, + @Nonnull final WriteContext ctx, + boolean checkBefore) { + final Optional subInterfaceData = checkBefore + ? + ctx.readBefore(RWUtils.cutId(id, SubInterface.class)) + : + ctx.readAfter(RWUtils.cutId(id, SubInterface.class)); + + if (subInterfaceData.isPresent()) { + final SubInterface subInterface = subInterfaceData.get(); + + final boolean v4NotPresent = + java.util.Optional.ofNullable(subInterface.getIpv4()).map(Ipv4::getAddress).map(List::isEmpty) + .orElse(true); + + final boolean v6NotPresent = + java.util.Optional.ofNullable(subInterface.getIpv6()).map(Ipv6::getAddress).map(List::isEmpty) + .orElse(true); + return v4NotPresent && v6NotPresent; + } + return true; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceUnnumberedCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceUnnumberedCustomizer.java new file mode 100644 index 000000000..314e9a4fe --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceUnnumberedCustomizer.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static io.fd.hc2vpp.v3po.util.SubInterfaceUtils.subInterfaceFullNameConfig; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.future.FutureJVppCore; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.unnumbered.interfaces.rev180103.unnumbered.config.attributes.Unnumbered; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public final class SubInterfaceUnnumberedCustomizer extends AbstractUnnumberedCustomizer { + + public SubInterfaceUnnumberedCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final NamingContext interfaceContext) { + super(futureJVppCore, interfaceContext); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Unnumbered dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + setUnnumbered(id, subInterfaceFullNameConfig(id), dataAfter, writeContext); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Unnumbered dataBefore, @Nonnull final Unnumbered dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + setUnnumbered(id, subInterfaceFullNameConfig(id), dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Unnumbered dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + disableUnnumbered(id, subInterfaceFullNameConfig(id), dataBefore, writeContext); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceUnnumberedValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceUnnumberedValidator.java new file mode 100644 index 000000000..d4224534a --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceUnnumberedValidator.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.unnumbered.interfaces.rev180103.unnumbered.config.attributes.Unnumbered; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class SubInterfaceUnnumberedValidator implements Validator { + + public SubInterfaceUnnumberedValidator(final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final Unnumbered dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + checkNotNull(dataAfter.getUse()); + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final Unnumbered dataBefore, + @Nonnull final Unnumbered dataAfter, @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + checkNotNull(dataAfter.getUse()); + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final Unnumbered dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + checkNotNull(dataBefore.getUse()); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceValidator.java new file mode 100644 index 000000000..92b64bcaa --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/SubInterfaceValidator.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev180319.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class SubInterfaceValidator implements Validator { + + public SubInterfaceValidator(@Nonnull final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final SubInterface dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + try { + checkSubInterface(dataAfter); + } catch (Exception e) { + throw new DataValidationFailedException.CreateValidationFailedException(id, dataAfter, e); + } + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, + @Nonnull final SubInterface dataBefore, + @Nonnull final SubInterface dataAfter, @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + try { + checkSubInterface(dataAfter); + } catch (Exception e) { + throw new DataValidationFailedException.UpdateValidationFailedException(id, dataBefore, dataAfter, e); + } + } + + private void checkSubInterface(final SubInterface data) { + checkNotNull(data.getIdentifier(), "Identifier cannot be null"); + checkNotNull(data.getMatch(), "Match cannot be null"); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/TapV2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/TapV2Customizer.java new file mode 100644 index 000000000..773a48fa0 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/TapV2Customizer.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2018 Pantheon Technologies and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer; +import io.fd.hc2vpp.common.translate.util.Ipv4Translator; +import io.fd.hc2vpp.common.translate.util.Ipv6Translator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.MacTranslator; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.TapCreateV2; +import io.fd.jvpp.core.dto.TapCreateV2Reply; +import io.fd.jvpp.core.dto.TapDeleteV2; +import io.fd.jvpp.core.dto.TapDeleteV2Reply; +import io.fd.jvpp.core.future.FutureJVppCore; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.TapV2; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TapV2Customizer extends AbstractInterfaceTypeCustomizer + implements MacTranslator, Ipv4Translator, Ipv6Translator, JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(TapV2Customizer.class); + private final NamingContext interfaceContext; + + public TapV2Customizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + protected Class getExpectedInterfaceType() { + return org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.TapV2.class; + } + + @Override + protected final void writeInterface(@Nonnull final InstanceIdentifier id, @Nonnull final TapV2 dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifcName = id.firstKeyOf(Interface.class).getName(); + createTapV2(id, ifcName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final TapV2 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); + } + + deleteTapV2(id, ifcName, index, dataBefore, writeContext); + } + + private void createTapV2(final InstanceIdentifier id, final String swIfName, final TapV2 tapv2, + final WriteContext writeContext) throws WriteFailedException { + LOG.debug("Setting TapV2 interface: {}. TapV2: {}", swIfName, tapv2); + final CompletionStage tapV2CreateFuture = getFutureJVpp() + .tapCreateV2(getTapV2CreateRequest(tapv2)); + final TapCreateV2Reply reply = getReplyForCreate(tapV2CreateFuture.toCompletableFuture(), id, tapv2); + LOG.debug("TapV2 set successfully for: {}, TapV2: {}", swIfName, tapv2); + // Add new interface to our interface context + interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); + } + + private void deleteTapV2(final InstanceIdentifier id, final String swIfName, final int index, + final TapV2 dataBefore, final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Deleting TapV2 interface: {}. TapV2: {}", swIfName, dataBefore); + final CompletionStage vxlanAddDelTunnelReplyCompletionStage = + getFutureJVpp().tapDeleteV2(getTapV2DeleteRequest(index)); + getReplyForDelete(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("TapV2 deleted successfully for: {}, TapV2: {}", swIfName, dataBefore); + // Remove deleted interface from interface context + interfaceContext.removeName(swIfName, writeContext.getMappingContext()); + } + + private TapCreateV2 getTapV2CreateRequest(final TapV2 tapv2) { + final TapCreateV2 tapConnect = new TapCreateV2(); + final PhysAddress mac = tapv2.getMac(); + if (mac == null) { + tapConnect.useRandomMac = 1; + tapConnect.macAddress = new byte[6]; + } else { + tapConnect.useRandomMac = 0; + tapConnect.macAddress = parseMac(mac.getValue()); + } + + final Integer rxRingSz = tapv2.getRxRingSize(); + if (rxRingSz != null) { + tapConnect.rxRingSz = rxRingSz.shortValue(); + } + + final Integer txRingSz = tapv2.getTxRingSize(); + if (txRingSz != null) { + tapConnect.txRingSz = txRingSz.shortValue(); + } + + final String tag = tapv2.getTag(); + if (tag != null) { + tapConnect.tag = tag.getBytes(StandardCharsets.US_ASCII); + } + + setHostProperties(tapConnect, tapv2); + return tapConnect; + } + + private TapDeleteV2 getTapV2DeleteRequest(final int swIndex) { + final TapDeleteV2 tapDeleteV2 = new TapDeleteV2(); + tapDeleteV2.swIfIndex = swIndex; + return tapDeleteV2; + } + + private void setHostProperties(TapCreateV2 tapConnect, TapV2 tapv2) { + + final PhysAddress hostMacAddress = tapv2.getHostMac(); + if (hostMacAddress != null) { + tapConnect.hostMacAddr = parseMac(hostMacAddress.getValue()); + tapConnect.hostMacAddrSet = 1; + } else { + tapConnect.hostMacAddr = new byte[6]; + tapConnect.hostMacAddrSet = 0; + } + + final String hostIfName = tapv2.getHostInterfaceName(); + if (hostIfName != null) { + tapConnect.hostIfName = hostIfName.getBytes(UTF_8); + tapConnect.hostIfNameSet = 1; + } else { + tapConnect.hostIfNameSet = 0; + tapConnect.hostIfName = new byte[64]; + } + + final String hostBridge = tapv2.getHostBridge(); + if (hostBridge != null) { + tapConnect.hostBridgeSet = 1; + tapConnect.hostBridge = hostBridge.getBytes(UTF_8); + } else { + tapConnect.hostBridgeSet = 0; + tapConnect.hostBridge = new byte[64]; + } + + final String hostNamespace = tapv2.getHostNamespace(); + if (hostNamespace != null) { + tapConnect.hostNamespaceSet = 1; + tapConnect.hostNamespace = hostNamespace.getBytes(UTF_8); + } else { + tapConnect.hostNamespaceSet = 0; + tapConnect.hostNamespace = new byte[64]; + } + + final Ipv4Prefix hostIpv4address = tapv2.getHostIpv4Address(); + if (hostIpv4address != null) { + tapConnect.hostIp4Addr = ipv4AddressPrefixToArray(hostIpv4address); + tapConnect.hostIp4AddrSet = 1; + tapConnect.hostIp4PrefixLen = extractPrefix(hostIpv4address); + } else { + tapConnect.hostIp4Addr = new byte[4]; + tapConnect.hostIp4AddrSet = 0; + tapConnect.hostIp4PrefixLen = 0; + } + + final Ipv4Address hostIpv4GW = tapv2.getHostIpv4Gateway(); + if (hostIpv4GW != null) { + tapConnect.hostIp4Gw = ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(hostIpv4GW)); + tapConnect.hostIp4GwSet = 1; + } else { + tapConnect.hostIp4Gw = new byte[4]; + tapConnect.hostIp4GwSet = 0; + } + + final Ipv6Prefix hostIpv6address = tapv2.getHostIpv6Address(); + if (hostIpv6address != null) { + tapConnect.hostIp6Addr = ipv6AddressPrefixToArray(hostIpv6address); + tapConnect.hostIp6AddrSet = 1; + tapConnect.hostIp6PrefixLen = extractPrefix(hostIpv6address); + } else { + tapConnect.hostIp6Addr = new byte[16]; + tapConnect.hostIp6AddrSet = 0; + tapConnect.hostIp6PrefixLen = 0; + } + + final Ipv6Address hostIpv6GW = tapv2.getHostIpv6Gateway(); + if (hostIpv6GW != null) { + tapConnect.hostIp6Gw = ipv6AddressNoZoneToArray(hostIpv6GW); + tapConnect.hostIp6GwSet = 1; + } else { + tapConnect.hostIp6Gw = new byte[16]; + tapConnect.hostIp6GwSet = 0; + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/TapV2Validator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/TapV2Validator.java new file mode 100644 index 000000000..83ca218da --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/TapV2Validator.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.TapV2; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class TapV2Validator implements Validator { + + public TapV2Validator(final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final TapV2 dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + // there is nothing to validate yet + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final TapV2 dataBefore, + @Nonnull final TapV2 dataAfter, @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + // there is nothing to validate yet + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final TapV2 dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + // there is nothing to validate yet + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VhostUserCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VhostUserCustomizer.java new file mode 100644 index 000000000..69ade6a75 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VhostUserCustomizer.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.CreateVhostUserIf; +import io.fd.jvpp.core.dto.CreateVhostUserIfReply; +import io.fd.jvpp.core.dto.DeleteVhostUserIf; +import io.fd.jvpp.core.dto.DeleteVhostUserIfReply; +import io.fd.jvpp.core.dto.ModifyVhostUserIf; +import io.fd.jvpp.core.dto.ModifyVhostUserIfReply; +import io.fd.jvpp.core.future.FutureJVppCore; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.VhostUserRole; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.VhostUser; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writer Customizer responsible for passing vhost user interface CRD operations to VPP + */ +public class VhostUserCustomizer extends AbstractInterfaceTypeCustomizer + implements ByteDataTranslator, JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(VhostUserCustomizer.class); + private final NamingContext interfaceContext; + + public VhostUserCustomizer(@Nonnull final FutureJVppCore vppApi, @Nonnull final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + protected Class getExpectedInterfaceType() { + return org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.VhostUser.class; + } + + @Override + protected final void writeInterface(@Nonnull final InstanceIdentifier id, + @Nonnull final VhostUser dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + createVhostUserIf(id, swIfName, dataAfter, writeContext); + } + + private void createVhostUserIf(final InstanceIdentifier id, final String swIfName, + final VhostUser vhostUser, final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Creating vhost user interface: name={}, vhostUser={}", swIfName, vhostUser); + + final CompletionStage createVhostUserIfReplyCompletionStage = + getFutureJVpp().createVhostUserIf(getCreateVhostUserIfRequest(vhostUser)); + final CreateVhostUserIfReply reply = + getReplyForCreate(createVhostUserIfReplyCompletionStage.toCompletableFuture(), id, vhostUser); + LOG.debug("Vhost user interface created successfully for: {}, vhostUser: {}", swIfName, vhostUser); + // Add new interface to our interface context + interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); + } + + private CreateVhostUserIf getCreateVhostUserIfRequest(final VhostUser vhostUser) { + CreateVhostUserIf request = new CreateVhostUserIf(); + request.isServer = booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole())); + request.sockFilename = vhostUser.getSocket().getBytes(); + final Long deviceInstance = vhostUser.getDeviceInstance(); + if (deviceInstance == null) { + request.renumber = 0; + } else { + request.renumber = 1; + request.customDevInstance = Math.toIntExact(deviceInstance); + } + final String tag = vhostUser.getTag(); + if (tag != null) { + request.tag = tag.getBytes(StandardCharsets.US_ASCII); + } + request.useCustomMac = 0; + request.macAddress = new byte[]{}; + return request; + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VhostUser dataBefore, @Nonnull final VhostUser dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + modifyVhostUserIf(id, swIfName, dataBefore, dataAfter, writeContext); + } + + private void modifyVhostUserIf(final InstanceIdentifier id, final String swIfName, + final VhostUser vhostUserBefore, final VhostUser vhostUserAfter, + final WriteContext writeContext) throws WriteFailedException { + LOG.debug("Updating vhost user interface: name={}, vhostUser={}", swIfName, vhostUserAfter); + final CompletionStage modifyVhostUserIfReplyCompletionStage = + getFutureJVpp() + .modifyVhostUserIf(getModifyVhostUserIfRequest(vhostUserAfter, + interfaceContext.getIndex(swIfName, writeContext.getMappingContext()))); + + getReplyForUpdate(modifyVhostUserIfReplyCompletionStage.toCompletableFuture(), id, vhostUserBefore, + vhostUserAfter); + LOG.debug("Vhost user interface updated successfully for: {}, vhostUser: {}", swIfName, vhostUserAfter); + } + + private ModifyVhostUserIf getModifyVhostUserIfRequest(final VhostUser vhostUser, final int swIfIndex) { + ModifyVhostUserIf request = new ModifyVhostUserIf(); + request.isServer = booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole())); + request.sockFilename = vhostUser.getSocket().getBytes(); + final Long deviceInstance = vhostUser.getDeviceInstance(); + if (deviceInstance == null) { + request.renumber = 0; + } else { + request.renumber = 1; + request.customDevInstance = Math.toIntExact(deviceInstance); + } + request.swIfIndex = swIfIndex; + return request; + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VhostUser dataBefore, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + deleteVhostUserIf(id, swIfName, dataBefore, writeContext); + } + + private void deleteVhostUserIf(final InstanceIdentifier id, final String swIfName, + final VhostUser vhostUser, final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Deleting vhost user interface: name={}, vhostUser={}", swIfName, vhostUser); + final CompletionStage deleteVhostUserIfReplyCompletionStage = + getFutureJVpp().deleteVhostUserIf(getDeleteVhostUserIfRequest( + interfaceContext.getIndex(swIfName, writeContext.getMappingContext()))); + + getReplyForDelete(deleteVhostUserIfReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Vhost user interface deleted successfully for: {}, vhostUser: {}", swIfName, vhostUser); + // Remove interface from our interface context + interfaceContext.removeName(swIfName, writeContext.getMappingContext()); + } + + private DeleteVhostUserIf getDeleteVhostUserIfRequest(final int swIfIndex) { + DeleteVhostUserIf request = new DeleteVhostUserIf(); + request.swIfIndex = swIfIndex; + return request; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VhostUserValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VhostUserValidator.java new file mode 100644 index 000000000..c6b84b2b4 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VhostUserValidator.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.VhostUser; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class VhostUserValidator implements Validator { + + public VhostUserValidator(@Nonnull final NamingContext interfaceContext) { + checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final VhostUser dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + checkNotNull(dataAfter.getSocket(), "Socket cannot be null"); + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final VhostUser dataBefore, + @Nonnull final VhostUser dataAfter, @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + checkNotNull(dataAfter.getSocket(), "Socket cannot be null"); + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final VhostUser dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + // there is nothing to validate yet + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanCustomizer.java new file mode 100644 index 000000000..6cac99c38 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanCustomizer.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer; +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.v3po.DisabledInterfacesManager; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.VxlanAddDelTunnel; +import io.fd.jvpp.core.dto.VxlanAddDelTunnelReply; +import io.fd.jvpp.core.future.FutureJVppCore; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.L2Input; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.NshProxy; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.VxlanTunnel; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.Vxlan; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer implements JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class); + + private final NamingContext interfaceNamingContext; + private final DisabledInterfacesManager interfaceDisableContext; + + public VxlanCustomizer(@Nonnull final FutureJVppCore vppApi, + @Nonnull final NamingContext interfaceNamingContext, + @Nonnull final DisabledInterfacesManager interfaceDisableContext) { + super(vppApi); + this.interfaceNamingContext = interfaceNamingContext; + this.interfaceDisableContext = interfaceDisableContext; + } + + @Override + protected Class getExpectedInterfaceType() { + return VxlanTunnel.class; + } + + @Override + protected final void writeInterface(@Nonnull final InstanceIdentifier id, @Nonnull final Vxlan dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + createVxlanTunnel(id, swIfName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Vxlan dataBefore, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + deleteVxlanTunnel(id, swIfName, dataBefore, writeContext); + } + + private void createVxlanTunnel(final InstanceIdentifier id, final String swIfName, final Vxlan vxlan, + final WriteContext writeContext) + throws WriteFailedException { + final byte isIpv6 = (byte) (isIpv6(vxlan) + ? 1 + : 0); + + int encapVrfId = vxlan.getEncapVrfId().getValue().intValue(); + int vni = vxlan.getVni().getValue().intValue(); + + int decapNext = -1; + if (vxlan.getDecapNext() == L2Input.class) { + decapNext = 1; + } else if (vxlan.getDecapNext() == NshProxy.class) { + decapNext = 2; + } + + LOG.debug("Setting vxlan tunnel for interface: {}. Vxlan: {}", swIfName, vxlan); + final CompletionStage vxlanAddDelTunnelReplyCompletionStage = + getFutureJVpp().vxlanAddDelTunnel(getVxlanTunnelRequest((byte) 1 /* is add */, vxlan.getSrc(), + vxlan.getDst(), encapVrfId, decapNext, vni, isIpv6)); + + final VxlanAddDelTunnelReply reply = + getReplyForCreate(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id, vxlan); + LOG.debug("Vxlan tunnel set successfully for: {}, vxlan: {}", swIfName, vxlan); + if (interfaceNamingContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) { + // VPP keeps vxlan tunnels present even after they are delete(reserving ID for next tunnel) + // This may cause inconsistencies in mapping context when configuring tunnels like this: + // 1. Add tunnel 2. Delete tunnel 3. Read interfaces (reserved mapping e.g. vxlan_tunnel0 -> 6 + // will get into mapping context) 4. Add tunnel (this will add another mapping with the same + // reserved ID and context is invalid) + // That's why a check has to be performed here removing mapping vxlan_tunnel0 -> 6 mapping and storing + // new name for that ID + final String formerName = interfaceNamingContext.getName(reply.swIfIndex, writeContext.getMappingContext()); + LOG.debug("Removing updated mapping of a vxlan tunnel, id: {}, former name: {}, new name: {}", + reply.swIfIndex, formerName, swIfName); + interfaceNamingContext.removeName(formerName, writeContext.getMappingContext()); + + } + + // Removing disability of an interface in case a vxlan tunnel formerly deleted is being reused in VPP + // further details in above comment + if (interfaceDisableContext.isInterfaceDisabled(reply.swIfIndex, writeContext.getMappingContext())) { + LOG.debug("Removing disability of vxlan tunnel, id: {}, name: {}", reply.swIfIndex, swIfName); + interfaceDisableContext.removeDisabledInterface(reply.swIfIndex, writeContext.getMappingContext()); + } + + // Add new interface to our interface context + interfaceNamingContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); + } + + private boolean isIpv6(final Vxlan vxlan) { + return vxlan.getSrc().getIpv4AddressNoZone() == null; + + } + + private void deleteVxlanTunnel(final InstanceIdentifier id, final String swIfName, final Vxlan vxlan, + final WriteContext writeContext) throws WriteFailedException { + final byte isIpv6 = (byte) (isIpv6(vxlan) + ? 1 + : 0); + + int encapVrfId = vxlan.getEncapVrfId().getValue().intValue(); + int vni = vxlan.getVni().getValue().intValue(); + + int decapNext = -1; + if (vxlan.getDecapNext() == L2Input.class) { + decapNext = 1; + } else if (vxlan.getDecapNext() == NshProxy.class) { + decapNext = 2; + } + + LOG.debug("Deleting vxlan tunnel for interface: {}. Vxlan: {}", swIfName, vxlan); + final CompletionStage vxlanAddDelTunnelReplyCompletionStage = + getFutureJVpp().vxlanAddDelTunnel(getVxlanTunnelRequest((byte) 0 /* is add */, vxlan.getSrc(), + vxlan.getDst(), encapVrfId, decapNext, vni, isIpv6)); + + getReplyForDelete(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Vxlan tunnel deleted successfully for: {}, vxlan: {}", swIfName, vxlan); + + final int index = interfaceNamingContext.getIndex(swIfName, writeContext.getMappingContext()); + // Mark this interface as disabled to not include it in operational reads + // because VPP will keep the interface there + LOG.debug("Marking vxlan tunnel as disabled, id: {}, name: {}", index, swIfName); + interfaceDisableContext.disableInterface(index, writeContext.getMappingContext()); + // Remove interface from our interface naming context + interfaceNamingContext.removeName(swIfName, writeContext.getMappingContext()); + } + + private static VxlanAddDelTunnel getVxlanTunnelRequest(final byte isAdd, final IpAddressNoZone srcAddr, + final IpAddressNoZone dstAddr, + final int encapVrfId, + final int decapNextIndex, final int vni, final byte isIpv6) { + final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel(); + vxlanAddDelTunnel.isAdd = isAdd; + vxlanAddDelTunnel.srcAddress = AddressTranslator.INSTANCE.ipAddressToArray(srcAddr); + vxlanAddDelTunnel.dstAddress = AddressTranslator.INSTANCE.ipAddressToArray(dstAddr); + vxlanAddDelTunnel.encapVrfId = encapVrfId; + vxlanAddDelTunnel.vni = vni; + vxlanAddDelTunnel.decapNextIndex = decapNextIndex; + vxlanAddDelTunnel.isIpv6 = isIpv6; + return vxlanAddDelTunnel; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanGpeCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanGpeCustomizer.java new file mode 100644 index 000000000..b435fa169 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanGpeCustomizer.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import io.fd.hc2vpp.common.translate.util.AbstractInterfaceTypeCustomizer; +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.v3po.DisabledInterfacesManager; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.VxlanGpeAddDelTunnel; +import io.fd.jvpp.core.dto.VxlanGpeAddDelTunnelReply; +import io.fd.jvpp.core.future.FutureJVppCore; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.VxlanGpeTunnel; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.VxlanGpe; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VxlanGpeCustomizer extends AbstractInterfaceTypeCustomizer implements JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class); + private final NamingContext interfaceNamingContext; + private final DisabledInterfacesManager interfaceDisableContext; + + public VxlanGpeCustomizer(@Nonnull final FutureJVppCore vppApi, + @Nonnull final NamingContext interfaceNamingContext, + @Nonnull final DisabledInterfacesManager interfaceDisableContext) { + super(vppApi); + this.interfaceNamingContext = interfaceNamingContext; + this.interfaceDisableContext = interfaceDisableContext; + } + + @Override + protected Class getExpectedInterfaceType() { + return VxlanGpeTunnel.class; + } + + @Override + protected final void writeInterface(@Nonnull final InstanceIdentifier id, + @Nonnull final VxlanGpe dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + createVxlanGpeTunnel(id, swIfName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VxlanGpe dataBefore, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + deleteVxlanGpeTunnel(id, swIfName, dataBefore, writeContext); + } + + private void createVxlanGpeTunnel(final InstanceIdentifier id, final String swIfName, + final VxlanGpe vxlanGpe, final WriteContext writeContext) + throws WriteFailedException { + final byte isIpv6 = (byte) (isIpv6(vxlanGpe) + ? 1 + : 0); + + 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 VxlanGpeAddDelTunnelReplyCompletionStage = + getFutureJVpp() + .vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 1 /* is add */, vxlanGpe.getLocal(), + vxlanGpe.getRemote(), vni, protocol, encapVrfId, decapVrfId, isIpv6)); + + final VxlanGpeAddDelTunnelReply reply = + getReplyForCreate(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id, vxlanGpe); + LOG.debug("VxlanGpe tunnel set successfully for: {}, VxlanGpe: {}", swIfName, vxlanGpe); + if (interfaceNamingContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) { + final String formerName = interfaceNamingContext.getName(reply.swIfIndex, writeContext.getMappingContext()); + LOG.debug("Removing updated mapping of a vxlan-gpe tunnel, id: {}, former name: {}, new name: {}", + reply.swIfIndex, formerName, swIfName); + interfaceNamingContext.removeName(formerName, writeContext.getMappingContext()); + } + + // Removing disability of an interface in case a vxlan-gpe tunnel formerly deleted is being reused in VPP + // further details in above comment + if (interfaceDisableContext.isInterfaceDisabled(reply.swIfIndex, writeContext.getMappingContext())) { + LOG.debug("Removing disability of vxlan tunnel, id: {}, name: {}", reply.swIfIndex, swIfName); + interfaceDisableContext.removeDisabledInterface(reply.swIfIndex, writeContext.getMappingContext()); + } + + // Add new interface to our interface context + interfaceNamingContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); + } + + private boolean isIpv6(final VxlanGpe vxlanGpe) { + return vxlanGpe.getLocal().getIpv4AddressNoZone() == null; + + } + + private void deleteVxlanGpeTunnel(final InstanceIdentifier id, final String swIfName, + final VxlanGpe vxlanGpe, final WriteContext writeContext) + throws WriteFailedException { + final byte isIpv6 = (byte) (isIpv6(vxlanGpe) + ? 1 + : 0); + + 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 VxlanGpeAddDelTunnelReplyCompletionStage = + getFutureJVpp() + .vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 0 /* is delete */, vxlanGpe.getLocal(), + vxlanGpe.getRemote(), vni, protocol, encapVrfId, decapVrfId, isIpv6)); + getReplyForDelete(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + final int index = interfaceNamingContext.getIndex(swIfName, writeContext.getMappingContext()); + // Mark this interface as disabled to not include it in operational reads + // because VPP will keep the interface there + LOG.debug("Marking vxlan tunnel as disabled, id: {}, name: {}", index, swIfName); + interfaceDisableContext.disableInterface(index, writeContext.getMappingContext()); + // Remove interface from our interface naming context + interfaceNamingContext.removeName(swIfName, writeContext.getMappingContext()); + } + + private static VxlanGpeAddDelTunnel getVxlanGpeTunnelRequest(final byte isAdd, final IpAddressNoZone local, + final IpAddressNoZone 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 = AddressTranslator.INSTANCE.ipAddressToArray(local); + VxlanGpeAddDelTunnel.remote = AddressTranslator.INSTANCE.ipAddressToArray(remote); + VxlanGpeAddDelTunnel.vni = vni; + VxlanGpeAddDelTunnel.protocol = protocol; + VxlanGpeAddDelTunnel.encapVrfId = encapVrfId; + VxlanGpeAddDelTunnel.decapVrfId = decapVrfId; + VxlanGpeAddDelTunnel.isIpv6 = isIpv6; + return VxlanGpeAddDelTunnel; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanGpeValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanGpeValidator.java new file mode 100644 index 000000000..3be51b8df --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanGpeValidator.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.v3po.DisabledInterfacesManager; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.VxlanGpe; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class VxlanGpeValidator implements Validator { + + public VxlanGpeValidator(@Nonnull final NamingContext interfaceNamingContext, + @Nonnull final DisabledInterfacesManager interfaceDisableContext) { + checkNotNull(interfaceNamingContext, "interfaceContext should not be null"); + checkNotNull(interfaceDisableContext, "DisabledInterfacesManager should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final VxlanGpe dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + try { + validateVxlanGpe(dataAfter); + } catch (Exception e) { + throw new DataValidationFailedException.CreateValidationFailedException(id, dataAfter, e); + } + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final VxlanGpe dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + try { + validateVxlanGpe(dataBefore); + } catch (Exception e) { + throw new DataValidationFailedException.DeleteValidationFailedException(id, e); + } + } + + private void validateVxlanGpe(final VxlanGpe data) { + checkNotNull(data.getLocal(), "Local address cannot be null"); + checkNotNull(data.getRemote(), "Remote address cannot be null"); + if (data.getLocal().getIpv4AddressNoZone() == null) { + checkArgument(data.getRemote().getIpv4AddressNoZone() == null, "Inconsistent ip addresses: %s, %s", + data.getLocal(), + data.getRemote()); + } else { + checkArgument(data.getRemote().getIpv6AddressNoZone() == null, "Inconsistent ip addresses: %s, %s", + data.getLocal(), + data.getRemote()); + } + checkNotNull(data.getEncapVrfId(), "encap-vrf-id is mandatory but was not given"); + checkNotNull(data.getDecapVrfId(), "decap-vrf-id is mandatory but was not given"); + checkNotNull(data.getVni(), "VNI cannot be null"); + checkNotNull(data.getNextProtocol(), "Next protocol cannot be null"); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanValidator.java new file mode 100644 index 000000000..5ca34fdd4 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/VxlanValidator.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.v3po.DisabledInterfacesManager; +import io.fd.honeycomb.translate.write.DataValidationFailedException.CreateValidationFailedException; +import io.fd.honeycomb.translate.write.DataValidationFailedException.DeleteValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.interfaces._interface.Vxlan; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class VxlanValidator implements Validator { + + public VxlanValidator(@Nonnull final NamingContext interfaceNamingContext, + @Nonnull final DisabledInterfacesManager disabledInterfacesManager) { + checkNotNull(interfaceNamingContext, "interfaceContext should not be null"); + checkNotNull(disabledInterfacesManager, "disabledInterfacesManager should not be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final Vxlan dataAfter, + @Nonnull final WriteContext writeContext) + throws CreateValidationFailedException { + try { + validateVxlan(dataAfter); + } catch (Exception e) { + throw new CreateValidationFailedException(id, dataAfter, e); + } + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final Vxlan dataBefore, + @Nonnull final WriteContext writeContext) + throws DeleteValidationFailedException { + try { + validateVxlan(dataBefore); + } catch (Exception e) { + throw new DeleteValidationFailedException(id, e); + } + } + + private void validateVxlan(final Vxlan data) { + + checkNotNull(data.getSrc(), "Source cannot be null"); + checkNotNull(data.getDst(), "Destination cannot be null"); + if (data.getSrc().getIpv4AddressNoZone() == null) { + checkArgument(data.getDst().getIpv4AddressNoZone() == null, "Inconsistent ip addresses: %s, %s", + data.getSrc(), + data.getDst()); + } else { + checkArgument(data.getDst().getIpv6AddressNoZone() == null, "Inconsistent ip addresses: %s, %s", + data.getSrc(), + data.getDst()); + } + checkArgument(data.getEncapVrfId() != null && data.getEncapVrfId().getValue() != null, + "encap-vrf-id is mandatory but was not given"); + checkNotNull(data.getVni(), "VNI cannot be null"); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/pbb/PbbRewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/pbb/PbbRewriteCustomizer.java new file mode 100644 index 000000000..42d6b1969 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/pbb/PbbRewriteCustomizer.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.hc2vpp.v3po.write.pbb; + +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.MacTranslator; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.VppBaseCallException; +import io.fd.jvpp.core.dto.L2InterfacePbbTagRewrite; +import io.fd.jvpp.core.future.FutureJVppCore; +import java.util.concurrent.TimeoutException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.pbb.rev161214.interfaces._interface.PbbRewrite; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class PbbRewriteCustomizer extends FutureJVppCustomizer + implements WriterCustomizer, MacTranslator, JvppReplyConsumer { + + private static final int OPERATION_DISABLE = 0; + + private final NamingContext interfaceNamingContext; + + public PbbRewriteCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final NamingContext interfaceNamingContext) { + super(futureJVppCore); + this.interfaceNamingContext = interfaceNamingContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final PbbRewrite dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + try { + setPbbRewrite(id, dataAfter, writeContext, false); + } catch (TimeoutException | VppBaseCallException e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final PbbRewrite dataBefore, @Nonnull final PbbRewrite dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + try { + setPbbRewrite(id, dataAfter, writeContext, false); + } catch (TimeoutException | VppBaseCallException e) { + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final PbbRewrite dataBefore, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + + try { + setPbbRewrite(id, dataBefore, writeContext, true); + } catch (TimeoutException | VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void setPbbRewrite(final InstanceIdentifier id, final PbbRewrite data, + final WriteContext writeContext, final boolean disable) + throws TimeoutException, VppBaseCallException { + final String interfaceName = id.firstKeyOf(Interface.class).getName(); + + final L2InterfacePbbTagRewrite request = new L2InterfacePbbTagRewrite(); + + //checking all attributes in preconditions(pbb-rewrite is subcontainer, so there can't be mandatory statements) + request.swIfIndex = interfaceNamingContext.getIndex(interfaceName, writeContext.getMappingContext()); + request.bDmac = parseMac(data.getDestinationAddress().getValue()); + request.bSmac = parseMac(data.getSourceAddress().getValue()); + request.bVlanid = data.getBVlanTagVlanId().shortValue(); + request.iSid = data.getITagIsid().intValue(); + request.vtrOp = verifiedOperation(data, disable); + + //not sure whats gonna happen to this attribute, so its left optional for now + if (data.getOuterTag() != null) { + request.outerTag = data.getOuterTag().shortValue(); + } + + getReply(getFutureJVpp().l2InterfacePbbTagRewrite(request).toCompletableFuture()); + } + + // if disabled ,then uses non-public allowed value 0, which is equal to operation disable + private int verifiedOperation(final PbbRewrite data, final boolean disable) { + return disable + ? OPERATION_DISABLE + : data.getInterfaceOperation().getIntValue(); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/pbb/PbbRewriteValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/pbb/PbbRewriteValidator.java new file mode 100644 index 000000000..90ea236a0 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/pbb/PbbRewriteValidator.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write.pbb; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.pbb.rev161214.interfaces._interface.PbbRewrite; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class PbbRewriteValidator implements Validator { + + + public PbbRewriteValidator(@Nonnull final NamingContext interfaceNamingContext) { + checkNotNull(interfaceNamingContext, "Interface naming context cannot be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, @Nonnull final PbbRewrite dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + try { + validatePbbRewrite(id, dataAfter, false); + } catch(Exception e) { + throw new DataValidationFailedException.CreateValidationFailedException(id, dataAfter, e); + } + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, @Nonnull final PbbRewrite dataBefore, + @Nonnull final PbbRewrite dataAfter, @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + + try { + validatePbbRewrite(id, dataAfter, false); + } catch(Exception e) { + throw new DataValidationFailedException.UpdateValidationFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, @Nonnull final PbbRewrite dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + try { + validatePbbRewrite(id, dataBefore, true); + } catch(Exception e) { + throw new DataValidationFailedException.DeleteValidationFailedException(id, e); + } + } + + private void validatePbbRewrite(final InstanceIdentifier id, @Nonnull final PbbRewrite data, + final boolean disable) { + checkNotNull(id.firstKeyOf(Interface.class), "Interface key not found"); + checkNotNull(data.getDestinationAddress(), "Destination address cannot be null"); + checkNotNull(data.getSourceAddress(), "Source address cannot be null"); + checkNotNull(data.getBVlanTagVlanId(), "BVlan id cannot be null"); + checkNotNull(data.getITagIsid(), "ISid cannot be null"); + if (disable) { + checkNotNull(data.getInterfaceOperation(), "Operation cannot be null"); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/span/MirroredInterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/span/MirroredInterfaceCustomizer.java new file mode 100644 index 000000000..31b129537 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/span/MirroredInterfaceCustomizer.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write.span; + +import static io.fd.honeycomb.translate.util.RWUtils.cutId; + +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.jvpp.core.dto.SwInterfaceSpanEnableDisable; +import io.fd.jvpp.core.future.FutureJVppCore; +import java.util.function.Function; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.SpanState; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.span.attributes.MirroredInterfaces; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.span.attributes.mirrored.interfaces.MirroredInterface; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.span.attributes.mirrored.interfaces.MirroredInterfaceKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class MirroredInterfaceCustomizer extends FutureJVppCustomizer + implements ListWriterCustomizer, JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(MirroredInterfaceCustomizer.class); + + private final NamingContext ifcContext; + private final Function, String> destinationInterfaceNameExtractor; + + public MirroredInterfaceCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final NamingContext ifcContext, + @Nonnull final Function, String> destinationInterfaceNameExtractor) { + super(futureJVppCore); + this.ifcContext = ifcContext; + this.destinationInterfaceNameExtractor = destinationInterfaceNameExtractor; + } + + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final MirroredInterface mirroredInterface, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String destinationInterfaceName = + destinationInterfaceNameExtractor.apply(cutId(id, MirroredInterfaces.class)); + final String sourceInterfaceName = mirroredInterface.getIfaceRef(); + final SpanState spanState = mirroredInterface.getState(); + + LOG.debug("Enabling span for source interface {} | destination interface {} | state {}", sourceInterfaceName, + destinationInterfaceName, spanState); + + getReplyForWrite(getFutureJVpp().swInterfaceSpanEnableDisable( + getSpanAddDelRequest( + interfaceId(writeContext, ifcContext, destinationInterfaceName), + interfaceId(writeContext, ifcContext, sourceInterfaceName), + true, + spanState)) + .toCompletableFuture(), id); + LOG.debug("Span for source interface {} | destination interface {} | state {} successfully enabled", + sourceInterfaceName, destinationInterfaceName, spanState); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final MirroredInterface mirroredInterface, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + final String destinationInterfaceName = + destinationInterfaceNameExtractor.apply(cutId(id, MirroredInterfaces.class)); + final String sourceInterfaceName = mirroredInterface.getIfaceRef(); + LOG.debug("Disabling span for source interface {} | destination interface {} ", sourceInterfaceName, + destinationInterfaceName); + + getReplyForWrite(getFutureJVpp().swInterfaceSpanEnableDisable( + getSpanAddDelRequest( + interfaceId(writeContext, ifcContext, destinationInterfaceName), + interfaceId(writeContext, ifcContext, sourceInterfaceName), + false, + null)) + .toCompletableFuture(), id); + LOG.debug("Span for source interface {} | destination interface {} successfully disabled", + sourceInterfaceName, destinationInterfaceName); + } + + private SwInterfaceSpanEnableDisable getSpanAddDelRequest(final int dstId, final Integer srcId, final boolean isAdd, + @Nullable final SpanState state) { + final SwInterfaceSpanEnableDisable spanAddDel = new SwInterfaceSpanEnableDisable(); + spanAddDel.state = (byte) (isAdd + ? state != null + ? state.getIntValue() + : 0 + : 0);// either one of 1(rx),2(tx),3(both) or 0 for disable/delete + spanAddDel.swIfIndexFrom = srcId; + spanAddDel.swIfIndexTo = dstId; + return spanAddDel; + } + + private static int interfaceId(final WriteContext writeContext, final NamingContext ifcContext, final String name) { + return ifcContext.getIndex(name, writeContext.getMappingContext()); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/span/MirroredInterfaceValidator.java b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/span/MirroredInterfaceValidator.java new file mode 100644 index 000000000..90c740be8 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/hc2vpp/v3po/write/span/MirroredInterfaceValidator.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.v3po.write.span; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.DataValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import java.util.function.Function; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.span.attributes.MirroredInterfaces; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.v3po.rev190502.span.attributes.mirrored.interfaces.MirroredInterface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class MirroredInterfaceValidator implements Validator { + + public MirroredInterfaceValidator(@Nonnull final NamingContext ifcContext, + @Nonnull final Function, String> destinationInterfaceNameExtractor) { + checkNotNull(ifcContext, "Interface naming context cannot be null"); + checkNotNull(destinationInterfaceNameExtractor, "Destination Interface Name extractor cannot be null"); + } + + @Override + public void validateWrite(@Nonnull final InstanceIdentifier id, + @Nonnull final MirroredInterface dataAfter, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.CreateValidationFailedException { + try { + checkMirroredInterfaceData(dataAfter); + } catch (Exception e) { + throw new DataValidationFailedException.CreateValidationFailedException(id, dataAfter, e); + } + } + + @Override + public void validateUpdate(@Nonnull final InstanceIdentifier id, + @Nonnull final MirroredInterface dataBefore, + @Nonnull final MirroredInterface dataAfter, @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.UpdateValidationFailedException { + try { + checkMirroredInterfaceData(dataAfter); + } catch (Exception e) { + throw new DataValidationFailedException.UpdateValidationFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void validateDelete(@Nonnull final InstanceIdentifier id, + @Nonnull final MirroredInterface dataBefore, + @Nonnull final WriteContext writeContext) + throws DataValidationFailedException.DeleteValidationFailedException { + try { + checkMirroredInterfaceData(dataBefore); + } catch (Exception e) { + throw new DataValidationFailedException.DeleteValidationFailedException(id, e); + } + } + + private void checkMirroredInterfaceData(final MirroredInterface data) { + checkNotNull(data.getIfaceRef(), "IfaceRef cannot be null"); + checkNotNull(data.getState(), "State cannot be null"); + } +} -- cgit 1.2.3-korg