2 * Copyright (c) 2015 Cisco 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.rib.spi;
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import java.util.Collection;
14 import java.util.Collections;
15 import javax.annotation.Nonnull;
16 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.UpdateBuilder;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Attributes;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AttributesBuilder;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1Builder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2Builder;
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.MpUnreachNlri;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutes;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.unreach.nlri.WithdrawnRoutes;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.CNextHop;
33 import org.opendaylight.yangtools.yang.binding.DataObject;
34 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
35 import org.opendaylight.yangtools.yang.common.QName;
36 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
38 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
39 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
40 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
42 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
48 public abstract class AbstractRIBSupport implements RIBSupport {
49 private static final Logger LOG = LoggerFactory.getLogger(AbstractRIBSupport.class);
50 private static final NodeIdentifier ADVERTIZED_ROUTES = new NodeIdentifier(AdvertizedRoutes.QNAME);
51 private static final NodeIdentifier WITHDRAWN_ROUTES = new NodeIdentifier(WithdrawnRoutes.QNAME);
52 private static final NodeIdentifier DESTINATION_TYPE = new NodeIdentifier(DestinationType.QNAME);
53 private static final NodeIdentifier ROUTES = new NodeIdentifier(Routes.QNAME);
55 private final NodeIdentifier routesContainerIdentifier;
56 private final NodeIdentifier routesListIdentifier;
57 private final NodeIdentifier routeAttributesIdentifier;
58 private final Class<? extends Routes> cazeClass;
59 private final Class<? extends DataObject> containerClass;
60 private final Class<? extends Route> listClass;
64 * Default constructor. Requires the QName of the container augmented under the routes choice
65 * node in instantiations of the rib grouping. It is assumed that this container is defined by
66 * the same model which populates it with route grouping instantiation, and by extension with
67 * the route attributes container.
69 * @param cazeClass Binding class of the AFI/SAFI-specific case statement, must not be null
70 * @param containerClass Binding class of the container in routes choice, must not be null.
71 * @param listClass Binding class of the route list, nust not be null;
73 protected AbstractRIBSupport(final Class<? extends Routes> cazeClass, final Class<? extends DataObject> containerClass, final Class<? extends Route> listClass) {
74 final QName qname = QName.cachedReference(BindingReflections.findQName(containerClass));
75 this.routesContainerIdentifier = new NodeIdentifier(qname);
76 this.routeAttributesIdentifier = new NodeIdentifier(QName.cachedReference(QName.create(qname, Attributes.QNAME.getLocalName())));
77 this.cazeClass = Preconditions.checkNotNull(cazeClass);
78 this.containerClass = Preconditions.checkNotNull(containerClass);
79 this.listClass = Preconditions.checkNotNull(listClass);
80 this.routesListIdentifier = new NodeIdentifier(QName.cachedReference(BindingReflections.findQName(listClass)));
84 public final Class<? extends Routes> routesCaseClass() {
85 return this.cazeClass;
89 public final Class<? extends DataObject> routesContainerClass() {
90 return this.containerClass;
94 public final Class<? extends Route> routesListClass() {
95 return this.listClass;
99 * Return the {@link NodeIdentifier} of the AFI/SAFI-specific container under
102 * @return Container identifier, may not be null.
104 protected final NodeIdentifier routesContainerIdentifier() {
105 return this.routesContainerIdentifier;
109 * Return the {@link NodeIdentifier} of the AFI/SAFI-specific container under
110 * the NLRI destination.
112 * @return Container identifier, may not be null.
114 @Nonnull protected abstract NodeIdentifier destinationContainerIdentifier();
117 * Given the destination as ContainerNode, implementation needs to parse the DOM model
118 * from this point onward:
120 * {@code /bgp-mp:mp-unreach-nlri/bgp-mp:withdrawn-routes/bgp-mp:destination-type }
122 * and delete the routes from its RIBs.
124 * @param tx DOMDataWriteTransaction to be passed into implementation
125 * @param tablePath YangInstanceIdentifier to be passed into implementation
126 * @param destination ContainerNode DOM representation of NLRI in Update message
127 * @param routesNodeId NodeIdentifier
129 protected abstract void deleteDestinationRoutes(DOMDataWriteTransaction tx, YangInstanceIdentifier tablePath, ContainerNode destination, NodeIdentifier routesNodeId);
132 * Given the destination as ContainerNode, implementation needs to parse the DOM model
133 * from this point onward:
135 * {@code /bgp-mp:mp-reach-nlri/bgp-mp:advertized-routes/bgp-mp:destination-type }
137 * and put the routes to its RIBs.
139 * @param tx DOMDataWriteTransaction to be passed into implementation
140 * @param tablePath YangInstanceIdentifier to be passed into implementation
141 * @param destination ContainerNode DOM representation of NLRI in Update message
142 * @param attributes ContainerNode to be passed into implementation
143 * @param routesNodeId NodeIdentifier
145 protected abstract void putDestinationRoutes(DOMDataWriteTransaction tx, YangInstanceIdentifier tablePath, ContainerNode destination, ContainerNode attributes,
146 NodeIdentifier routesNodeId);
148 private static ContainerNode getDestination(final DataContainerChild<? extends PathArgument, ?> routes, final NodeIdentifier destinationId) {
149 if (routes instanceof ContainerNode) {
150 final Optional<DataContainerChild<? extends PathArgument, ?>> maybeDestination = ((ContainerNode)routes).getChild(DESTINATION_TYPE);
151 if (maybeDestination.isPresent()) {
152 final DataContainerChild<? extends PathArgument, ?> destination = maybeDestination.get();
153 if (destination instanceof ChoiceNode) {
154 final Optional<DataContainerChild<? extends PathArgument, ?>> maybeRet = ((ChoiceNode)destination).getChild(destinationId);
155 if (maybeRet.isPresent()) {
156 final DataContainerChild<? extends PathArgument, ?> ret = maybeRet.get();
157 if (ret instanceof ContainerNode) {
158 return (ContainerNode)ret;
160 LOG.debug("Specified node {} is not a container, ignoring it", ret);
163 LOG.debug("Specified container {} is not present in destination {}", destinationId, destination);
166 LOG.warn("Destination {} is not a choice, ignoring it", destination);
169 LOG.debug("Destination is not present in routes {}", routes);
172 LOG.warn("Advertized routes {} are not a container, ignoring it", routes);
179 public final NodeIdentifier routeAttributesIdentifier() {
180 return this.routeAttributesIdentifier;
184 public final Collection<DataTreeCandidateNode> changedRoutes(final DataTreeCandidateNode routes) {
185 final DataTreeCandidateNode myRoutes = routes.getModifiedChild(this.routesContainerIdentifier);
186 if (myRoutes == null) {
187 return Collections.emptySet();
189 final DataTreeCandidateNode routesMap = myRoutes.getModifiedChild(this.routesListIdentifier);
190 if (routesMap == null) {
191 return Collections.emptySet();
193 // Well, given the remote possibility of augmentation, we should perform a filter here,
194 // to make sure the type matches what routeType() reports.
195 return routesMap.getChildNodes();
199 public final YangInstanceIdentifier routePath(final YangInstanceIdentifier routesPath, final PathArgument routeId) {
200 return routesPath.node(this.routesContainerIdentifier).node(this.routesListIdentifier).node(routeId);
204 public final void deleteRoutes(final DOMDataWriteTransaction tx, final YangInstanceIdentifier tablePath, final ContainerNode nlri) {
205 deleteRoutes(tx, tablePath, nlri, ROUTES);
209 public final void putRoutes(final DOMDataWriteTransaction tx, final YangInstanceIdentifier tablePath, final ContainerNode nlri, final ContainerNode attributes) {
210 putRoutes(tx, tablePath, nlri, attributes, ROUTES);
214 * Build MpReachNlri object from DOM representation.
216 * @param routes Collection of MapEntryNode DOM representation of routes
217 * @param hop CNextHop as it was parsed from Attributes, to be included in MpReach object
218 * @return MpReachNlri
220 @Nonnull protected abstract MpReachNlri buildReach(Collection<MapEntryNode> routes, CNextHop hop);
223 * Build MpUnReachNlri object from DOM representation.
225 * @param routes Collection of MapEntryNode DOM representation of routes
226 * @return MpUnreachNlri
228 @Nonnull protected abstract MpUnreachNlri buildUnreach(Collection<MapEntryNode> routes);
231 public Update buildUpdate(final Collection<MapEntryNode> advertised, final Collection<MapEntryNode> withdrawn, final Attributes attr) {
232 final UpdateBuilder ub = new UpdateBuilder();
233 final AttributesBuilder ab = new AttributesBuilder(attr);
234 final CNextHop hop = ab.getCNextHop();
236 // do not preserve next hop in attributes if we are using MpReach
237 ab.setCNextHop(null);
239 if (!advertised.isEmpty()) {
240 final MpReachNlri mb = buildReach(advertised, hop);
241 ab.addAugmentation(Attributes1.class, new Attributes1Builder().setMpReachNlri(mb).build());
243 if (!withdrawn.isEmpty()) {
244 final MpUnreachNlri mb = buildUnreach(withdrawn);
245 ab.addAugmentation(Attributes2.class, new Attributes2Builder().setMpUnreachNlri(mb).build());
248 ub.setAttributes(ab.build());
253 public final void deleteRoutes(final DOMDataWriteTransaction tx, final YangInstanceIdentifier tablePath, final ContainerNode nlri,
254 final NodeIdentifier routesNodeId) {
255 final Optional<DataContainerChild<? extends PathArgument, ?>> maybeRoutes = nlri.getChild(WITHDRAWN_ROUTES);
256 if (maybeRoutes.isPresent()) {
257 final ContainerNode destination = getDestination(maybeRoutes.get(), destinationContainerIdentifier());
258 if (destination != null) {
259 deleteDestinationRoutes(tx, tablePath, destination, routesNodeId);
262 LOG.debug("Withdrawn routes are not present in NLRI {}", nlri);
267 public final void putRoutes(final DOMDataWriteTransaction tx, final YangInstanceIdentifier tablePath, final ContainerNode nlri,
268 final ContainerNode attributes, final NodeIdentifier routesNodeId) {
269 final Optional<DataContainerChild<? extends PathArgument, ?>> maybeRoutes = nlri.getChild(ADVERTIZED_ROUTES);
270 if (maybeRoutes.isPresent()) {
271 final ContainerNode destination = getDestination(maybeRoutes.get(), destinationContainerIdentifier());
272 if (destination != null) {
273 putDestinationRoutes(tx, tablePath, destination, attributes, routesNodeId);
276 LOG.debug("Advertized routes are not present in NLRI {}", nlri);