diff options
Diffstat (limited to 'routing/routing-impl/src')
72 files changed, 6773 insertions, 0 deletions
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/RoutingConfiguration.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/RoutingConfiguration.java new file mode 100644 index 000000000..c8f0ba634 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/RoutingConfiguration.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing; + +import net.jmob.guice.conf.core.BindConfig; +import net.jmob.guice.conf.core.InjectConfig; +import net.jmob.guice.conf.core.Syntax; + +@BindConfig(value = "routing", syntax = Syntax.JSON) +public class RoutingConfiguration { + + /** + * Route ids start from + */ + public static final int MULTI_MAPPING_START_INDEX = 1; + + /** + * Contains routing protocol to table id mapping + */ + public static final String ROUTING_PROTOCOL_CONTEXT = "routing-protocol-context"; + + /** + * Used to map routes to routing-protocols + */ + public static final String ROUTE_CONTEXT = "route-context"; + + /** + * Used to map hop ids to routes + */ + public static final String ROUTE_HOP_CONTEXT = "route-hop-context"; + + + @InjectConfig("default-routing-instance-name") + private String defaultRoutingInstanceName; + + @InjectConfig("learned-route-name-prefix") + private String learnedRouteNamePrefix; + + public String getDefaultRoutingInstanceName() { + return defaultRoutingInstanceName; + } + + public String getLearnedRouteNamePrefix() { + return learnedRouteNamePrefix; + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/RoutingModule.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/RoutingModule.java new file mode 100644 index 000000000..a6fadf78c --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/RoutingModule.java @@ -0,0 +1,71 @@ +/* + * 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.routing; + +import com.google.inject.AbstractModule; +import com.google.inject.multibindings.Multibinder; +import com.google.inject.name.Names; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.read.RoutingStateReaderFactory; +import io.fd.hc2vpp.routing.write.RoutingWriterFactory; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.write.WriterFactory; +import net.jmob.guice.conf.core.ConfigurationModule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * RoutingModule class instantiating routing plugin components. + */ +public final class RoutingModule extends AbstractModule { + + private static final Logger LOG = LoggerFactory.getLogger(RoutingModule.class); + + @Override + protected void configure() { + LOG.info("Starting initialization"); + // requests injection of properties + install(ConfigurationModule.create()); + requestInjection(RoutingConfiguration.class); + + bind(NamingContext.class) + .annotatedWith(Names.named(RoutingConfiguration.ROUTING_PROTOCOL_CONTEXT)) + .toInstance(new NamingContext("learned-protocol-", RoutingConfiguration.ROUTING_PROTOCOL_CONTEXT)); + + bind(NamingContext.class) + .annotatedWith(Names.named(RoutingConfiguration.ROUTE_CONTEXT)) + .toInstance(new NamingContext("route-", RoutingConfiguration.ROUTE_CONTEXT)); + + bind(MultiNamingContext.class) + .annotatedWith(Names.named(RoutingConfiguration.ROUTE_HOP_CONTEXT)) + .toInstance(new MultiNamingContext(RoutingConfiguration.ROUTE_HOP_CONTEXT, + RoutingConfiguration.MULTI_MAPPING_START_INDEX)); + + LOG.info("Injecting reader factories"); + // creates reader factory binding + final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class); + readerFactoryBinder.addBinding().to(RoutingStateReaderFactory.class); + + LOG.info("Injecting writers factories"); + // create writer factory binding + final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class); + writerFactoryBinder.addBinding().to(RoutingWriterFactory.class); + + LOG.info("Started successfully"); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/naming/Ipv4RouteNamesFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/naming/Ipv4RouteNamesFactory.java new file mode 100644 index 000000000..5d3d76ff6 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/naming/Ipv4RouteNamesFactory.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.naming; + + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.trait.RouteMapper; +import io.fd.hc2vpp.routing.write.trait.RouteRequestProducer; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.dto.IpFibDetails; +import io.fd.vpp.jvpp.core.types.FibPath; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop; + + +public final class Ipv4RouteNamesFactory implements RouteMapper, RouteRequestProducer { + + private static final String DOT = "."; + private static final String EMPTY = ""; + + private final NamingContext interfaceContext; + private final NamingContext routingProtocolContext; + + public Ipv4RouteNamesFactory(@Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext routingProtocolContext) { + this.interfaceContext = interfaceContext; + this.routingProtocolContext = routingProtocolContext; + } + + /** + * Construct unique name from provided {@code Route} + */ + public String uniqueRouteName(@Nonnull final String parentProtocolName, @Nonnull final Route route) { + return bindName(parentProtocolName, dotlessAddress(route.getDestinationPrefix()), + String.valueOf(extractPrefix(route.getDestinationPrefix()))); + } + + /** + * Construct unique name from provided {@code IpFibDetails} + */ + public String uniqueRouteName(@Nonnull final IpFibDetails details, @Nonnull final MappingContext mappingContext) { + return bindName(routingProtocolContext.getName(details.tableId, mappingContext), + dotlessAddress(details.address), + String.valueOf(details.addressLength)); + } + + + public String uniqueRouteHopName(@Nonnull final NextHop hop) { + return bindName(hop.getOutgoingInterface(), + dotlessAddress(hop.getAddress()), + String.valueOf(hop.getWeight())); + } + + + public String uniqueRouteHopName(@Nonnull final FibPath path, + @Nonnull final MappingContext mappingContext) { + return bindName(interfaceContext.getName(path.swIfIndex, mappingContext), + dotlessAddress(path.nextHop), String.valueOf(path.weight)); + } + + private String dotlessAddress(final byte[] address) { + // trimming in case of ipv4 address beeing sent as 16 byte array + byte[] trimmed = address; + if (trimmed.length > 4) { + trimmed = Arrays.copyOfRange(trimmed, 0, 4); + } + + //no reverting, just takes address as it is and converts it + try { + return dotless(InetAddress.getByAddress(trimmed).getHostAddress()); + } catch (UnknownHostException e) { + throw new IllegalArgumentException(e); + } + } + + private String dotlessAddress(@Nonnull final Ipv4Prefix address) { + final String addressValue = address.getValue(); + return dotless(addressValue.substring(0, addressValue.indexOf("/"))); + } + + private String dotlessAddress(@Nonnull final Ipv4Address address) { + return dotless(address.getValue()); + } + + private String dotless(@Nonnull final String input) { + return input.replace(DOT, EMPTY); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/naming/Ipv6RouteNamesFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/naming/Ipv6RouteNamesFactory.java new file mode 100644 index 000000000..8408c82b6 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/naming/Ipv6RouteNamesFactory.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.naming; + +import com.google.common.net.InetAddresses; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.trait.RouteMapper; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.dto.Ip6FibDetails; +import io.fd.vpp.jvpp.core.types.FibPath; +import java.net.InetAddress; +import java.net.UnknownHostException; +import javax.annotation.Nonnull; +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; + + +public final class Ipv6RouteNamesFactory implements RouteMapper { + + private static final String DOUBLE_DOT = ":"; + private static final String EMPTY = ""; + + private final NamingContext interfaceContext; + private final NamingContext routingProtocolContext; + + public Ipv6RouteNamesFactory(@Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext routingProtocolContext) { + this.interfaceContext = interfaceContext; + this.routingProtocolContext = routingProtocolContext; + } + + /** + * Construct unique name from provided {@code Route} + */ + public String uniqueRouteName(@Nonnull final String parentProtocolName, + @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route route) { + return bindName(parentProtocolName, + // to have address in compressed form + doubleDotlessAddress(route.getDestinationPrefix()), + String.valueOf(extractPrefix(route.getDestinationPrefix()))); + } + + /** + * Construct unique name from provided {@code IpFibDetails} + */ + public String uniqueRouteName(@Nonnull final Ip6FibDetails details, @Nonnull final MappingContext mappingContext) { + return bindName(routingProtocolContext.getName(details.tableId, mappingContext), + doubleDotlessAddress(details.address), + String.valueOf(details.addressLength)); + } + + public String uniqueRouteHopName( + @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop hop) { + return bindName(hop.getOutgoingInterface(), + doubleDotlessAddress(hop.getAddress()), + String.valueOf(hop.getWeight())); + } + + public String uniqueRouteHopName(@Nonnull final FibPath path, @Nonnull final MappingContext mappingContext) { + return bindName(interfaceContext.getName(path.swIfIndex, mappingContext), + doubleDotlessAddress(path.nextHop), + String.valueOf(path.weight)); + } + + /** + * Uses combination of standard java.net.InetAddress and com.google.common.net.InetAddresses for following reasons + * <ul> + * <li> + * InetAddresses.toAddrString uses maximal ipv6 compression - eliminate possibility of mismatch between same + * addresses with different compression + * </li> + * <li> + * InetAddress.getByAddress just converts byte array to address, that's + * why InetAddresses.fromLittleEndianByteArray is not used, because it internaly reverts order of address + * bytes,which is something that is not needed here + * </li> + * </ul> + */ + private String doubleDotlessAddress(final byte[] address) { + try { + return doubleDotless(InetAddresses.toAddrString(InetAddress.getByAddress(address))); + } catch (UnknownHostException e) { + throw new IllegalArgumentException(e); + } + } + + private String doubleDotlessAddress(@Nonnull final Ipv6Prefix address) { + final String addressValue = address.getValue(); + return doubleDotless(compressedIpv6(addressValue.substring(0, addressValue.indexOf("/")))); + } + + private String doubleDotlessAddress(@Nonnull final Ipv6Address address) { + // converted to use maximal compression + // for details - https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/net/InetAddresses.html#toAddrString-java.net.InetAddress + return doubleDotless(compressedIpv6(address.getValue())); + } + + /** + * Use maximal compresion of ipv6 address string + */ + private String compressedIpv6(@Nonnull final String input) { + return InetAddresses.toAddrString(InetAddresses.forString(input)); + } + + private String doubleDotless(@Nonnull final String input) { + return input.replace(DOUBLE_DOT, EMPTY); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv4ReadRoutingNodes.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv4ReadRoutingNodes.java new file mode 100644 index 000000000..dde2f9c46 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv4ReadRoutingNodes.java @@ -0,0 +1,95 @@ +/* + * 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.routing.read; + + +import com.google.common.collect.ImmutableSet; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.RoutingConfiguration; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.vpp.jvpp.core.dto.IpFibDetailsReplyDump; +import io.fd.vpp.jvpp.core.dto.IpFibDump; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.Set; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes2; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes2Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4RouteState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopList; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutes; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +interface Ipv4ReadRoutingNodes extends JvppReplyConsumer { + + static InstanceIdentifier<StaticRoutes2> staticRoutesInstanceIdentifier( + final InstanceIdentifier<StaticRoutes> staticRoutesInstanceIdentifier) { + return staticRoutesInstanceIdentifier.augmentation(StaticRoutes2.class); + } + + static InstanceIdentifier<Ipv4> ipv4Identifier( + final InstanceIdentifier<StaticRoutes2> staticRoutes2InstanceIdentifier) { + return staticRoutes2InstanceIdentifier.child(Ipv4.class); + } + + default DumpCacheManager<IpFibDetailsReplyDump, Void> newIpv4RoutesDumpManager( + @Nonnull final FutureJVppCore vppApi) { + return new DumpCacheManager.DumpCacheManagerBuilder<IpFibDetailsReplyDump, Void>() + .withExecutor( + (identifier, params) -> getReplyForRead(vppApi.ipFibDump(new IpFibDump()).toCompletableFuture(), + identifier)) + .acceptOnly(IpFibDetailsReplyDump.class) + .build(); + } + + default void registerIpv4Routes(@Nonnull final InstanceIdentifier<StaticRoutes> subTreeId, + @Nonnull final ModifiableReaderRegistryBuilder registry, + @Nonnull final DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4DumpManager, + @Nonnull final RoutingConfiguration configuration, + @Nonnull final MultiNamingContext routeHopContext, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext routeContext, + @Nonnull final NamingContext routingProtocolContext) { + + final InstanceIdentifier<StaticRoutes2> staticRoutes2InstanceIdentifier = + staticRoutesInstanceIdentifier(subTreeId); + final InstanceIdentifier<Ipv4> ipv4InstanceIdentifier = ipv4Identifier(staticRoutes2InstanceIdentifier); + + registry.addStructuralReader(staticRoutes2InstanceIdentifier, StaticRoutes2Builder.class); + + registry.addStructuralReader(ipv4InstanceIdentifier, Ipv4Builder.class); + registry.subtreeAdd(ipv4RoutingHandledChildren(InstanceIdentifier.create(Route.class)), + new GenericListReader<>(ipv4InstanceIdentifier.child(Route.class), + new Ipv4RouteCustomizer(ipv4DumpManager, configuration, routeHopContext, interfaceContext, + routeContext, routingProtocolContext))); + } + + default Set<InstanceIdentifier<?>> ipv4RoutingHandledChildren( + final InstanceIdentifier<Route> parent) { + return ImmutableSet.of(parent.child(NextHopList.class), + parent.child(NextHopList.class).child(NextHop.class), + parent.child(VppIpv4RouteState.class)); + } + +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv4RouteCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv4RouteCustomizer.java new file mode 100644 index 000000000..71758b4fe --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv4RouteCustomizer.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.read; + +import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS; + +import com.google.common.base.Optional; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.RoutingConfiguration; +import io.fd.hc2vpp.routing.naming.Ipv4RouteNamesFactory; +import io.fd.hc2vpp.routing.trait.Ipv4RoutePathParser; +import io.fd.hc2vpp.routing.trait.RouteMapper; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.vpp.jvpp.core.dto.IpFibDetails; +import io.fd.vpp.jvpp.core.dto.IpFibDetailsReplyDump; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4RouteStateBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class Ipv4RouteCustomizer + implements ListReaderCustomizer<Route, RouteKey, RouteBuilder>, RouteMapper, Ipv4RoutePathParser { + + + private final DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4RoutesDumpManager; + private final RoutingConfiguration configuration; + private final MultiNamingContext routeHopContext; + private final NamingContext interfaceContext; + private final NamingContext routesContext; + private final NamingContext routingProtocolContext; + + private final Ipv4RouteNamesFactory namesFactory; + + public Ipv4RouteCustomizer(@Nonnull final DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4RoutesDumpManager, + @Nonnull final RoutingConfiguration configuration, + @Nonnull final MultiNamingContext routeHopContext, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext routesContext, + @Nonnull final NamingContext routingProtocolContext) { + this.ipv4RoutesDumpManager = ipv4RoutesDumpManager; + this.configuration = configuration; + this.interfaceContext = interfaceContext; + this.routeHopContext = routeHopContext; + this.routesContext = routesContext; + this.routingProtocolContext = routingProtocolContext; + this.namesFactory = new Ipv4RouteNamesFactory(interfaceContext, routingProtocolContext); + } + + @Nonnull + @Override + public List<RouteKey> getAllIds(@Nonnull final InstanceIdentifier<Route> instanceIdentifier, + @Nonnull final ReadContext readContext) throws ReadFailedException { + + final Optional<IpFibDetailsReplyDump> ipv4RoutesDump = + ipv4RoutesDumpManager.getDump(instanceIdentifier, readContext.getModificationCache(), NO_PARAMS); + + final String protocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName(); + final int protocolTableId = routingProtocolContext.getIndex(protocolName, readContext.getMappingContext()); + + return ipv4RoutesDump.isPresent() + ? ipv4RoutesDump.get().ipFibDetails.stream() + .filter(details -> protocolTableId == details.tableId) + .map(ipFibDetails -> toKey(ipFibDetails, readContext.getMappingContext())) + .collect(Collectors.toList()) + : Collections.emptyList(); + } + + /** + * route id is represented as number, but there's no index in dumped data, + * so index is assigned to name formatted as tableId_address_addressLength(should be unique combination) + */ + private RouteKey toKey(final IpFibDetails details, final MappingContext mappingContext) { + String routeName = namesFactory.uniqueRouteName(details, mappingContext); + // first condition excludes data written manually, second one data that has been already learned + if (!routesContext.containsIndex(routeName, mappingContext)) { + String learnedRouteName = nameWithPrefix(configuration.getLearnedRouteNamePrefix(), routeName); + if (!routesContext.containsIndex(learnedRouteName, mappingContext)) { + routesContext.addName(learnedRouteName, mappingContext); + } + return keyForName(mappingContext, learnedRouteName); + } + return keyForName(mappingContext, routeName); + } + + private RouteKey keyForName(final MappingContext mappingContext, final String name) { + return new RouteKey( + Long.valueOf(routesContext.getIndex(name, mappingContext))); + } + + @Override + public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<Route> list) { + Ipv4Builder.class.cast(builder).setRoute(list); + } + + @Nonnull + @Override + public RouteBuilder getBuilder(@Nonnull final InstanceIdentifier<Route> instanceIdentifier) { + return new RouteBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier, + @Nonnull final RouteBuilder routeBuilder, @Nonnull final ReadContext readContext) + throws ReadFailedException { + final RouteKey key = instanceIdentifier.firstKeyOf(Route.class); + final String mappedName = routesContext.getName(key.getId().intValue(), readContext.getMappingContext()); + final String protocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName(); + final int protocolTableId = routingProtocolContext.getIndex(protocolName, readContext.getMappingContext()); + final Optional<IpFibDetailsReplyDump> ipv4RoutesDump = + ipv4RoutesDumpManager.getDump(instanceIdentifier, readContext.getModificationCache(), NO_PARAMS); + + if (ipv4RoutesDump.isPresent() && !ipv4RoutesDump.get().ipFibDetails.isEmpty()) { + + final java.util.Optional<IpFibDetails> opDetail = ipv4RoutesDump.get().ipFibDetails.stream() + .filter(details -> protocolTableId == details.tableId) + .filter(details -> equalsWithConfigOrLearned(configuration.getLearnedRouteNamePrefix(), mappedName, + namesFactory.uniqueRouteName(details, readContext.getMappingContext()))) + .findAny(); + + if (opDetail.isPresent()) { + final IpFibDetails detail = opDetail.get(); + + routeBuilder.setNextHopOptions( + resolveHopType(mappedName, Arrays.asList(detail.path), interfaceContext, routeHopContext, + readContext.getMappingContext(), namesFactory)) + .setKey(key) + .setId(key.getId()) + .setDestinationPrefix(toIpv4Prefix(detail.address, toJavaByte(detail.addressLength))) + .setVppIpv4RouteState(new VppIpv4RouteStateBuilder().build()); + } + } + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv6ReadRoutingNodes.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv6ReadRoutingNodes.java new file mode 100644 index 000000000..06eaaf913 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv6ReadRoutingNodes.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.read; + +import com.google.common.collect.ImmutableSet; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.RoutingConfiguration; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.vpp.jvpp.core.dto.Ip6FibDetailsReplyDump; +import io.fd.vpp.jvpp.core.dto.Ip6FibDump; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.Set; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes2; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes2Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6RouteState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopList; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutes; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +interface Ipv6ReadRoutingNodes extends JvppReplyConsumer { + + static InstanceIdentifier<StaticRoutes2> staticRoutesInstanceIdentifier( + final InstanceIdentifier<StaticRoutes> staticRoutesInstanceIdentifier) { + return staticRoutesInstanceIdentifier.augmentation(StaticRoutes2.class); + } + + static InstanceIdentifier<Ipv6> ipv6Identifier( + final InstanceIdentifier<StaticRoutes2> staticRoutes2InstanceIdentifier) { + return staticRoutes2InstanceIdentifier.child(Ipv6.class); + } + + default DumpCacheManager<Ip6FibDetailsReplyDump, Void> newIpv6RoutesDumpManager( + @Nonnull final FutureJVppCore vppApi) { + return new DumpCacheManager.DumpCacheManagerBuilder<Ip6FibDetailsReplyDump, Void>() + .withExecutor( + (identifier, params) -> getReplyForRead( + vppApi.ip6FibDump(new Ip6FibDump()).toCompletableFuture(), identifier)) + .acceptOnly(Ip6FibDetailsReplyDump.class) + .build(); + } + + default void registerIpv6Routes(@Nonnull final InstanceIdentifier<StaticRoutes> subTreeId, + @Nonnull final ModifiableReaderRegistryBuilder registry, + @Nonnull final DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6DumpManager, + @Nonnull final RoutingConfiguration configuration, + @Nonnull final MultiNamingContext routeHopContext, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext routeContext, + @Nonnull final NamingContext routingProtocolContext) { + + final InstanceIdentifier<StaticRoutes2> staticRoutes2InstanceIdentifier = + staticRoutesInstanceIdentifier(subTreeId); + final InstanceIdentifier<Ipv6> ipv6InstanceIdentifier = ipv6Identifier(staticRoutes2InstanceIdentifier); + + registry.addStructuralReader(staticRoutes2InstanceIdentifier, StaticRoutes2Builder.class); + + registry.addStructuralReader(ipv6InstanceIdentifier, Ipv6Builder.class); + registry.subtreeAdd(ipv6RoutingHandledChildren(InstanceIdentifier.create(Route.class)), + new GenericListReader<>(ipv6InstanceIdentifier.child(Route.class), + new Ipv6RouteCustomizer(ipv6DumpManager, configuration, routeHopContext, interfaceContext, + routeContext, routingProtocolContext))); + } + + default Set<InstanceIdentifier<?>> ipv6RoutingHandledChildren( + final InstanceIdentifier<Route> parent) { + return ImmutableSet.of(parent.child(NextHopList.class), + parent.child(NextHopList.class).child(NextHop.class), + parent.child(VppIpv6RouteState.class)); + } + +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv6RouteCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv6RouteCustomizer.java new file mode 100644 index 000000000..c83891d85 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv6RouteCustomizer.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.routing.read; + +import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS; + +import com.google.common.base.Optional; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.RoutingConfiguration; +import io.fd.hc2vpp.routing.naming.Ipv6RouteNamesFactory; +import io.fd.hc2vpp.routing.trait.Ipv6RoutePathParser; +import io.fd.hc2vpp.routing.trait.RouteMapper; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.vpp.jvpp.core.dto.Ip6FibDetails; +import io.fd.vpp.jvpp.core.dto.Ip6FibDetailsReplyDump; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6RouteStateBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class Ipv6RouteCustomizer + implements ListReaderCustomizer<Route, RouteKey, RouteBuilder>, RouteMapper, Ipv6RoutePathParser { + + private final DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6RoutesDumpManager; + private final RoutingConfiguration configuration; + private final MultiNamingContext routeHopContext; + private final NamingContext interfaceContext; + private final NamingContext routesContext; + private final NamingContext routingProtocolContext; + private final Ipv6RouteNamesFactory namesFactory; + + public Ipv6RouteCustomizer(@Nonnull final DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6RoutesDumpManager, + @Nonnull final RoutingConfiguration configuration, + @Nonnull final MultiNamingContext routeHopContext, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext routesContext, + @Nonnull final NamingContext routingProtocolContext) { + this.ipv6RoutesDumpManager = ipv6RoutesDumpManager; + this.configuration = configuration; + this.interfaceContext = interfaceContext; + this.routeHopContext = routeHopContext; + this.routesContext = routesContext; + this.routingProtocolContext = routingProtocolContext; + this.namesFactory = new Ipv6RouteNamesFactory(interfaceContext, routingProtocolContext); + } + + @Nonnull + @Override + public List<RouteKey> getAllIds(@Nonnull final InstanceIdentifier<Route> instanceIdentifier, + @Nonnull final ReadContext readContext) throws ReadFailedException { + + final Optional<Ip6FibDetailsReplyDump> ipv6RoutesDump = + ipv6RoutesDumpManager.getDump(instanceIdentifier, readContext.getModificationCache(), NO_PARAMS); + + final String protocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName(); + final int protocolTableId = routingProtocolContext.getIndex(protocolName, readContext.getMappingContext()); + + return ipv6RoutesDump.isPresent() + ? ipv6RoutesDump.get().ip6FibDetails.stream() + .filter(details -> protocolTableId == details.tableId) + .map(ip6FibDetails -> toKey(ip6FibDetails, readContext.getMappingContext())) + .collect(Collectors.toList()) + : Collections.emptyList(); + } + + /** + * route id is represented as number, but there's no index in dumped data, + * so index is assigned to name formatted as tableId_address_addressLength(should be unique combination) + */ + private RouteKey toKey(final Ip6FibDetails details, final MappingContext mappingContext) { + String routeName = namesFactory.uniqueRouteName(details, mappingContext); + // first condition excludes data written manually, second one data that has been already learned + if (!routesContext.containsIndex(routeName, mappingContext)) { + String learnedRouteName = nameWithPrefix(configuration.getLearnedRouteNamePrefix(), routeName); + if (!routesContext.containsIndex(learnedRouteName, mappingContext)) { + routesContext.addName(learnedRouteName, mappingContext); + } + return keyForName(mappingContext, learnedRouteName); + } + return keyForName(mappingContext, routeName); + } + + private RouteKey keyForName(final MappingContext mappingContext, final String name) { + return new RouteKey(Long.valueOf(routesContext.getIndex(name, mappingContext))); + } + + @Override + public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<Route> list) { + Ipv6Builder.class.cast(builder).setRoute(list); + } + + @Nonnull + @Override + public RouteBuilder getBuilder(@Nonnull final InstanceIdentifier<Route> instanceIdentifier) { + return new RouteBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier, + @Nonnull final RouteBuilder routeBuilder, @Nonnull final ReadContext readContext) + throws ReadFailedException { + final RouteKey key = instanceIdentifier.firstKeyOf(Route.class); + final String mappedName = routesContext.getName(key.getId().intValue(), readContext.getMappingContext()); + final String protocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName(); + final int protocolTableId = routingProtocolContext.getIndex(protocolName, readContext.getMappingContext()); + final Optional<Ip6FibDetailsReplyDump> ipv6RoutesDump = + ipv6RoutesDumpManager.getDump(instanceIdentifier, readContext.getModificationCache(), NO_PARAMS); + + if (ipv6RoutesDump.isPresent() && !ipv6RoutesDump.get().ip6FibDetails.isEmpty()) { + + final java.util.Optional<Ip6FibDetails> opDetail = ipv6RoutesDump.get().ip6FibDetails.stream() + .filter(details -> protocolTableId == details.tableId) + .filter(details -> equalsWithConfigOrLearned(configuration.getLearnedRouteNamePrefix(), mappedName, + namesFactory.uniqueRouteName(details, readContext.getMappingContext()))) + .findAny(); + + if (opDetail.isPresent()) { + final Ip6FibDetails detail = opDetail.get(); + + routeBuilder.setNextHopOptions( + resolveHopType(mappedName, Arrays.asList(detail.path), interfaceContext, routeHopContext, + readContext.getMappingContext(), namesFactory)) + .setKey(key) + .setId(key.getId()) + .setDestinationPrefix(toIpv6Prefix(detail.address, toJavaByte(detail.addressLength))) + .setVppIpv6RouteState(new VppIpv6RouteStateBuilder().build()); + } + } + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingInstanceCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingInstanceCustomizer.java new file mode 100644 index 000000000..78e869f9a --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingInstanceCustomizer.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.read; + +import com.google.common.collect.ImmutableList; +import io.fd.hc2vpp.routing.RoutingConfiguration; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.RoutingStateBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.StandardRoutingInstance; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.RoutingInstance; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.RoutingInstanceBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.RoutingInstanceKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Returns default instance of routing instance + */ +public class RoutingInstanceCustomizer + implements ListReaderCustomizer<RoutingInstance, RoutingInstanceKey, RoutingInstanceBuilder> { + + private RoutingInstanceKey defaultKey; + + public RoutingInstanceCustomizer(@Nonnull final RoutingConfiguration configuration) { + defaultKey = new RoutingInstanceKey(configuration.getDefaultRoutingInstanceName()); + } + + @Nonnull + @Override + public List<RoutingInstanceKey> getAllIds(@Nonnull final InstanceIdentifier<RoutingInstance> instanceIdentifier, + @Nonnull final ReadContext readContext) throws ReadFailedException { + return ImmutableList.of(defaultKey); + } + + @Override + public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<RoutingInstance> list) { + RoutingStateBuilder.class.cast(builder).setRoutingInstance(list); + } + + @Nonnull + @Override + public RoutingInstanceBuilder getBuilder(@Nonnull final InstanceIdentifier<RoutingInstance> instanceIdentifier) { + return new RoutingInstanceBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingInstance> instanceIdentifier, + @Nonnull final RoutingInstanceBuilder routingInstanceBuilder, + @Nonnull final ReadContext readContext) throws ReadFailedException { + routingInstanceBuilder.setType(StandardRoutingInstance.class) + .setKey(defaultKey) + .setName(defaultKey.getName()); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingProtocolCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingProtocolCustomizer.java new file mode 100644 index 000000000..c8a379b83 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingProtocolCustomizer.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.read; + +import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS; + +import com.google.common.base.Optional; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.trait.RouteMapper; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.vpp.jvpp.core.dto.Ip6FibDetailsReplyDump; +import io.fd.vpp.jvpp.core.dto.IpFibDetailsReplyDump; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Static; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocolsBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocolBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocolKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolStateVppAttr; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolStateVppAttrBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.VniReference; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.routing.state.routing.instance.routing.protocols.routing.protocol.VppProtocolStateAttributesBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + + +public class RoutingProtocolCustomizer + implements ListReaderCustomizer<RoutingProtocol, RoutingProtocolKey, RoutingProtocolBuilder>, RouteMapper { + + private final NamingContext routingProtocolContext; + private final DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4RoutesDumpManager; + private final DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6RoutesDumpManager; + + + public RoutingProtocolCustomizer(@Nonnull final NamingContext routingProtocolContext, + @Nonnull final DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4RoutesDumpManager, + @Nonnull final DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6RoutesDumpManager) { + this.routingProtocolContext = routingProtocolContext; + this.ipv4RoutesDumpManager = ipv4RoutesDumpManager; + this.ipv6RoutesDumpManager = ipv6RoutesDumpManager; + } + + @Nonnull + @Override + public List<RoutingProtocolKey> getAllIds(@Nonnull final InstanceIdentifier<RoutingProtocol> instanceIdentifier, + @Nonnull final ReadContext readContext) throws ReadFailedException { + + final ModificationCache modificationCache = readContext.getModificationCache(); + + // builds keys from routing protocol prefix and unique set of table ids + return Stream.of( + ipv4TableIds(instanceIdentifier, modificationCache), + ipv6TableIds(instanceIdentifier, modificationCache)) + .flatMap(Collection::stream) + .map(tableId -> routingProtocolContext.getName(tableId, readContext.getMappingContext())) + .distinct() + .map(RoutingProtocolKey::new) + .collect(Collectors.toList()); + } + + private List<Integer> ipv4TableIds(final InstanceIdentifier<RoutingProtocol> instanceIdentifier, + final ModificationCache modificationCache) throws ReadFailedException { + final Optional<IpFibDetailsReplyDump> + ipv4Routes = ipv4RoutesDumpManager.getDump(instanceIdentifier, modificationCache, NO_PARAMS); + + if (ipv4Routes.isPresent()) { + return ipv4Routes.get().ipFibDetails.stream() + .map(ipFibDetails -> ipFibDetails.tableId) + .collect(Collectors.toList()); + } + return Collections.emptyList(); + } + + private List<Integer> ipv6TableIds(final InstanceIdentifier<RoutingProtocol> instanceIdentifier, + final ModificationCache modificationCache) throws ReadFailedException { + final Optional<Ip6FibDetailsReplyDump> + ipv6Routes = ipv6RoutesDumpManager.getDump(instanceIdentifier, modificationCache, NO_PARAMS); + + if (ipv6Routes.isPresent()) { + return ipv6Routes.get().ip6FibDetails.stream() + .map(ipFibDetails -> ipFibDetails.tableId) + .collect(Collectors.toList()); + } + return Collections.emptyList(); + } + + @Override + public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<RoutingProtocol> list) { + RoutingProtocolsBuilder.class.cast(builder).setRoutingProtocol(list); + } + + @Nonnull + @Override + public RoutingProtocolBuilder getBuilder(@Nonnull final InstanceIdentifier<RoutingProtocol> instanceIdentifier) { + return new RoutingProtocolBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingProtocol> instanceIdentifier, + @Nonnull final RoutingProtocolBuilder routingProtocolBuilder, + @Nonnull final ReadContext readContext) throws ReadFailedException { + + final RoutingProtocolKey key = instanceIdentifier.firstKeyOf(RoutingProtocol.class); + routingProtocolBuilder.setName(key.getName()).setKey(key).setType(Static.class) + .addAugmentation(RoutingProtocolStateVppAttr.class, new RoutingProtocolStateVppAttrBuilder() + .setVppProtocolStateAttributes(new VppProtocolStateAttributesBuilder() + .setPrimaryVrf(new VniReference(Long.valueOf(routingProtocolContext + .getIndex(key.getName(), readContext.getMappingContext())))) + .build()) + .build()); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingStateCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingStateCustomizer.java new file mode 100644 index 000000000..5a6b23b7d --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingStateCustomizer.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.read; + +import io.fd.hc2vpp.routing.write.Ipv4WriteRoutingNodes; +import io.fd.hc2vpp.routing.write.Ipv6WriteRoutingNodes; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.Initialized; +import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Routing; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.RoutingBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.RoutingState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.RoutingStateBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.StandardRoutingInstance; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstance; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstanceBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.RoutingProtocols; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.RoutingProtocolsBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocolBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutesBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolStateVppAttr; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolVppAttr; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolVppAttrBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.routing.routing.instance.routing.protocols.routing.protocol.VppProtocolAttributesBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RoutingStateCustomizer + implements InitializingReaderCustomizer<RoutingState, RoutingStateBuilder>, Ipv4WriteRoutingNodes { + + private static final Logger LOG = LoggerFactory.getLogger(RoutingStateCustomizer.class); + + private static RoutingInstance mapRoutingInstances( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.RoutingInstance state) { + return new RoutingInstanceBuilder() + .setName(state.getName()) + .setEnabled(true) + .setRouterId(state.getRouterId()) + .setType(StandardRoutingInstance.class) + .setRoutingProtocols(RoutingStateCustomizer.mapRoutingProtocols(state.getRoutingProtocols())) + .build(); + } + + private static RoutingProtocols mapRoutingProtocols( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocols state) { + + if (state != null) { + return new RoutingProtocolsBuilder() + .setRoutingProtocol(state.getRoutingProtocol() != null + ? RoutingStateCustomizer.mapRoutingProtocol(state.getRoutingProtocol()) + : null) + .build(); + } else { + return null; + } + } + + private static List<RoutingProtocol> mapRoutingProtocol( + final List<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol> state) { + return state.stream() + .map(routingProtocol -> new RoutingProtocolBuilder() + .setName(routingProtocol.getName()) + .setEnabled(true) + .setType(routingProtocol.getType()) + .setStaticRoutes(RoutingStateCustomizer.mapStaticRoutes(routingProtocol.getStaticRoutes())) + .addAugmentation(RoutingProtocolVppAttr.class, + mapVppAttr(routingProtocol.getAugmentation(RoutingProtocolStateVppAttr.class))) + .build()) + .collect(Collectors.toList()); + } + + private static RoutingProtocolVppAttr mapVppAttr(final RoutingProtocolStateVppAttr attrState) { + return new RoutingProtocolVppAttrBuilder() + .setVppProtocolAttributes(attrState.getVppProtocolStateAttributes() == null + ? null + : + new VppProtocolAttributesBuilder() + .setPrimaryVrf(attrState.getVppProtocolStateAttributes().getPrimaryVrf()) + .build()) + .build(); + } + + private static StaticRoutes mapStaticRoutes( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutes state) { + return new StaticRoutesBuilder() + .addAugmentation(CONFIG_IPV4_AUG_CLASS, + Ipv4WriteRoutingNodes.INSTANCE.mapIpv4Augmentation(state.getAugmentation(STATE_IPV4_AUG_CLASS))) + .addAugmentation(Ipv6WriteRoutingNodes.CONFIG_IPV6_AUG_CLASS, + Ipv6WriteRoutingNodes.INSTANCE.mapIpv6Augmentation(state.getAugmentation( + Ipv6WriteRoutingNodes.STATE_IPV6_AUG_CLASS))) + .build(); + } + + @Nonnull + @Override + public RoutingStateBuilder getBuilder(@Nonnull final InstanceIdentifier<RoutingState> instanceIdentifier) { + return new RoutingStateBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingState> instanceIdentifier, + @Nonnull final RoutingStateBuilder routingStateBuilder, + @Nonnull final ReadContext readContext) throws ReadFailedException { + // does nothing + LOG.info("Reading {}", instanceIdentifier); + } + + @Override + public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final RoutingState routingState) { + //Routing state is root + } + + @Nonnull + @Override + public Initialized<? extends DataObject> init(@Nonnull final InstanceIdentifier<RoutingState> id, + @Nonnull final RoutingState readValue, + @Nonnull final ReadContext ctx) { + + return Initialized.create(InstanceIdentifier.create(Routing.class), new RoutingBuilder() + .setRoutingInstance(readValue.getRoutingInstance() + .stream() + .map(routingInstance -> mapRoutingInstances(routingInstance)) + .collect(Collectors.toList())) + .build()); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingStateReaderFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingStateReaderFactory.java new file mode 100644 index 000000000..c26de124e --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingStateReaderFactory.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.read; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.RoutingConfiguration; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.impl.read.GenericReader; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.vpp.jvpp.core.dto.Ip6FibDetailsReplyDump; +import io.fd.vpp.jvpp.core.dto.IpFibDetailsReplyDump; +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.routing.rev140524.RoutingState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.RoutingInstance; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocols; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocolsBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutes; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutesBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolStateVppAttr; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.routing.state.routing.instance.routing.protocols.routing.protocol.VppProtocolStateAttributes; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Factory producing readers for routing plugin's data. + */ +public final class RoutingStateReaderFactory implements ReaderFactory, Ipv4ReadRoutingNodes, Ipv6ReadRoutingNodes { + + private static final InstanceIdentifier<RoutingState> ROOT_STATE_CONTAINER_ID = + InstanceIdentifier.create(RoutingState.class); + + @Inject + private RoutingConfiguration configuration; + + @Inject + @Named("interface-context") + private NamingContext interfaceContext; + + @Inject + @Named(RoutingConfiguration.ROUTING_PROTOCOL_CONTEXT) + private NamingContext routingProtocolContext; + + @Inject + @Named(RoutingConfiguration.ROUTE_CONTEXT) + private NamingContext routeContext; + + @Inject + @Named(RoutingConfiguration.ROUTE_HOP_CONTEXT) + private MultiNamingContext routeHopContext; + + @Inject + private FutureJVppCore vppApi; + + @Override + public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) { + final DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4DumpManager = newIpv4RoutesDumpManager(vppApi); + final DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6DumpManager = newIpv6RoutesDumpManager(vppApi); + + final InstanceIdentifier<RoutingInstance> routingInstanceInstanceIdentifier = + routingInstanceIdentifier(ROOT_STATE_CONTAINER_ID); + final InstanceIdentifier<RoutingProtocols> routingProtocolsInstanceIdentifier = + routingProtocolsId(routingInstanceInstanceIdentifier); + final InstanceIdentifier<RoutingProtocol> routingProtocolInstanceIdentifier = + routingProtocolInstanceIdentifier(routingProtocolsInstanceIdentifier); + final InstanceIdentifier<StaticRoutes> staticRoutesInstanceIdentifier = + staticRoutesInstanceIdentifier(routingProtocolInstanceIdentifier); + + // RoutingState + registry.add(new GenericReader<>(ROOT_STATE_CONTAINER_ID, new RoutingStateCustomizer())); + // RoutingInstance + registry.add(new GenericListReader<>(routingInstanceInstanceIdentifier, + new RoutingInstanceCustomizer(configuration))); + + // RoutingProtocols + registry.addStructuralReader(routingProtocolsInstanceIdentifier, RoutingProtocolsBuilder.class); + + // RoutingProtocol + registry.subtreeAdd(routingProtocolHandledChildren(), new GenericListReader<>(routingProtocolInstanceIdentifier, + new RoutingProtocolCustomizer(routingProtocolContext, ipv4DumpManager, ipv6DumpManager))); + + // StaticRoutes + registry.addStructuralReader(staticRoutesInstanceIdentifier, StaticRoutesBuilder.class); + + registerIpv4Routes(staticRoutesInstanceIdentifier, registry, ipv4DumpManager, configuration, routeHopContext, + interfaceContext, routeContext, routingProtocolContext); + registerIpv6Routes(staticRoutesInstanceIdentifier, registry, ipv6DumpManager, configuration, routeHopContext, + interfaceContext, routeContext, routingProtocolContext); + } + + private static ImmutableSet<InstanceIdentifier<?>> routingProtocolHandledChildren() { + return ImmutableSet + .of(InstanceIdentifier.create(RoutingProtocol.class).augmentation(RoutingProtocolStateVppAttr.class) + .child(VppProtocolStateAttributes.class)); + } + + private InstanceIdentifier<StaticRoutes> staticRoutesInstanceIdentifier( + final InstanceIdentifier<RoutingProtocol> routingProtocolInstanceIdentifier) { + return routingProtocolInstanceIdentifier.child(StaticRoutes.class); + } + + private InstanceIdentifier<RoutingProtocol> routingProtocolInstanceIdentifier( + final InstanceIdentifier<RoutingProtocols> routingProtocolsInstanceIdentifier) { + return routingProtocolsInstanceIdentifier.child(RoutingProtocol.class); + } + + private InstanceIdentifier<RoutingProtocols> routingProtocolsId( + final InstanceIdentifier<RoutingInstance> routingInstanceInstanceIdentifier) { + return routingInstanceInstanceIdentifier.child(RoutingProtocols.class); + } + + private InstanceIdentifier<RoutingInstance> routingInstanceIdentifier( + final InstanceIdentifier<RoutingState> routingStateId) { + return routingStateId.child(RoutingInstance.class); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/Ipv4RoutePathParser.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/Ipv4RoutePathParser.java new file mode 100644 index 000000000..58dee232b --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/Ipv4RoutePathParser.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.trait; + +import static io.fd.hc2vpp.routing.trait.RouteMapper.isDefaultInterfaceIndex; + +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.naming.Ipv4RouteNamesFactory; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.types.FibPath; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.NextHopOptions; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopListBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder; + +public interface Ipv4RoutePathParser extends RouteMapper { + + static NextHopOptions resolveOption(final String routeName, + final List<FibPath> parsedHops, + final NamingContext interfaceContext, + final MultiNamingContext routeHopContext, + final MappingContext mappingContext, + final Ipv4RouteNamesFactory namesFactory) { + return parsedHops.size() == 1 + ? RouteMapper.INSTANCE.isSpecialHop(parsedHops.get(0)) + ? specialHop(parsedHops.get(0)) + : simpleHop(parsedHops.get(0), interfaceContext, mappingContext) + : hopList(routeName, parsedHops, interfaceContext, routeHopContext, mappingContext, namesFactory); + } + + static SpecialNextHop specialHop(final FibPath singlePath) { + return new SpecialNextHopBuilder() + .setSpecialNextHop(RouteMapper.INSTANCE.specialHopType(singlePath)) + .build(); + } + + static SimpleNextHop simpleHop(final FibPath path, final NamingContext interfaceContext, + final MappingContext mappingContext) { + return resolveInterfaceIfSpecified(new SimpleNextHopBuilder(), path.swIfIndex, interfaceContext, mappingContext) + .setNextHop(AddressTranslator.INSTANCE.arrayToIpv4AddressNoZone(path.nextHop)) + .build(); + } + + static SimpleNextHopBuilder resolveInterfaceIfSpecified(final SimpleNextHopBuilder builder, final int index, + final NamingContext interfaceContext, + final MappingContext mappingContext) { + if (!isDefaultInterfaceIndex(index)) { + builder.setOutgoingInterface(interfaceContext.getName(index, mappingContext)); + } + return builder; + } + + static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList hopList( + final String routeName, + final List<FibPath> parsedHops, + final NamingContext interfaceContext, + final MultiNamingContext routeHopContext, + final MappingContext mappingContext, + final Ipv4RouteNamesFactory namesFactory) { + return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopListBuilder() + .setNextHopList( + new NextHopListBuilder().setNextHop(parsedHops.stream() + .map(fibPath -> resolveInterfaceIfSpecified(new NextHopBuilder(), fibPath.swIfIndex, + interfaceContext, mappingContext) + .setId((long) (routeHopContext.getChildIndex(routeName, + namesFactory.uniqueRouteHopName(fibPath, mappingContext), + mappingContext))) + .setWeight(((short) fibPath.weight)) + .setAddress( + AddressTranslator.INSTANCE + .arrayToIpv4AddressNoZone(fibPath.nextHop)) + .build()) + .collect(Collectors.toList())) + .build()) + .build(); + } + + static NextHopBuilder resolveInterfaceIfSpecified(final NextHopBuilder builder, final int index, + final NamingContext interfaceContext, + final MappingContext mappingContext) { + if (!isDefaultInterfaceIndex(index)) { + builder.setOutgoingInterface(interfaceContext.getName(index, mappingContext)); + } + return builder; + } + + default NextHopOptions resolveHopType(@Nonnull final String routeName, + final List<FibPath> parsedHops, + @Nonnull final NamingContext interfaceContext, + @Nonnull final MultiNamingContext routeHopContext, + @Nonnull final MappingContext mappingContext, + @Nonnull final Ipv4RouteNamesFactory namesFactory) { + + return parsedHops == null || parsedHops.isEmpty() + ? null + : resolveOption(routeName, parsedHops, interfaceContext, routeHopContext, mappingContext, namesFactory); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/Ipv6RoutePathParser.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/Ipv6RoutePathParser.java new file mode 100644 index 000000000..908472931 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/Ipv6RoutePathParser.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.trait; + +import static io.fd.hc2vpp.routing.trait.RouteMapper.isDefaultInterfaceIndex; + +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.naming.Ipv6RouteNamesFactory; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.types.FibPath; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.NextHopOptions; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopList; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopListBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder; + +public interface Ipv6RoutePathParser extends RouteMapper { + + static NextHopOptions resolveOption(final String routeName, + final List<FibPath> parsedHops, + final NamingContext interfaceContext, + final MultiNamingContext routeHopContext, + final MappingContext mappingContext, + final Ipv6RouteNamesFactory namesFactory) { + return parsedHops.size() == 1 + ? INSTANCE.isSpecialHop(parsedHops.get(0)) + ? specialHop(parsedHops.get(0)) + : simpleHop(parsedHops.get(0), interfaceContext, mappingContext) + : hopList(routeName, parsedHops, interfaceContext, routeHopContext, mappingContext, namesFactory); + } + + static SpecialNextHop specialHop(final FibPath fibPath) { + return new SpecialNextHopBuilder() + .setSpecialNextHop(INSTANCE.specialHopType(fibPath)) + .build(); + } + + static SimpleNextHop simpleHop(final FibPath path, final NamingContext interfaceContext, + final MappingContext mappingContext) { + return resolveInterfaceIfSpecified(new SimpleNextHopBuilder(), path.swIfIndex, interfaceContext, mappingContext) + .setNextHop(AddressTranslator.INSTANCE.arrayToIpv6AddressNoZone(path.nextHop)) + .build(); + } + + static SimpleNextHopBuilder resolveInterfaceIfSpecified(SimpleNextHopBuilder builder, final int index, + final NamingContext interfaceContext, + final MappingContext mappingContext) { + if (!isDefaultInterfaceIndex(index)) { + builder.setOutgoingInterface(interfaceContext.getName(index, mappingContext)); + } + + return builder; + } + + static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList hopList( + final String routeName, + final List<FibPath> parsedHops, + final NamingContext interfaceContext, + final MultiNamingContext routeHopContext, + final MappingContext mappingContext, + final Ipv6RouteNamesFactory namesFactory) { + return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopListBuilder() + .setNextHopList( + buildNextHopList(routeName, parsedHops, interfaceContext, routeHopContext, mappingContext, + namesFactory)) + .build(); + } + + static NextHopList buildNextHopList(final String routeName, final List<FibPath> parsedHops, + final NamingContext interfaceContext, + final MultiNamingContext routeHopContext, + final MappingContext mappingContext, + final Ipv6RouteNamesFactory namesFactory) { + return new NextHopListBuilder().setNextHop(parsedHops.stream() + .map(fibPath -> resolveInterfaceIfSpecified(new NextHopBuilder(), fibPath.swIfIndex, interfaceContext, + mappingContext) + .setId(findIdWithinRouteContext(routeName, routeHopContext, mappingContext, fibPath, + namesFactory)) + .setWeight((short) fibPath.weight) + .setAddress(AddressTranslator.INSTANCE.arrayToIpv6AddressNoZone(fibPath.nextHop)) + .build()) + .collect(Collectors.toList())) + .build(); + } + + static NextHopBuilder resolveInterfaceIfSpecified(NextHopBuilder builder, final int index, + final NamingContext interfaceContext, + final MappingContext mappingContext) { + if (!isDefaultInterfaceIndex(index)) { + builder.setOutgoingInterface(interfaceContext.getName(index, mappingContext)); + } + + return builder; + } + + static long findIdWithinRouteContext(final String routeName, final MultiNamingContext routeHopContext, + final MappingContext mappingContext, final FibPath fibPath, + final Ipv6RouteNamesFactory namesFactory) { + return (long) (routeHopContext + .getChildIndex(routeName, namesFactory.uniqueRouteHopName(fibPath, mappingContext), mappingContext)); + } + + default NextHopOptions resolveHopType(@Nonnull final String routeName, + final List<FibPath> parsedHops, + @Nonnull final NamingContext interfaceContext, + @Nonnull final MultiNamingContext routeHopContext, + @Nonnull final MappingContext mappingContext, + @Nonnull final Ipv6RouteNamesFactory namesFactory) { + + return parsedHops == null || parsedHops.isEmpty() + ? null + : resolveOption(routeName, parsedHops, interfaceContext, routeHopContext, mappingContext, namesFactory); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/RouteMapper.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/RouteMapper.java new file mode 100644 index 000000000..deabdacee --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/RouteMapper.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.trait; + +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.vpp.jvpp.core.types.FibPath; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping; + +public interface RouteMapper extends AddressTranslator, ByteDataTranslator { + + int DEFAULT_INTERFACE_INDEX = -1; + RouteMapper INSTANCE = new RouteMapper() { + }; + + static boolean isDefaultInterfaceIndex(final int index) { + return DEFAULT_INTERFACE_INDEX == index; + } + + static boolean flagEnabled(final byte flag) { + return ByteDataTranslator.INSTANCE.byteToBoolean(flag); + } + + /** + * Verifies whether provided table id is for provided protocol name + */ + default boolean isWithinProtocol(@Nonnull final String protocolName, + @Nonnull final String routingProtocolNamePrefix, + @Nonnull final Integer tableId) { + return protocolName.equals(fullRoutingProtocolName(routingProtocolNamePrefix, tableId)); + } + + /** + * Return full protocol name in form routing_protocol_name_prefix + table + */ + default String fullRoutingProtocolName(@Nonnull final String routingProtocolNamePrefix, + @Nonnull final Integer tableId) { + return nameWithPrefix(routingProtocolNamePrefix, String.valueOf(tableId)); + } + + default String bindName(@Nonnull final String first, @Nonnull final String second, @Nonnull final String third) { + return String.format("%s_%s_%s", first, second, third); + } + + default String nameWithPrefix(@Nonnull final String prefix, @Nonnull final String name) { + return String.format("%s_%s", prefix, name); + } + + default boolean equalsWithConfigOrLearned(@Nonnull final String learnedPrefix, @Nonnull final String searched, + @Nonnull final String name) { + return searched.equals(name) || searched.equals(nameWithPrefix(learnedPrefix, name)); + } + + /** + * Resolve if provided {@link FibPath} should be considered as special hop. + * Special hop is hop that has any of special flags turned on(drop,local,prohibit,unreachable) + */ + default boolean isSpecialHop(@Nonnull final FibPath path) { + return byteToBoolean(path.isDrop) || byteToBoolean(path.isLocal) || byteToBoolean(path.isProhibit) || + byteToBoolean(path.isUnreach); + } + + default SpecialNextHopGrouping.SpecialNextHop specialHopType(final FibPath singlePath) { + if (flagEnabled(singlePath.isDrop)) { + return SpecialNextHopGrouping.SpecialNextHop.Blackhole; + } else if (flagEnabled(singlePath.isLocal)) { + return SpecialNextHopGrouping.SpecialNextHop.Receive; + } else if (flagEnabled(singlePath.isProhibit)) { + return SpecialNextHopGrouping.SpecialNextHop.Prohibit; + } else if (flagEnabled(singlePath.isUnreach)) { + return SpecialNextHopGrouping.SpecialNextHop.Unreachable; + } else { + throw new IllegalArgumentException( + String.format("An attempt to resolve illegal path %s detected ", singlePath.toString())); + } + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv4RouteCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv4RouteCustomizer.java new file mode 100644 index 000000000..6252b8d3a --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv4RouteCustomizer.java @@ -0,0 +1,213 @@ +/* + * 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.routing.write; + +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.naming.Ipv4RouteNamesFactory; +import io.fd.hc2vpp.routing.trait.RouteMapper; +import io.fd.hc2vpp.routing.write.factory.MultipathHopRequestFactory; +import io.fd.hc2vpp.routing.write.factory.SimpleHopRequestFactory; +import io.fd.hc2vpp.routing.write.factory.SpecialNextHopRequestFactory; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.translate.MappingContext; +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.vpp.jvpp.core.dto.IpAddDelRoute; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for handling write operations for {@link Ipv4} according to ietf-ipv4-unicast-routing.yang + */ +public class Ipv4RouteCustomizer extends FutureJVppCustomizer + implements ListWriterCustomizer<Route, RouteKey>, JvppReplyConsumer, RouteMapper { + + private static final Logger LOG = LoggerFactory.getLogger(Ipv4RouteCustomizer.class); + + + private final NamingContext routesContext; + private final MultiNamingContext routesHopsContext; + /** + * Request factories + */ + private final SimpleHopRequestFactory simpleHopRequestFactory; + private final MultipathHopRequestFactory multipathHopRequestFactory; + private final SpecialNextHopRequestFactory specialNextHopRequestFactory; + + /** + * Names factory + */ + private final Ipv4RouteNamesFactory routeNamesFactory; + + public Ipv4RouteCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext routesContext, + @Nonnull final NamingContext routingProtocolContext, + @Nonnull final MultiNamingContext routesHopsContext, + @Nonnull final VppClassifierContextManager classifierContextManager) { + super(futureJVppCore); + + this.routesContext = routesContext; + this.routesHopsContext = routesHopsContext; + simpleHopRequestFactory = + SimpleHopRequestFactory.forContexts(classifierContextManager, interfaceContext, routingProtocolContext); + multipathHopRequestFactory = MultipathHopRequestFactory + .forContexts(classifierContextManager, interfaceContext, routingProtocolContext); + specialNextHopRequestFactory = SpecialNextHopRequestFactory.forClassifierContext(classifierContextManager); + routeNamesFactory = new Ipv4RouteNamesFactory(interfaceContext, routingProtocolContext); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier, + @Nonnull final Route route, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + final String parentProtocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName(); + final String routeName = routeNamesFactory.uniqueRouteName(parentProtocolName, route); + writeRoute(instanceIdentifier, parentProtocolName, routeName, route, writeContext, true); + + // maps new route by next available index, + routesContext.addName(routeName, writeContext.getMappingContext()); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier, + @Nonnull final Route routeBefore, + @Nonnull final Route routeAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + throw new WriteFailedException.UpdateFailedException(instanceIdentifier, routeBefore, routeAfter, + new UnsupportedOperationException("Operation not supported")); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier, + @Nonnull final Route route, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + final String parentProtocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName(); + final String routeName = routeNamesFactory.uniqueRouteName(parentProtocolName, route); + writeRoute(instanceIdentifier, parentProtocolName, routeName, route, writeContext, false); + routesContext.removeName(routeName, writeContext.getMappingContext()); + } + + private void writeRoute(@Nonnull final InstanceIdentifier<Route> identifier, + @Nonnull final String parentProtocolName, + @Nonnull final String routeName, + @Nonnull final Route route, + @Nonnull final WriteContext writeContext, + final boolean isAdd) throws WriteFailedException { + if (route.getNextHopOptions() instanceof SimpleNextHop) { + writeRoute( + simpleHopRequestFactory.createIpv4SimpleHopRequest(isAdd, parentProtocolName, route, + writeContext.getMappingContext()), + identifier); + } else if (route.getNextHopOptions() instanceof NextHopList) { + final List<NextHop> createdHops = + writeMultihopRoute(identifier, parentProtocolName, route, writeContext, isAdd); + + // after all hops has been added, add mappings to preserve hop ids, or remove them + if (isAdd) { + addMappingForEachHop(routeName, writeContext, createdHops); + } else { + removeMappingForEachHop(routeName, writeContext, createdHops); + } + } else if (route.getNextHopOptions() instanceof SpecialNextHop) { + writeSpecialHopRoute(identifier, route, writeContext, isAdd); + } else { + throw new IllegalArgumentException("Unsupported next-hop type"); + } + } + + private void removeMappingForEachHop(final @Nonnull String routeName, final @Nonnull WriteContext writeContext, + final List<NextHop> createdHops) { + createdHops.forEach(nextHop -> routesHopsContext.removeChild(routeName, + routeNamesFactory.uniqueRouteHopName(nextHop), + writeContext.getMappingContext())); + } + + private void addMappingForEachHop(final @Nonnull String routeName, final @Nonnull WriteContext writeContext, + final List<NextHop> createdHops) { + createdHops.forEach(nextHop -> routesHopsContext.addChild(routeName, + nextHop.getId().intValue(), + routeNamesFactory.uniqueRouteHopName(nextHop), + writeContext.getMappingContext())); + } + + private List<NextHop> writeMultihopRoute(@Nonnull final InstanceIdentifier<Route> identifier, + @Nonnull final String parentProtocolName, + @Nonnull final Route route, + @Nonnull final WriteContext writeContext, + final boolean isAdd) + throws WriteFailedException { + // list of next hops + final NextHopList hopList = NextHopList.class.cast(route.getNextHopOptions()); + final MappingContext mappingContext = writeContext.getMappingContext(); + LOG.debug("Writing hop list {} for route {}", hopList, identifier); + + // order hops to preserve order by ids(even that model is not ordered) + final List<NextHop> orderedHops = hopList.getNextHopList().getNextHop() + .stream() + .sorted((left, right) -> (int) (left.getId() - right.getId())) + .collect(Collectors.toList()); + + for (NextHop hop : orderedHops) { + LOG.debug("Writing hop {} for route {}", hop, identifier); + + final IpAddDelRoute request = multipathHopRequestFactory + .createIpv4MultipathHopRequest(isAdd, parentProtocolName, route, hop, mappingContext); + + writeRoute(request, identifier); + } + + return orderedHops; + } + + + private void writeSpecialHopRoute(final @Nonnull InstanceIdentifier<Route> identifier, final @Nonnull Route route, + final @Nonnull WriteContext writeContext, final boolean isAdd) + throws WriteFailedException { + final SpecialNextHop hop = SpecialNextHop.class.cast(route.getNextHopOptions()); + final MappingContext mappingContext = writeContext.getMappingContext(); + + final IpAddDelRoute request = specialNextHopRequestFactory + .createIpv4SpecialHopRequest(isAdd, route, mappingContext, hop.getSpecialNextHop()); + + writeRoute(request, identifier); + } + + + private void writeRoute(final IpAddDelRoute request, final InstanceIdentifier<Route> identifier) + throws WriteFailedException { + LOG.debug("Writing request {} for path {}", request, identifier); + getReplyForWrite(getFutureJVpp().ipAddDelRoute(request).toCompletableFuture(), identifier); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv4WriteRoutingNodes.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv4WriteRoutingNodes.java new file mode 100644 index 000000000..a7a7e94b6 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv4WriteRoutingNodes.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.routing.write; + +import com.google.common.collect.ImmutableSet; +import java.util.Set; +import java.util.stream.Collectors; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes1Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes2; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.NextHopOptions; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4RouteBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopListBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHopKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public interface Ipv4WriteRoutingNodes { + + Ipv4WriteRoutingNodes INSTANCE = new Ipv4WriteRoutingNodes() { + }; + + Class<StaticRoutes1> CONFIG_IPV4_AUG_CLASS = StaticRoutes1.class; + Class<StaticRoutes2> STATE_IPV4_AUG_CLASS = StaticRoutes2.class; + + static Ipv4 mapIpv4( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4 state) { + return new Ipv4Builder() + .setRoute(state.getRoute() + .stream() + .map(route -> new RouteBuilder() + .setKey(new RouteKey(route.getKey().getId())) + .setDestinationPrefix(route.getDestinationPrefix()) + .setDescription(route.getDescription()) + .setId(route.getId()) + .setVppIpv4Route(mapVppIpv4Route(route.getVppIpv4RouteState())) + .setNextHopOptions(mapNextHopOptions(route.getNextHopOptions())) + .build()) + .collect(Collectors.toList())) + .build(); + } + + static VppIpv4Route mapVppIpv4Route( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4RouteState state) { + + return state == null + ? null + : new VppIpv4RouteBuilder() + // false is default + .setSecondaryVrf(state.getSecondaryVrf()) + .setClassifyTable(state.getClassifyTable()) + .build(); + } + + static NextHopOptions mapNextHopOptions( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.NextHopOptions state) { + if (state instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop) { + return mapSimpleNextHop( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop.class + .cast(state)); + } else if (state instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList) { + return mapNextHopList( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList.class + .cast(state)); + } else if (state instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop) { + return mapSpecialNextHop( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop.class + .cast(state)); + } else { + throw new UnsupportedOperationException("Unsupported next hop type"); + } + } + + static SimpleNextHop mapSimpleNextHop( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop hop) { + return new SimpleNextHopBuilder() + .setNextHop(hop.getNextHop()) + .setOutgoingInterface(hop.getOutgoingInterface()) + .build(); + } + + static NextHopList mapNextHopList( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList state) { + return new NextHopListBuilder() + .setNextHopList(mapNextHopListList(state.getNextHopList())) + .build(); + } + + static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopList mapNextHopListList( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopList state) { + return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopListBuilder() + .setNextHop(state.getNextHop() + .stream() + .map(nextHop -> new NextHopBuilder() + .setId(nextHop.getId()) + .setOutgoingInterface(nextHop.getOutgoingInterface()) + .setWeight(nextHop.getWeight()) + .setPriority(nextHop.getPriority()) + .setAddress(nextHop.getAddress()) + .setKey(new NextHopKey(nextHop.getKey().getId())) + .build()) + .collect(Collectors.toList())) + .build(); + } + + static SpecialNextHop mapSpecialNextHop( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop hop) { + return new SpecialNextHopBuilder() + .setSpecialNextHop(hop.getSpecialNextHop()) + .build(); + } + + default InstanceIdentifier<Route> ipv4RouteIdentifier( + final InstanceIdentifier<StaticRoutes> staticRoutesIdentifier) { + return staticRoutesIdentifier + .augmentation(StaticRoutes1.class) + .child(Ipv4.class) + .child(Route.class); + } + + default Set<InstanceIdentifier<?>> ipv4RoutingHandledChildren(final InstanceIdentifier<Route> parent) { + return ImmutableSet.of(parent + .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopList.class), + parent.child( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopList.class) + .child(NextHop.class), + parent.child(VppIpv4Route.class)); + } + + default InstanceIdentifier<Route> ipv4RouteSubtree() { + return InstanceIdentifier.create(Route.class); + } + + default StaticRoutes1 mapIpv4Augmentation(final StaticRoutes2 state) { + if (state == null) { + return null; + } + return new StaticRoutes1Builder() + .setIpv4(mapIpv4(state.getIpv4())) + .build(); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv6RouteCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv6RouteCustomizer.java new file mode 100644 index 000000000..aa7138624 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv6RouteCustomizer.java @@ -0,0 +1,211 @@ +/* + * 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.routing.write; + + +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.naming.Ipv6RouteNamesFactory; +import io.fd.hc2vpp.routing.trait.RouteMapper; +import io.fd.hc2vpp.routing.write.factory.MultipathHopRequestFactory; +import io.fd.hc2vpp.routing.write.factory.SimpleHopRequestFactory; +import io.fd.hc2vpp.routing.write.factory.SpecialNextHopRequestFactory; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.translate.MappingContext; +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.vpp.jvpp.core.dto.IpAddDelRoute; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for handling write operations for {@link Ipv6} according to ietf-ipv6-unicast-routing.yang + */ +public class Ipv6RouteCustomizer extends FutureJVppCustomizer + implements ListWriterCustomizer<Route, RouteKey>, JvppReplyConsumer, RouteMapper { + + private static final Logger LOG = LoggerFactory.getLogger(Ipv6RouteCustomizer.class); + + private final NamingContext routesContext; + private final MultiNamingContext routesHopsContext; + /** + * Request factories + */ + private final SimpleHopRequestFactory simpleHopRequestFactory; + private final MultipathHopRequestFactory multipathHopRequestFactory; + private final SpecialNextHopRequestFactory specialNextHopRequestFactory; + + /** + * Naming factory + */ + private final Ipv6RouteNamesFactory namesFactory; + + public Ipv6RouteCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext routesContext, + @Nonnull final NamingContext routingProtocolContext, + @Nonnull final MultiNamingContext routesHopsContext, + @Nonnull final VppClassifierContextManager classifierContextManager) { + super(futureJVppCore); + + this.routesContext = routesContext; + this.routesHopsContext = routesHopsContext; + simpleHopRequestFactory = + SimpleHopRequestFactory.forContexts(classifierContextManager, interfaceContext, routingProtocolContext); + multipathHopRequestFactory = MultipathHopRequestFactory + .forContexts(classifierContextManager, interfaceContext, routingProtocolContext); + specialNextHopRequestFactory = SpecialNextHopRequestFactory.forClassifierContext(classifierContextManager); + namesFactory = new Ipv6RouteNamesFactory(interfaceContext, routingProtocolContext); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier, + @Nonnull final Route route, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + final String parentProtocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName(); + final String routeName = namesFactory.uniqueRouteName(parentProtocolName, route); + writeRoute(instanceIdentifier, parentProtocolName, routeName, route, writeContext, true); + + // maps new route by next available index, + routesContext.addName(routeName, writeContext.getMappingContext()); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier, + @Nonnull final Route route, + @Nonnull final Route d1, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + throw new WriteFailedException(instanceIdentifier, + new UnsupportedOperationException("Operation not supported")); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier, + @Nonnull final Route route, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + final String parentProtocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName(); + final String routeName = namesFactory.uniqueRouteName(parentProtocolName, route); + writeRoute(instanceIdentifier, parentProtocolName, routeName, route, writeContext, false); + routesContext.removeName(routeName, writeContext.getMappingContext()); + } + + private void writeRoute(@Nonnull final InstanceIdentifier<Route> identifier, + @Nonnull final String parentProtocolName, + @Nonnull final String routeName, + @Nonnull final Route route, + @Nonnull final WriteContext writeContext, + final boolean isAdd) throws WriteFailedException { + if (route.getNextHopOptions() instanceof SimpleNextHop) { + writeRoute( + simpleHopRequestFactory.createIpv6SimpleHopRequest(isAdd, parentProtocolName, route, + writeContext.getMappingContext()), + identifier); + } else if (route.getNextHopOptions() instanceof NextHopList) { + final List<NextHop> createdHops = + writeMultihopRoute(identifier, parentProtocolName, route, writeContext, isAdd); + + // after all hops has been added, add mappings to preserve hop ids, or remove them + if (isAdd) { + addMappingForEachHop(routeName, writeContext, createdHops); + } else { + removeMappingForEachHop(routeName, writeContext, createdHops); + } + } else if (route.getNextHopOptions() instanceof SpecialNextHop) { + writeSpecialHopRoute(identifier, route, writeContext, isAdd); + } else { + throw new IllegalArgumentException("Unsupported next-hop type"); + } + } + + private List<NextHop> writeMultihopRoute(final InstanceIdentifier<Route> identifier, + final String parentProtocolName, + final Route route, + final WriteContext writeContext, final boolean isAdd) + throws WriteFailedException { + // list of next hops + final NextHopList hopList = NextHopList.class.cast(route.getNextHopOptions()); + final MappingContext mappingContext = writeContext.getMappingContext(); + LOG.debug("Writing hop list {} for route {}", hopList, identifier); + + // order hops to preserve order by ids(even that model is not ordered) + final List<NextHop> orderedHops = hopList.getNextHopList().getNextHop() + .stream() + .sorted((left, right) -> (int) (left.getId() - right.getId())) + .collect(Collectors.toList()); + + for (NextHop hop : orderedHops) { + LOG.debug("Writing hop {} for route {}", hop, identifier); + + final IpAddDelRoute request = multipathHopRequestFactory + .createIpv6MultipathHopRequest(isAdd, parentProtocolName, route, hop, mappingContext); + + writeRoute(request, identifier); + } + + return orderedHops; + } + + + private void writeSpecialHopRoute(final @Nonnull InstanceIdentifier<Route> identifier, final @Nonnull Route route, + final @Nonnull WriteContext writeContext, final boolean isAdd) + throws WriteFailedException { + final SpecialNextHop hop = SpecialNextHop.class.cast(route.getNextHopOptions()); + final MappingContext mappingContext = writeContext.getMappingContext(); + + final IpAddDelRoute request = specialNextHopRequestFactory + .createIpv6SpecialHopRequest(isAdd, route, mappingContext, hop.getSpecialNextHop()); + + writeRoute(request, identifier); + } + + private void writeRoute(final IpAddDelRoute request, final InstanceIdentifier<Route> identifier) + throws WriteFailedException { + LOG.debug("Writing request {} for path {}", request, identifier); + getReplyForWrite(getFutureJVpp().ipAddDelRoute(request).toCompletableFuture(), identifier); + } + + private void removeMappingForEachHop(final @Nonnull String routeName, final @Nonnull WriteContext writeContext, + final List<NextHop> createdHops) { + createdHops.forEach(nextHop -> routesHopsContext.removeChild(routeName, + namesFactory.uniqueRouteHopName(nextHop), + writeContext.getMappingContext())); + } + + private void addMappingForEachHop(final @Nonnull String routeName, final @Nonnull WriteContext writeContext, + final List<NextHop> createdHops) { + createdHops.forEach(nextHop -> routesHopsContext.addChild(routeName, + nextHop.getId().intValue(), + namesFactory.uniqueRouteHopName(nextHop), + writeContext.getMappingContext())); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv6WriteRoutingNodes.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv6WriteRoutingNodes.java new file mode 100644 index 000000000..2c9bbada2 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv6WriteRoutingNodes.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.write; + +import com.google.common.collect.ImmutableSet; +import java.util.Set; +import java.util.stream.Collectors; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes2; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.NextHopOptions; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6RouteBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopListBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopList; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHopKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + + +public interface Ipv6WriteRoutingNodes { + + Ipv6WriteRoutingNodes INSTANCE = new Ipv6WriteRoutingNodes() { + }; + + Class<StaticRoutes1> CONFIG_IPV6_AUG_CLASS = StaticRoutes1.class; + Class<StaticRoutes2> STATE_IPV6_AUG_CLASS = StaticRoutes2.class; + + static Ipv6 mapIpv6( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6 state) { + return new Ipv6Builder() + .setRoute(state.getRoute() + .stream() + .map(route -> new RouteBuilder() + .setKey(new RouteKey(route.getKey().getId())) + .setDestinationPrefix(route.getDestinationPrefix()) + .setDescription(route.getDescription()) + .setId(route.getId()) + .setVppIpv6Route(mapVppIpv6Route(route.getVppIpv6RouteState())) + .setNextHopOptions(mapNextHopOptions(route.getNextHopOptions())) + .build()) + .collect(Collectors.toList())) + .build(); + } + + static VppIpv6Route mapVppIpv6Route( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6RouteState state) { + return state == null + ? null + : new VppIpv6RouteBuilder() + .setSecondaryVrf(state.getSecondaryVrf()) + .setClassifyTable(state.getClassifyTable()) + .build(); + } + + static NextHopOptions mapNextHopOptions( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.NextHopOptions state) { + if (state instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop) { + return mapSimpleNextHop( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop.class + .cast(state)); + } else if (state instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList) { + return mapNextHopList( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList.class + .cast(state)); + } else if (state instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop) { + return mapSpecialNextHop( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop.class + .cast(state)); + } else { + throw new UnsupportedOperationException("Unsupported next hop type"); + } + } + + static SimpleNextHop mapSimpleNextHop( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop hop) { + return new SimpleNextHopBuilder() + .setNextHop(hop.getNextHop()) + .setOutgoingInterface(hop.getOutgoingInterface()) + .build(); + } + + static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList mapNextHopList( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList state) { + return new NextHopListBuilder() + .setNextHopList(mapNextHopListList(state.getNextHopList())) + .build(); + } + + static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopList mapNextHopListList( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopList state) { + return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopListBuilder() + .setNextHop(state.getNextHop() + .stream() + .map(nextHop -> new NextHopBuilder() + .setId(nextHop.getId()) + .setOutgoingInterface(nextHop.getOutgoingInterface()) + .setWeight(nextHop.getWeight()) + .setPriority(nextHop.getPriority()) + .setAddress(nextHop.getAddress()) + .setKey(new NextHopKey(nextHop.getKey().getId())) + .build()) + .collect(Collectors.toList())) + .build(); + } + + static SpecialNextHop mapSpecialNextHop( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop hop) { + return new SpecialNextHopBuilder() + .setSpecialNextHop(hop.getSpecialNextHop()) + .build(); + } + + default InstanceIdentifier<Route> ipv6RouteIdentifier( + final InstanceIdentifier<StaticRoutes> staticRoutesIdentifier) { + return staticRoutesIdentifier + .augmentation(StaticRoutes1.class) + .child(Ipv6.class) + .child(Route.class); + } + + default InstanceIdentifier<Route> ipv6RouteSubtree() { + return InstanceIdentifier + .create(Route.class); + } + + default Set<InstanceIdentifier<?>> ipv6RoutingHandledChildren( + final InstanceIdentifier<Route> parent) { + return ImmutableSet.of(parent.child(NextHopList.class), + parent.child(NextHopList.class).child(NextHop.class), + parent.child(VppIpv6Route.class)); + } + + default org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1 mapIpv6Augmentation( + final StaticRoutes2 state) { + if (state == null) { + return null; + } + return new StaticRoutes1Builder() + .setIpv6(mapIpv6(state.getIpv6())) + .build(); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingCustomizer.java new file mode 100644 index 000000000..bd50ce77b --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingCustomizer.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.write; + +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.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Routing; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Dummy customizer for Root node,to "handle" non-operational changes + */ +public class RoutingCustomizer implements WriterCustomizer<Routing> { + + private static final Logger LOG = LoggerFactory.getLogger(RoutingCustomizer.class); + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> instanceIdentifier, + @Nonnull final Routing routing, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Writing {}", instanceIdentifier); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> instanceIdentifier, + @Nonnull final Routing before, @Nonnull final Routing after, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + LOG.debug("Updating {} to {}", instanceIdentifier, after); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> instanceIdentifier, + @Nonnull final Routing routing, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Removing {}", instanceIdentifier); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingInstanceCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingInstanceCustomizer.java new file mode 100644 index 000000000..fa6885d5d --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingInstanceCustomizer.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.write; + +import static com.google.common.base.Preconditions.checkArgument; + +import io.fd.hc2vpp.routing.RoutingConfiguration; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstance; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstanceKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Only ensures that requests are written under singleton instance + */ +public class RoutingInstanceCustomizer implements ListWriterCustomizer<RoutingInstance, RoutingInstanceKey> { + + private final RoutingConfiguration configuration; + + public RoutingInstanceCustomizer(@Nonnull final RoutingConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingInstance> id, + @Nonnull final RoutingInstance dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + checkSingletonInstance(dataAfter); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingInstance> id, + @Nonnull final RoutingInstance dataBefore, + @Nonnull final RoutingInstance dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, + new UnsupportedOperationException("Operation not supported")); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingInstance> id, + @Nonnull final RoutingInstance dataBefore, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + checkSingletonInstance(dataBefore); + } + + private void checkSingletonInstance(final RoutingInstance data) { + final String defaultRoutingInstanceName = configuration.getDefaultRoutingInstanceName(); + final String instanceName = data.getName(); + + checkArgument(defaultRoutingInstanceName.equals(instanceName), + "Attempt to write/delete data for different than default routing instance detected." + + "Vpp allows only single instance, configured with name %s, request contains name %s", + defaultRoutingInstanceName, instanceName); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingProtocolCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingProtocolCustomizer.java new file mode 100644 index 000000000..220f07690 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingProtocolCustomizer.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.write; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Static; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocolKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolVppAttr; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Customizer for handling of write operations for {@link RoutingProtocol} + */ +public class RoutingProtocolCustomizer + implements ListWriterCustomizer<RoutingProtocol, RoutingProtocolKey> { + + private final NamingContext routingProtocolContext; + + public RoutingProtocolCustomizer(@Nonnull final NamingContext routingProtocolContext) { + this.routingProtocolContext = routingProtocolContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingProtocol> instanceIdentifier, + @Nonnull final RoutingProtocol routingProtocol, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + checkIsStatic(routingProtocol); + + final int tableId = extractTableId(routingProtocol); + final MappingContext mappingContext = writeContext.getMappingContext(); + final String newProtocolName = routingProtocol.getName(); + + // enclosed in synchronized block to prevent change of state after containsName/before addName + synchronized (routingProtocolContext) { + if (!routingProtocolContext.containsName(tableId, mappingContext)) { + // if not present in mapping,create assignment to table id. This works only with auto-create flag enabled + // while using ip_add_del_table + routingProtocolContext.addName(tableId, newProtocolName, mappingContext); + } else { + throw new IllegalStateException(String.format( + "An attempt to assign protocol %s to table id %s. Table id already assigned to protocol %s", + newProtocolName, tableId, routingProtocolContext.getName(tableId, mappingContext))); + } + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingProtocol> instanceIdentifier, + @Nonnull final RoutingProtocol routingProtocolBefore, + @Nonnull final RoutingProtocol routingProtocolAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + throw new WriteFailedException.UpdateFailedException(instanceIdentifier, routingProtocolBefore, + routingProtocolAfter, new UnsupportedOperationException("Operation not supported")); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingProtocol> instanceIdentifier, + @Nonnull final RoutingProtocol routingProtocol, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + routingProtocolContext.removeName(routingProtocol.getName(), writeContext.getMappingContext()); + } + + /** + * Checks whether routing protocol is static(we support only static ones for now) + */ + private void checkIsStatic(final RoutingProtocol routingProtocol) { + checkArgument(routingProtocol.getType() == Static.class, "Only static routes are allowed"); + } + + private int extractTableId(final RoutingProtocol protocol) { + final RoutingProtocolVppAttr vppAttr = protocol.getAugmentation(RoutingProtocolVppAttr.class); + + checkState(vppAttr != null && vppAttr.getVppProtocolAttributes() != null, + "Vpp routing protocol attributes not defined"); + + return vppAttr.getVppProtocolAttributes().getPrimaryVrf().getValue().intValue(); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingWriterFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingWriterFactory.java new file mode 100644 index 000000000..02fa7d1b2 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingWriterFactory.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.write; + +import static io.fd.hc2vpp.routing.RoutingConfiguration.ROUTE_CONTEXT; +import static io.fd.hc2vpp.routing.RoutingConfiguration.ROUTE_HOP_CONTEXT; +import static io.fd.hc2vpp.routing.RoutingConfiguration.ROUTING_PROTOCOL_CONTEXT; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.RoutingConfiguration; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.translate.impl.write.GenericWriter; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.Set; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Routing; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstance; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.RoutingProtocols; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolVppAttr; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.routing.routing.instance.routing.protocols.routing.protocol.VppProtocolAttributes; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Factory producing writers for routing plugin's data. + */ +public final class RoutingWriterFactory implements WriterFactory, Ipv4WriteRoutingNodes, Ipv6WriteRoutingNodes { + + private static final InstanceIdentifier<Routing> ROOT_CONTAINER_ID = InstanceIdentifier.create(Routing.class); + + @Inject + private FutureJVppCore vppApi; + + @Inject + private RoutingConfiguration configuration; + + @Inject + @Named("interface-context") + private NamingContext interfaceContext; + + @Inject + @Named(ROUTING_PROTOCOL_CONTEXT) + private NamingContext routingProtocolContext; + + @Inject + @Named(ROUTE_CONTEXT) + private NamingContext routeContext; + + @Inject + @Named("classify-table-context") + private VppClassifierContextManager vppClassifierContextManager; + + @Inject + @Named(ROUTE_HOP_CONTEXT) + private MultiNamingContext routHopContext; + + @Override + public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { + + registry.subtreeAdd(rootNodeHandledChildren(ROOT_CONTAINER_ID), + new GenericWriter<>(ROOT_CONTAINER_ID, new RoutingCustomizer())); + + registry.add(new GenericWriter<>(routingInstanceIdentifier(), new RoutingInstanceCustomizer(configuration))); + + registry.subtreeAdd(routingProtocolHandledChildren(),new GenericWriter<>(routingProtocolIdentifier(), + new RoutingProtocolCustomizer(routingProtocolContext))); + + final InstanceIdentifier<StaticRoutes> staticRoutesInstanceIdentifier = staticRoutesIdentifier(); + final InstanceIdentifier<Route> ipv4RouteIdentifier = ipv4RouteIdentifier(staticRoutesInstanceIdentifier); + final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route> + ipv6RouteIdentifier = ipv6RouteIdentifier(staticRoutesInstanceIdentifier); + registry.subtreeAdd(ipv4RoutingHandledChildren(ipv4RouteSubtree()), new GenericWriter<>(ipv4RouteIdentifier, + new Ipv4RouteCustomizer(vppApi, interfaceContext, routeContext, routingProtocolContext, routHopContext, + vppClassifierContextManager))); + registry.subtreeAdd(ipv6RoutingHandledChildren(ipv6RouteSubtree()), new GenericWriter<>(ipv6RouteIdentifier, + new Ipv6RouteCustomizer(vppApi, interfaceContext, routeContext, routingProtocolContext, routHopContext, + vppClassifierContextManager))); + } + + private static ImmutableSet<InstanceIdentifier<?>> routingProtocolHandledChildren() { + return ImmutableSet + .of(InstanceIdentifier.create(RoutingProtocol.class).augmentation(RoutingProtocolVppAttr.class).child(VppProtocolAttributes.class)); + } + + private static InstanceIdentifier<RoutingInstance> routingInstanceIdentifier() { + return ROOT_CONTAINER_ID.child(RoutingInstance.class); + } + + private static InstanceIdentifier<RoutingProtocol> routingProtocolIdentifier() { + return routingInstanceIdentifier().child(RoutingProtocols.class).child(RoutingProtocol.class); + } + + private static InstanceIdentifier<StaticRoutes> staticRoutesIdentifier() { + return routingProtocolIdentifier().child(StaticRoutes.class); + } + + private static Set<InstanceIdentifier<?>> rootNodeHandledChildren(final InstanceIdentifier<Routing> parent) { + return ImmutableSet.of(parent.child(RoutingInstance.class).child(RoutingProtocols.class)); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactory.java new file mode 100644 index 000000000..4599c8b82 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactory.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.write.factory; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.write.factory.base.BasicHopRequestFactory; +import io.fd.hc2vpp.routing.write.trait.RouteRequestProducer; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.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.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6Route; + + +/** + * Factory for creating requests to create route with multiple hops + */ +public class MultipathHopRequestFactory extends BasicHopRequestFactory implements RouteRequestProducer { + + private MultipathHopRequestFactory(final VppClassifierContextManager classifierContextManager, + final NamingContext interfaceContext, + final NamingContext routingProtocolContext) { + super(classifierContextManager, interfaceContext, routingProtocolContext); + } + + public static MultipathHopRequestFactory forContexts( + @Nonnull final VppClassifierContextManager classifierContextManager, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext routingProtocolContext) { + return new MultipathHopRequestFactory(classifierContextManager, interfaceContext, routingProtocolContext); + } + + public IpAddDelRoute createIpv4MultipathHopRequest(final boolean add, + @Nonnull final String parentProtocolName, + @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route route, + @Nonnull final NextHop hop, + @Nonnull final MappingContext mappingContext) { + + final VppIpv4Route routingAttributes = checkNotNull(route.getVppIpv4Route(), "VppIpv4Route not defined"); + + final int nextHopInterfaceIndex = + getInterfaceNamingContext().getIndex(hop.getOutgoingInterface(), mappingContext); + + if (classifyTablePresent(routingAttributes.getClassifyTable(), getVppClassifierContextManager(), + mappingContext)) { + return getMultipathHopRequest(add, + route.getDestinationPrefix(), + nextHopInterfaceIndex, + hop.getAddress(), + toByte(hop.getWeight()), + getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext), + optionalVni(routingAttributes.getSecondaryVrf()), + classifyTableIndex(routingAttributes.getClassifyTable(), getVppClassifierContextManager(), + mappingContext), + true); + } else { + return getMultipathHopRequest(add, + route.getDestinationPrefix(), + nextHopInterfaceIndex, + hop.getAddress(), + toByte(hop.getWeight()), + getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext), + optionalVni(routingAttributes.getSecondaryVrf()), + 0, + false); + } + } + + public IpAddDelRoute createIpv6MultipathHopRequest(final boolean add, + @Nonnull final String parentProtocolName, + @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route route, + @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop hop, + @Nonnull final MappingContext mappingContext) { + final VppIpv6Route routingAttributes = checkNotNull(route.getVppIpv6Route(), "VppIpv6Route not defined"); + + final int nextHopInterfaceIndex = + getInterfaceNamingContext().getIndex(hop.getOutgoingInterface(), mappingContext); + + if (classifyTablePresent(routingAttributes.getClassifyTable(), getVppClassifierContextManager(), + mappingContext)) { + return getMultipathHopRequest(add, + route.getDestinationPrefix(), + nextHopInterfaceIndex, + hop.getAddress(), + toByte(hop.getWeight()), + getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext), + optionalVni(routingAttributes.getSecondaryVrf()), + classifyTableIndex(routingAttributes.getClassifyTable(), getVppClassifierContextManager(), + mappingContext), + true); + } else { + return getMultipathHopRequest(add, + route.getDestinationPrefix(), + nextHopInterfaceIndex, + hop.getAddress(), + toByte(hop.getWeight()), + getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext), + optionalVni(routingAttributes.getSecondaryVrf()), + 0, + false); + } + } + + + private IpAddDelRoute getMultipathHopRequest(final boolean isAdd, @Nonnull final Ipv6Prefix destinationAddress, + final int nextHopInterfaceIndex, + @Nonnull final Ipv6Address nextHopAddress, + final byte nextHopWeight, + final int primaryVrf, final int secondaryVrf, + final int classifyTableIndex, final boolean classifyIndexSet) { + return flaglessAddDelRouteRequest(booleanToByte(isAdd), nextHopInterfaceIndex, + ipv6AddressNoZoneToArray(nextHopAddress.getValue()), nextHopWeight, toByte(1), + ipv6AddressPrefixToArray(destinationAddress), extractPrefix(destinationAddress.getValue()), toByte(1), + primaryVrf, secondaryVrf, classifyTableIndex, + booleanToByte(classifyIndexSet)); + } + + private IpAddDelRoute getMultipathHopRequest(final boolean isAdd, @Nonnull final Ipv4Prefix destinationAddress, + final int nextHopInterfaceIndex, + @Nonnull final Ipv4Address nextHopAddress, + final byte nextHopWeight, + final int primaryVrf, final int secondaryVrf, + final int classifyTableIndex, final boolean classifyIndexSet) { + return flaglessAddDelRouteRequest(booleanToByte(isAdd), nextHopInterfaceIndex, + ipv4AddressNoZoneToArray(nextHopAddress.getValue()), nextHopWeight, toByte(0), + ipv4AddressPrefixToArray(destinationAddress), extractPrefix(destinationAddress.getValue()), toByte(1), + primaryVrf, secondaryVrf, classifyTableIndex, + booleanToByte(classifyIndexSet)); + } + + +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactory.java new file mode 100644 index 000000000..68a5f3d71 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactory.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.write.factory; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.write.factory.base.BasicHopRequestFactory; +import io.fd.hc2vpp.routing.write.trait.RouteRequestProducer; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.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.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6Route; + + +/** + * Factory for creating requests to create route with hop simple hop + */ +public class SimpleHopRequestFactory extends BasicHopRequestFactory implements RouteRequestProducer { + + private SimpleHopRequestFactory(final VppClassifierContextManager classifierContextManager, + final NamingContext interfaceContext, + final NamingContext routingProtocolContext) { + super(classifierContextManager, interfaceContext, routingProtocolContext); + } + + public static SimpleHopRequestFactory forContexts( + @Nonnull final VppClassifierContextManager classifierContextManager, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext routingProtocolContext) { + return new SimpleHopRequestFactory(classifierContextManager, interfaceContext, routingProtocolContext); + } + + public IpAddDelRoute createIpv4SimpleHopRequest(final boolean add, + @Nonnull final String parentProtocolName, + @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route route, + @Nonnull final MappingContext mappingContext) { + + final SimpleNextHop hop = SimpleNextHop.class.cast(route.getNextHopOptions()); + final VppIpv4Route routingAttributes = checkNotNull(route.getVppIpv4Route(), "VppIpv4Route not defined"); + final int nextHopInterfaceIndex = + getInterfaceNamingContext().getIndex(hop.getOutgoingInterface(), mappingContext); + + if (classifyTablePresent(routingAttributes.getClassifyTable(), getVppClassifierContextManager(), + mappingContext)) { + return getSimpleHopRequest(add, + route.getDestinationPrefix(), + nextHopInterfaceIndex, + hop.getNextHop(), + getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext), + optionalVni(routingAttributes.getSecondaryVrf()), + classifyTableIndex(routingAttributes.getClassifyTable(), getVppClassifierContextManager(), + mappingContext), + true); + } else { + return getSimpleHopRequest(add, + route.getDestinationPrefix(), + nextHopInterfaceIndex, + hop.getNextHop(), + getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext), + optionalVni(routingAttributes.getSecondaryVrf()), + 0, + false); + } + } + + public IpAddDelRoute createIpv6SimpleHopRequest(final boolean add, + @Nonnull final String parentProtocolName, + @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route route, + @Nonnull final MappingContext mappingContext) { + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop + hop = + (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop) route + .getNextHopOptions(); + final VppIpv6Route routingAttributes = checkNotNull(route.getVppIpv6Route(), "VppIpv6Route not defined"); + final int nextHopInterfaceIndex = + getInterfaceNamingContext().getIndex(hop.getOutgoingInterface(), mappingContext); + + if (classifyTablePresent(routingAttributes.getClassifyTable(), getVppClassifierContextManager(), + mappingContext)) { + return getSimpleHopRequest(add, + route.getDestinationPrefix(), + nextHopInterfaceIndex, + hop.getNextHop(), + getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext), + optionalVni(routingAttributes.getSecondaryVrf()), + classifyTableIndex(routingAttributes.getClassifyTable(), getVppClassifierContextManager(), + mappingContext), + true); + } else { + return getSimpleHopRequest(add, + route.getDestinationPrefix(), + nextHopInterfaceIndex, + hop.getNextHop(), + getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext), + optionalVni(routingAttributes.getSecondaryVrf()), + 0, + false); + } + } + + + private IpAddDelRoute getSimpleHopRequest(final boolean isAdd, @Nonnull final Ipv6Prefix destinationAddress, + final int nextHopInterfaceIndex, + @Nonnull final Ipv6Address nextHopAddress, + final int primaryVrf, final int secondaryVrf, + final int classifyTableIndex, final boolean classifyIndexSet) { + return flaglessAddDelRouteRequest(booleanToByte(isAdd), nextHopInterfaceIndex, + ipv6AddressNoZoneToArray(nextHopAddress.getValue()), DEFAULT_HOP_WEIGHT, BYTE_TRUE, + ipv6AddressPrefixToArray(destinationAddress), extractPrefix(destinationAddress.getValue()), BYTE_FALSE, + primaryVrf, secondaryVrf, classifyTableIndex, booleanToByte(classifyIndexSet)); + } + + private IpAddDelRoute getSimpleHopRequest(final boolean isAdd, @Nonnull final Ipv4Prefix destinationAddress, + final int nextHopInterfaceIndex, + @Nonnull final Ipv4Address nextHopAddress, + final int primaryVrf, final int secondaryVrf, + final int classifyTableIndex, final boolean classifyIndexSet) { + return flaglessAddDelRouteRequest(booleanToByte(isAdd), nextHopInterfaceIndex, + ipv4AddressNoZoneToArray(nextHopAddress.getValue()), DEFAULT_HOP_WEIGHT, BYTE_FALSE, + ipv4AddressPrefixToArray(destinationAddress), extractPrefix(destinationAddress.getValue()), BYTE_FALSE, + primaryVrf, secondaryVrf, classifyTableIndex, booleanToByte(classifyIndexSet)); + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactory.java new file mode 100644 index 000000000..2a5ab9821 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactory.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.write.factory; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.routing.write.factory.base.ClassifierContextHolder; +import io.fd.hc2vpp.routing.write.trait.RouteRequestProducer; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import javax.annotation.Nonnull; +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.Ipv6Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping; + +public class SpecialNextHopRequestFactory extends ClassifierContextHolder + implements RouteRequestProducer { + + private SpecialNextHopRequestFactory(final VppClassifierContextManager classifierContextManager) { + super(classifierContextManager); + } + + public static SpecialNextHopRequestFactory forClassifierContext( + @Nonnull final VppClassifierContextManager classifierContextManager) { + return new SpecialNextHopRequestFactory(classifierContextManager); + } + + public IpAddDelRoute createIpv4SpecialHopRequest(final boolean add, + @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route route, + @Nonnull final MappingContext mappingContext, + @Nonnull final SpecialNextHopGrouping.SpecialNextHop flagsVariant) { + checkNotNull(route, "Route cannot be null"); + checkNotNull(mappingContext, "Mapping Context cannot be null"); + checkNotNull(flagsVariant, "Flags variant cannot be null"); + + return resolveFlags(getSpecialHopRequest(add, route.getDestinationPrefix()), flagsVariant); + } + + public IpAddDelRoute createIpv6SpecialHopRequest(final boolean add, + @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route route, + @Nonnull final MappingContext mappingContext, + @Nonnull final SpecialNextHopGrouping.SpecialNextHop flagsVariant) { + + checkNotNull(route, "Route cannot be null"); + checkNotNull(mappingContext, "Mapping Context cannot be null"); + checkNotNull(flagsVariant, "Flags variant cannot be null"); + + return resolveFlags(getSpecialHopRequest(add, route.getDestinationPrefix()), flagsVariant); + } + + private IpAddDelRoute getSpecialHopRequest(final boolean isAdd, @Nonnull final Ipv6Prefix destinationAddress) { + + return flaglessAddDelRouteRequest(booleanToByte(isAdd), 0, null, DEFAULT_HOP_WEIGHT, BYTE_TRUE, + ipv6AddressPrefixToArray(destinationAddress), extractPrefix(destinationAddress.getValue()), BYTE_FALSE, + DEFAULT_VNI, DEFAULT_VNI, DEFAULT_CLASSIFY_TABLE_INDEX, BYTE_FALSE); + } + + private IpAddDelRoute getSpecialHopRequest(final boolean isAdd, @Nonnull final Ipv4Prefix destinationAddress) { + return flaglessAddDelRouteRequest(booleanToByte(isAdd), 0, null, DEFAULT_HOP_WEIGHT, BYTE_FALSE, + ipv4AddressPrefixToArray(destinationAddress), extractPrefix(destinationAddress.getValue()), BYTE_FALSE, + DEFAULT_VNI, DEFAULT_VNI, DEFAULT_CLASSIFY_TABLE_INDEX, BYTE_FALSE); + } + + private IpAddDelRoute resolveFlags(IpAddDelRoute request, + final SpecialNextHopGrouping.SpecialNextHop flagsVariant) { + switch (flagsVariant) { + case Blackhole: + return resolveAsBlackholeVariant(request); + case Unreachable: + return resolveAsUnreachableVariant(request); + case Prohibit: + return resolveAsProhibitedVariant(request); + case Receive: + return resolveAsReceiveVariant(request); + default: + throw new IllegalArgumentException("Unsupported type"); + } + } + + private IpAddDelRoute resolveAsBlackholeVariant(IpAddDelRoute request) { + return bindFlags(request, true, false, false, false); + } + + private IpAddDelRoute resolveAsReceiveVariant(IpAddDelRoute request) { + return bindFlags(request, false, true, false, false); + } + + private IpAddDelRoute resolveAsUnreachableVariant(IpAddDelRoute request) { + return bindFlags(request, false, false, true, false); + } + + private IpAddDelRoute resolveAsProhibitedVariant(IpAddDelRoute request) { + return bindFlags(request, false, false, false, true); + } + + private IpAddDelRoute bindFlags(IpAddDelRoute request, final boolean isDrop, final boolean isReceive, + final boolean isUnreachable, final boolean isProhibited) { + request.isDrop = booleanToByte(isDrop); + request.isLocal = booleanToByte(isReceive); + request.isUnreach = booleanToByte(isUnreachable); + request.isProhibit = booleanToByte(isProhibited); + + return request; + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/base/BasicHopRequestFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/base/BasicHopRequestFactory.java new file mode 100644 index 000000000..abaf0fa84 --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/base/BasicHopRequestFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.write.factory.base; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import javax.annotation.Nonnull; + +/** + * Extension to {@code ClassifierContextHolder} to hold also {@code NamingContext} + */ +public abstract class BasicHopRequestFactory extends ClassifierContextHolder { + + private final NamingContext interfaceNamingContext; + private final NamingContext routingProtocolContext; + + protected BasicHopRequestFactory( + @Nonnull final VppClassifierContextManager classifierContextManager, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext routingProtocolContext) { + super(classifierContextManager); + this.interfaceNamingContext = checkNotNull(interfaceContext, "Interface context cannot be null"); + this.routingProtocolContext = checkNotNull(routingProtocolContext, "Routing protocol context cannot be null"); + } + + protected NamingContext getInterfaceNamingContext() { + return interfaceNamingContext; + } + + protected NamingContext getRoutingProtocolContext() { + return routingProtocolContext; + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/base/ClassifierContextHolder.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/base/ClassifierContextHolder.java new file mode 100644 index 000000000..0b11a9b3b --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/base/ClassifierContextHolder.java @@ -0,0 +1,38 @@ +/* + * 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.routing.write.factory.base; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import javax.annotation.Nonnull; + +/** + * Holds reference for + */ +public abstract class ClassifierContextHolder { + + private final VppClassifierContextManager classifierContextManager; + + protected ClassifierContextHolder(@Nonnull final VppClassifierContextManager classifierContextManager) { + this.classifierContextManager = checkNotNull(classifierContextManager, "Classifier context cannot be null"); + } + + protected VppClassifierContextManager getVppClassifierContextManager() { + return this.classifierContextManager; + } +} diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/trait/RouteRequestProducer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/trait/RouteRequestProducer.java new file mode 100644 index 000000000..63ee5a13e --- /dev/null +++ b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/trait/RouteRequestProducer.java @@ -0,0 +1,138 @@ +/* + * 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.routing.write.trait; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.isNull; +import static org.apache.commons.lang3.StringUtils.isNotEmpty; + +import com.google.common.collect.ImmutableSet.Builder; +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import java.util.Set; +import java.util.regex.Pattern; +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.Ipv6Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.VniReference; + + +/** + * Common logic for writing of routes + */ +public interface RouteRequestProducer extends ByteDataTranslator, AddressTranslator, JvppReplyConsumer { + + Set<String> allowedPrefixPatterns = new Builder<String>().addAll(Ipv4Prefix.PATTERN_CONSTANTS) + .addAll(Ipv6Prefix.PATTERN_CONSTANTS).build(); + + byte DEFAULT_VNI = 0; + byte DEFAULT_CLASSIFY_TABLE_INDEX = 0; + byte DEFAULT_HOP_WEIGHT = 0; + + default int mandatoryVni(final VniReference vniReference) { + return checkNotNull(vniReference, "Vni reference cannot be null").getValue().intValue(); + } + + default int optionalVni(final VniReference vniReference) { + return isNull(vniReference) + ? DEFAULT_VNI + : vniReference.getValue().intValue(); + } + + default byte extractPrefix(final String value) { + checkArgument( + allowedPrefixPatterns.stream().anyMatch(pattern -> Pattern.compile(pattern).matcher(value).matches()), + "%s is not a valid Ip-prefix value"); + return Byte.valueOf(value.substring(value.indexOf("/") + 1)); + } + + default boolean classifyTablePresent(final String classifyTableName, + final VppClassifierContextManager classifierContextManager, + final MappingContext mappingContext) { + return isNotEmpty(classifyTableName) && + classifierContextManager.containsTable(classifyTableName, mappingContext); + } + + default int classifyTableIndex(final String classifyTableName, + final VppClassifierContextManager classifierContextManager, + final MappingContext mappingContext) { + return classifierContextManager.getTableIndex(classifyTableName, mappingContext); + } + + /** + * Creates fully bind {@code IpAddDelRoute} request + * + * @param add 1 if add,delete otherwise + * @param nextHopInterfaceIndex interface for <b>nextHopAddress</b> + * @param nextHopAddress address of hop + * @param nextHopWeight if <b>mutlipath</b>, then set to "order" hops + * @param ipv6 determine if writing ipv4/ipv6 route + * @param destinationAddress address of destination for hop + * @param destinationAddressPrefixLength prefix length of <b>destinationAddress</b> + * @param multipath You can only write one next-hop at a time. set this to true when you are + * adding paths/next-hops to an existing route. It can be true when adding a + * new route. + * @param primaryVrf primary vrf for configured route + * @param secondaryVrf lookup vrf for route + * @param classifyTableIndex index of classify table + * @param classifyTableSet set if classify table index was set + */ + default IpAddDelRoute flaglessAddDelRouteRequest(final byte add, + final int nextHopInterfaceIndex, + final byte[] nextHopAddress, + final byte nextHopWeight, + final byte ipv6, + final byte[] destinationAddress, + final byte destinationAddressPrefixLength, + final byte multipath, + final int primaryVrf, + final int secondaryVrf, + final int classifyTableIndex, + final byte classifyTableSet) { + + final IpAddDelRoute request = new IpAddDelRoute(); + request.isAdd = add; + request.nextHopSwIfIndex = nextHopInterfaceIndex; + request.dstAddress = destinationAddress; + request.dstAddressLength = destinationAddressPrefixLength; + request.isIpv6 = ipv6; + request.isMultipath = multipath; + request.nextHopAddress = nextHopAddress; + + // Model contains also priority but VPP does not support the concept of priority next-hops + request.nextHopWeight = nextHopWeight; + + // vrf_id - fib table /vrf associated with the route Not mentioned in model + request.tableId = primaryVrf; + + // create vrf if needed needs to be turned on all the time,due to how we map table ids on routing protocols + request.createVrfIfNeeded = 1; + + // nextHopTableId - this is used when you want to have a second lookup done in another table. + request.nextHopTableId = secondaryVrf; + + // classify_table_index + request.classifyTableIndex = classifyTableIndex; + request.isClassify = classifyTableSet; + + return request; + } +} diff --git a/routing/routing-impl/src/main/resources/honeycomb-minimal-resources/config/routing.json b/routing/routing-impl/src/main/resources/honeycomb-minimal-resources/config/routing.json new file mode 100644 index 000000000..95f85414f --- /dev/null +++ b/routing/routing-impl/src/main/resources/honeycomb-minimal-resources/config/routing.json @@ -0,0 +1,4 @@ +{ + "default-routing-instance-name": "vpp-routing-instance", + "learned-route-name-prefix": "learned-route" +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv4RouteData.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv4RouteData.java new file mode 100644 index 000000000..71072ba9a --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv4RouteData.java @@ -0,0 +1,23 @@ +/* + * 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.routing; + + +public class Ipv4RouteData { + public static final byte[] FIRST_ADDRESS_AS_ARRAY = {-64, -88, 2, 1}; + public static final byte[] SECOND_ADDRESS_AS_ARRAY = {-64, -88, 2, 2}; +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv4RouteNamesFactoryTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv4RouteNamesFactoryTest.java new file mode 100644 index 000000000..1fc8152eb --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv4RouteNamesFactoryTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing; + +import static org.junit.Assert.assertEquals; + +import io.fd.hc2vpp.common.test.util.NamingContextHelper; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper; +import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper; +import io.fd.hc2vpp.routing.naming.Ipv4RouteNamesFactory; +import io.fd.honeycomb.test.tools.HoneycombTestRunner; +import io.fd.honeycomb.test.tools.annotations.InjectTestData; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.dto.IpFibDetails; +import io.fd.vpp.jvpp.core.types.FibPath; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +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.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; + +@RunWith(HoneycombTestRunner.class) +public class Ipv4RouteNamesFactoryTest + implements RoutingRequestTestHelper, SchemaContextTestHelper, NamingContextHelper { + + @Mock + private MappingContext mappingContext; + + private NamingContext interfaceContext; + private NamingContext routingProtocolContext; + private IpFibDetails vppRoute; + private FibPath vppPath; + private Ipv4RouteNamesFactory factory; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + interfaceContext = new NamingContext("interface-", "interface-context"); + routingProtocolContext = new NamingContext("routing-protocol-", "routing-protocol-context"); + vppRoute = new IpFibDetails(); + vppRoute.address = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY; + vppRoute.addressLength = 24; + vppRoute.tableId = 1; + + vppPath = new FibPath(); + vppPath.nextHop = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY; + vppPath.swIfIndex = 2; + vppPath.weight = 3; + + factory = new Ipv4RouteNamesFactory(interfaceContext, routingProtocolContext); + defineMapping(mappingContext, "iface", 2, "interface-context"); + defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context"); + } + + @Test + public void testUniqueRouteName( + @InjectTestData(resourcePath = "/ipv4/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) + StaticRoutes data) { + assertEquals("tst-protocol_19216821_24", + factory.uniqueRouteName(ROUTE_PROTOCOL_NAME, getIpv4RouteWithId(data, 1L))); + assertEquals("tst-protocol_19216821_24", factory.uniqueRouteName(vppRoute, mappingContext)); + } + + @Test + public void testUniqueRouteHopName() { + assertEquals("iface_19216821_3", factory.uniqueRouteHopName(new NextHopBuilder() + .setAddress(new Ipv4Address("192.168.2.1")) + .setWeight((short) 3) + .setOutgoingInterface("iface") + .build())); + assertEquals("iface_19216821_3", factory.uniqueRouteHopName(vppPath, mappingContext)); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv6RouteData.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv6RouteData.java new file mode 100644 index 000000000..808252844 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv6RouteData.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing; + +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.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteBuilder; + +public class Ipv6RouteData { + + public static final Ipv6Prefix + FIRST_ADDRESS_AS_V6_PREFIX = new Ipv6Prefix("2001:0db8:0a0b:12f0:0000:0000:0000:0001/64"); + + public static final byte[] FIRST_ADDRESS_AS_ARRAY = {32, 1, 13, -72, 10, 11, 18, -16, 0, 0, 0, 0, 0, 0, 0, 1}; + + public static final Ipv6Address + SECOND_ADDRESS_AS_ADDRESS = new Ipv6Address("2001:0db8:0a0b:12f0:0000:0000:0000:0002"); + + public static final byte[] SECOND_ADDRESS_AS_ARRAY = {32, 1, 13, -72, 10, 11, 18, -16, 0, 0, 0, 0, 0, 0, 0, 2}; + + + public static final Route IPV6_ROUTE_WITH_CLASSIFIER_BLACKHOLE_HOP = new RouteBuilder() + .setDestinationPrefix(FIRST_ADDRESS_AS_V6_PREFIX) + /*.setNextHopOptions(new SpecialNextHopBuilder() + .setSpecialNextHop(SpecialNextHopGrouping.SpecialNextHop.Blackhole) + /*.addAugmentation(SpecialNextHop2.class, new SpecialNextHop2Builder() + .setPrimaryVrf(new VniReference(2L)) + .setAutoCreateVrf(true) + .setClassifyTable(CLASSIFY_TABLE_NAME) + .build()) + .build())*/ + .build(); + + public static final Route IPV6_ROUTE_WITHOUT_CLASSIFIER_BLACKHOLE_HOP = new RouteBuilder() + .setDestinationPrefix(FIRST_ADDRESS_AS_V6_PREFIX) + /*.setNextHopOptions(new SpecialNextHopBuilder() + .setSpecialNextHop(SpecialNextHopGrouping.SpecialNextHop.Blackhole) + /* .addAugmentation(SpecialNextHop2.class, new SpecialNextHop2Builder() + .setPrimaryVrf(new VniReference(2L)) + .setAutoCreateVrf(true) + .build()) + .build())*/ + .build(); + + public static final Route IPV6_ROUTE_WITH_CLASSIFIER_RECEIVE_HOP = new RouteBuilder() + .setDestinationPrefix(FIRST_ADDRESS_AS_V6_PREFIX) + /*.setNextHopOptions(new SpecialNextHopBuilder() + .setSpecialNextHop(SpecialNextHopGrouping.SpecialNextHop.Blackhole) + /*.addAugmentation(SpecialNextHop2.class, new SpecialNextHop2Builder() + .setPrimaryVrf(new VniReference(2L)) + .setAutoCreateVrf(true) + .setClassifyTable(CLASSIFY_TABLE_NAME) + .build()) + .build())*/ + .build(); + + public static final Route IPV6_ROUTE_WITHOUT_CLASSIFIER_RECEIVE_HOP = new RouteBuilder() + .setDestinationPrefix(FIRST_ADDRESS_AS_V6_PREFIX) + /*.setNextHopOptions(new SpecialNextHopBuilder() + .setSpecialNextHop(SpecialNextHopGrouping.SpecialNextHop.Blackhole) + /*.addAugmentation(SpecialNextHop2.class, new SpecialNextHop2Builder() + .setPrimaryVrf(new VniReference(2L)) + .setAutoCreateVrf(true) + .build()) + .build())*/ + .build(); +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv6RouteNamesFactoryTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv6RouteNamesFactoryTest.java new file mode 100644 index 000000000..4f95ae328 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv6RouteNamesFactoryTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing; + +import static io.fd.hc2vpp.routing.Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY; +import static org.junit.Assert.assertEquals; + +import io.fd.hc2vpp.common.test.util.NamingContextHelper; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper; +import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper; +import io.fd.hc2vpp.routing.naming.Ipv6RouteNamesFactory; +import io.fd.honeycomb.test.tools.HoneycombTestRunner; +import io.fd.honeycomb.test.tools.annotations.InjectTestData; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.dto.Ip6FibDetails; +import io.fd.vpp.jvpp.core.types.FibPath; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +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.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; + +@RunWith(HoneycombTestRunner.class) +public class Ipv6RouteNamesFactoryTest implements RoutingRequestTestHelper, SchemaContextTestHelper, + NamingContextHelper { + + @Mock + private MappingContext mappingContext; + + private NamingContext interfaceContext; + private NamingContext routingProtocolContext; + private Ip6FibDetails vppRoute; + private FibPath vppPath; + private Ipv6RouteNamesFactory factory; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + interfaceContext = new NamingContext("interface-", "interface-context"); + routingProtocolContext = new NamingContext("routing-protocol-", "routing-protocol-context"); + vppRoute = new Ip6FibDetails(); + vppRoute.address = FIRST_ADDRESS_AS_ARRAY; + vppRoute.addressLength = 64; + vppRoute.tableId = 1; + + vppPath = new FibPath(); + vppPath.nextHop = FIRST_ADDRESS_AS_ARRAY; + vppPath.swIfIndex = 2; + vppPath.weight = 3; + factory = new Ipv6RouteNamesFactory(interfaceContext, routingProtocolContext); + defineMapping(mappingContext, "iface", 2, "interface-context"); + defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context"); + } + + @Test + public void testUniqueRouteName( + @InjectTestData(resourcePath = "/ipv6/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) + StaticRoutes data) { + assertEquals("tst-protocol_2001db8a0b12f01_64", + factory.uniqueRouteName(ROUTE_PROTOCOL_NAME, getIpv6RouteWithId(data, 1L))); + assertEquals("tst-protocol_2001db8a0b12f01_64", factory.uniqueRouteName(vppRoute, mappingContext)); + } + + @Test + public void testUniqueRouteHopName() { + assertEquals("iface_2001db8a0b12f01_3", factory.uniqueRouteHopName(new NextHopBuilder() + .setAddress(new Ipv6Address("2001:0db8:0a0b:12f0:0000:0000:0000:0001")) + .setWeight((short) 3) + .setOutgoingInterface("iface") + .build())); + assertEquals("iface_2001db8a0b12f01_3", + factory.uniqueRouteHopName(vppPath, mappingContext)); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/RoutingModuleTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/RoutingModuleTest.java new file mode 100644 index 000000000..670f7afe3 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/RoutingModuleTest.java @@ -0,0 +1,110 @@ +/* + * 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.routing; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.Matchers.empty; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.name.Named; +import com.google.inject.testing.fieldbinder.Bind; +import com.google.inject.testing.fieldbinder.BoundFieldModule; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.read.RoutingStateReaderFactory; +import io.fd.hc2vpp.routing.write.RoutingWriterFactory; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.translate.impl.read.registry.CompositeReaderRegistryBuilder; +import io.fd.honeycomb.translate.impl.write.registry.FlatWriterRegistryBuilder; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.HashSet; +import java.util.Set; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; + +public class RoutingModuleTest { + + @Named("honeycomb-context") + @Bind + @Mock + private DataBroker honeycombContext; + + @Named("honeycomb-initializer") + @Bind + @Mock + private DataBroker honeycombInitializer; + + @Named("interface-context") + @Bind + private NamingContext interfaceContext; + + @Named("classify-table-context") + @Bind + @Mock + private VppClassifierContextManager classifierContextManager; + + @Bind + @Mock + private FutureJVppCore futureJVppCore; + + @Inject + private Set<ReaderFactory> readerFactories = new HashSet<>(); + + @Inject + private Set<WriterFactory> writerFactories = new HashSet<>(); + + @Before + public void setUp() { + initMocks(this); + interfaceContext = new NamingContext("interfaceContext", "interfaceContext"); + Guice.createInjector(new RoutingModule(), BoundFieldModule.of(this)).injectMembers(this); + } + + @Test + public void testReaderFactories() throws Exception { + assertThat(readerFactories, is(not(empty()))); + + // Test registration process (all dependencies present, topological order of readers does exist, etc.) + final CompositeReaderRegistryBuilder registryBuilder = new CompositeReaderRegistryBuilder(); + readerFactories.stream().forEach(factory -> factory.init(registryBuilder)); + assertNotNull(registryBuilder.build()); + assertEquals(1, readerFactories.size()); + assertTrue(readerFactories.iterator().next() instanceof RoutingStateReaderFactory); + } + + @Test + public void testWriterFactories() throws Exception { + assertThat(writerFactories, is(not(empty()))); + + // Test registration process (all dependencies present, topological order of writers does exist, etc.) + final FlatWriterRegistryBuilder registryBuilder = new FlatWriterRegistryBuilder(); + writerFactories.stream().forEach(factory -> factory.init(registryBuilder)); + assertNotNull(registryBuilder.build()); + assertEquals(1, writerFactories.size()); + assertTrue(writerFactories.iterator().next() instanceof RoutingWriterFactory); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/ClassifyTableTestHelper.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/ClassifyTableTestHelper.java new file mode 100644 index 000000000..8e8f50c3d --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/ClassifyTableTestHelper.java @@ -0,0 +1,35 @@ +/* + * 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.routing.helpers; + + +import static org.mockito.Mockito.when; + +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.translate.MappingContext; + +public interface ClassifyTableTestHelper { + + String CLASSIFY_TABLE_NAME = "classify-table-one"; + int CLASSIFY_TABLE_INDEX = 2; + + default void addMapping(final VppClassifierContextManager classifyManager, final String name, final int index, + final MappingContext mappingContext) { + when(classifyManager.containsTable(name, mappingContext)).thenReturn(true); + when(classifyManager.getTableIndex(name, mappingContext)).thenReturn(index); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/InterfaceTestHelper.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/InterfaceTestHelper.java new file mode 100644 index 000000000..95561e621 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/InterfaceTestHelper.java @@ -0,0 +1,25 @@ +/* + * 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.routing.helpers; + +import io.fd.hc2vpp.common.test.util.NamingContextHelper; + +public interface InterfaceTestHelper extends NamingContextHelper { + + String INTERFACE_NAME = "iface"; + int INTERFACE_INDEX = 3; +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/RoutingRequestTestHelper.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/RoutingRequestTestHelper.java new file mode 100644 index 000000000..bcb8e6800 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/RoutingRequestTestHelper.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.helpers; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.fd.hc2vpp.common.test.util.FutureProducer; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.routing.trait.RouteMapper; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import io.fd.vpp.jvpp.core.dto.IpAddDelRouteReply; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.List; +import org.mockito.ArgumentCaptor; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; + +public interface RoutingRequestTestHelper extends ByteDataTranslator, FutureProducer, RouteMapper { + + String ROUTE_PROTOCOL_NAME = "tst-protocol"; + String ROUTE_NAME = "tst-route"; + String STATIC_ROUTE_PATH = "/ietf-routing:routing" + + "/ietf-routing:routing-instance[ietf-routing:name='" + ROUTE_PROTOCOL_NAME + "']" + + "/ietf-routing:routing-protocols" + + "/ietf-routing:routing-protocol[ietf-routing:name='" + ROUTE_NAME + "']" + + "/ietf-routing:static-routes"; + + default IpAddDelRoute desiredFlaglessResult(final int add, final int ipv6, final int isMultipath, + final byte[] destinationAddress, + final int destinationPrefixLength, + final byte[] nextHopAddr, + final int nextHopIndex, + final int nextHopWeight, + final int vrfId, + final int createVrfIfNeeded, + final int secondaryVrfId, + final int classifyTableIndex, + final int classifyTableIndexSet) { + + // verification of flagless request, so setting them to 0 + return desiredResult(add, ipv6, isMultipath, destinationAddress, destinationPrefixLength, nextHopAddr, + nextHopIndex, nextHopWeight, vrfId, createVrfIfNeeded, secondaryVrfId, classifyTableIndex, + classifyTableIndexSet, 0, 0, 0, 0); + } + + default IpAddDelRoute desiredSpecialResult(final int add, final int ipv6, + final byte[] destinationAddress, + final int destinationPrefixLength, + final int isDrop, + final int isReceive, + final int isUnreach, + final int isProhibit) { + // verifiaction of special request that has only destination address and flag + return desiredResult(add, ipv6, 0, destinationAddress, destinationPrefixLength, null, 0, 0, 0, 1, 0, 0, 0, + isDrop, isReceive, isUnreach, isProhibit); + } + + default IpAddDelRoute desiredResult(final int add, final int ipv6, final int isMultipath, + final byte[] destinationAddress, + final int destinationPrefixLength, + final byte[] nextHopAddr, + final int nextHopIndex, + final int nextHopWeight, + final int vrfId, + final int createVrfIfNeeded, + final int secondaryVrfId, + final int classifyTableIndex, + final int classifyTableIndexSet, + final int isDrop, + final int isLocal, + final int isUnreach, + final int isProhibit) { + final IpAddDelRoute request = new IpAddDelRoute(); + + request.isAdd = toByte(add); + request.isIpv6 = toByte(ipv6); + request.isMultipath = toByte(isMultipath); + request.dstAddress = destinationAddress; + request.dstAddressLength = toByte(destinationPrefixLength); + request.nextHopAddress = nextHopAddr; + request.nextHopSwIfIndex = nextHopIndex; + request.nextHopWeight = toByte(nextHopWeight); + request.classifyTableIndex = classifyTableIndexSet; + request.tableId = vrfId; + request.nextHopTableId = secondaryVrfId; + request.createVrfIfNeeded = toByte(createVrfIfNeeded); + request.classifyTableIndex = classifyTableIndex; + request.isClassify = toByte(classifyTableIndexSet); + // special hop flags + request.isDrop = toByte(isDrop); + request.isLocal = toByte(isLocal); + request.isUnreach = toByte(isUnreach); + request.isProhibit = toByte(isProhibit); + return request; + } + + default void verifyInvocation(final int nrOfInvocations, final List<IpAddDelRoute> desiredRequests, final + FutureJVppCore api, final ArgumentCaptor<IpAddDelRoute> requestCaptor) { + verify(api, times(nrOfInvocations)).ipAddDelRoute(requestCaptor.capture()); + + final List<IpAddDelRoute> actualRequests = requestCaptor.getAllValues(); + + for (int i = 0; i < nrOfInvocations; i++) { + assertEquals(actualRequests.get(i), desiredRequests.get(i)); + } + } + + default void verifyNotInvoked(final FutureJVppCore api) { + verify(api, times(0)).ipAddDelRoute(any()); + } + + default void whenAddRouteThenSuccess(final FutureJVppCore api) { + when(api.ipAddDelRoute(any())).thenReturn(future(new IpAddDelRouteReply())); + } + + default Route getIpv4RouteWithId(final StaticRoutes staticRoutes, final long id) { + return staticRoutes.getAugmentation(StaticRoutes1.class) + .getIpv4() + .getRoute() + .stream() + .filter(route -> route.getId() == id) + .collect(RWUtils.singleItemCollector()); + } + + default NextHop getHopWithId( + final Route route, final int id) { + return org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList.class + .cast(route.getNextHopOptions()) + .getNextHopList() + .getNextHop() + .stream() + .filter(nextHop -> nextHop.getKey().getId().intValue() == id) + .collect(RWUtils.singleItemCollector()); + } + + default org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route getIpv6RouteWithId( + final StaticRoutes staticRoutes, final long id) { + return staticRoutes.getAugmentation( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1.class) + .getIpv6() + .getRoute() + .stream() + .filter(route -> route.getId() == id) + .collect(RWUtils.singleItemCollector()); + } + +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/SchemaContextTestHelper.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/SchemaContextTestHelper.java new file mode 100644 index 000000000..118595aa6 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/SchemaContextTestHelper.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.helpers; + +import com.google.common.collect.ImmutableSet; +import io.fd.honeycomb.test.tools.annotations.InjectablesProcessor; +import io.fd.honeycomb.test.tools.annotations.SchemaContextProvider; +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; + +public interface SchemaContextTestHelper extends InjectablesProcessor { + + @SchemaContextProvider + default ModuleInfoBackedContext getSchemaContext() { + return provideSchemaContextFor(ImmutableSet.of( + // Default ietf-ip + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.$YangModuleInfoImpl + .getInstance(), + // Default ietf-routing + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.$YangModuleInfoImpl + .getInstance(), + // Ipv4 augmentations + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.$YangModuleInfoImpl + .getInstance(), + // Ipv4 augmentations + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.$YangModuleInfoImpl + .getInstance(), + // Vpp routing + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.$YangModuleInfoImpl + .getInstance())); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/Ipv4RouteCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/Ipv4RouteCustomizerTest.java new file mode 100644 index 000000000..814345f0e --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/Ipv4RouteCustomizerTest.java @@ -0,0 +1,265 @@ +/* + * 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.routing.read; + +import static io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper.ROUTE_PROTOCOL_NAME; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.collection.IsCollectionWithSize.hasSize; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import io.fd.hc2vpp.common.test.read.ListReaderCustomizerTest; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.Ipv4RouteData; +import io.fd.hc2vpp.routing.RoutingConfiguration; +import io.fd.hc2vpp.routing.naming.Ipv4RouteNamesFactory; +import io.fd.hc2vpp.routing.trait.RouteMapper; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor; +import io.fd.vpp.jvpp.core.dto.IpFibDetails; +import io.fd.vpp.jvpp.core.dto.IpFibDetailsReplyDump; +import io.fd.vpp.jvpp.core.types.FibPath; +import java.util.Arrays; +import java.util.List; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.junit.Test; +import org.mockito.Mock; +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.ipv4.unicast.routing.rev140524.StaticRoutes2; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.NextHopOptions; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHopKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocols; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocolKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutes; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class Ipv4RouteCustomizerTest extends ListReaderCustomizerTest<Route, RouteKey, RouteBuilder> + implements RouteMapper { + + private final InstanceIdentifier<Ipv4> ipv4InstanceIdentifier = InstanceIdentifier.create(RoutingProtocols.class) + .child(RoutingProtocol.class, new RoutingProtocolKey(ROUTE_PROTOCOL_NAME)) + .child(StaticRoutes.class) + .augmentation(StaticRoutes2.class) + .child(Ipv4.class); + private DumpCacheManager<IpFibDetailsReplyDump, Void> manager; + @Mock + private RoutingConfiguration configuration; + @Mock + private MultiNamingContext routeHopContext; + @Mock + private EntityDumpExecutor<IpFibDetailsReplyDump, Void> executor; + private NamingContext interfaceContext = new NamingContext("ifaces", "interface-context"); + private NamingContext routesContext = new NamingContext("routes", "route-context"); + private NamingContext routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context"); + private InstanceIdentifier<Route> routeIdSpecialHop = ipv4InstanceIdentifier.child(Route.class, new RouteKey(1L)); + private InstanceIdentifier<Route> routeIdSimpleHop = ipv4InstanceIdentifier.child(Route.class, new RouteKey(2L)); + private InstanceIdentifier<Route> routeIdListHop = ipv4InstanceIdentifier.child(Route.class, new RouteKey(3L)); + + + public Ipv4RouteCustomizerTest() { + super(Route.class, Ipv4Builder.class); + } + + @Override + public void setUp() throws ReadFailedException { + manager = new DumpCacheManager.DumpCacheManagerBuilder<IpFibDetailsReplyDump, Void>() + .withExecutor(executor) + .acceptOnly(IpFibDetailsReplyDump.class) + .build(); + + final IpFibDetailsReplyDump replyDump = replyDump(); + when(executor.executeDump(routeIdSpecialHop, EntityDumpExecutor.NO_PARAMS)).thenReturn(replyDump); + when(executor.executeDump(routeIdSimpleHop, EntityDumpExecutor.NO_PARAMS)).thenReturn(replyDump); + when(executor.executeDump(routeIdListHop, EntityDumpExecutor.NO_PARAMS)).thenReturn(replyDump); + + IpFibDetails listRoute = replyDump.ipFibDetails.get(2); + final Ipv4RouteNamesFactory factory = new Ipv4RouteNamesFactory(interfaceContext, routingProtocolContext); + + defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context"); + defineMapping(mappingContext, "iface-1", 1, "interface-context"); + defineMapping(mappingContext, factory.uniqueRouteName(replyDump.ipFibDetails.get(0), mappingContext), 1, + "route-context"); + defineMapping(mappingContext, factory.uniqueRouteName(replyDump.ipFibDetails.get(1), mappingContext), 2, + "route-context"); + + String listRouteName = factory.uniqueRouteName(listRoute, mappingContext); + defineMapping(mappingContext, listRouteName, 3, "route-context"); + + when(routeHopContext.getChildIndex(listRouteName, factory.uniqueRouteHopName(listRoute.path[0], mappingContext), + mappingContext)).thenReturn(0); + when(routeHopContext.getChildIndex(listRouteName, factory.uniqueRouteHopName(listRoute.path[1], mappingContext), + mappingContext)).thenReturn(1); + } + + private IpFibDetailsReplyDump replyDump() { + IpFibDetailsReplyDump replyDump = new IpFibDetailsReplyDump(); + + // first is special + IpFibDetails detail1 = new IpFibDetails(); + detail1.tableId = 1; + detail1.address = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY; + detail1.addressLength = 24; + + FibPath path1 = new FibPath(); + path1.isLocal = 1; + detail1.path = new FibPath[]{path1}; + + + //second is simple + IpFibDetails detail2 = new IpFibDetails(); + detail2.tableId = 1; + detail2.address = Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY; + detail2.addressLength = 22; + detail2.path = new FibPath[]{}; + + FibPath path2 = new FibPath(); + path2.weight = 3; + path2.nextHop = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY; + path2.afi = 0; + path2.swIfIndex = 1; + detail2.path = new FibPath[]{path2}; + + // third is list + IpFibDetails detail3 = new IpFibDetails(); + detail3.tableId = 1; + detail3.address = Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY; + detail3.addressLength = 16; + + FibPath path3 = new FibPath(); + path3.swIfIndex = 1; + path3.weight = 1; + path3.nextHop = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY; + path3.afi = 0; + + FibPath path4 = new FibPath(); + path4.swIfIndex = 1; + path4.weight = 2; + path4.nextHop = Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY; + path4.afi = 0; + + detail3.path = new FibPath[]{path3, path4}; + + replyDump.ipFibDetails = Arrays.asList(detail1, detail2, detail3); + return replyDump; + } + + @Test + public void getAllIds() throws Exception { + final List<RouteKey> keys = getCustomizer().getAllIds(routeIdSpecialHop, ctx); + + assertThat(keys, hasSize(3)); + assertThat(keys, hasItems(new RouteKey(1L), new RouteKey(2L), new RouteKey(3L))); + } + + @Test + public void readCurrentAttributesSpecialHop() throws Exception { + final RouteBuilder builder = new RouteBuilder(); + getCustomizer().readCurrentAttributes(routeIdSpecialHop, builder, ctx); + + assertEquals(1, builder.getId().intValue()); + assertEquals(1, builder.getKey().getId().intValue()); + assertEquals(new Ipv4Prefix("192.168.2.1/24"), builder.getDestinationPrefix()); + + NextHopOptions hopOptions = builder.getNextHopOptions(); + assertTrue(hopOptions instanceof SpecialNextHop); + + SpecialNextHop hop = SpecialNextHop.class.cast(hopOptions); + assertEquals(SpecialNextHopGrouping.SpecialNextHop.Receive, hop.getSpecialNextHop()); + } + + @Test + public void readCurrentAttributesSimpleHop() throws Exception { + final RouteBuilder builder = new RouteBuilder(); + getCustomizer().readCurrentAttributes(routeIdSimpleHop, builder, ctx); + + assertEquals(2, builder.getId().intValue()); + assertEquals(2, builder.getKey().getId().intValue()); + assertEquals(new Ipv4Prefix("192.168.2.2/22"), builder.getDestinationPrefix()); + + NextHopOptions hopOptions = builder.getNextHopOptions(); + assertTrue(hopOptions instanceof SimpleNextHop); + + SimpleNextHop hop = SimpleNextHop.class.cast(hopOptions); + assertEquals("192.168.2.1", hop.getNextHop().getValue()); + assertEquals("iface-1", hop.getOutgoingInterface()); + } + + @Test + public void readCurrentAttributesListHop() throws Exception { + + final RouteBuilder builder = new RouteBuilder(); + getCustomizer().readCurrentAttributes(routeIdListHop, builder, ctx); + + assertEquals(3, builder.getId().intValue()); + assertEquals(3, builder.getKey().getId().intValue()); + assertEquals(new Ipv4Prefix("192.168.2.2/16"), builder.getDestinationPrefix()); + + NextHopOptions hopOptions = builder.getNextHopOptions(); + assertTrue(hopOptions instanceof NextHopList); + + NextHopList hop = NextHopList.class.cast(hopOptions); + List<NextHop> hops = hop.getNextHopList().getNextHop(); + + assertThat(hops, hasSize(2)); + + assertTrue(areEqual(hops.get(0), desiredHop(0L, "192.168.2.1", 1, "iface-1"))); + assertTrue(areEqual(hops.get(1), desiredHop(1L, "192.168.2.2", 2, "iface-1"))); + } + + private boolean areEqual(final NextHop first, final NextHop second) { + return new EqualsBuilder() + .append(true, first.getAddress().getValue().equals(second.getAddress().getValue())) + .append(true, first.getId().equals(second.getId())) + .append(true, first.getKey().equals(second.getKey())) + .append(true, first.getOutgoingInterface().equals(second.getOutgoingInterface())) + .isEquals(); + } + + private NextHop desiredHop(final long id, final String address, final int weight, final String iface) { + return new NextHopBuilder() + .setAddress(new Ipv4Address(address)) + .setWeight((short) weight) + .setOutgoingInterface(iface) + .setId(id) + .setKey(new NextHopKey(id)) + .build(); + } + + @Override + protected ReaderCustomizer<Route, RouteBuilder> initCustomizer() { + return new Ipv4RouteCustomizer(manager, configuration, routeHopContext, interfaceContext, + routesContext, routingProtocolContext); + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/Ipv6RouteCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/Ipv6RouteCustomizerTest.java new file mode 100644 index 000000000..a026b5777 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/Ipv6RouteCustomizerTest.java @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.read; + +import static io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper.ROUTE_PROTOCOL_NAME; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.collection.IsCollectionWithSize.hasSize; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import io.fd.hc2vpp.common.test.read.ListReaderCustomizerTest; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.Ipv6RouteData; +import io.fd.hc2vpp.routing.RoutingConfiguration; +import io.fd.hc2vpp.routing.naming.Ipv6RouteNamesFactory; +import io.fd.hc2vpp.routing.trait.RouteMapper; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor; +import io.fd.vpp.jvpp.core.dto.Ip6FibDetails; +import io.fd.vpp.jvpp.core.dto.Ip6FibDetailsReplyDump; +import io.fd.vpp.jvpp.core.types.FibPath; +import java.util.Arrays; +import java.util.List; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.junit.Test; +import org.mockito.Mock; +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.ipv6.unicast.routing.rev140525.StaticRoutes2; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.NextHopOptions; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHopKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocols; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocolKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutes; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class Ipv6RouteCustomizerTest extends ListReaderCustomizerTest<Route, RouteKey, RouteBuilder> + implements RouteMapper { + + private static final String ROUTING_PROTOCOL_PREFIX = "route-p-"; + private DumpCacheManager<Ip6FibDetailsReplyDump, Void> manager; + + @Mock + private RoutingConfiguration configuration; + + @Mock + private MultiNamingContext routeHopContext; + + @Mock + private EntityDumpExecutor<Ip6FibDetailsReplyDump, Void> executor; + + @Mock + private ModificationCache cache; + + private NamingContext interfaceContext; + private NamingContext routesContext; + private NamingContext routingProtocolContext; + + private InstanceIdentifier<Route> routeIdSpecialHop; + private InstanceIdentifier<Route> routeIdSimpleHop; + private InstanceIdentifier<Route> routeIdListHop; + private Ipv6RouteNamesFactory factory; + + public Ipv6RouteCustomizerTest() { + super(Route.class, Ipv6Builder.class); + } + + @Override + public void setUp() throws ReadFailedException { + manager = new DumpCacheManager.DumpCacheManagerBuilder<Ip6FibDetailsReplyDump, Void>() + .withExecutor(executor) + .acceptOnly(Ip6FibDetailsReplyDump.class) + .build(); + + interfaceContext = new NamingContext("ifaces", "interface-context"); + routesContext = new NamingContext("routes", "route-context"); + routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context"); + + final InstanceIdentifier<Ipv6> ipv6InstanceIdentifier = InstanceIdentifier.create(RoutingProtocols.class) + .child(RoutingProtocol.class, new RoutingProtocolKey(ROUTE_PROTOCOL_NAME)) + .child(StaticRoutes.class) + .augmentation(StaticRoutes2.class) + .child(Ipv6.class); + + routeIdSpecialHop = ipv6InstanceIdentifier.child(Route.class, new RouteKey(1L)); + routeIdSimpleHop = ipv6InstanceIdentifier.child(Route.class, new RouteKey(2L)); + routeIdListHop = ipv6InstanceIdentifier.child(Route.class, new RouteKey(3L)); + + factory = new Ipv6RouteNamesFactory(interfaceContext, routingProtocolContext); + + + final Ip6FibDetailsReplyDump replyDump = replyDump(); + when(executor.executeDump(routeIdSpecialHop, EntityDumpExecutor.NO_PARAMS)).thenReturn(replyDump); + when(executor.executeDump(routeIdSimpleHop, EntityDumpExecutor.NO_PARAMS)).thenReturn(replyDump); + when(executor.executeDump(routeIdListHop, EntityDumpExecutor.NO_PARAMS)).thenReturn(replyDump); + + defineMapping(mappingContext, "iface-1", 1, "interface-context"); + defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context"); + defineMapping(mappingContext, factory.uniqueRouteName(replyDump.ip6FibDetails.get(0), mappingContext), 1, + "route-context"); + defineMapping(mappingContext, factory.uniqueRouteName(replyDump.ip6FibDetails.get(1), mappingContext), 2, + "route-context"); + + Ip6FibDetails listRoute = replyDump.ip6FibDetails.get(2); + String listRouteName = factory.uniqueRouteName(listRoute, mappingContext); + defineMapping(mappingContext, listRouteName, 3, "route-context"); + + when(routeHopContext.getChildIndex(listRouteName, factory.uniqueRouteHopName(listRoute.path[0], mappingContext), + mappingContext)) + .thenReturn(0); + when(routeHopContext.getChildIndex(listRouteName, factory.uniqueRouteHopName(listRoute.path[1], mappingContext), + mappingContext)) + .thenReturn(1); + } + + private Ip6FibDetailsReplyDump replyDump() { + Ip6FibDetailsReplyDump replyDump = new Ip6FibDetailsReplyDump(); + + // first is special + Ip6FibDetails detail1 = new Ip6FibDetails(); + detail1.tableId = 1; + detail1.address = Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY; + detail1.addressLength = 24; + + FibPath path1 = new FibPath(); + path1.isLocal = 1; + detail1.path = new FibPath[]{path1}; + + + //second is simple + Ip6FibDetails detail2 = new Ip6FibDetails(); + detail2.tableId = 1; + detail2.address = Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY; + detail2.addressLength = 22; + detail2.path = new FibPath[]{}; + + FibPath path2 = new FibPath(); + path2.weight = 3; + path2.nextHop = Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY; + path2.afi = 0; + path2.swIfIndex = 1; + detail2.path = new FibPath[]{path2}; + + // third is list + Ip6FibDetails detail3 = new Ip6FibDetails(); + detail3.tableId = 1; + detail3.address = Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY; + detail3.addressLength = 16; + + FibPath path3 = new FibPath(); + path3.swIfIndex = 1; + path3.weight = 1; + path3.nextHop = Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY; + path3.afi = 0; + + FibPath path4 = new FibPath(); + path4.swIfIndex = 1; + path4.weight = 2; + path4.nextHop = Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY; + path4.afi = 0; + + detail3.path = new FibPath[]{path3, path4}; + + replyDump.ip6FibDetails = Arrays.asList(detail1, detail2, detail3); + return replyDump; + } + + @Test + public void getAllIds() throws Exception { + final List<RouteKey> keys = getCustomizer().getAllIds(routeIdSpecialHop, ctx); + + assertThat(keys, hasSize(3)); + assertThat(keys, hasItems(new RouteKey(1L), new RouteKey(2L), new RouteKey(3L))); + } + + @Test + public void readCurrentAttributesSpecialHop() throws Exception { + final RouteBuilder builder = new RouteBuilder(); + getCustomizer().readCurrentAttributes(routeIdSpecialHop, builder, ctx); + + assertEquals(1, builder.getId().intValue()); + assertEquals(1, builder.getKey().getId().intValue()); + assertEquals("2001:db8:a0b:12f0:0:0:0:1/24", builder.getDestinationPrefix().getValue()); + + NextHopOptions hopOptions = builder.getNextHopOptions(); + assertTrue(hopOptions instanceof SpecialNextHop); + + SpecialNextHop hop = SpecialNextHop.class.cast(hopOptions); + assertEquals(SpecialNextHopGrouping.SpecialNextHop.Receive, hop.getSpecialNextHop()); + } + + @Test + public void readCurrentAttributesSimpleHop() throws Exception { + final RouteBuilder builder = new RouteBuilder(); + getCustomizer().readCurrentAttributes(routeIdSimpleHop, builder, ctx); + + assertEquals(2, builder.getId().intValue()); + assertEquals(2, builder.getKey().getId().intValue()); + assertEquals("2001:db8:a0b:12f0:0:0:0:2/22", builder.getDestinationPrefix().getValue()); + + NextHopOptions hopOptions = builder.getNextHopOptions(); + assertTrue(hopOptions instanceof SimpleNextHop); + + SimpleNextHop hop = SimpleNextHop.class.cast(hopOptions); + assertEquals("2001:db8:a0b:12f0::1", hop.getNextHop().getValue()); + assertEquals("iface-1", hop.getOutgoingInterface()); + } + + @Test + public void readCurrentAttributesListHop() throws Exception { + + + final RouteBuilder builder = new RouteBuilder(); + getCustomizer().readCurrentAttributes(routeIdListHop, builder, ctx); + + assertEquals(3, builder.getId().intValue()); + assertEquals(3, builder.getKey().getId().intValue()); + assertEquals("2001:db8:a0b:12f0:0:0:0:2/16", builder.getDestinationPrefix().getValue()); + + NextHopOptions hopOptions = builder.getNextHopOptions(); + assertTrue(hopOptions instanceof NextHopList); + + NextHopList hop = NextHopList.class.cast(hopOptions); + List<NextHop> hops = hop.getNextHopList().getNextHop(); + + assertThat(hops, hasSize(2)); + + assertTrue(areEqual(hops.get(0), desiredHop(0L, "2001:db8:a0b:12f0::1", 1, "iface-1"))); + assertTrue(areEqual(hops.get(1), desiredHop(1L, "2001:db8:a0b:12f0::2", 2, "iface-1"))); + } + + private boolean areEqual(final NextHop first, final NextHop second) { + return new EqualsBuilder() + .append(true, first.getAddress().getValue().equals(second.getAddress().getValue())) + .append(true, first.getId().equals(second.getId())) + .append(true, first.getKey().equals(second.getKey())) + .append(true, first.getOutgoingInterface().equals(second.getOutgoingInterface())) + .isEquals(); + } + + private NextHop desiredHop(final long id, final String address, final int weight, final String iface) { + return new NextHopBuilder() + .setAddress(new Ipv6Address(address)) + .setWeight((short) weight) + .setOutgoingInterface(iface) + .setId(id) + .setKey(new NextHopKey(id)) + .build(); + } + + @Override + protected ReaderCustomizer<Route, RouteBuilder> initCustomizer() { + return new Ipv6RouteCustomizer(manager, configuration, routeHopContext, + interfaceContext, routesContext, routingProtocolContext); + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/RoutingProtocolCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/RoutingProtocolCustomizerTest.java new file mode 100644 index 000000000..1d0057cf2 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/RoutingProtocolCustomizerTest.java @@ -0,0 +1,225 @@ +/* + * 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.routing.read; + +import static io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper.ROUTE_PROTOCOL_NAME; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.core.IsCollectionContaining.hasItems; +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import io.fd.hc2vpp.common.test.read.ListReaderCustomizerTest; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.Ipv4RouteData; +import io.fd.hc2vpp.routing.Ipv6RouteData; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor; +import io.fd.vpp.jvpp.core.dto.Ip6FibDetails; +import io.fd.vpp.jvpp.core.dto.Ip6FibDetailsReplyDump; +import io.fd.vpp.jvpp.core.dto.IpFibDetails; +import io.fd.vpp.jvpp.core.dto.IpFibDetailsReplyDump; +import io.fd.vpp.jvpp.core.types.FibPath; +import java.util.Arrays; +import java.util.List; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Static; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocols; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocolsBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocolBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocolKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class RoutingProtocolCustomizerTest + extends ListReaderCustomizerTest<RoutingProtocol, RoutingProtocolKey, RoutingProtocolBuilder> + implements ByteDataTranslator { + + private static final String VPP_PROTOCOL_PREFIX = "vpp-protocol"; + + @Mock + private EntityDumpExecutor<IpFibDetailsReplyDump, Void> ipv4Executor; + + @Mock + private EntityDumpExecutor<Ip6FibDetailsReplyDump, Void> ipv6Executor; + private DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4RoutesDumpManager; + private DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6RoutesDumpManager; + + private NamingContext routingProtocolContext; + + public RoutingProtocolCustomizerTest() { + super(RoutingProtocol.class, RoutingProtocolsBuilder.class); + } + + @Override + protected void setUp() throws Exception { + when(ipv4Executor.executeDump(any(), any())).thenReturn(replyDumpIpv4()); + when(ipv6Executor.executeDump(any(), any())).thenReturn(replyDumpIpv6()); + when(ctx.getModificationCache()).thenReturn(cache); + + ipv4RoutesDumpManager = new DumpCacheManager.DumpCacheManagerBuilder<IpFibDetailsReplyDump, Void>() + .withExecutor(ipv4Executor) + .acceptOnly(IpFibDetailsReplyDump.class) + .build(); + + ipv6RoutesDumpManager = new DumpCacheManager.DumpCacheManagerBuilder<Ip6FibDetailsReplyDump, Void>() + .withExecutor(ipv6Executor) + .acceptOnly(Ip6FibDetailsReplyDump.class) + .build(); + + routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context"); + defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context"); + defineMapping(mappingContext, "tst-protocol-2", 2, "routing-protocol-context"); + defineMapping(mappingContext, "tst-protocol-3", 3, "routing-protocol-context"); + } + + @Test + public void getAllIds() throws Exception { + final List<RoutingProtocolKey> keys = + getCustomizer().getAllIds(InstanceIdentifier.create(RoutingProtocol.class), ctx); + + assertThat(keys, hasSize(3)); + assertThat(keys, hasItems(new RoutingProtocolKey(ROUTE_PROTOCOL_NAME), new RoutingProtocolKey("tst-protocol-2"), + new RoutingProtocolKey("tst-protocol-3"))); + } + + @Test + public void readCurrentAttributes() throws Exception { + final InstanceIdentifier<RoutingProtocol> identifier = InstanceIdentifier.create(RoutingProtocols.class) + .child(RoutingProtocol.class, new RoutingProtocolKey(ROUTE_PROTOCOL_NAME)); + + final RoutingProtocolBuilder builder = new RoutingProtocolBuilder(); + getCustomizer().readCurrentAttributes(identifier, builder, ctx); + + assertEquals(ROUTE_PROTOCOL_NAME, builder.getName()); + assertEquals(ROUTE_PROTOCOL_NAME, builder.getKey().getName()); + assertEquals(Static.class, builder.getType()); + } + + @Override + protected ReaderCustomizer<RoutingProtocol, RoutingProtocolBuilder> initCustomizer() { + return new RoutingProtocolCustomizer(routingProtocolContext, ipv4RoutesDumpManager, ipv6RoutesDumpManager); + } + + private Ip6FibDetailsReplyDump replyDumpIpv6() { + Ip6FibDetailsReplyDump replyDump = new Ip6FibDetailsReplyDump(); + + // first is special + Ip6FibDetails detail1 = new Ip6FibDetails(); + detail1.tableId = 1; + detail1.address = Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY; + detail1.addressLength = 24; + + FibPath path1 = new FibPath(); + path1.isLocal = 1; + detail1.path = new FibPath[]{path1}; + + + //second is simple + Ip6FibDetails detail2 = new Ip6FibDetails(); + detail2.tableId = 2; + detail2.address = Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY; + detail2.addressLength = 22; + detail2.path = new FibPath[]{}; + + FibPath path2 = new FibPath(); + path2.weight = 3; + path2.nextHop = Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY; + path2.afi = 0; + path2.swIfIndex = 1; + detail2.path = new FibPath[]{path2}; + + // third is list + Ip6FibDetails detail3 = new Ip6FibDetails(); + detail3.tableId = 1; + detail3.address = Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY; + detail3.addressLength = 16; + + FibPath path3 = new FibPath(); + path3.swIfIndex = 1; + path3.weight = 1; + path3.nextHop = Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY; + path3.afi = 0; + + FibPath path4 = new FibPath(); + path4.swIfIndex = 1; + path4.weight = 2; + path4.nextHop = Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY; + path4.afi = 0; + + detail3.path = new FibPath[]{path3, path4}; + + replyDump.ip6FibDetails = Arrays.asList(detail1, detail2, detail3); + return replyDump; + } + + private IpFibDetailsReplyDump replyDumpIpv4() { + IpFibDetailsReplyDump replyDump = new IpFibDetailsReplyDump(); + + // first is special + IpFibDetails detail1 = new IpFibDetails(); + detail1.tableId = 1; + detail1.address = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY; + detail1.addressLength = 24; + + FibPath path1 = new FibPath(); + path1.isLocal = 1; + detail1.path = new FibPath[]{path1}; + + + //second is simple + IpFibDetails detail2 = new IpFibDetails(); + detail2.tableId = 3; + detail2.address = Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY; + detail2.addressLength = 22; + detail2.path = new FibPath[]{}; + + FibPath path2 = new FibPath(); + path2.weight = 3; + path2.nextHop = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY; + path2.afi = 0; + path2.swIfIndex = 1; + detail2.path = new FibPath[]{path2}; + + // third is list + IpFibDetails detail3 = new IpFibDetails(); + detail3.tableId = 1; + detail3.address = Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY; + detail3.addressLength = 16; + + FibPath path3 = new FibPath(); + path3.swIfIndex = 1; + path3.weight = 1; + path3.nextHop = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY; + path3.afi = 0; + + FibPath path4 = new FibPath(); + path4.swIfIndex = 1; + path4.weight = 2; + path4.nextHop = Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY; + path4.afi = 0; + + detail3.path = new FibPath[]{path3, path4}; + + replyDump.ipFibDetails = Arrays.asList(detail1, detail2, detail3); + return replyDump; + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/RoutingStateCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/RoutingStateCustomizerTest.java new file mode 100644 index 000000000..7bece735b --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/RoutingStateCustomizerTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.read; + + +import static org.junit.Assert.assertEquals; + +import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper; +import io.fd.honeycomb.test.tools.HoneycombTestRunner; +import io.fd.honeycomb.test.tools.annotations.InjectTestData; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.Initialized; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Routing; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.RoutingState; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +@RunWith(HoneycombTestRunner.class) +public class RoutingStateCustomizerTest implements SchemaContextTestHelper { + + @InjectTestData(resourcePath = "/init/config-data.json") + private Routing config; + + @InjectTestData(resourcePath = "/init/state-data.json") + private RoutingState state; + + @Mock + private ReadContext readContext; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testInit() { + final InstanceIdentifier<RoutingState> identifier = InstanceIdentifier.create(RoutingState.class); + final Initialized<? extends DataObject> initilized = + new RoutingStateCustomizer().init(identifier, state, readContext); + + final Routing initializedRouting = Routing.class.cast(initilized.getData()); + + assertEquals(config, initializedRouting); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/Ipv4RouteCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/Ipv4RouteCustomizerTest.java new file mode 100644 index 000000000..13b434716 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/Ipv4RouteCustomizerTest.java @@ -0,0 +1,220 @@ +/* + * 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.routing.write; + + +import static io.fd.hc2vpp.routing.helpers.InterfaceTestHelper.INTERFACE_INDEX; +import static io.fd.hc2vpp.routing.helpers.InterfaceTestHelper.INTERFACE_NAME; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import com.google.common.collect.ImmutableList; +import io.fd.hc2vpp.common.test.write.WriterCustomizerTest; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.Ipv4RouteData; +import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper; +import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper; +import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper; +import io.fd.hc2vpp.routing.naming.Ipv4RouteNamesFactory; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.test.tools.HoneycombTestRunner; +import io.fd.honeycomb.test.tools.annotations.InjectTestData; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.RoutingProtocols; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocolKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +@RunWith(HoneycombTestRunner.class) +public class Ipv4RouteCustomizerTest extends WriterCustomizerTest + implements ClassifyTableTestHelper, RoutingRequestTestHelper, SchemaContextTestHelper { + + @Captor + private ArgumentCaptor<IpAddDelRoute> requestCaptor; + + @Mock + private VppClassifierContextManager classifyManager; + + @Mock + private MultiNamingContext routeHopContext; + + private Ipv4RouteCustomizer customizer; + private InstanceIdentifier<Route> validId; + private Ipv4RouteNamesFactory namesFactory; + private NamingContext routingProtocolContext; + + @Override + protected void setUpTest() throws Exception { + NamingContext interfaceContext = new NamingContext("interface", "interface-context"); + routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context"); + customizer = new Ipv4RouteCustomizer(api, interfaceContext, + new NamingContext("route", "route-context"), + routingProtocolContext, routeHopContext, classifyManager); + + validId = InstanceIdentifier.create(RoutingProtocols.class) + .child(RoutingProtocol.class, new RoutingProtocolKey(ROUTE_PROTOCOL_NAME)) + .child(StaticRoutes.class) + .augmentation(StaticRoutes1.class) + .child(Ipv4.class) + .child(Route.class); + + namesFactory = new Ipv4RouteNamesFactory(interfaceContext, routingProtocolContext); + + defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context"); + defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context"); + addMapping(classifyManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext); + whenAddRouteThenSuccess(api); + } + + @Test + public void testWriteSingleHop( + @InjectTestData(resourcePath = "/ipv4/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route) + throws WriteFailedException { + final Route route1 = getIpv4RouteWithId(route, 1L); + noMappingDefined(mappingContext, namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), "route-context"); + + customizer.writeCurrentAttributes(validId, route1, writeContext); + verifyInvocation(1, ImmutableList + .of(desiredFlaglessResult(1, 0, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, + Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, 1, 1, 0, + CLASSIFY_TABLE_INDEX, 1)), + api, requestCaptor); + } + + @Test + public void testWriteHopList( + @InjectTestData(resourcePath = "/ipv4/multiHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route) + throws WriteFailedException { + final Route route1 = getIpv4RouteWithId(route, 1L); + noMappingDefined(mappingContext, namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), "route-context"); + + customizer.writeCurrentAttributes(validId, route1, writeContext); + verifyInvocation(2, + ImmutableList.of( + desiredFlaglessResult(1, 0, 1, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, + Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, + CLASSIFY_TABLE_INDEX, 1), + desiredFlaglessResult(1, 0, 1, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, + Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 3, 1, 1, 0, + CLASSIFY_TABLE_INDEX, 1)), api, + requestCaptor); + + verify(routeHopContext, times(1)) + .addChild( + namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), 1, + namesFactory.uniqueRouteHopName(getHopWithId(route1, 1)), + mappingContext); + verify(routeHopContext, times(1)) + .addChild( + namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), 2, + namesFactory.uniqueRouteHopName(getHopWithId(route1, 2)), + mappingContext); + } + + @Test + public void testWriteSpecialHop( + @InjectTestData(resourcePath = "/ipv4/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH) StaticRoutes route) + throws WriteFailedException { + final Route route1 = getIpv4RouteWithId(route, 1L); + noMappingDefined(mappingContext, namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), "route-context"); + + customizer.writeCurrentAttributes(validId, route1, writeContext); + verifyInvocation(1, ImmutableList + .of(desiredSpecialResult(1, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 1, 0, 0, 0)), api, + requestCaptor); + } + + @Test + public void testUpdate( + @InjectTestData(resourcePath = "/ipv4/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH) StaticRoutes route) { + try { + customizer.updateCurrentAttributes(validId, new RouteBuilder().build(), getIpv4RouteWithId(route, 1L), + writeContext); + } catch (WriteFailedException e) { + assertTrue(e.getCause() instanceof UnsupportedOperationException); + verifyNotInvoked(api); + return; + } + fail("Test should have thrown exception"); + } + + + @Test + public void testDeleteSingleHop( + @InjectTestData(resourcePath = "/ipv4/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route) + throws WriteFailedException { + customizer.deleteCurrentAttributes(validId, getIpv4RouteWithId(route, 1L), writeContext); + verifyInvocation(1, ImmutableList + .of(desiredFlaglessResult(0, 0, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, + Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, + 0, 1, 1, 0, CLASSIFY_TABLE_INDEX, 1)), api, requestCaptor); + } + + @Test + public void testDeleteHopList( + @InjectTestData(resourcePath = "/ipv4/multiHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route) + throws WriteFailedException { + final Route route1 = getIpv4RouteWithId(route, 1L); + noMappingDefined(mappingContext, namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), "route-context"); + + customizer.deleteCurrentAttributes(validId, route1, writeContext); + verifyInvocation(2, + ImmutableList.of( + desiredFlaglessResult(0, 0, 1, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, + Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, + CLASSIFY_TABLE_INDEX, 1), + desiredFlaglessResult(0, 0, 1, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, + new byte[]{-64, -88, 2, 2}, INTERFACE_INDEX, 3, 1, 1, 0, + CLASSIFY_TABLE_INDEX, 1)), api, requestCaptor); + + verify(routeHopContext, times(1)) + .removeChild( + namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), + namesFactory.uniqueRouteHopName(getHopWithId(route1, 1)), + mappingContext); + verify(routeHopContext, times(1)) + .removeChild( + namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), + namesFactory.uniqueRouteHopName(getHopWithId(route1, 2)), + mappingContext); + } + + @Test + public void testDeleteSpecialHop( + @InjectTestData(resourcePath = "/ipv4/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH) StaticRoutes route) + throws WriteFailedException { + customizer.deleteCurrentAttributes(validId, getIpv4RouteWithId(route, 1L), writeContext); + + verifyInvocation(1, + ImmutableList.of(desiredSpecialResult(0, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 1, 0, 0, 0)), api, + requestCaptor); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/Ipv6RouteCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/Ipv6RouteCustomizerTest.java new file mode 100644 index 000000000..c776ca7f7 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/Ipv6RouteCustomizerTest.java @@ -0,0 +1,186 @@ +/* + * 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.routing.write; + +import static io.fd.hc2vpp.routing.helpers.InterfaceTestHelper.INTERFACE_INDEX; +import static io.fd.hc2vpp.routing.helpers.InterfaceTestHelper.INTERFACE_NAME; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import com.google.common.collect.ImmutableList; +import io.fd.hc2vpp.common.test.write.WriterCustomizerTest; +import io.fd.hc2vpp.common.translate.util.MultiNamingContext; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.Ipv6RouteData; +import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper; +import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper; +import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.test.tools.HoneycombTestRunner; +import io.fd.honeycomb.test.tools.annotations.InjectTestData; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.RoutingProtocols; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocolKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +@RunWith(HoneycombTestRunner.class) +public class Ipv6RouteCustomizerTest extends WriterCustomizerTest + implements RoutingRequestTestHelper, ClassifyTableTestHelper, SchemaContextTestHelper { + + @Captor + private ArgumentCaptor<IpAddDelRoute> requestCaptor; + + @Mock + private VppClassifierContextManager classifyManager; + + @Mock + private MultiNamingContext routeHopContext; + + private NamingContext interfaceContext; + private NamingContext routeContext; + private NamingContext routingProtocolContext; + private Ipv6RouteCustomizer customizer; + + private InstanceIdentifier<Route> validId; + + @Override + protected void setUpTest() throws Exception { + interfaceContext = new NamingContext("interface", "interface-context"); + routeContext = new NamingContext("interface", "interface-context"); + routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context"); + customizer = + new Ipv6RouteCustomizer(api, interfaceContext, routeContext, routingProtocolContext, routeHopContext, + classifyManager); + + validId = InstanceIdentifier.create(RoutingProtocols.class) + .child(RoutingProtocol.class, new RoutingProtocolKey(ROUTE_PROTOCOL_NAME)) + .child(StaticRoutes.class) + .augmentation(StaticRoutes1.class) + .child(Ipv6.class) + .child(Route.class); + + defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context"); + addMapping(classifyManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext); + defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context"); + } + + @Test + public void testWriteSingleHop( + @InjectTestData(resourcePath = "/ipv6/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route) + throws WriteFailedException { + whenAddRouteThenSuccess(api); + customizer.writeCurrentAttributes(validId, getIpv6RouteWithId(route, 1L), writeContext); + verifyInvocation(1, ImmutableList + .of(desiredFlaglessResult(1, 1, 0, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64, + Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, 1, + 1, 0, CLASSIFY_TABLE_INDEX, 1)), api, requestCaptor); + } + + @Test + public void testWriteHopList( + @InjectTestData(resourcePath = "/ipv6/multiHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route) + throws WriteFailedException { + whenAddRouteThenSuccess(api); + customizer.writeCurrentAttributes(validId, getIpv6RouteWithId(route, 1L), writeContext); + verifyInvocation(2, + ImmutableList.of( + desiredFlaglessResult(1, 1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64, + Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, + CLASSIFY_TABLE_INDEX, 1), + desiredFlaglessResult(1, 1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64, + Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, + CLASSIFY_TABLE_INDEX, 1)), api, + requestCaptor); + } + + @Test + public void testUpdate() { + try { + customizer.updateCurrentAttributes(validId, Ipv6RouteData.IPV6_ROUTE_WITH_CLASSIFIER_BLACKHOLE_HOP, + Ipv6RouteData.IPV6_ROUTE_WITH_CLASSIFIER_RECEIVE_HOP, writeContext); + } catch (WriteFailedException e) { + assertTrue(e.getCause() instanceof UnsupportedOperationException); + verifyNotInvoked(api); + return; + } + fail("Test should have thrown exception"); + } + + @Test + public void testDeleteSpecialHop( + @InjectTestData(resourcePath = "/ipv6/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH) StaticRoutes route) + throws WriteFailedException { + whenAddRouteThenSuccess(api); + customizer.deleteCurrentAttributes(validId, getIpv6RouteWithId(route, 1L), + writeContext); + verifyInvocation(1, ImmutableList + .of(desiredSpecialResult(0, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 1, 0, 0, 0)), api, + requestCaptor); + } + + @Test + public void testDeleteSingleHop( + @InjectTestData(resourcePath = "/ipv6/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route) + throws WriteFailedException { + whenAddRouteThenSuccess(api); + customizer.deleteCurrentAttributes(validId, getIpv6RouteWithId(route, 1L), writeContext); + verifyInvocation(1, ImmutableList + .of(desiredFlaglessResult(0, 1, 0, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64, + Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, 1, + 1, 0, CLASSIFY_TABLE_INDEX, 1)), api, requestCaptor); + } + + @Test + public void testDeleteHopList( + @InjectTestData(resourcePath = "/ipv6/multiHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route) + throws WriteFailedException { + whenAddRouteThenSuccess(api); + customizer.deleteCurrentAttributes(validId, getIpv6RouteWithId(route, 1L), writeContext); + verifyInvocation(2, + ImmutableList.of( + desiredFlaglessResult(0, 1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64, + Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, + CLASSIFY_TABLE_INDEX, 1), + desiredFlaglessResult(0, 1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64, + Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, + CLASSIFY_TABLE_INDEX, 1)), api, + requestCaptor); + } + + @Test + public void testWriteSpecialHop( + @InjectTestData(resourcePath = "/ipv6/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH) StaticRoutes route) + throws WriteFailedException { + whenAddRouteThenSuccess(api); + customizer.writeCurrentAttributes(validId, getIpv6RouteWithId(route, 1L), + writeContext); + verifyInvocation(1, ImmutableList + .of(desiredSpecialResult(1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 1, 0, 0, 0)), api, + requestCaptor); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/RoutingInstanceCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/RoutingInstanceCustomizerTest.java new file mode 100644 index 000000000..68fcba5ac --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/RoutingInstanceCustomizerTest.java @@ -0,0 +1,95 @@ +/* + * 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.routing.write; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.when; + +import io.fd.hc2vpp.common.test.write.WriterCustomizerTest; +import io.fd.hc2vpp.routing.RoutingConfiguration; +import io.fd.honeycomb.translate.write.WriteFailedException; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstance; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstanceBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class RoutingInstanceCustomizerTest extends WriterCustomizerTest { + + private static final String VALID_NAME = "valid-name"; + private static final String INVALID_NAME = "invalid-name"; + + @Mock + private RoutingConfiguration configuration; + + private RoutingInstanceCustomizer customizer; + private InstanceIdentifier<RoutingInstance> id; + + private RoutingInstance validData; + private RoutingInstance invalidData; + + @Override + protected void setUpTest() throws Exception { + customizer = new RoutingInstanceCustomizer(configuration); + + when(configuration.getDefaultRoutingInstanceName()).thenReturn(VALID_NAME); + + id = InstanceIdentifier.create(RoutingInstance.class); + validData = new RoutingInstanceBuilder().setName(VALID_NAME).build(); + invalidData = new RoutingInstanceBuilder().setName(INVALID_NAME).build(); + } + + @Test + public void writeCurrentAttributesValid() throws Exception { + try { + customizer.writeCurrentAttributes(id, validData, writeContext); + } catch (Exception e) { + fail("Test should passed without exception"); + } + } + + @Test(expected = IllegalArgumentException.class) + public void writeCurrentAttributesInvalid() throws Exception { + customizer.writeCurrentAttributes(id, invalidData, writeContext); + } + + @Test + public void updateCurrentAttributes() throws Exception { + try { + customizer.updateCurrentAttributes(id, validData, validData, writeContext); + } catch (WriteFailedException.UpdateFailedException e) { + assertTrue(e.getCause() instanceof UnsupportedOperationException); + return; + } + fail("Test should throw WriteFailedException.UpdateFailedException"); + } + + @Test + public void deleteCurrentAttributesValid() throws Exception { + try { + customizer.deleteCurrentAttributes(id, validData, writeContext); + } catch (Exception e) { + fail("Test should passed without exception"); + } + } + + @Test(expected = IllegalArgumentException.class) + public void deleteCurrentAttributesInvalid() throws Exception { + customizer.deleteCurrentAttributes(id, invalidData, writeContext); + } + +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/RoutingProtocolCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/RoutingProtocolCustomizerTest.java new file mode 100644 index 000000000..d734aab66 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/RoutingProtocolCustomizerTest.java @@ -0,0 +1,110 @@ +/* + * 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.routing.write; + +import static io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper.ROUTE_PROTOCOL_NAME; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import io.fd.hc2vpp.common.test.write.WriterCustomizerTest; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Direct; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Static; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocolBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolVppAttr; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolVppAttrBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.VniReference; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.routing.routing.instance.routing.protocols.routing.protocol.VppProtocolAttributesBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class RoutingProtocolCustomizerTest extends WriterCustomizerTest { + + private InstanceIdentifier<RoutingProtocol> validId; + private RoutingProtocol validData; + private RoutingProtocol invalidData; + private RoutingProtocolCustomizer customizer; + private NamingContext routingProtocolContext; + + @Before + public void init() { + validId = InstanceIdentifier.create(RoutingProtocol.class); + validData = new RoutingProtocolBuilder() + .setName(ROUTE_PROTOCOL_NAME) + .setType(Static.class) + .addAugmentation(RoutingProtocolVppAttr.class, new RoutingProtocolVppAttrBuilder() + .setVppProtocolAttributes(new VppProtocolAttributesBuilder() + .setPrimaryVrf(new VniReference(1L)) + .build()) + .build()) + .build(); + + invalidData = new RoutingProtocolBuilder() + .setType(Direct.class) + .build(); + + routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context"); + customizer = new RoutingProtocolCustomizer(routingProtocolContext); + } + + @Test + public void testWriteIsStatic() throws WriteFailedException { + noMappingDefined(mappingContext, ROUTE_PROTOCOL_NAME, "routing-protocol-context"); + try { + customizer.writeCurrentAttributes(validId, validData, writeContext); + } catch (Exception e) { + fail("Test should have passed without throwing exception"); + } + } + + @Test + public void testWriteIsStaticAllreadyExist() throws WriteFailedException { + defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context"); + try { + customizer.writeCurrentAttributes(validId, validData, writeContext); + } catch (Exception e) { + assertTrue(e instanceof IllegalStateException); + return; + } + fail("Test should have thrown exception"); + } + + @Test + public void testWriteIsntStatic() throws WriteFailedException { + try { + customizer.writeCurrentAttributes(validId, invalidData, writeContext); + } catch (Exception e) { + assertTrue(e instanceof IllegalArgumentException); + return; + } + fail("Test should have thrown exception"); + } + + @Test + public void testUpdate() throws WriteFailedException { + try { + customizer.updateCurrentAttributes(validId, validData, validData, writeContext); + } catch (Exception e) { + assertTrue(e.getCause() instanceof UnsupportedOperationException); + return; + } + fail("Test should have thrown exception"); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactoryIpv4Test.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactoryIpv4Test.java new file mode 100644 index 000000000..43d01abbf --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactoryIpv4Test.java @@ -0,0 +1,119 @@ +/* + * 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.routing.write.factory; + + +import static org.junit.Assert.assertEquals; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.Ipv4RouteData; +import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper; +import io.fd.hc2vpp.routing.helpers.InterfaceTestHelper; +import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper; +import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.test.tools.HoneycombTestRunner; +import io.fd.honeycomb.test.tools.annotations.InjectTestData; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; + +@RunWith(HoneycombTestRunner.class) +public class MultipathHopRequestFactoryIpv4Test + implements RoutingRequestTestHelper, ClassifyTableTestHelper, SchemaContextTestHelper, InterfaceTestHelper { + + @Mock + private VppClassifierContextManager classifierContextManager; + + @Mock + private MappingContext mappingContext; + + @InjectTestData(resourcePath = "/ipv4/multiHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) + private StaticRoutes ipv4StaticRoutesWithClassifier; + + @InjectTestData(resourcePath = "/ipv4/multiHopRouteWithoutClassifier.json", id = STATIC_ROUTE_PATH) + private StaticRoutes ipv4StaticRoutesWithoutClassifier; + + private Route ipv4MutlipathRouteWithClassifier; + private NextHop ipv4nextHopWithClassifier; + + private Route ipv4MutlipathRouteWithoutClassifier; + private NextHop ipv4nextHopWithoutClassifier; + + private NamingContext interfaceContext; + private NamingContext routingProtocolContext; + private MultipathHopRequestFactory factory; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + interfaceContext = new NamingContext("interface", "interface-context"); + routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context"); + factory = MultipathHopRequestFactory + .forContexts(classifierContextManager, interfaceContext, routingProtocolContext); + + addMapping(classifierContextManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext); + defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context"); + defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context"); + + ipv4MutlipathRouteWithClassifier = getIpv4RouteWithId(ipv4StaticRoutesWithClassifier, 1L); + final List<NextHop> ipv4HopsClassified = + NextHopList.class.cast(ipv4MutlipathRouteWithClassifier.getNextHopOptions()).getNextHopList() + .getNextHop(); + ipv4nextHopWithClassifier = + ipv4HopsClassified.stream().filter(nextHop -> nextHop.getId() == 1L).findFirst().get(); + + ipv4MutlipathRouteWithoutClassifier = getIpv4RouteWithId(ipv4StaticRoutesWithoutClassifier, 1L); + final List<NextHop> ipv4HopsNonClassified = + NextHopList.class.cast(ipv4MutlipathRouteWithClassifier.getNextHopOptions()).getNextHopList() + .getNextHop(); + ipv4nextHopWithoutClassifier = + ipv4HopsNonClassified.stream().filter(nextHop -> nextHop.getId() == 1L).findFirst().get(); + } + + @Test + public void testIpv4WithClassifier() { + final IpAddDelRoute request = + factory.createIpv4MultipathHopRequest(false, ROUTE_PROTOCOL_NAME, ipv4MutlipathRouteWithClassifier, + ipv4nextHopWithClassifier, + mappingContext); + + assertEquals(desiredFlaglessResult(0, 0, 1, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, + Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, CLASSIFY_TABLE_INDEX, 1), request); + } + + @Test + public void testIpv4WithoutClassifier() { + final IpAddDelRoute request = + factory.createIpv4MultipathHopRequest(false, ROUTE_PROTOCOL_NAME, ipv4MutlipathRouteWithoutClassifier, + ipv4nextHopWithoutClassifier, + mappingContext); + + assertEquals( + desiredFlaglessResult(0, 0, 1, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, + Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, 0, 0), request); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactoryIpv6Test.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactoryIpv6Test.java new file mode 100644 index 000000000..9fc5fae65 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactoryIpv6Test.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.write.factory; + +import static org.junit.Assert.assertEquals; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.Ipv6RouteData; +import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper; +import io.fd.hc2vpp.routing.helpers.InterfaceTestHelper; +import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper; +import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.test.tools.HoneycombTestRunner; +import io.fd.honeycomb.test.tools.annotations.InjectTestData; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; + +@RunWith(HoneycombTestRunner.class) +public class MultipathHopRequestFactoryIpv6Test + implements RoutingRequestTestHelper, ClassifyTableTestHelper, InterfaceTestHelper, SchemaContextTestHelper { + + @Mock + private VppClassifierContextManager classifierContextManager; + + @Mock + private MappingContext mappingContext; + + @InjectTestData(resourcePath = "/ipv6/multiHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) + private StaticRoutes ipv6StaticRoutesWithClassifier; + + @InjectTestData(resourcePath = "/ipv6/multiHopRouteWithoutClassifier.json", id = STATIC_ROUTE_PATH) + private StaticRoutes ipv6StaticRoutesWithoutClassifier; + + private Route ipv6MultipathRouteWithClassifier; + private NextHop ipv6nextHopForClassified; + + private Route ipv6MultipathRouteWithoutClassifier; + private NextHop ipv6nextHopForNonClassified; + + private NamingContext interfaceContext; + private NamingContext routingProtocolContext; + private MultipathHopRequestFactory factory; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + interfaceContext = new NamingContext("interface", "interface-context"); + routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context"); + factory = MultipathHopRequestFactory + .forContexts(classifierContextManager, interfaceContext, routingProtocolContext); + + addMapping(classifierContextManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext); + defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context"); + defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context"); + + ipv6MultipathRouteWithClassifier = getIpv6RouteWithId(ipv6StaticRoutesWithClassifier, 1L); + ipv6MultipathRouteWithoutClassifier = getIpv6RouteWithId(ipv6StaticRoutesWithoutClassifier, 1L); + + final List<NextHop> ipv6HopsClassified = + NextHopList.class.cast(ipv6MultipathRouteWithClassifier.getNextHopOptions()).getNextHopList() + .getNextHop(); + + final List<NextHop> ipv6HopsNonClassified = + NextHopList.class.cast(ipv6MultipathRouteWithoutClassifier.getNextHopOptions()).getNextHopList() + .getNextHop(); + + ipv6nextHopForClassified = ipv6HopsClassified.stream() + .filter(nextHop -> nextHop.getId() == 1L) + .findFirst().get(); + ipv6nextHopForNonClassified = ipv6HopsNonClassified.stream() + .filter(nextHop -> nextHop.getId() == 1L) + .findFirst().get(); + } + + @Test + public void testIpv6WithClassifier() { + final IpAddDelRoute request = + factory.createIpv6MultipathHopRequest(false, ROUTE_PROTOCOL_NAME, ipv6MultipathRouteWithClassifier, + ipv6nextHopForClassified, + mappingContext); + + assertEquals( + desiredFlaglessResult(0, 1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64, + Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, CLASSIFY_TABLE_INDEX, 1), + request); + } + + @Test + public void testIpv6WithoutClassifier() { + final IpAddDelRoute request = + factory.createIpv6MultipathHopRequest(false, ROUTE_PROTOCOL_NAME, ipv6MultipathRouteWithoutClassifier, + ipv6nextHopForNonClassified, + mappingContext); + + assertEquals( + desiredFlaglessResult(0, 1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64, + Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, 0, 0), request); + } + + +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactoryIpv4Test.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactoryIpv4Test.java new file mode 100644 index 000000000..cfb352daa --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactoryIpv4Test.java @@ -0,0 +1,95 @@ +/* + * 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.routing.write.factory; + +import static org.junit.Assert.assertEquals; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.Ipv4RouteData; +import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper; +import io.fd.hc2vpp.routing.helpers.InterfaceTestHelper; +import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper; +import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.test.tools.HoneycombTestRunner; +import io.fd.honeycomb.test.tools.annotations.InjectTestData; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; + +@RunWith(HoneycombTestRunner.class) +public class SimpleHopRequestFactoryIpv4Test + implements RoutingRequestTestHelper, ClassifyTableTestHelper, InterfaceTestHelper, SchemaContextTestHelper { + @Mock + private VppClassifierContextManager classifierContextManager; + + @Mock + private MappingContext mappingContext; + + @InjectTestData(resourcePath = "/ipv4/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) + private StaticRoutes ipv4StaticRouteWithClassifier; + + @InjectTestData(resourcePath = "/ipv4/simpleHopRouteWithoutClassifier.json", id = STATIC_ROUTE_PATH) + private StaticRoutes ipv4StaticRouteWithoutClassifier; + + private NamingContext interfaceContext; + private NamingContext routingProtocolContext; + private SimpleHopRequestFactory factory; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + interfaceContext = new NamingContext("interface", "interface-context"); + routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context"); + factory = + SimpleHopRequestFactory.forContexts(classifierContextManager, interfaceContext, routingProtocolContext); + + addMapping(classifierContextManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext); + defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context"); + defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context"); + } + + @Test + public void testIpv4WithClassifier() { + final IpAddDelRoute request = + factory.createIpv4SimpleHopRequest(false, ROUTE_PROTOCOL_NAME, + getIpv4RouteWithId(ipv4StaticRouteWithClassifier, 1L), + mappingContext); + + assertEquals(desiredFlaglessResult(0, 0, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, + Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, + 1, 1, 0, CLASSIFY_TABLE_INDEX, 1), request); + } + + @Test + public void testIpv4WithoutClassifier() { + final IpAddDelRoute request = + factory.createIpv4SimpleHopRequest(false, ROUTE_PROTOCOL_NAME, + ipv4StaticRouteWithoutClassifier.getAugmentation(StaticRoutes1.class).getIpv4().getRoute() + .get(0), mappingContext); + + assertEquals( + desiredFlaglessResult(0, 0, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, + Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, 1, 1, 0, 0, 0), request); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactoryIpv6Test.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactoryIpv6Test.java new file mode 100644 index 000000000..e95a66775 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactoryIpv6Test.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.write.factory; + +import static org.junit.Assert.assertEquals; + +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.hc2vpp.routing.Ipv6RouteData; +import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper; +import io.fd.hc2vpp.routing.helpers.InterfaceTestHelper; +import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper; +import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.test.tools.HoneycombTestRunner; +import io.fd.honeycomb.test.tools.annotations.InjectTestData; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; + +@RunWith(HoneycombTestRunner.class) +public class SimpleHopRequestFactoryIpv6Test + implements RoutingRequestTestHelper, ClassifyTableTestHelper, InterfaceTestHelper, SchemaContextTestHelper { + + @Mock + private VppClassifierContextManager classifierContextManager; + + @Mock + private MappingContext mappingContext; + + @InjectTestData(resourcePath = "/ipv6/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) + private StaticRoutes ipv6StaticRouteWithClassifier; + + @InjectTestData(resourcePath = "/ipv6/simpleHopRouteWithoutClassifier.json", id = STATIC_ROUTE_PATH) + private StaticRoutes ipv6StaticRouteWithoutClassifier; + + private NamingContext interfaceContext; + private NamingContext routingProtocolContext; + private SimpleHopRequestFactory factory; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + interfaceContext = new NamingContext("interface", "interface-context"); + routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context"); + factory = + SimpleHopRequestFactory.forContexts(classifierContextManager, interfaceContext, routingProtocolContext); + + addMapping(classifierContextManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext); + defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context"); + defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context"); + } + + @Test + public void testIpv6WithClassifier() { + final IpAddDelRoute request = + factory.createIpv6SimpleHopRequest(false, ROUTE_PROTOCOL_NAME, + ipv6StaticRouteWithClassifier.getAugmentation(StaticRoutes1.class).getIpv6().getRoute().get(0), + mappingContext); + + assertEquals(desiredFlaglessResult(0, 1, 0, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64, + Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, 1, + 1, 0, CLASSIFY_TABLE_INDEX, 1), request); + } + + @Test + public void testIpv6WithoutClassifier() { + final IpAddDelRoute request = + factory.createIpv6SimpleHopRequest(false, ROUTE_PROTOCOL_NAME, + ipv6StaticRouteWithoutClassifier.getAugmentation(StaticRoutes1.class).getIpv6().getRoute() + .get(0), + mappingContext); + + assertEquals(desiredFlaglessResult(0, 1, 0, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64, + Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, 1, 1, 0, 0, 0), request); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactoryIpv4Test.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactoryIpv4Test.java new file mode 100644 index 000000000..dd93de59a --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactoryIpv4Test.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.routing.write.factory; + +import static org.junit.Assert.assertEquals; +import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Prohibit; +import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Receive; +import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Unreachable; + +import io.fd.hc2vpp.routing.Ipv4RouteData; +import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper; +import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper; +import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper; +import io.fd.hc2vpp.routing.write.trait.RouteRequestProducer; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.test.tools.HoneycombTestRunner; +import io.fd.honeycomb.test.tools.annotations.InjectTestData; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; + +@RunWith(HoneycombTestRunner.class) +public class SpecialNextHopRequestFactoryIpv4Test + implements RouteRequestProducer, RoutingRequestTestHelper, ClassifyTableTestHelper, + SchemaContextTestHelper { + + @Mock + private VppClassifierContextManager classifierContextManager; + + @Mock + private MappingContext mappingContext; + + private SpecialNextHopRequestFactory factory; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + factory = SpecialNextHopRequestFactory.forClassifierContext(classifierContextManager); + + addMapping(classifierContextManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext); + } + + @Test + public void testIpv4WithClassifierBlackhole( + @InjectTestData(resourcePath = "/ipv4/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH) + StaticRoutes routes) { + final IpAddDelRoute request = + factory.createIpv4SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, + SpecialNextHopGrouping.SpecialNextHop.Blackhole); + + assertEquals(desiredSpecialResult(1, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 1, 0, 0, 0), request); + } + + @Test + public void testIpv4WithClassifierReceive( + @InjectTestData(resourcePath = "/ipv4/specialHopRouteReceive.json", id = STATIC_ROUTE_PATH) + StaticRoutes routes) { + final IpAddDelRoute request = + factory.createIpv4SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Receive); + + assertEquals(desiredSpecialResult(1, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 0, 1, 0, 0), request); + } + + @Test + public void testIpv4WithClassifierUnreach( + @InjectTestData(resourcePath = "/ipv4/specialHopRouteUnreachable.json", id = STATIC_ROUTE_PATH) + StaticRoutes routes) { + final IpAddDelRoute request = + factory.createIpv4SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Unreachable); + + assertEquals(desiredSpecialResult(1, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 0, 0, 1, 0), request); + } + + @Test + public void testIpv4WithClassifierProhibited( + @InjectTestData(resourcePath = "/ipv4/specialHopRouteProhibited.json", id = STATIC_ROUTE_PATH) + StaticRoutes routes) { + final IpAddDelRoute request = + factory.createIpv4SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Prohibit); + + assertEquals(desiredSpecialResult(1, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 0, 0, 0, 1), request); + } + + private Route extractSingleRoute(final StaticRoutes staticRoutes, final long id) { + return staticRoutes.getAugmentation(StaticRoutes1.class).getIpv4().getRoute().stream() + .filter(route -> route.getId() == id) + .collect(RWUtils.singleItemCollector()); + } +} diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactoryIpv6Test.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactoryIpv6Test.java new file mode 100644 index 000000000..b129eef59 --- /dev/null +++ b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactoryIpv6Test.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.routing.write.factory; + +import static org.junit.Assert.assertEquals; +import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Blackhole; +import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Prohibit; +import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Receive; +import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Unreachable; + +import io.fd.hc2vpp.routing.Ipv6RouteData; +import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper; +import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper; +import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper; +import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.test.tools.HoneycombTestRunner; +import io.fd.honeycomb.test.tools.annotations.InjectTestData; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.vpp.jvpp.core.dto.IpAddDelRoute; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes; + +@RunWith(HoneycombTestRunner.class) +public class SpecialNextHopRequestFactoryIpv6Test + implements RoutingRequestTestHelper, ClassifyTableTestHelper, SchemaContextTestHelper { + + @Mock + private VppClassifierContextManager classifierContextManager; + + @Mock + private MappingContext mappingContext; + + private SpecialNextHopRequestFactory factory; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + factory = SpecialNextHopRequestFactory.forClassifierContext(classifierContextManager); + + addMapping(classifierContextManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext); + } + + @Test + public void testIpv6Blackhole( + @InjectTestData(resourcePath = "/ipv6/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH) + StaticRoutes routes) { + final IpAddDelRoute request = + factory.createIpv6SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Blackhole); + + assertEquals(desiredSpecialResult(1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 1, 0, 0, 0), + request); + } + + @Test + public void testIpv6Receive( + @InjectTestData(resourcePath = "/ipv6/specialHopRouteReceive.json", id = STATIC_ROUTE_PATH) + StaticRoutes routes) { + final IpAddDelRoute request = + factory.createIpv6SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Receive); + + assertEquals(desiredSpecialResult(1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 0, 1, 0, 0), request); + } + + @Test + public void testIpv6Unreach( + @InjectTestData(resourcePath = "/ipv6/specialHopRouteUnreachable.json", id = STATIC_ROUTE_PATH) + StaticRoutes routes) { + final IpAddDelRoute request = + factory.createIpv6SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Unreachable); + + assertEquals(desiredSpecialResult(1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 0, 0, 1, 0), request); + } + + @Test + public void testIpv6Prohibited( + @InjectTestData(resourcePath = "/ipv6/specialHopRouteProhibited.json", id = STATIC_ROUTE_PATH) + StaticRoutes routes) { + final IpAddDelRoute request = + factory.createIpv6SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Prohibit); + + assertEquals(desiredSpecialResult(1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 0, 0, 0, 1), request); + } + + private Route extractSingleRoute(final StaticRoutes staticRoutes, final long id) { + return staticRoutes.getAugmentation(StaticRoutes1.class).getIpv6().getRoute().stream() + .filter(route -> route.getId() == id).collect( + RWUtils.singleItemCollector()); + } + +} diff --git a/routing/routing-impl/src/test/resources/init/config-data.json b/routing/routing-impl/src/test/resources/init/config-data.json new file mode 100644 index 000000000..05a888b30 --- /dev/null +++ b/routing/routing-impl/src/test/resources/init/config-data.json @@ -0,0 +1,109 @@ +{ + "routing": { + "routing-instance": { + "name": "routing-3", + "router-id": "192.168.2.1", + "routing-protocols": { + "routing-protocol": [ + { + "name": "test-routing-protocol", + "type": "static", + "vpp-protocol-attributes": { + "primary-vrf": "1" + }, + "static-routes": { + "ipv4": { + "route": [ + { + "id": 1, + "destination-prefix": "192.168.2.3/32", + "next-hop": "192.168.2.8", + "outgoing-interface": "local0", + "vpp-ipv4-route": { + "secondary-vrf": "1" + } + }, + { + "id": 2, + "destination-prefix": "192.168.2.4/32", + "vpp-ipv4-route": { + "secondary-vrf": "1" + }, + "next-hop-list": { + "next-hop": [ + { + "id": "1", + "address": "192.168.2.5", + "outgoing-interface": "local0", + "weight": "1" + }, + { + "id": "2", + "address": "192.168.2.6", + "outgoing-interface": "local0", + "weight": "2" + } + ] + } + }, + { + "id": 3, + "destination-prefix": "192.168.2.5/32", + "special-next-hop": "receive" + } + ] + }, + "ipv6": { + "route": [ + { + "id": 1, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64", + "next-hop": "2001:0db8:0a0b:12f0:0000:0000:0000:0002", + "outgoing-interface": "GigabitEthernet0/8/0", + "vpp-ipv6-route": { + "secondary-vrf": "1" + } + }, + { + "id": 2, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0008/64", + "vpp-ipv6-route": { + "secondary-vrf": "1" + }, + "next-hop-list": { + "next-hop": [ + { + "id": "1", + "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0003", + "outgoing-interface": "GigabitEthernet0/8/0", + "weight": "1" + }, + { + "id": "2", + "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0004", + "outgoing-interface": "GigabitEthernet0/8/0", + "weight": "2" + }, + { + "id": "3", + "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0005", + "outgoing-interface": "GigabitEthernet0/8/0", + "weight": "3" + } + ] + } + }, + { + "id": 3, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0005/32", + "special-next-hop": "receive" + } + ] + } + } + } + ] + } + } + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/resources/init/state-data.json b/routing/routing-impl/src/test/resources/init/state-data.json new file mode 100644 index 000000000..7830c8e0a --- /dev/null +++ b/routing/routing-impl/src/test/resources/init/state-data.json @@ -0,0 +1,109 @@ +{ + "routing-state": { + "routing-instance": { + "name": "routing-3", + "router-id": "192.168.2.1", + "routing-protocols": { + "routing-protocol": [ + { + "name": "test-routing-protocol", + "type": "static", + "vpp-protocol-state-attributes": { + "primary-vrf": "1" + }, + "static-routes": { + "ipv4": { + "route": [ + { + "id": 1, + "destination-prefix": "192.168.2.3/32", + "next-hop": "192.168.2.8", + "outgoing-interface": "local0", + "vpp-ipv4-route-state": { + "secondary-vrf": "1" + } + }, + { + "id": 2, + "destination-prefix": "192.168.2.4/32", + "vpp-ipv4-route-state": { + "secondary-vrf": "1" + }, + "next-hop-list": { + "next-hop": [ + { + "id": "1", + "address": "192.168.2.5", + "outgoing-interface": "local0", + "weight": "1" + }, + { + "id": "2", + "address": "192.168.2.6", + "outgoing-interface": "local0", + "weight": "2" + } + ] + } + }, + { + "id": 3, + "destination-prefix": "192.168.2.5/32", + "special-next-hop": "receive" + } + ] + }, + "ipv6": { + "route": [ + { + "id": 1, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64", + "next-hop": "2001:0db8:0a0b:12f0:0000:0000:0000:0002", + "outgoing-interface": "GigabitEthernet0/8/0", + "vpp-ipv6-route-state": { + "secondary-vrf": "1" + } + }, + { + "id": 2, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0008/64", + "vpp-ipv6-route-state": { + "secondary-vrf": "1" + }, + "next-hop-list": { + "next-hop": [ + { + "id": "1", + "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0003", + "outgoing-interface": "GigabitEthernet0/8/0", + "weight": "1" + }, + { + "id": "2", + "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0004", + "outgoing-interface": "GigabitEthernet0/8/0", + "weight": "2" + }, + { + "id": "3", + "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0005", + "outgoing-interface": "GigabitEthernet0/8/0", + "weight": "3" + } + ] + } + }, + { + "id": 3, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0005/32", + "special-next-hop": "receive" + } + ] + } + } + } + ] + } + } + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/resources/ipv4/multiHopRouteWithClassifier.json b/routing/routing-impl/src/test/resources/ipv4/multiHopRouteWithClassifier.json new file mode 100644 index 000000000..99c987e03 --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv4/multiHopRouteWithClassifier.json @@ -0,0 +1,31 @@ +{ + "static-routes": { + "ipv4": { + "route": [ + { + "id": 1, + "destination-prefix": "192.168.2.1/24", + "vpp-ipv4-route": { + "classify-table": "classify-table-one" + }, + "next-hop-list": { + "next-hop": [ + { + "id": "1", + "address": "192.168.2.1", + "outgoing-interface": "iface", + "weight": "2" + }, + { + "id": "2", + "address": "192.168.2.2", + "outgoing-interface": "iface", + "weight": "3" + } + ] + } + } + ] + } + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/resources/ipv4/multiHopRouteWithoutClassifier.json b/routing/routing-impl/src/test/resources/ipv4/multiHopRouteWithoutClassifier.json new file mode 100644 index 000000000..d4d4a0693 --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv4/multiHopRouteWithoutClassifier.json @@ -0,0 +1,30 @@ +{ + "static-routes": { + "ipv4": { + "route": [ + { + "id": 1, + "destination-prefix": "192.168.2.1/24", + "vpp-ipv4-route": { + }, + "next-hop-list": { + "next-hop": [ + { + "id": "1", + "address": "192.168.2.1", + "outgoing-interface": "iface", + "weight": "2" + }, + { + "id": "2", + "address": "192.168.2.2", + "outgoing-interface": "iface", + "weight": "3" + } + ] + } + } + ] + } + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/resources/ipv4/simpleHopRouteWithClassifier.json b/routing/routing-impl/src/test/resources/ipv4/simpleHopRouteWithClassifier.json new file mode 100644 index 000000000..d00d9a06a --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv4/simpleHopRouteWithClassifier.json @@ -0,0 +1,17 @@ +{ + "static-routes": { + "ipv4": { + "route": [ + { + "id": 1, + "destination-prefix": "192.168.2.1/24", + "vpp-ipv4-route": { + "classify-table": "classify-table-one" + }, + "next-hop": "192.168.2.2", + "outgoing-interface": "iface" + } + ] + } + } +} diff --git a/routing/routing-impl/src/test/resources/ipv4/simpleHopRouteWithoutClassifier.json b/routing/routing-impl/src/test/resources/ipv4/simpleHopRouteWithoutClassifier.json new file mode 100644 index 000000000..0ef7cf765 --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv4/simpleHopRouteWithoutClassifier.json @@ -0,0 +1,16 @@ +{ + "static-routes": { + "ipv4": { + "route": [ + { + "id": 1, + "destination-prefix": "192.168.2.1/24", + "vpp-ipv4-route": { + }, + "next-hop": "192.168.2.2", + "outgoing-interface": "iface" + } + ] + } + } +} diff --git a/routing/routing-impl/src/test/resources/ipv4/specialHopRouteBlackhole.json b/routing/routing-impl/src/test/resources/ipv4/specialHopRouteBlackhole.json new file mode 100644 index 000000000..b2ddc238b --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv4/specialHopRouteBlackhole.json @@ -0,0 +1,13 @@ +{ + "static-routes": { + "ipv4": { + "route": [ + { + "id": 1, + "destination-prefix": "192.168.2.1/24", + "special-next-hop": "blackhole" + } + ] + } + } +} diff --git a/routing/routing-impl/src/test/resources/ipv4/specialHopRouteProhibited.json b/routing/routing-impl/src/test/resources/ipv4/specialHopRouteProhibited.json new file mode 100644 index 000000000..fe9faf44c --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv4/specialHopRouteProhibited.json @@ -0,0 +1,13 @@ +{ + "static-routes": { + "ipv4": { + "route": [ + { + "id": 1, + "destination-prefix": "192.168.2.1/24", + "special-next-hop": "prohibit" + } + ] + } + } +} diff --git a/routing/routing-impl/src/test/resources/ipv4/specialHopRouteReceive.json b/routing/routing-impl/src/test/resources/ipv4/specialHopRouteReceive.json new file mode 100644 index 000000000..c967aa542 --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv4/specialHopRouteReceive.json @@ -0,0 +1,13 @@ +{ + "static-routes": { + "ipv4": { + "route": [ + { + "id": 1, + "destination-prefix": "192.168.2.1/24", + "special-next-hop": "receive" + } + ] + } + } +} diff --git a/routing/routing-impl/src/test/resources/ipv4/specialHopRouteUnreachable.json b/routing/routing-impl/src/test/resources/ipv4/specialHopRouteUnreachable.json new file mode 100644 index 000000000..bae467fbd --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv4/specialHopRouteUnreachable.json @@ -0,0 +1,13 @@ +{ + "static-routes": { + "ipv4": { + "route": [ + { + "id": 1, + "destination-prefix": "192.168.2.1/24", + "special-next-hop": "unreachable" + } + ] + } + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/resources/ipv6/multiHopRouteWithClassifier.json b/routing/routing-impl/src/test/resources/ipv6/multiHopRouteWithClassifier.json new file mode 100644 index 000000000..c8b1e208e --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv6/multiHopRouteWithClassifier.json @@ -0,0 +1,31 @@ +{ + "static-routes": { + "ipv6": { + "route": [ + { + "id": 1, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64", + "vpp-ipv6-route": { + "classify-table": "classify-table-one" + }, + "next-hop-list": { + "next-hop": [ + { + "id": "1", + "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0002", + "outgoing-interface": "iface", + "weight": "2" + }, + { + "id": "2", + "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0002", + "outgoing-interface": "iface", + "weight": "2" + } + ] + } + } + ] + } + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/resources/ipv6/multiHopRouteWithoutClassifier.json b/routing/routing-impl/src/test/resources/ipv6/multiHopRouteWithoutClassifier.json new file mode 100644 index 000000000..2e44ebcf5 --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv6/multiHopRouteWithoutClassifier.json @@ -0,0 +1,30 @@ +{ + "static-routes": { + "ipv6": { + "route": [ + { + "id": 1, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64", + "vpp-ipv6-route": { + }, + "next-hop-list": { + "next-hop": [ + { + "id": "1", + "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0002", + "outgoing-interface": "iface", + "weight": "2" + }, + { + "id": "2", + "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0002", + "outgoing-interface": "iface", + "weight": "2" + } + ] + } + } + ] + } + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/resources/ipv6/simpleHopRouteWithClassifier.json b/routing/routing-impl/src/test/resources/ipv6/simpleHopRouteWithClassifier.json new file mode 100644 index 000000000..c011a8d01 --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv6/simpleHopRouteWithClassifier.json @@ -0,0 +1,17 @@ +{ + "static-routes": { + "ipv6": { + "route": [ + { + "id": 1, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64", + "vpp-ipv6-route": { + "classify-table": "classify-table-one" + }, + "next-hop": "2001:0db8:0a0b:12f0:0000:0000:0000:0002", + "outgoing-interface": "iface" + } + ] + } + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/resources/ipv6/simpleHopRouteWithoutClassifier.json b/routing/routing-impl/src/test/resources/ipv6/simpleHopRouteWithoutClassifier.json new file mode 100644 index 000000000..1cb663ca7 --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv6/simpleHopRouteWithoutClassifier.json @@ -0,0 +1,16 @@ +{ + "static-routes": { + "ipv6": { + "route": [ + { + "id": 1, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64", + "vpp-ipv6-route": { + }, + "next-hop": "2001:0db8:0a0b:12f0:0000:0000:0000:0002", + "outgoing-interface": "iface" + } + ] + } + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/resources/ipv6/specialHopRouteBlackhole.json b/routing/routing-impl/src/test/resources/ipv6/specialHopRouteBlackhole.json new file mode 100644 index 000000000..1cc319107 --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv6/specialHopRouteBlackhole.json @@ -0,0 +1,13 @@ +{ + "static-routes": { + "ipv6": { + "route": [ + { + "id": 1, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/24", + "special-next-hop": "blackhole" + } + ] + } + } +} diff --git a/routing/routing-impl/src/test/resources/ipv6/specialHopRouteProhibited.json b/routing/routing-impl/src/test/resources/ipv6/specialHopRouteProhibited.json new file mode 100644 index 000000000..d69e817d7 --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv6/specialHopRouteProhibited.json @@ -0,0 +1,13 @@ +{ + "static-routes": { + "ipv6": { + "route": [ + { + "id": 1, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/24", + "special-next-hop": "prohibit" + } + ] + } + } +} diff --git a/routing/routing-impl/src/test/resources/ipv6/specialHopRouteReceive.json b/routing/routing-impl/src/test/resources/ipv6/specialHopRouteReceive.json new file mode 100644 index 000000000..50d447de0 --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv6/specialHopRouteReceive.json @@ -0,0 +1,13 @@ +{ + "static-routes": { + "ipv6": { + "route": [ + { + "id": 1, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/24", + "special-next-hop": "receive" + } + ] + } + } +} diff --git a/routing/routing-impl/src/test/resources/ipv6/specialHopRouteUnreachable.json b/routing/routing-impl/src/test/resources/ipv6/specialHopRouteUnreachable.json new file mode 100644 index 000000000..c874549d1 --- /dev/null +++ b/routing/routing-impl/src/test/resources/ipv6/specialHopRouteUnreachable.json @@ -0,0 +1,13 @@ +{ + "static-routes": { + "ipv6": { + "route": [ + { + "id": 1, + "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/24", + "special-next-hop": "unreachable" + } + ] + } + } +}
\ No newline at end of file diff --git a/routing/routing-impl/src/test/resources/routing.json b/routing/routing-impl/src/test/resources/routing.json new file mode 100644 index 000000000..95f85414f --- /dev/null +++ b/routing/routing-impl/src/test/resources/routing.json @@ -0,0 +1,4 @@ +{ + "default-routing-instance-name": "vpp-routing-instance", + "learned-route-name-prefix": "learned-route" +}
\ No newline at end of file |