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 static com.google.common.base.Verify.verify;
11 import static com.google.common.base.Verify.verifyNotNull;
12 import static java.util.Objects.requireNonNull;
13 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.BGPRIB_NID;
14 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.LOCRIB_NID;
15 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.RIB_NID;
16 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ROUTES_NID;
17 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.TABLES_NID;
18 import static org.opendaylight.protocol.bgp.rib.spi.RIBQNames.AFI_QNAME;
19 import static org.opendaylight.protocol.bgp.rib.spi.RIBQNames.SAFI_QNAME;
21 import com.google.common.annotations.Beta;
22 import com.google.common.cache.CacheBuilder;
23 import com.google.common.cache.CacheLoader;
24 import com.google.common.cache.LoadingCache;
25 import com.google.common.collect.ImmutableList;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.List;
29 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
30 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
31 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
32 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.Update;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.UpdateBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.AttributesBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.AttributesReachBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.AttributesUnreachBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.MpReachNlri;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.MpReachNlriBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.mp.reach.nlri.AdvertizedRoutes;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.mp.reach.nlri.AdvertizedRoutesBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.MpUnreachNlri;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.MpUnreachNlriBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.mp.unreach.nlri.WithdrawnRoutes;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.mp.unreach.nlri.WithdrawnRoutesBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.destination.DestinationType;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.BgpRib;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.LocRib;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.AddressFamily;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.RouteDistinguisher;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.RouteDistinguisherBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.SubsequentAddressFamily;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.next.hop.CNextHop;
61 import org.opendaylight.yangtools.util.ImmutableOffsetMapTemplate;
62 import org.opendaylight.yangtools.yang.binding.ChildOf;
63 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
64 import org.opendaylight.yangtools.yang.binding.DataObject;
65 import org.opendaylight.yangtools.yang.binding.Identifiable;
66 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
67 import org.opendaylight.yangtools.yang.common.QName;
68 import org.opendaylight.yangtools.yang.common.QNameModule;
69 import org.opendaylight.yangtools.yang.common.Uint32;
70 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
74 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
75 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
76 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
77 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
78 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
79 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
80 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
81 import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
82 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
83 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
84 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidateNode;
85 import org.slf4j.Logger;
86 import org.slf4j.LoggerFactory;
89 public abstract class AbstractRIBSupport<
90 C extends Routes & DataObject & ChoiceIn<Tables>,
91 S extends ChildOf<? super C>,
92 R extends Route & ChildOf<? super S> & Identifiable<?>>
93 implements RIBSupport<C, S> {
94 public static final String ROUTE_KEY = "route-key";
95 private static final Logger LOG = LoggerFactory.getLogger(AbstractRIBSupport.class);
96 private static final NodeIdentifier ADVERTISED_ROUTES = NodeIdentifier.create(AdvertizedRoutes.QNAME);
97 private static final NodeIdentifier WITHDRAWN_ROUTES = NodeIdentifier.create(WithdrawnRoutes.QNAME);
98 private static final NodeIdentifier DESTINATION_TYPE = NodeIdentifier.create(DestinationType.QNAME);
99 private static final InstanceIdentifier<Tables> TABLES_II = InstanceIdentifier.builder(BgpRib.class)
100 .child(Rib.class).child(LocRib.class).child(Tables.class).build();
101 private static final ApplyRoute DELETE_ROUTE = new DeleteRoute();
102 private static final ImmutableOffsetMapTemplate<QName> TABLES_KEY_TEMPLATE = ImmutableOffsetMapTemplate.ordered(
103 ImmutableList.of(AFI_QNAME, SAFI_QNAME));
105 // Instance identifier to table/(choice routes)/(map of route)
106 private final LoadingCache<YangInstanceIdentifier, YangInstanceIdentifier> routesPath = CacheBuilder.newBuilder()
107 .weakValues().build(new CacheLoader<YangInstanceIdentifier, YangInstanceIdentifier>() {
109 public YangInstanceIdentifier load(final YangInstanceIdentifier routesTablePaths) {
110 return routesTablePaths.node(routesContainerIdentifier()).node(routeQName());
113 private final NodeIdentifier routesContainerIdentifier;
114 private final NodeIdentifier routesListIdentifier;
115 private final NodeIdentifier routeAttributesIdentifier;
116 private final Class<C> cazeClass;
118 private final Class<S> containerClass;
119 private final Class<R> listClass;
120 private final ApplyRoute putRoute = new PutRoute();
121 private final MapEntryNode emptyTable;
122 private final QName routeQname;
123 private final QName routeKeyQname;
124 private final AddressFamily afiClass;
125 private final SubsequentAddressFamily safiClass;
126 private final NodeIdentifier destinationNid;
127 private final NodeIdentifier pathIdNid;
128 private final NodeIdentifier prefixTypeNid;
129 private final NodeIdentifier rdNid;
130 protected final BindingNormalizedNodeSerializer mappingService;
131 protected final YangInstanceIdentifier routeDefaultYii;
132 private final TablesKey tk;
133 private final NodeIdentifierWithPredicates tablesKey;
134 private final ImmutableList<PathArgument> relativeRoutesPath;
135 private final ImmutableOffsetMapTemplate<QName> routeKeyTemplate;
138 * Default constructor. Requires the QName of the container augmented under the routes choice
139 * node in instantiations of the rib grouping. It is assumed that this container is defined by
140 * the same model which populates it with route grouping instantiation, and by extension with
141 * the route attributes container.
143 * @param mappingService Serialization service
144 * @param cazeClass Binding class of the AFI/SAFI-specific case statement, must not be null
145 * @param containerClass Binding class of the container in routes choice, must not be null.
146 * @param listClass Binding class of the route list, nust not be null;
147 * @param afiClass address Family Class
148 * @param safiClass SubsequentAddressFamily
149 * @param destContainerQname destination Container Qname
151 protected AbstractRIBSupport(
152 final BindingNormalizedNodeSerializer mappingService,
153 final Class<C> cazeClass,
154 final Class<S> containerClass,
155 final Class<R> listClass,
156 final AddressFamily afiClass,
157 final SubsequentAddressFamily safiClass,
158 final QName destContainerQname) {
159 final QNameModule module = BindingReflections.getQNameModule(cazeClass);
160 this.routesContainerIdentifier = NodeIdentifier.create(
161 BindingReflections.findQName(containerClass).bindTo(module));
162 this.routeAttributesIdentifier = NodeIdentifier.create(Attributes.QNAME.bindTo(module));
163 this.cazeClass = requireNonNull(cazeClass);
164 this.mappingService = requireNonNull(mappingService);
165 this.containerClass = requireNonNull(containerClass);
166 this.listClass = requireNonNull(listClass);
167 this.routeQname = BindingReflections.findQName(listClass).bindTo(module);
168 this.routeKeyQname = QName.create(module, ROUTE_KEY).intern();
169 this.routesListIdentifier = NodeIdentifier.create(routeQname);
170 this.afiClass = requireNonNull(afiClass);
171 this.safiClass = requireNonNull(safiClass);
172 this.tk = new TablesKey(afiClass, safiClass);
173 this.tablesKey = NodeIdentifierWithPredicates.of(Tables.QNAME, TABLES_KEY_TEMPLATE.instantiateWithValues(
174 BindingReflections.findQName(afiClass.implementedInterface()),
175 BindingReflections.findQName(safiClass.implementedInterface())));
177 this.emptyTable = (MapEntryNode) this.mappingService
178 .toNormalizedNode(TABLES_II, new TablesBuilder().withKey(tk)
179 .setAttributes(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib
180 .rev180329.rib.tables.AttributesBuilder().build()).build()).getValue();
181 this.destinationNid = NodeIdentifier.create(destContainerQname);
182 this.pathIdNid = NodeIdentifier.create(QName.create(routeQName(), "path-id").intern());
183 this.prefixTypeNid = NodeIdentifier.create(QName.create(destContainerQname, "prefix").intern());
184 this.rdNid = NodeIdentifier.create(QName.create(destContainerQname, "route-distinguisher").intern());
185 this.routeDefaultYii = YangInstanceIdentifier.create(BGPRIB_NID, RIB_NID, RIB_NID, LOCRIB_NID,
186 TABLES_NID, TABLES_NID, ROUTES_NID, routesContainerIdentifier, routesListIdentifier, routesListIdentifier);
187 this.relativeRoutesPath = ImmutableList.of(routesContainerIdentifier, routesListIdentifier);
188 this.routeKeyTemplate = ImmutableOffsetMapTemplate.ordered(
189 ImmutableList.of(pathIdNid.getNodeType(), routeKeyQname));
193 public final TablesKey getTablesKey() {
198 public final NodeIdentifierWithPredicates tablesKey() {
203 public final Class<C> routesCaseClass() {
208 public final Class<S> routesContainerClass() {
209 return containerClass;
213 public final Class<R> routesListClass() {
218 public final MapEntryNode emptyTable() {
222 public final QName routeQName() {
226 protected final NodeIdentifier prefixNid() {
227 return prefixTypeNid;
230 protected final NodeIdentifier routeNid() {
231 return routesListIdentifier;
235 public final AddressFamily getAfi() {
240 public final SubsequentAddressFamily getSafi() {
245 * Build MpReachNlri object from DOM representation.
247 * @param routes Collection of MapEntryNode DOM representation of routes
248 * @param hop CNextHop as it was parsed from Attributes, to be included in MpReach object
249 * @return MpReachNlri
251 private MpReachNlri buildReach(final Collection<MapEntryNode> routes, final CNextHop hop) {
252 return new MpReachNlriBuilder()
256 .setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(buildDestination(routes)).build())
261 * Build MpUnReachNlri object from DOM representation.
263 * @param routes Collection of MapEntryNode DOM representation of routes
264 * @return MpUnreachNlri
266 private MpUnreachNlri buildUnreach(final Collection<MapEntryNode> routes) {
267 return new MpUnreachNlriBuilder()
270 .setWithdrawnRoutes(new WithdrawnRoutesBuilder()
271 .setDestinationType(buildWithdrawnDestination(routes))
276 protected abstract DestinationType buildDestination(Collection<MapEntryNode> routes);
278 protected abstract DestinationType buildWithdrawnDestination(Collection<MapEntryNode> routes);
281 * Return the {@link NodeIdentifier} of the AFI/SAFI-specific container under
284 * @return Container identifier, may not be null.
286 public final NodeIdentifier routesContainerIdentifier() {
287 return this.routesContainerIdentifier;
291 * Return the {@link NodeIdentifier} of the AFI/SAFI-specific container under
292 * the NLRI destination.
294 * @return Container identifier, may not be null.
296 private NodeIdentifier destinationContainerIdentifier() {
297 return this.destinationNid;
301 * Given the destination as ContainerNode, implementation needs to parse the DOM model
302 * from this point onward:
304 * {@code /bgp-mp:mp-unreach-nlri/bgp-mp:withdrawn-routes/bgp-mp:destination-type}
305 * and delete the routes from its RIBs.
307 * @param tx DOMDataWriteTransaction to be passed into implementation
308 * @param tablePath YangInstanceIdentifier to be passed into implementation
309 * @param destination ContainerNode DOM representation of NLRI in Update message
310 * @param routesNodeId NodeIdentifier
312 private void deleteDestinationRoutes(final DOMDataTreeWriteTransaction tx, final YangInstanceIdentifier tablePath,
313 final ContainerNode destination, final NodeIdentifier routesNodeId) {
314 processDestination(tx, tablePath.node(routesNodeId), destination, null, DELETE_ROUTE);
318 * Given the destination as ContainerNode, implementation needs to parse the DOM model
319 * from this point onward:
321 * {@code /bgp-mp:mp-reach-nlri/bgp-mp:advertized-routes/bgp-mp:destination-type}
322 * and put the routes to its RIBs.
324 * @param tx DOMDataWriteTransaction to be passed into implementation
325 * @param tablePath YangInstanceIdentifier to be passed into implementation
326 * @param destination ContainerNode DOM representation of NLRI in Update message
327 * @param attributes ContainerNode to be passed into implementation
328 * @param routesNodeId NodeIdentifier
329 * @return List of processed route identifiers
331 private Collection<NodeIdentifierWithPredicates> putDestinationRoutes(final DOMDataTreeWriteTransaction tx,
332 final YangInstanceIdentifier tablePath, final ContainerNode destination, final ContainerNode attributes,
333 final NodeIdentifier routesNodeId) {
334 return processDestination(tx, tablePath.node(routesNodeId), destination, attributes, this.putRoute);
337 protected abstract Collection<NodeIdentifierWithPredicates> processDestination(DOMDataTreeWriteTransaction tx,
338 YangInstanceIdentifier routesPath, ContainerNode destination, ContainerNode attributes,
339 ApplyRoute applyFunction);
341 private static ContainerNode getDestination(final DataContainerChild routes, final NodeIdentifier destinationId) {
342 if (routes instanceof ContainerNode) {
343 final DataContainerChild destination = ((ContainerNode) routes).childByArg(DESTINATION_TYPE);
344 if (destination instanceof ChoiceNode) {
345 final DataContainerChild ret = ((ChoiceNode) destination).childByArg(destinationId);
347 if (ret instanceof ContainerNode) {
348 return (ContainerNode) ret;
351 LOG.debug("Specified node {} is not a container, ignoring it", ret);
353 LOG.debug("Specified container {} is not present in destination {}", destinationId, destination);
356 LOG.warn("Destination {} is not a choice, ignoring it", destination);
359 LOG.warn("Advertized routes {} are not a container, ignoring it", routes);
366 public final NodeIdentifier routeAttributesIdentifier() {
367 return this.routeAttributesIdentifier;
371 public final Collection<DataTreeCandidateNode> changedRoutes(final DataTreeCandidateNode routes) {
372 return routes.getModifiedChild(this.routesContainerIdentifier)
373 .flatMap(myRoutes -> myRoutes.getModifiedChild(routeNid()))
374 // Well, given the remote possibility of augmentation, we should perform a filter here,
375 // to make sure the type matches what routeType() reports.
376 .map(DataTreeCandidateNode::getChildNodes)
377 .orElse(Collections.emptySet());
381 public final YangInstanceIdentifier routesPath(final YangInstanceIdentifier routesTablePaths) {
382 return routesYangInstanceIdentifier(routesTablePaths.node(ROUTES_NID));
386 public final List<PathArgument> relativeRoutesPath() {
387 return relativeRoutesPath;
391 public final YangInstanceIdentifier createRouteIdentifier(final YangInstanceIdentifier tablePath,
392 final NodeIdentifierWithPredicates newRouteKey) {
393 return routesPath(tablePath).node(newRouteKey);
397 public final MapEntryNode createRoute(final MapEntryNode route, final NodeIdentifierWithPredicates key,
398 final ContainerNode attributes) {
399 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder;
401 builder = Builders.mapEntryBuilder(route);
403 builder = Builders.mapEntryBuilder();
407 .withNodeIdentifier(key)
408 .withChild(ImmutableNodes.leafNode(pathIdNid, extractPathId(key)))
409 .withChild(ImmutableNodes.leafNode(routeKeyQname, extractRouteKey(key)))
410 .withChild(attributes)
415 public final NodeIdentifierWithPredicates createRouteListArgument(final Uint32 pathId, final String routeKey) {
416 return NodeIdentifierWithPredicates.of(routeQname, routeKeyTemplate.instantiateWithValues(pathId, routeKey));
420 public final void deleteRoutes(final DOMDataTreeWriteTransaction tx, final YangInstanceIdentifier tablePath,
421 final ContainerNode nlri) {
422 deleteRoutes(tx, tablePath, nlri, ROUTES_NID);
426 @SuppressWarnings("checkstyle:OverloadMethodsDeclarationOrder")
427 public final void deleteRoutes(final DOMDataTreeWriteTransaction tx, final YangInstanceIdentifier tablePath,
428 final ContainerNode nlri, final NodeIdentifier routesNodeId) {
429 final DataContainerChild routes = nlri.childByArg(WITHDRAWN_ROUTES);
430 if (routes != null) {
431 final ContainerNode destination = getDestination(routes, destinationContainerIdentifier());
432 if (destination != null) {
433 deleteDestinationRoutes(tx, tablePath, destination, routesNodeId);
436 LOG.debug("Withdrawn routes are not present in NLRI {}", nlri);
441 public final Collection<NodeIdentifierWithPredicates> putRoutes(final DOMDataTreeWriteTransaction tx,
442 final YangInstanceIdentifier tablePath,
443 final ContainerNode nlri,
444 final ContainerNode attributes) {
445 return putRoutes(tx, tablePath, nlri, attributes, ROUTES_NID);
449 public final Collection<NodeIdentifierWithPredicates> putRoutes(final DOMDataTreeWriteTransaction tx,
450 final YangInstanceIdentifier tablePath,
451 final ContainerNode nlri,
452 final ContainerNode attributes,
453 final NodeIdentifier routesNodeId) {
454 final DataContainerChild routes = nlri.childByArg(ADVERTISED_ROUTES);
455 if (routes != null) {
456 final ContainerNode destination = getDestination(routes, destinationContainerIdentifier());
457 if (destination != null) {
458 return putDestinationRoutes(tx, tablePath, destination, attributes, routesNodeId);
461 LOG.debug("Advertized routes are not present in NLRI {}", nlri);
467 public final Update buildUpdate(final Collection<MapEntryNode> advertised, final Collection<MapEntryNode> withdrawn,
468 final Attributes attr) {
469 final UpdateBuilder ub = new UpdateBuilder();
470 final AttributesBuilder ab = new AttributesBuilder(attr);
471 final CNextHop hop = ab.getCNextHop();
473 LOG.debug("cnextHop before={}", hop);
474 // do not preserve next hop in attributes if we are using MpReach
475 ab.setCNextHop(null);
477 if (!advertised.isEmpty()) {
478 final MpReachNlri mb = buildReach(advertised, hop);
479 ab.addAugmentation(new AttributesReachBuilder().setMpReachNlri(mb).build());
480 LOG.debug("mpreach nexthop={}", mb);
482 if (!withdrawn.isEmpty()) {
483 final MpUnreachNlri mb = buildUnreach(withdrawn);
484 ab.addAugmentation(new AttributesUnreachBuilder().setMpUnreachNlri(mb).build());
485 LOG.debug("mpunrach mb={}", mb);
488 ub.setAttributes(ab.build());
489 LOG.debug("update {}", ub.build());
493 private static final class DeleteRoute implements ApplyRoute {
495 public void apply(final DOMDataTreeWriteTransaction tx, final YangInstanceIdentifier base,
496 final NodeIdentifierWithPredicates routeKey, final DataContainerNode route,
497 final ContainerNode attributes) {
498 tx.delete(LogicalDatastoreType.OPERATIONAL, base.node(routeKey));
502 private final class PutRoute implements ApplyRoute {
504 public void apply(final DOMDataTreeWriteTransaction tx, final YangInstanceIdentifier base,
505 final NodeIdentifierWithPredicates routeKey, final DataContainerNode route,
506 final ContainerNode attributes) {
507 // Build the DataContainer data
508 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> b =
509 ImmutableNodes.mapEntryBuilder();
510 b.withNodeIdentifier(routeKey);
512 route.body().forEach(b::withChild);
514 final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> cb =
515 Builders.containerBuilder(attributes);
516 cb.withNodeIdentifier(routeAttributesIdentifier());
517 b.withChild(cb.build());
518 tx.put(LogicalDatastoreType.OPERATIONAL, base.node(routeKey), b.build());
522 protected final NodeIdentifier routePathIdNid() {
526 protected final ImmutableOffsetMapTemplate<QName> routeKeyTemplate() {
527 return routeKeyTemplate;
530 protected final String extractPrefix(final DataContainerNode route) {
531 return (String) verifyNotNull(route.childByArg(prefixTypeNid)).body();
534 protected final RouteDistinguisher extractRouteDistinguisher(final DataContainerNode route) {
535 final DataContainerChild child = route.childByArg(rdNid);
536 return child == null ? null : RouteDistinguisherBuilder.getDefaultInstance((String) child.body());
539 protected final YangInstanceIdentifier routesYangInstanceIdentifier(final YangInstanceIdentifier routesTablePaths) {
540 return routesPath.getUnchecked(routesTablePaths);
544 public R fromNormalizedNode(final YangInstanceIdentifier routePath, final NormalizedNode normalizedNode) {
545 final DataObject node = mappingService.fromNormalizedNode(routePath, normalizedNode).getValue();
546 verify(node instanceof Route, "node %s is not a Route", node);
551 public Attributes attributeFromContainerNode(final ContainerNode advertisedAttrs) {
552 final YangInstanceIdentifier path = this.routeDefaultYii.node(routeAttributesIdentifier());
553 return (Attributes) verifyNotNull(mappingService.fromNormalizedNode(path, advertisedAttrs).getValue());
557 public ContainerNode attributeToContainerNode(final YangInstanceIdentifier attPath, final Attributes attributes) {
558 final InstanceIdentifier<DataObject> iid = this.mappingService.fromYangInstanceIdentifier(attPath);
559 return (ContainerNode) verifyNotNull(mappingService.toNormalizedNode(iid, attributes).getValue());
563 public final String extractRouteKey(final NodeIdentifierWithPredicates routeListKey) {
564 return verifyNotNull(routeListKey.getValue(routeKeyQname, String.class),
565 "Missing route key in %s", routeListKey);
569 public final Uint32 extractPathId(final NodeIdentifierWithPredicates routeListKey) {
570 return verifyNotNull(routeListKey.getValue(pathIdNid.getNodeType(), Uint32.class),
571 "Missing path ID in %s", routeListKey);
575 public final ContainerNode extractAttributes(final MapEntryNode value) {
576 return NormalizedNodes.findNode(value, routeAttributesIdentifier).map(ContainerNode.class::cast).orElse(null);