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.List;
29 import org.eclipse.jdt.annotation.NonNull;
30 import org.eclipse.jdt.annotation.Nullable;
31 import org.opendaylight.bgp.concepts.RouteDistinguisherUtil;
32 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
33 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
34 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.Update;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.UpdateBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.AttributesBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.AttributesReachBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.AttributesUnreachBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.MpReachNlri;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.MpReachNlriBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.mp.reach.nlri.AdvertizedRoutes;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.mp.reach.nlri.AdvertizedRoutesBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.MpUnreachNlri;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.MpUnreachNlriBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.mp.unreach.nlri.WithdrawnRoutes;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.mp.unreach.nlri.WithdrawnRoutesBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.destination.DestinationType;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.BgpRib;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.LocRib;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.AddressFamily;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.RouteDistinguisher;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.SubsequentAddressFamily;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.next.hop.CNextHop;
62 import org.opendaylight.yangtools.util.ImmutableOffsetMapTemplate;
63 import org.opendaylight.yangtools.yang.binding.ChildOf;
64 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
65 import org.opendaylight.yangtools.yang.binding.DataObject;
66 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
67 import org.opendaylight.yangtools.yang.binding.KeyAware;
68 import org.opendaylight.yangtools.yang.common.QName;
69 import org.opendaylight.yangtools.yang.common.QNameModule;
70 import org.opendaylight.yangtools.yang.common.Uint32;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
74 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
75 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
76 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
77 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
78 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
79 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
80 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
81 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode.BuilderFactory;
82 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
83 import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
84 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
85 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidateNode;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
90 public abstract class AbstractRIBSupport<
91 C extends Routes & DataObject & ChoiceIn<Tables>,
92 S extends ChildOf<? super C>,
93 R extends Route & ChildOf<? super S> & KeyAware<?>>
94 implements RIBSupport<C, S> {
95 public static final String ROUTE_KEY = "route-key";
96 private static final Logger LOG = LoggerFactory.getLogger(AbstractRIBSupport.class);
97 private static final NodeIdentifier ADVERTISED_ROUTES = NodeIdentifier.create(AdvertizedRoutes.QNAME);
98 private static final NodeIdentifier WITHDRAWN_ROUTES = NodeIdentifier.create(WithdrawnRoutes.QNAME);
99 private static final NodeIdentifier DESTINATION_TYPE = NodeIdentifier.create(DestinationType.QNAME);
100 private static final InstanceIdentifier<Tables> TABLES_II = InstanceIdentifier.builder(BgpRib.class)
101 .child(Rib.class).child(LocRib.class).child(Tables.class).build();
102 private static final ApplyRoute DELETE_ROUTE = new DeleteRoute();
103 private static final ImmutableOffsetMapTemplate<QName> TABLES_KEY_TEMPLATE = ImmutableOffsetMapTemplate.ordered(
104 ImmutableList.of(AFI_QNAME, SAFI_QNAME));
105 private static final BuilderFactory BUILDER_FACTORY = ImmutableNodes.builderFactory();
107 // Instance identifier to table/(choice routes)/(map of route)
108 private final LoadingCache<YangInstanceIdentifier, YangInstanceIdentifier> routesPath = CacheBuilder.newBuilder()
109 .weakValues().build(new CacheLoader<YangInstanceIdentifier, YangInstanceIdentifier>() {
111 public YangInstanceIdentifier load(final YangInstanceIdentifier routesTablePaths) {
112 return routesTablePaths.node(routesContainerIdentifier()).node(routeQName());
115 private final NodeIdentifier routesContainerIdentifier;
116 private final NodeIdentifier routesListIdentifier;
117 private final NodeIdentifier routeAttributesIdentifier;
118 private final Class<C> cazeClass;
120 private final Class<S> containerClass;
121 private final Class<R> listClass;
122 private final ApplyRoute putRoute = new PutRoute();
123 private final MapEntryNode emptyTable;
124 private final QName routeQname;
125 private final QName routeKeyQname;
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 @NonNull 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 afi Address Family
148 * @param safi Subsequent Address Family
149 * @param destContainerQname destination Container Qname
151 protected AbstractRIBSupport(
152 final BindingNormalizedNodeSerializer mappingService,
153 final Class<C> cazeClass, final QName cazeQName,
154 final Class<S> containerClass, final QName containerQName,
155 final Class<R> listClass, final QName listQName,
156 final AddressFamily afi, final QName afiQName,
157 final SubsequentAddressFamily safi, final QName safiQName,
158 final QName destContainerQname) {
159 this.mappingService = requireNonNull(mappingService);
160 this.cazeClass = requireNonNull(cazeClass);
161 this.containerClass = requireNonNull(containerClass);
162 this.listClass = requireNonNull(listClass);
163 tk = new TablesKey(afi, safi);
164 tablesKey = NodeIdentifierWithPredicates.of(Tables.QNAME,
165 TABLES_KEY_TEMPLATE.instantiateWithValues(afiQName, safiQName));
166 destinationNid = NodeIdentifier.create(destContainerQname);
168 final QNameModule module = cazeQName.getModule();
169 routesContainerIdentifier = NodeIdentifier.create(containerQName.bindTo(module));
170 routeAttributesIdentifier = NodeIdentifier.create(Attributes.QNAME.bindTo(module));
171 routeQname = listQName.bindTo(module);
172 routeKeyQname = QName.create(module, ROUTE_KEY).intern();
173 routesListIdentifier = NodeIdentifier.create(routeQname);
175 emptyTable = (MapEntryNode) mappingService.toNormalizedDataObject(TABLES_II, new TablesBuilder().withKey(tk)
176 .setAttributes(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329
177 .rib.tables.AttributesBuilder().build()).build()).node();
178 pathIdNid = NodeIdentifier.create(QName.create(routeQName(), "path-id").intern());
179 prefixTypeNid = NodeIdentifier.create(QName.create(destContainerQname, "prefix").intern());
180 rdNid = NodeIdentifier.create(QName.create(destContainerQname, "route-distinguisher").intern());
181 routeDefaultYii = YangInstanceIdentifier.of(BGPRIB_NID, RIB_NID, RIB_NID, LOCRIB_NID,
182 TABLES_NID, TABLES_NID, ROUTES_NID, routesContainerIdentifier, routesListIdentifier, routesListIdentifier);
183 relativeRoutesPath = ImmutableList.of(routesContainerIdentifier, routesListIdentifier);
184 routeKeyTemplate = ImmutableOffsetMapTemplate.ordered(
185 ImmutableList.of(pathIdNid.getNodeType(), routeKeyQname));
189 public final TablesKey getTablesKey() {
194 public final NodeIdentifierWithPredicates tablesKey() {
199 public final Class<C> routesCaseClass() {
204 public final Class<S> routesContainerClass() {
205 return containerClass;
209 public final Class<R> routesListClass() {
214 public final MapEntryNode emptyTable() {
218 public final QName routeQName() {
222 protected final NodeIdentifier prefixNid() {
223 return prefixTypeNid;
226 protected final NodeIdentifier routeNid() {
227 return routesListIdentifier;
231 * Build MpReachNlri object from DOM representation.
233 * @param routes Collection of MapEntryNode DOM representation of routes
234 * @param hop CNextHop as it was parsed from Attributes, to be included in MpReach object
235 * @return MpReachNlri
237 private MpReachNlri buildReach(final Collection<MapEntryNode> routes, final CNextHop hop) {
238 return new MpReachNlriBuilder()
240 .setSafi(tk.getSafi())
242 .setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(buildDestination(routes)).build())
247 * Build MpUnReachNlri object from DOM representation.
249 * @param routes Collection of MapEntryNode DOM representation of routes
250 * @return MpUnreachNlri
252 private MpUnreachNlri buildUnreach(final Collection<MapEntryNode> routes) {
253 return new MpUnreachNlriBuilder()
255 .setSafi(tk.getSafi())
256 .setWithdrawnRoutes(new WithdrawnRoutesBuilder()
257 .setDestinationType(buildWithdrawnDestination(routes))
262 protected abstract DestinationType buildDestination(Collection<MapEntryNode> routes);
264 protected abstract DestinationType buildWithdrawnDestination(Collection<MapEntryNode> routes);
267 * Return the {@link NodeIdentifier} of the AFI/SAFI-specific container under
270 * @return Container identifier, may not be null.
272 public final NodeIdentifier routesContainerIdentifier() {
273 return routesContainerIdentifier;
277 * Return the {@link NodeIdentifier} of the AFI/SAFI-specific container under
278 * the NLRI destination.
280 * @return Container identifier, may not be null.
282 private NodeIdentifier destinationContainerIdentifier() {
283 return destinationNid;
287 * Given the destination as ContainerNode, implementation needs to parse the DOM model
288 * from this point onward:
290 * {@code /bgp-mp:mp-unreach-nlri/bgp-mp:withdrawn-routes/bgp-mp:destination-type}
291 * and delete the routes from its RIBs.
293 * @param tx DOMDataWriteTransaction to be passed into implementation
294 * @param tablePath YangInstanceIdentifier to be passed into implementation
295 * @param destination ContainerNode DOM representation of NLRI in Update message
296 * @param routesNodeId NodeIdentifier
298 private void deleteDestinationRoutes(final DOMDataTreeWriteTransaction tx, final YangInstanceIdentifier tablePath,
299 final ContainerNode destination, final NodeIdentifier routesNodeId) {
300 processDestination(tx, tablePath.node(routesNodeId), destination, null, DELETE_ROUTE);
304 * Given the destination as ContainerNode, implementation needs to parse the DOM model
305 * from this point onward:
307 * {@code /bgp-mp:mp-reach-nlri/bgp-mp:advertized-routes/bgp-mp:destination-type}
308 * and put the routes to its RIBs.
310 * @param tx DOMDataWriteTransaction to be passed into implementation
311 * @param tablePath YangInstanceIdentifier to be passed into implementation
312 * @param destination ContainerNode DOM representation of NLRI in Update message
313 * @param attributes ContainerNode to be passed into implementation
314 * @param routesNodeId NodeIdentifier
315 * @return List of processed route identifiers
317 private Collection<NodeIdentifierWithPredicates> putDestinationRoutes(final DOMDataTreeWriteTransaction tx,
318 final YangInstanceIdentifier tablePath, final ContainerNode destination, final ContainerNode attributes,
319 final NodeIdentifier routesNodeId) {
320 return processDestination(tx, tablePath.node(routesNodeId), destination, attributes, putRoute);
323 protected abstract Collection<NodeIdentifierWithPredicates> processDestination(DOMDataTreeWriteTransaction tx,
324 YangInstanceIdentifier routesPath, ContainerNode destination, ContainerNode attributes,
325 ApplyRoute applyFunction);
327 private static ContainerNode getDestination(final DataContainerChild routes, final NodeIdentifier destinationId) {
328 if (routes instanceof ContainerNode) {
329 final DataContainerChild destination = ((ContainerNode) routes).childByArg(DESTINATION_TYPE);
330 if (destination instanceof ChoiceNode) {
331 final DataContainerChild ret = ((ChoiceNode) destination).childByArg(destinationId);
333 if (ret instanceof ContainerNode) {
334 return (ContainerNode) ret;
337 LOG.debug("Specified node {} is not a container, ignoring it", ret);
339 LOG.debug("Specified container {} is not present in destination {}", destinationId, destination);
342 LOG.warn("Destination {} is not a choice, ignoring it", destination);
345 LOG.warn("Advertized routes {} are not a container, ignoring it", routes);
352 public final NodeIdentifier routeAttributesIdentifier() {
353 return routeAttributesIdentifier;
357 public final Collection<DataTreeCandidateNode> changedRoutes(final DataTreeCandidateNode routes) {
358 final var myRoutes = routes.modifiedChild(routesContainerIdentifier);
359 if (myRoutes != null) {
360 final var route = myRoutes.modifiedChild(routeNid());
362 // Well, given the remote possibility of augmentation, we should perform a filter here,
363 // to make sure the type matches what routeType() reports.
364 return route.childNodes();
371 public final YangInstanceIdentifier routesPath(final YangInstanceIdentifier routesTablePaths) {
372 return routesYangInstanceIdentifier(routesTablePaths.node(ROUTES_NID));
376 public final List<PathArgument> relativeRoutesPath() {
377 return relativeRoutesPath;
381 public final YangInstanceIdentifier createRouteIdentifier(final YangInstanceIdentifier tablePath,
382 final NodeIdentifierWithPredicates newRouteKey) {
383 return routesPath(tablePath).node(newRouteKey);
387 public final MapEntryNode createRoute(final MapEntryNode route, final NodeIdentifierWithPredicates key,
388 final ContainerNode attributes) {
389 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder;
391 builder = BUILDER_FACTORY.newMapEntryBuilder(route);
393 builder = BUILDER_FACTORY.newMapEntryBuilder();
397 .withNodeIdentifier(key)
398 .withChild(ImmutableNodes.leafNode(pathIdNid, extractPathId(key)))
399 .withChild(ImmutableNodes.leafNode(routeKeyQname, extractRouteKey(key)))
400 .withChild(attributes)
405 public final NodeIdentifierWithPredicates createRouteListArgument(final Uint32 pathId, final String routeKey) {
406 return NodeIdentifierWithPredicates.of(routeQname, routeKeyTemplate.instantiateWithValues(pathId, routeKey));
410 public final void deleteRoutes(final DOMDataTreeWriteTransaction tx, final YangInstanceIdentifier tablePath,
411 final ContainerNode nlri) {
412 deleteRoutes(tx, tablePath, nlri, ROUTES_NID);
416 public final void deleteRoutes(final DOMDataTreeWriteTransaction tx, final YangInstanceIdentifier tablePath,
417 final ContainerNode nlri, final NodeIdentifier routesNodeId) {
418 final DataContainerChild routes = nlri.childByArg(WITHDRAWN_ROUTES);
419 if (routes != null) {
420 final ContainerNode destination = getDestination(routes, destinationContainerIdentifier());
421 if (destination != null) {
422 deleteDestinationRoutes(tx, tablePath, destination, routesNodeId);
425 LOG.debug("Withdrawn routes are not present in NLRI {}", nlri);
430 public final Collection<NodeIdentifierWithPredicates> putRoutes(final DOMDataTreeWriteTransaction tx,
431 final YangInstanceIdentifier tablePath,
432 final ContainerNode nlri,
433 final ContainerNode attributes) {
434 return putRoutes(tx, tablePath, nlri, attributes, ROUTES_NID);
438 public final Collection<NodeIdentifierWithPredicates> putRoutes(final DOMDataTreeWriteTransaction tx,
439 final YangInstanceIdentifier tablePath,
440 final ContainerNode nlri,
441 final ContainerNode attributes,
442 final NodeIdentifier routesNodeId) {
443 final DataContainerChild routes = nlri.childByArg(ADVERTISED_ROUTES);
444 if (routes != null) {
445 final ContainerNode destination = getDestination(routes, destinationContainerIdentifier());
446 if (destination != null) {
447 return putDestinationRoutes(tx, tablePath, destination, attributes, routesNodeId);
450 LOG.debug("Advertized routes are not present in NLRI {}", nlri);
456 public final Update buildUpdate(final Collection<MapEntryNode> advertised, final Collection<MapEntryNode> withdrawn,
457 final Attributes attr) {
458 final UpdateBuilder ub = new UpdateBuilder();
459 final AttributesBuilder ab = new AttributesBuilder(attr);
460 final CNextHop hop = ab.getCNextHop();
462 LOG.debug("cnextHop before={}", hop);
463 // do not preserve next hop in attributes if we are using MpReach
464 ab.setCNextHop(null);
466 if (!advertised.isEmpty()) {
467 final MpReachNlri mb = buildReach(advertised, hop);
468 ab.addAugmentation(new AttributesReachBuilder().setMpReachNlri(mb).build());
469 LOG.debug("mpreach nexthop={}", mb);
471 if (!withdrawn.isEmpty()) {
472 final MpUnreachNlri mb = buildUnreach(withdrawn);
473 ab.addAugmentation(new AttributesUnreachBuilder().setMpUnreachNlri(mb).build());
474 LOG.debug("mpunrach mb={}", mb);
477 ub.setAttributes(ab.build());
478 LOG.debug("update {}", ub.build());
482 private static final class DeleteRoute implements ApplyRoute {
484 public void apply(final DOMDataTreeWriteTransaction tx, final YangInstanceIdentifier base,
485 final NodeIdentifierWithPredicates routeKey, final DataContainerNode route,
486 final ContainerNode attributes) {
487 tx.delete(LogicalDatastoreType.OPERATIONAL, base.node(routeKey));
491 private final class PutRoute implements ApplyRoute {
493 public void apply(final DOMDataTreeWriteTransaction tx, final YangInstanceIdentifier base,
494 final NodeIdentifierWithPredicates routeKey, final DataContainerNode route,
495 final ContainerNode attributes) {
496 // Build the DataContainer data
497 final var b = ImmutableNodes.newMapEntryBuilder().withNodeIdentifier(routeKey);
498 route.body().forEach(b::withChild);
500 b.withChild(BUILDER_FACTORY.newContainerBuilder(attributes)
501 .withNodeIdentifier(routeAttributesIdentifier())
503 tx.put(LogicalDatastoreType.OPERATIONAL, base.node(routeKey), b.build());
507 protected final NodeIdentifier routePathIdNid() {
511 protected final ImmutableOffsetMapTemplate<QName> routeKeyTemplate() {
512 return routeKeyTemplate;
515 protected final @NonNull String extractPrefix(final DataContainerNode route) {
516 return (String) route.getChildByArg(prefixTypeNid).body();
519 protected final @Nullable RouteDistinguisher extractRouteDistinguisher(final DataContainerNode route) {
520 return RouteDistinguisherUtil.extractRouteDistinguisher(route, rdNid);
523 protected final YangInstanceIdentifier routesYangInstanceIdentifier(final YangInstanceIdentifier routesTablePaths) {
524 return routesPath.getUnchecked(routesTablePaths);
528 public R fromNormalizedNode(final YangInstanceIdentifier routePath, final NormalizedNode normalizedNode) {
529 final DataObject node = mappingService.fromNormalizedNode(routePath, normalizedNode).getValue();
530 verify(node instanceof Route, "node %s is not a Route", node);
535 public Attributes attributeFromContainerNode(final ContainerNode advertisedAttrs) {
536 final YangInstanceIdentifier path = routeDefaultYii.node(routeAttributesIdentifier());
537 return (Attributes) verifyNotNull(mappingService.fromNormalizedNode(path, advertisedAttrs).getValue());
541 public ContainerNode attributeToContainerNode(final YangInstanceIdentifier attPath, final Attributes attributes) {
542 final var iid = mappingService.fromYangInstanceIdentifier(attPath);
543 return (ContainerNode) verifyNotNull(mappingService.toNormalizedDataObject(iid, attributes).node());
547 public final String extractRouteKey(final NodeIdentifierWithPredicates routeListKey) {
548 return verifyNotNull(routeListKey.getValue(routeKeyQname, String.class),
549 "Missing route key in %s", routeListKey);
553 public final Uint32 extractPathId(final NodeIdentifierWithPredicates routeListKey) {
554 return verifyNotNull(routeListKey.getValue(pathIdNid.getNodeType(), Uint32.class),
555 "Missing path ID in %s", routeListKey);
559 public final ContainerNode extractAttributes(final MapEntryNode value) {
560 return NormalizedNodes.findNode(value, routeAttributesIdentifier).map(ContainerNode.class::cast).orElse(null);