summaryrefslogtreecommitdiffstats
path: root/mpls/impl/src/main/java
diff options
context:
space:
mode:
authorMarek Gradzki <mgradzki@cisco.com>2017-11-22 17:56:52 +0100
committerMarek Gradzki <mgradzki@cisco.com>2017-11-23 12:17:34 +0000
commit82d2da4853410c0e7c00f383c01760cc7f26f75e (patch)
tree2a5fdac137267d8a657eb6325a46909b8c78a731 /mpls/impl/src/main/java
parent1715b92455356a52e01ff5c4f2a42fe5336b9088 (diff)
HC2VPP-259: add support for mpls swap-and-forward
Limitations: - only IPv4 next hop address - swap is supported only for the last label in the stack - only single outgoing label is supported. Change-Id: I9479e3d322561ed94683bd206e7e7852250d788c Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
Diffstat (limited to 'mpls/impl/src/main/java')
-rw-r--r--mpls/impl/src/main/java/io/fd/hc2vpp/mpls/ImposeAndForwardWriter.java100
-rw-r--r--mpls/impl/src/main/java/io/fd/hc2vpp/mpls/Ipv4LookupWriter.java29
-rw-r--r--mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsInSegmentTranslator.java38
-rw-r--r--mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsLookupWriter.java29
-rw-r--r--mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsSwapWriter.java93
-rw-r--r--mpls/impl/src/main/java/io/fd/hc2vpp/mpls/StaticLspCustomizer.java5
6 files changed, 211 insertions, 83 deletions
diff --git a/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/ImposeAndForwardWriter.java b/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/ImposeAndForwardWriter.java
index b7ac96735..14053b63d 100644
--- a/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/ImposeAndForwardWriter.java
+++ b/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/ImposeAndForwardWriter.java
@@ -27,11 +27,13 @@ import io.fd.vpp.jvpp.core.future.FutureJVppCore;
import java.util.List;
import javax.annotation.Nonnull;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310.StaticLspConfig.Operation;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp.Config;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.InSegment;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.OutSegment;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.in.segment.Type;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.in.segment.type.IpPrefix;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.out.segment.PathList;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.out.segment.SimplePath;
@@ -60,64 +62,80 @@ final class ImposeAndForwardWriter implements LspWriter, Ipv4Translator {
final Config config = data.getConfig();
final IpAddDelRoute request = new IpAddDelRoute();
request.isAdd = booleanToByte(isAdd);
- request.nextHopWeight = 1; // default value used in make test
- final InSegment inSegment = config.getInSegment();
- checkArgument(inSegment != null, "Configuring impose-and-forward, but in-segment is missing.");
+ translate(config.getInSegment(), request);
+ translate(config.getOutSegment(), request, ctx);
+
+ // default values based on inspecting VPP's CLI and make test code
+ request.nextHopWeight = 1;
+ request.nextHopViaLabel = MPLS_LABEL_INVALID;
+
+ getReplyForWrite(vppApi.ipAddDelRoute(request).toCompletableFuture(), id);
+ }
- checkArgument(inSegment.getType() instanceof IpPrefix, "Only ip-prefix type is supported, but %s given.",
- inSegment.getType());
- final Ipv4Prefix prefix = ((IpPrefix) inSegment.getType()).getIpPrefix().getIpv4Prefix();
+ private void translate(@Nonnull final InSegment inSegment, @Nonnull final IpAddDelRoute request) {
+ checkArgument(inSegment != null, "Configuring impose-and-forward, but in-segment is missing.");
+ final Type type = inSegment.getType();
+ checkArgument(type instanceof IpPrefix, "Only ip-prefix type is supported, but %s given.", type);
// TODO(HC2VPP-264): add support for mpls + v6
+ final Ipv4Prefix prefix = ((IpPrefix) type).getIpPrefix().getIpv4Prefix();
request.dstAddressLength = extractPrefix(prefix);
request.dstAddress = ipv4AddressPrefixToArray(prefix);
+ }
- final OutSegment outSegment = config.getOutSegment();
+ private void translate(@Nonnull final OutSegment outSegment, @Nonnull final IpAddDelRoute request,
+ @Nonnull final MappingContext ctx) {
checkArgument(outSegment != null, "Configuring impose-and-forward, but out-segment is missing.");
- translateOutSegment(outSegment, request, ctx);
- getReplyForWrite(vppApi.ipAddDelRoute(request).toCompletableFuture(), id);
- }
- private void translateOutSegment(@Nonnull final OutSegment outSegment, @Nonnull final IpAddDelRoute request,
- @Nonnull final MappingContext ctx) {
final String outgoingInterface;
if (outSegment instanceof SimplePath) {
- final SimplePath path = (SimplePath) outSegment;
- outgoingInterface = path.getOutgoingInterface();
- final IpAddress nextHop = path.getNextHop();
- checkArgument(nextHop != null, "Configuring impose-and-forward, but next-hop is missing.");
- // TODO(HC2VPP-264): add support for mpls + v6
- checkArgument(nextHop.getIpv4Address() != null, "Only IPv4 next-hop address is supported.");
- request.nextHopAddress = ipv4AddressNoZoneToArray(nextHop.getIpv4Address().getValue());
- request.nextHopNOutLabels = 1;
- checkArgument(path.getOutgoingLabel() != null,
- "Configuring impose-and-forward, but outgoing-label is missing.");
- request.nextHopOutLabelStack = new int[] {path.getOutgoingLabel().getValue().intValue()};
+ outgoingInterface = translate((SimplePath) outSegment, request);
} else if (outSegment instanceof PathList) {
- final PathList pathList = (PathList) outSegment;
- checkArgument(pathList.getPaths() != null && pathList.getPaths().size() == 1,
- "Only single path is supported");
- final Paths paths = pathList.getPaths().get(0);
- outgoingInterface = paths.getOutgoingInterface();
- // TODO(HC2VPP-264): add support for mpls + v6
- final IpAddress nextHop = paths.getNextHop();
- checkArgument(nextHop != null, "Configuring impose-and-forward, but next-hop is missing.");
- checkArgument(nextHop.getIpv4Address() != null, "Only IPv4 next-hop address is supported.");
- request.nextHopAddress = ipv4AddressNoZoneToArray(nextHop.getIpv4Address().getValue());
- final List<MplsLabel> outgoingLabels = paths.getOutgoingLabels();
- final int numberOfLabels = outgoingLabels.size();
- checkArgument(numberOfLabels > 0 && numberOfLabels < MAX_LABELS,
- "Number of labels (%s) not in range (0, %s].", numberOfLabels, MAX_LABELS, numberOfLabels);
- request.nextHopNOutLabels = (byte) numberOfLabels;
- request.nextHopOutLabelStack =
- outgoingLabels.stream().mapToInt(label -> label.getValue().intValue()).toArray();
+ outgoingInterface = translate((PathList) outSegment, request);
} else {
throw new IllegalArgumentException("Unsupported out-segment type: " + outSegment);
}
checkArgument(outgoingInterface != null, "Configuring impose-and-forward, but outgoing-interface is missing.");
request.nextHopSwIfIndex = interfaceContext.getIndex(outgoingInterface, ctx);
- request.nextHopViaLabel = MPLS_LABEL_INVALID;
+ }
+
+ private String translate(@Nonnull final SimplePath path, @Nonnull final IpAddDelRoute request) {
+ final IpAddress nextHop = path.getNextHop();
+ checkArgument(nextHop != null, "Configuring impose-and-forward, but next-hop is missing.");
+
+ // TODO(HC2VPP-264): add support for mpls + v6
+ final Ipv4Address address = nextHop.getIpv4Address();
+ checkArgument(address != null, "Only IPv4 next-hop address is supported.");
+ request.nextHopAddress = ipv4AddressNoZoneToArray(address.getValue());
+
+ final MplsLabel outgoingLabel = path.getOutgoingLabel();
+ checkArgument(outgoingLabel != null, "Configuring impose-and-forward, but outgoing-label is missing.");
+ request.nextHopOutLabelStack = new int[] {outgoingLabel.getValue().intValue()};
+ request.nextHopNOutLabels = 1;
+
+ return path.getOutgoingInterface();
+ }
+
+ private String translate(@Nonnull final PathList pathList, @Nonnull final IpAddDelRoute request) {
+ checkArgument(pathList.getPaths() != null && pathList.getPaths().size() == 1, "Only single path is supported");
+ final Paths paths = pathList.getPaths().get(0);
+ final IpAddress nextHop = paths.getNextHop();
+ checkArgument(nextHop != null, "Configuring impose-and-forward, but next-hop is missing.");
+
+ // TODO(HC2VPP-264): add support for mpls + v6
+ final Ipv4Address address = nextHop.getIpv4Address();
+ checkArgument(address != null, "Only IPv4 next-hop address is supported.");
+ request.nextHopAddress = ipv4AddressNoZoneToArray(address.getValue());
+
+ final List<MplsLabel> labels = paths.getOutgoingLabels();
+ final int numberOfLabels = labels.size();
+ checkArgument(numberOfLabels > 0 && numberOfLabels < MAX_LABELS, "Number of labels (%s) not in range (0, %s].",
+ numberOfLabels, MAX_LABELS, numberOfLabels);
+ request.nextHopNOutLabels = (byte) numberOfLabels;
+ request.nextHopOutLabelStack = labels.stream().mapToInt(label -> label.getValue().intValue()).toArray();
+
+ return paths.getOutgoingInterface();
}
}
diff --git a/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/Ipv4LookupWriter.java b/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/Ipv4LookupWriter.java
index 7ac164a96..94862c52b 100644
--- a/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/Ipv4LookupWriter.java
+++ b/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/Ipv4LookupWriter.java
@@ -25,8 +25,6 @@ import io.fd.vpp.jvpp.core.future.FutureJVppCore;
import javax.annotation.Nonnull;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310.StaticLspConfig;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp.Config;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.InSegment;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.in.segment.type.MplsLabel;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310.routing.mpls._static.lsps.StaticLsp;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.mpls.rev171120.LookupType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.mpls.rev171120.StaticLspVppLookupAugmentation;
@@ -38,7 +36,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
*
* @see <a href="https://git.fd.io/vpp/tree/src/vnet/mpls/mpls.api">mpls_route_add_del</a> definition
*/
-final class Ipv4LookupWriter implements LspWriter {
+final class Ipv4LookupWriter implements LspWriter, MplsInSegmentTranslator {
private static final byte IPV4_PROTOCOL = (byte) LookupType.Ipv4.getIntValue();
private final FutureJVppCore vppApi;
@@ -55,8 +53,8 @@ final class Ipv4LookupWriter implements LspWriter {
request.mrIsAdd = booleanToByte(isAdd);
- translate(request, config);
- translate(request, config.getAugmentation(StaticLspVppLookupAugmentation.class));
+ translate(config.getInSegment(), request);
+ translate(config.getAugmentation(StaticLspVppLookupAugmentation.class), request);
// default values based on inspecting VPP's CLI and make test code
request.mrClassifyTableIndex = -1;
@@ -70,23 +68,12 @@ final class Ipv4LookupWriter implements LspWriter {
getReplyForWrite(vppApi.mplsRouteAddDel(request).toCompletableFuture(), id);
}
- private void translate(@Nonnull final MplsRouteAddDel request, @Nonnull final Config config) {
- final InSegment inSegment = config.getInSegment();
- checkArgument(inSegment != null, "Configuring ipv4 pop-and-lookup, but in-segment is missing.");
-
- checkArgument(inSegment.getType() instanceof MplsLabel, "Expecting mpls-label in-segment type, but %s given.",
- inSegment.getType());
- final Long label = ((MplsLabel) inSegment.getType()).getIncomingLabel().getValue();
- request.mrLabel = label.intValue();
- }
-
- private void translate(@Nonnull final MplsRouteAddDel request,
- @Nonnull final StaticLspVppLookupAugmentation vppLabelLookup) {
+ private void translate(@Nonnull final StaticLspVppLookupAugmentation vppLabelLookup,
+ @Nonnull final MplsRouteAddDel request) {
// IPv4 lookup should only happen if there is no more labels to process, so setting the EOS bit:
request.mrEos = 1;
- final Long lookupInTable = vppLabelLookup.getLabelLookup().getIp4LookupInTable();
- checkArgument(lookupInTable != null,
- "Configuring pop and ipv4 lookup, but ipv4 lookup table was not given");
- request.mrNextHopTableId = lookupInTable.intValue();
+ final Long lookupTable = vppLabelLookup.getLabelLookup().getIp4LookupInTable();
+ checkArgument(lookupTable != null, "Configuring pop and ipv4 lookup, but ipv4 lookup table was not given");
+ request.mrNextHopTableId = lookupTable.intValue();
}
}
diff --git a/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsInSegmentTranslator.java b/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsInSegmentTranslator.java
new file mode 100644
index 000000000..9f531bba4
--- /dev/null
+++ b/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsInSegmentTranslator.java
@@ -0,0 +1,38 @@
+/*
+ * 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.mpls;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.vpp.jvpp.core.dto.MplsRouteAddDel;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.InSegment;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.in.segment.Type;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.in.segment.type.MplsLabel;
+
+/**
+ * Mixin that translates {@link InSegment} of {@link MplsLabel} type to {@link MplsRouteAddDel} message.
+ */
+interface MplsInSegmentTranslator {
+ default void translate(@Nonnull final InSegment inSegment, @Nonnull final MplsRouteAddDel request) {
+ checkArgument(inSegment != null, "Missing in-segment");
+ final Type type = inSegment.getType();
+ checkArgument(type instanceof MplsLabel, "Expecting in-segment of type mpls-label, but %s given.", type);
+ final Long label = ((MplsLabel) type).getIncomingLabel().getValue();
+ request.mrLabel = label.intValue();
+ }
+}
diff --git a/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsLookupWriter.java b/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsLookupWriter.java
index c845c7aeb..d5d4872dc 100644
--- a/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsLookupWriter.java
+++ b/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsLookupWriter.java
@@ -25,8 +25,6 @@ import io.fd.vpp.jvpp.core.future.FutureJVppCore;
import javax.annotation.Nonnull;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310.StaticLspConfig;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp.Config;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.InSegment;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.in.segment.type.MplsLabel;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310.routing.mpls._static.lsps.StaticLsp;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.mpls.rev171120.LookupType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.mpls.rev171120.StaticLspVppLookupAugmentation;
@@ -38,7 +36,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
*
* @see <a href="https://git.fd.io/vpp/tree/src/vnet/mpls/mpls.api">mpls_route_add_del</a> definition
*/
-final class MplsLookupWriter implements LspWriter {
+final class MplsLookupWriter implements LspWriter, MplsInSegmentTranslator {
private static final byte MPLS_PROTOCOL = (byte) LookupType.Mpls.getIntValue();
private final FutureJVppCore vppApi;
@@ -55,8 +53,8 @@ final class MplsLookupWriter implements LspWriter {
request.mrIsAdd = booleanToByte(isAdd);
- translate(request, config);
- translate(request, config.getAugmentation(StaticLspVppLookupAugmentation.class));
+ translate(config.getInSegment(), request);
+ translate(config.getAugmentation(StaticLspVppLookupAugmentation.class), request);
// default values based on inspecting VPP's CLI and make test code
request.mrClassifyTableIndex = -1;
@@ -70,24 +68,13 @@ final class MplsLookupWriter implements LspWriter {
getReplyForWrite(vppApi.mplsRouteAddDel(request).toCompletableFuture(), id);
}
- private void translate(@Nonnull final MplsRouteAddDel request, @Nonnull final Config config) {
- final InSegment inSegment = config.getInSegment();
- checkArgument(inSegment != null, "Configuring mpls pop-and-lookup, but in-segment is missing.");
-
- checkArgument(inSegment.getType() instanceof MplsLabel, "Expecting mpls-label in-segment type, but %s given.",
- inSegment.getType());
- final Long label = ((MplsLabel) inSegment.getType()).getIncomingLabel().getValue();
- request.mrLabel = label.intValue();
- }
-
- private void translate(@Nonnull final MplsRouteAddDel request,
- @Nonnull final StaticLspVppLookupAugmentation vppLabelLookup) {
+ private void translate(@Nonnull final StaticLspVppLookupAugmentation vppLabelLookup,
+ @Nonnull final MplsRouteAddDel request) {
// MPLS lookup for the last label is not valid operation (there is no next label to lookup),
// so match only labels without EOS bit set:
request.mrEos = 0;
- final Long mplsLookupInTable = vppLabelLookup.getLabelLookup().getMplsLookupInTable();
- checkArgument(mplsLookupInTable != null,
- "Configuring pop and mpls lookup, but MPLS lookup table was not given");
- request.mrNextHopTableId = mplsLookupInTable.intValue();
+ final Long lookupTable = vppLabelLookup.getLabelLookup().getMplsLookupInTable();
+ checkArgument(lookupTable != null, "Configuring pop and mpls lookup, but MPLS lookup table was not given");
+ request.mrNextHopTableId = lookupTable.intValue();
}
}
diff --git a/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsSwapWriter.java b/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsSwapWriter.java
new file mode 100644
index 000000000..8d834fe7c
--- /dev/null
+++ b/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/MplsSwapWriter.java
@@ -0,0 +1,93 @@
+/*
+ * 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.mpls;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.hc2vpp.common.translate.util.Ipv4Translator;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.MplsRouteAddDel;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310.StaticLspConfig;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp.Config;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.OutSegment;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310._static.lsp_config.out.segment.SimplePath;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310.routing.mpls._static.lsps.StaticLsp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.types.rev170227.MplsLabel;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Translates {@link StaticLspConfig.Operation#SwapAndForward} operation to mpls_route_add_del API.
+ *
+ * @see <a href="https://git.fd.io/vpp/tree/src/vnet/mpls/mpls.api">mpls_route_add_del</a> definition
+ */
+final class MplsSwapWriter implements LspWriter, Ipv4Translator, MplsInSegmentTranslator {
+
+ private final FutureJVppCore vppApi;
+ private final NamingContext interfaceContext;
+
+ MplsSwapWriter(@Nonnull final FutureJVppCore vppApi, @Nonnull final NamingContext interfaceContext) {
+ this.vppApi = vppApi;
+ this.interfaceContext = interfaceContext;
+ }
+
+ @Override
+ public void write(@Nonnull final InstanceIdentifier<StaticLsp> id, @Nonnull final StaticLsp data,
+ @Nonnull final MappingContext ctx, final boolean isAdd) throws WriteFailedException {
+ final Config config = data.getConfig();
+ final MplsRouteAddDel request = new MplsRouteAddDel();
+ request.mrIsAdd = booleanToByte(isAdd);
+ request.mrEos = 1; // only SWAP for the last label in the stack is currently supported
+
+ translate(config.getInSegment(), request);
+ translate(config.getOutSegment(), request, ctx);
+
+ // default values based on inspecting VPP's CLI and make test code
+ request.mrClassifyTableIndex = -1;
+ request.mrNextHopWeight = 1;
+ request.mrNextHopViaLabel = MPLS_LABEL_INVALID;
+
+ getReplyForWrite(vppApi.mplsRouteAddDel(request).toCompletableFuture(), id);
+ }
+
+ private void translate(@Nonnull final OutSegment outSegment, @Nonnull final MplsRouteAddDel request,
+ @Nonnull final MappingContext ctx) {
+ checkArgument(outSegment instanceof SimplePath, "Unsupported out-segment type: %s", outSegment);
+ final SimplePath path = (SimplePath) outSegment;
+ final IpAddress nextHop = path.getNextHop();
+ checkArgument(nextHop != null, "Configuring swap-and-forward, but next-hop is missing.");
+
+ // TODO(HC2VPP-264): add support for mpls + v6
+ final Ipv4Address address = nextHop.getIpv4Address();
+ checkArgument(address != null, "Only IPv4 next-hop address is supported.");
+ request.mrNextHop = ipv4AddressNoZoneToArray(address.getValue());
+
+ final MplsLabel outgoingLabel = path.getOutgoingLabel();
+ checkArgument(outgoingLabel != null, "Configuring swap-and-forward, but outgoing-label is missing.");
+ request.mrNextHopOutLabelStack = new int[] {outgoingLabel.getValue().intValue()};
+ request.mrNextHopNOutLabels = 1;
+
+ final String outgoingInterface = path.getOutgoingInterface();
+ checkArgument(outgoingInterface != null, "Configuring swap-and-forward, but outgoing-interface is missing.");
+ request.mrNextHopSwIfIndex = interfaceContext.getIndex(outgoingInterface, ctx);
+ }
+}
diff --git a/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/StaticLspCustomizer.java b/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/StaticLspCustomizer.java
index 54653b9c1..d93e0343c 100644
--- a/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/StaticLspCustomizer.java
+++ b/mpls/impl/src/main/java/io/fd/hc2vpp/mpls/StaticLspCustomizer.java
@@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310.StaticLspConfig.Operation.ImposeAndForward;
import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310.StaticLspConfig.Operation.PopAndLookup;
+import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.mpls._static.rev170310.StaticLspConfig.Operation.SwapAndForward;
import io.fd.hc2vpp.common.translate.util.NamingContext;
import io.fd.honeycomb.translate.MappingContext;
@@ -47,6 +48,7 @@ final class StaticLspCustomizer implements ListWriterCustomizer<StaticLsp, Stati
private final ImposeAndForwardWriter imposeAndForward;
private final MplsLookupWriter mplsLookup;
private final Ipv4LookupWriter ipv4Lookup;
+ private final MplsSwapWriter mplsSwap;
StaticLspCustomizer(@Nonnull final FutureJVppCore vppApi, @Nonnull NamingContext interfaceContext) {
checkNotNull(vppApi, "vppApi should not be null");
@@ -54,6 +56,7 @@ final class StaticLspCustomizer implements ListWriterCustomizer<StaticLsp, Stati
this.imposeAndForward = new ImposeAndForwardWriter(vppApi, interfaceContext);
this.mplsLookup = new MplsLookupWriter(vppApi);
this.ipv4Lookup = new Ipv4LookupWriter(vppApi);
+ this.mplsSwap = new MplsSwapWriter(vppApi, interfaceContext);
}
@Override
@@ -94,6 +97,8 @@ final class StaticLspCustomizer implements ListWriterCustomizer<StaticLsp, Stati
} else {
throw new IllegalArgumentException("Unsupported lookup type: " + type);
}
+ } else if (SwapAndForward.equals(operation)) {
+ mplsSwap.write(id, data, ctx, isAdd);
} else {
throw new IllegalArgumentException("Unsupported operation: " + operation);
}