2 * Copyright (c) 2016 Brocade Communications Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.protocol.bgp.l3vpn;
10 import com.google.common.base.Optional;
11 import com.google.common.collect.ImmutableCollection;
12 import com.google.common.collect.ImmutableSet;
13 import io.netty.buffer.ByteBuf;
14 import io.netty.buffer.Unpooled;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.stream.Collectors;
20 import javax.annotation.Nonnull;
21 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
22 import org.opendaylight.protocol.bgp.labeled.unicast.LabeledUnicastRIBSupport;
23 import org.opendaylight.protocol.bgp.rib.spi.AbstractRIBSupport;
24 import org.opendaylight.protocol.util.ByteArray;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.DestinationType;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlri;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlri;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlriBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AddressFamily;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.MplsLabeledVpnSubsequentAddressFamily;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RouteDistinguisher;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RouteDistinguisherBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.CNextHop;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.vpn.rev160413.l3vpn.ip.destination.type.VpnDestination;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.vpn.rev160413.l3vpn.ip.destination.type.VpnDestinationBuilder;
41 import org.opendaylight.yangtools.yang.binding.DataObject;
42 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
43 import org.opendaylight.yangtools.yang.common.QName;
44 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
45 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
46 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
47 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
48 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
49 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
50 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
51 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
52 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
53 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
54 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
55 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
56 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
63 public abstract class AbstractVpnRIBSupport extends AbstractRIBSupport {
64 private static final Logger LOG = LoggerFactory.getLogger(AbstractVpnRIBSupport.class);
65 private final NodeIdentifier NLRI_ROUTES_LIST;
66 private final NodeIdentifier PREFIX_TYPE_NID;
67 private final NodeIdentifier LABEL_STACK_NID;
68 private final NodeIdentifier LV_NID;
69 private final NodeIdentifier RD_NID;
70 private final NodeIdentifier DESTINATION;
71 private final QName ROUTE_KEY;
72 private final NodeIdentifier ROUTE;
73 private final Class<? extends AddressFamily> ADDRESS_FAMILY_CLAZZ;
74 private final QName CONTAINER_CLASS_QNAME;
75 private final QName LIST_CLASS_QNAME;
76 private final ChoiceNode EMPTY_ROUTES;
79 * Default constructor. Requires the QName of the container augmented under the routes choice
80 * node in instantiations of the rib grouping. It is assumed that this container is defined by
81 * the same model which populates it with route grouping instantiation, and by extension with
82 * the route attributes container.
84 * @param cazeClass Binding class of the AFI/SAFI-specific case statement, must not be null
85 * @param containerClass Binding class of the container in routes choice, must not be null.
86 * @param listClass Binding class of the route list, nust not be null;
88 protected AbstractVpnRIBSupport(
89 Class<? extends Routes> cazeClass,
90 Class<? extends DataObject> containerClass,
91 Class<? extends Route> listClass,
92 Class<? extends AddressFamily> addressFamilyClass,
93 final QName VPN_DST_CONTAINER_CLASS_QNAME
95 super(cazeClass, containerClass, listClass);
96 CONTAINER_CLASS_QNAME = BindingReflections.findQName(containerClass).intern();
99 CONTAINER_CLASS_QNAME.getNamespace(), CONTAINER_CLASS_QNAME.getRevision(), BindingReflections.findQName(listClass).intern().getLocalName()
101 ROUTE = NodeIdentifier.create(LIST_CLASS_QNAME);
102 ROUTE_KEY = QName.create(LIST_CLASS_QNAME, "route-key").intern();
103 EMPTY_ROUTES = Builders.choiceBuilder()
104 .withNodeIdentifier(YangInstanceIdentifier.NodeIdentifier.create(Routes.QNAME))
106 Builders.containerBuilder()
107 .withNodeIdentifier(YangInstanceIdentifier.NodeIdentifier.create(CONTAINER_CLASS_QNAME))
109 ImmutableNodes.mapNodeBuilder(
114 final QName VPN_DST_CLASS_QNAME =
116 CONTAINER_CLASS_QNAME.getNamespace(), CONTAINER_CLASS_QNAME.getRevision(), VpnDestination.QNAME.getLocalName()
118 NLRI_ROUTES_LIST = NodeIdentifier.create(VPN_DST_CLASS_QNAME);
119 PREFIX_TYPE_NID = NodeIdentifier.create(QName.create(VPN_DST_CLASS_QNAME, "prefix").intern());
120 LABEL_STACK_NID = NodeIdentifier.create(QName.create(VPN_DST_CLASS_QNAME, "label-stack").intern());
121 LV_NID = NodeIdentifier.create(QName.create(VPN_DST_CLASS_QNAME, "label-value").intern());
122 RD_NID = NodeIdentifier.create(QName.create(VPN_DST_CLASS_QNAME, "route-distinguisher").intern());
123 DESTINATION = NodeIdentifier.create(VPN_DST_CONTAINER_CLASS_QNAME);
124 ADDRESS_FAMILY_CLAZZ = addressFamilyClass;
127 private VpnDestination extractVpnDestination(DataContainerNode<? extends PathArgument> route) {
128 final VpnDestination dst = new VpnDestinationBuilder()
129 .setPrefix(LabeledUnicastRIBSupport.extractPrefix(route, PREFIX_TYPE_NID))
130 .setLabelStack(LabeledUnicastRIBSupport.extractLabel(route, LABEL_STACK_NID, LV_NID))
131 .setRouteDistinguisher(extractRouteDistinguisher(route))
136 private RouteDistinguisher extractRouteDistinguisher(final DataContainerNode<? extends YangInstanceIdentifier.PathArgument> route) {
137 if (route.getChild(RD_NID).isPresent()) {
138 return RouteDistinguisherBuilder.getDefaultInstance((String) route.getChild(RD_NID).get().getValue());
145 public ChoiceNode emptyRoutes() {
151 protected NodeIdentifier destinationContainerIdentifier() {
156 protected void deleteDestinationRoutes(DOMDataWriteTransaction tx, YangInstanceIdentifier tablePath, ContainerNode destination, YangInstanceIdentifier.NodeIdentifier routesNodeId) {
157 processDestination(tx, tablePath.node(routesNodeId), destination, null, DELETE_ROUTE);
161 protected void putDestinationRoutes(DOMDataWriteTransaction tx, YangInstanceIdentifier tablePath, ContainerNode destination, ContainerNode attributes, YangInstanceIdentifier.NodeIdentifier routesNodeId) {
162 processDestination(tx, tablePath.node(routesNodeId), destination, attributes, putRoute);
165 protected abstract DestinationType getAdvertizedDestinationType(List<VpnDestination> dests);
167 protected abstract DestinationType getWithdrawnDestinationType(List<VpnDestination> dests);
171 protected MpReachNlri buildReach(Collection<MapEntryNode> routes, CNextHop hop) {
172 final MpReachNlriBuilder mb = new MpReachNlriBuilder()
173 .setAfi(ADDRESS_FAMILY_CLAZZ)
174 .setSafi(MplsLabeledVpnSubsequentAddressFamily.class)
177 final List<VpnDestination> dests = new ArrayList<>(routes.size());
178 dests.addAll(routes.stream().map(this::extractVpnDestination).collect(Collectors.toList()));
180 mb.setAdvertizedRoutes(
181 new AdvertizedRoutesBuilder().setDestinationType(
182 getAdvertizedDestinationType(dests)
190 protected MpUnreachNlri buildUnreach(Collection<MapEntryNode> routes) {
191 final MpUnreachNlriBuilder mb = new MpUnreachNlriBuilder()
192 .setAfi(ADDRESS_FAMILY_CLAZZ)
193 .setSafi(MplsLabeledVpnSubsequentAddressFamily.class);
195 final List<VpnDestination> dests = new ArrayList<>(routes.size());
196 dests.addAll(routes.stream().map(this::extractVpnDestination).collect(Collectors.toList()));
198 mb.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
199 getWithdrawnDestinationType(dests)
207 public ImmutableCollection<Class<? extends DataObject>> cacheableAttributeObjects() {
208 return ImmutableSet.of();
213 public ImmutableCollection<Class<? extends DataObject>> cacheableNlriObjects() {
214 return ImmutableSet.of();
218 public boolean isComplexRoute() {
222 private void processDestination(final DOMDataWriteTransaction tx, final YangInstanceIdentifier routesPath,
223 final ContainerNode destination, final ContainerNode attributes, final ApplyRoute function) {
224 if (destination != null) {
225 final Optional<DataContainerChild<? extends PathArgument, ?>> maybeRoutes = destination.getChild(NLRI_ROUTES_LIST);
226 if (maybeRoutes.isPresent()) {
227 final DataContainerChild<? extends PathArgument, ?> routes = maybeRoutes.get();
228 if (routes instanceof UnkeyedListNode) {
229 UnkeyedListNode routeListNode = (UnkeyedListNode) routes;
230 LOG.debug("{} routes are found", routeListNode.getSize());
231 final YangInstanceIdentifier base = routesPath.node(routesContainerIdentifier()).node(ROUTE);
232 for (final UnkeyedListEntryNode e : routeListNode.getValue()) {
233 final NodeIdentifierWithPredicates routeKey = createRouteKey(e);
234 LOG.debug("Route {} is processed.", routeKey);
235 function.apply(tx, base, routeKey, e, attributes);
238 LOG.warn("Routes {} are not a map", routes);
242 LOG.debug("Destination is null.");
246 private NodeIdentifierWithPredicates createRouteKey(final UnkeyedListEntryNode l3vpn) {
247 final ByteBuf buffer = Unpooled.buffer();
249 final VpnDestination dest = extractVpnDestination(l3vpn);
250 AbstractVpnNlriParser.serializeNlri(Collections.singletonList(dest), buffer);
251 return new NodeIdentifierWithPredicates(LIST_CLASS_QNAME, ROUTE_KEY, ByteArray.readAllBytes(buffer));