/* * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.protocol.bgp.labeled.unicast; import com.google.common.base.Optional; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableSet; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.protocol.bgp.parser.spi.PathIdUtil; import org.opendaylight.protocol.bgp.rib.spi.MultiPathAbstractRIBSupport; import org.opendaylight.protocol.util.ByteArray; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.labeled.unicast.rev150525.labeled.unicast.LabelStack; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.labeled.unicast.rev150525.labeled.unicast.LabelStackBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.labeled.unicast.rev150525.labeled.unicast.destination.CLabeledUnicastDestination; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.labeled.unicast.rev150525.labeled.unicast.destination.CLabeledUnicastDestinationBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AddressFamily; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.SubsequentAddressFamily; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.MplsLabel; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; abstract class AbstractLabeledUnicastRIBSupport extends MultiPathAbstractRIBSupport { private static final NodeIdentifier PREFIX_TYPE_NID = NodeIdentifier.create(QName.create(CLabeledUnicastDestination.QNAME, "prefix").intern()); private static final NodeIdentifier LABEL_STACK_NID = NodeIdentifier.create(QName.create(CLabeledUnicastDestination.QNAME, "label-stack").intern()); private static final NodeIdentifier LV_NID = NodeIdentifier.create(QName.create(CLabeledUnicastDestination.QNAME, "label-value").intern()); private static final NodeIdentifier NLRI_ROUTES_LIST = NodeIdentifier.create(CLabeledUnicastDestination.QNAME); private static final Logger LOG = LoggerFactory.getLogger(AbstractLabeledUnicastRIBSupport.class); /** * Default constructor. Requires the QName of the container augmented under the routes choice * node in instantiations of the rib grouping. It is assumed that this container is defined by * the same model which populates it with route grouping instantiation, and by extension with * the route attributes container. * @param cazeClass Binding class of the AFI/SAFI-specific case statement, must not be null * @param containerClass Binding class of the container in routes choice, must not be null. * @param listClass Binding class of the route list, nust not be null; * @param addressFamilyClass address Family Class * @param safiClass SubsequentAddressFamily * @param destinationQname destination Qname */ AbstractLabeledUnicastRIBSupport(final Class cazeClass, final Class containerClass, final Class listClass, final Class addressFamilyClass, final Class safiClass, final QName destinationQname) { super(cazeClass, containerClass, listClass, addressFamilyClass, safiClass, "route-key", destinationQname); } @Override public ImmutableCollection> cacheableAttributeObjects() { return ImmutableSet.of(); } @Override public ImmutableCollection> cacheableNlriObjects() { return ImmutableSet.of(); } @Override public boolean isComplexRoute() { return true; } @Override protected void processDestination(final DOMDataWriteTransaction tx, final YangInstanceIdentifier routesPath, final ContainerNode destination, final ContainerNode attributes, final ApplyRoute function) { if (destination != null) { final Optional> maybeRoutes = destination.getChild(NLRI_ROUTES_LIST); if (maybeRoutes.isPresent()) { final DataContainerChild routes = maybeRoutes.get(); if (routes instanceof UnkeyedListNode) { final YangInstanceIdentifier base = routesPath.node(routesContainerIdentifier()).node(routeNid()); for (final UnkeyedListEntryNode e : ((UnkeyedListNode) routes).getValue()) { final NodeIdentifierWithPredicates routeKey = createRouteKey(e); function.apply(tx, base, routeKey, e, attributes); } } else { LOG.warn("Routes {} are not a map", routes); } } } } protected List extractRoutes(final Collection routes) { return routes.stream().map(this::extractCLabeledUnicastDestination).collect(Collectors.toList()); } private NodeIdentifierWithPredicates createRouteKey(final UnkeyedListEntryNode labeledUnicast) { final ByteBuf buffer = Unpooled.buffer(); final CLabeledUnicastDestination dest = extractCLabeledUnicastDestination(labeledUnicast); LUNlriParser.serializeNlri(Collections.singletonList(dest), buffer); final String routeKeyValue = ByteArray.encodeBase64(buffer); final Optional> maybePathIdLeaf = labeledUnicast.getChild(routePathIdNid()); final NodeIdentifierWithPredicates routeKey = PathIdUtil.createNidKey(routeQName(), routeKeyQName(), pathIdQName(), routeKeyValue, maybePathIdLeaf); return routeKey; } /** * Conversion from DataContainer to LabeledUnicastDestination Object * * @param route DataContainer * @return LabeledUnicastDestination Object */ private CLabeledUnicastDestination extractCLabeledUnicastDestination(final DataContainerNode route) { final CLabeledUnicastDestinationBuilder builder = new CLabeledUnicastDestinationBuilder(); builder.setPrefix(extractPrefix(route, PREFIX_TYPE_NID)); builder.setLabelStack(extractLabel(route, LABEL_STACK_NID, LV_NID)); builder.setPathId(PathIdUtil.buildPathId(route, routePathIdNid())); return builder.build(); } protected abstract IpPrefix extractPrefix(final DataContainerNode route, final NodeIdentifier prefixTypeNid); public static List extractLabel(final DataContainerNode route, final NodeIdentifier labelStackNid, final NodeIdentifier labelValueNid) { final List labels = new ArrayList<>(); final Optional> labelStacks = route.getChild(labelStackNid); if (labelStacks.isPresent()) { for (final UnkeyedListEntryNode label : ((UnkeyedListNode) labelStacks.get()).getValue()) { final Optional> labelStack = label.getChild(labelValueNid); if (labelStack.isPresent()) { final LabelStackBuilder labelStackbuilder = new LabelStackBuilder(); labelStackbuilder.setLabelValue(new MplsLabel((Long) labelStack.get().getValue())); labels.add(labelStackbuilder.build()); } } } return labels; } }