diff options
Diffstat (limited to 'routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write')
14 files changed, 1760 insertions, 0 deletions
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; + } +} |