X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=bgp%2Frib-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fprotocol%2Fbgp%2Frib%2Fimpl%2FAdjRibOutListener.java;h=3de8380761cca78083eaa17b4401f0177a9eb6e0;hb=refs%2Fchanges%2F40%2F106640%2F3;hp=81291c19debf37a5ae8b52d6df7152af242528f6;hpb=141ff6fd5b7304185bc81b4141d3a61540f16a67;p=bgpcep.git diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibOutListener.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibOutListener.java index 81291c19de..3de8380761 100644 --- a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibOutListener.java +++ b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibOutListener.java @@ -8,117 +8,123 @@ package org.opendaylight.protocol.bgp.rib.impl; import static java.util.Objects.requireNonNull; +import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ADJRIBOUT_NID; +import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.PEER_NID; +import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.TABLES_NID; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Optional; import java.util.concurrent.atomic.LongAdder; import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.NotThreadSafe; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.dom.api.ClusteredDOMDataTreeChangeListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService; -import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.mdsal.dom.api.ClusteredDOMDataTreeChangeListener; +import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService; +import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; import org.opendaylight.protocol.bgp.rib.impl.spi.Codecs; import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry; import org.opendaylight.protocol.bgp.rib.impl.state.peer.PrefixesSentCounters; import org.opendaylight.protocol.bgp.rib.spi.IdentifierUtils; import org.opendaylight.protocol.bgp.rib.spi.RIBSupport; -import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev171207.ipv4.routes.ipv4.routes.Ipv4Route; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.PathId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.Update; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.UpdateBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.Attributes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.update.message.Nlri; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.update.message.NlriBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.update.message.WithdrawnRoutes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.update.message.WithdrawnRoutesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.PeerId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.bgp.rib.rib.Peer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.bgp.rib.rib.peer.AdjRibOut; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.rib.Tables; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.rib.TablesKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.routes.ipv4.routes.Ipv4Route; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.PathId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.Update; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.UpdateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.update.message.NlriBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.update.message.WithdrawnRoutesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.Uint32; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; 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.MapEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; +import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate; +import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidateNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Instantiated for each peer and table, listens on a particular peer's adj-rib-out, - * performs transcoding to BA form (message) and sends it down the channel. + * Instantiated for each peer and table, listens on a particular peer's adj-rib-out, performs transcoding to BA form + * (message) and sends it down the channel. This class is NOT thread-safe. */ -@NotThreadSafe final class AdjRibOutListener implements ClusteredDOMDataTreeChangeListener, PrefixesSentCounters { - private static final Logger LOG = LoggerFactory.getLogger(AdjRibOutListener.class); - - static final QName PREFIX_QNAME = QName.create(Ipv4Route.QNAME, "prefix").intern(); - static final QName PATHID_QNAME = QName.create(Ipv4Route.QNAME, "path-id").intern(); - private final YangInstanceIdentifier.NodeIdentifier routeKeyPrefixLeaf = new YangInstanceIdentifier - .NodeIdentifier(PREFIX_QNAME); - private final YangInstanceIdentifier.NodeIdentifier routeKeyPathIdLeaf = new YangInstanceIdentifier - .NodeIdentifier(PATHID_QNAME); + private static final QName PREFIX_QNAME = QName.create(Ipv4Route.QNAME, "prefix").intern(); + private static final QName PATHID_QNAME = QName.create(Ipv4Route.QNAME, "path-id").intern(); + private static final NodeIdentifier ROUTE_KEY_PREFIX_LEAF = NodeIdentifier.create(PREFIX_QNAME); + private static final NodeIdentifier ROUTE_KEY_PATHID_LEAF = NodeIdentifier.create(PATHID_QNAME); private final ChannelOutputLimiter session; private final Codecs codecs; - private final RIBSupport support; + private final RIBSupport support; + // FIXME: this field needs to be eliminated: either subclass this class or create a filtering ribsupport private final boolean mpSupport; private final ListenerRegistration registerDataTreeChangeListener; private final LongAdder prefixesSentCounter = new LongAdder(); + private final TablesKey tablesKey; + private boolean initalState; private AdjRibOutListener(final PeerId peerId, final TablesKey tablesKey, final YangInstanceIdentifier ribId, - final CodecsRegistry registry, final RIBSupport support, final DOMDataTreeChangeService service, + final CodecsRegistry registry, final RIBSupport support, final DOMDataTreeChangeService service, final ChannelOutputLimiter session, final boolean mpSupport) { this.session = requireNonNull(session); this.support = requireNonNull(support); - this.codecs = registry.getCodecs(this.support); + codecs = registry.getCodecs(this.support); this.mpSupport = mpSupport; - final YangInstanceIdentifier adjRibOutId = ribId.node(Peer.QNAME).node(IdentifierUtils.domPeerId(peerId)) - .node(AdjRibOut.QNAME).node(Tables.QNAME).node(RibSupportUtils.toYangTablesKey(tablesKey)); - this.registerDataTreeChangeListener = service.registerDataTreeChangeListener( + this.tablesKey = requireNonNull(tablesKey); + final YangInstanceIdentifier adjRibOutId = ribId.node(PEER_NID).node(IdentifierUtils.domPeerId(peerId)) + .node(ADJRIBOUT_NID).node(TABLES_NID).node(RibSupportUtils.toYangTablesKey(tablesKey)); + /* + * After listener registration should always be executed ODTC. Even when empty table is present + * in data store. Within this first ODTC execution we should advertise present routes and than + * send EOR marker. initialState flag is distinguishing between first ODTC execution and the rest. + */ + initalState = true; + registerDataTreeChangeListener = service.registerDataTreeChangeListener( new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, adjRibOutId), this); } static AdjRibOutListener create( - @Nonnull final PeerId peerId, - @Nonnull final TablesKey tablesKey, - @Nonnull final YangInstanceIdentifier ribId, - @Nonnull final CodecsRegistry registry, - @Nonnull final RIBSupport support, - @Nonnull final DOMDataTreeChangeService service, - @Nonnull final ChannelOutputLimiter session, + final @NonNull PeerId peerId, + final @NonNull TablesKey tablesKey, + final @NonNull YangInstanceIdentifier ribId, + final @NonNull CodecsRegistry registry, + final @NonNull RIBSupport support, + final @NonNull DOMDataTreeChangeService service, + final @NonNull ChannelOutputLimiter session, final boolean mpSupport) { return new AdjRibOutListener(peerId, tablesKey, ribId, registry, support, service, session, mpSupport); } @Override - public void onDataTreeChanged(final Collection changes) { + public void onInitialData() { + // FIXME: flush initial state + } + + @Override + public void onDataTreeChanged(final List changes) { LOG.debug("Data change received for AdjRibOut {}", changes); for (final DataTreeCandidate tc : changes) { LOG.trace("Change {} type {}", tc.getRootNode(), tc.getRootNode().getModificationType()); for (final DataTreeCandidateNode child : tc.getRootNode().getChildNodes()) { - processSupportedFamilyRoutes(child); + for (final DataTreeCandidateNode route : support.changedRoutes(child)) { + processRouteChange(route); + } } } - this.session.flush(); - } - - private void processSupportedFamilyRoutes(final DataTreeCandidateNode child) { - for (final DataTreeCandidateNode route : this.support.changedRoutes(child)) { - processRouteChange(route); + if (initalState) { + final Update endOfRib = BgpPeerUtil.createEndOfRib(tablesKey); + session.write(endOfRib); + initalState = false; } + session.flush(); } private void processRouteChange(final DataTreeCandidateNode route) { @@ -130,20 +136,20 @@ final class AdjRibOutListener implements ClusteredDOMDataTreeChangeListener, Pre case DELETE: case DISAPPEARED: // FIXME: we can batch deletions into a single batch - update = withdraw((MapEntryNode) route.getDataBefore().get()); + update = withdraw((MapEntryNode) route.getDataBefore().orElseThrow()); LOG.debug("Withdrawing routes {}", update); break; case APPEARED: case SUBTREE_MODIFIED: case WRITE: - update = advertise((MapEntryNode) route.getDataAfter().get()); + update = advertise((MapEntryNode) route.getDataAfter().orElseThrow()); LOG.debug("Advertising routes {}", update); break; default: LOG.warn("Ignoring unhandled modification type {}", route.getModificationType()); return; } - this.session.write(update); + session.write(update); } private Attributes routeAttributes(final MapEntryNode route) { @@ -151,66 +157,61 @@ final class AdjRibOutListener implements ClusteredDOMDataTreeChangeListener, Pre LOG.debug("AdjRibOut parsing route {}", NormalizedNodes.toStringTree(route)); } final ContainerNode advertisedAttrs = (ContainerNode) NormalizedNodes.findNode(route, - this.support.routeAttributesIdentifier()).orElse(null); - return this.codecs.deserializeAttributes(advertisedAttrs); + support.routeAttributesIdentifier()).orElse(null); + return codecs.deserializeAttributes(advertisedAttrs); } private Update withdraw(final MapEntryNode route) { - if (!this.mpSupport) { - return buildUpdate(Collections.emptyList(), Collections.singleton(route), routeAttributes(route)); - } - return this.support.buildUpdate(Collections.emptyList(), Collections.singleton(route), routeAttributes(route)); + return mpSupport + ? support.buildUpdate(Collections.emptyList(), Collections.singleton(route), routeAttributes(route)) + : buildUpdate(Collections.emptyList(), Collections.singleton(route), routeAttributes(route)); } private Update advertise(final MapEntryNode route) { - this.prefixesSentCounter.increment(); - if (!this.mpSupport) { - return buildUpdate(Collections.singleton(route), Collections.emptyList(), routeAttributes(route)); - } - return this.support.buildUpdate(Collections.singleton(route), Collections.emptyList(), routeAttributes(route)); - } - - private Update buildUpdate( - @Nonnull final Collection advertised, - @Nonnull final Collection withdrawn, - @Nonnull final Attributes attr) { - final UpdateBuilder ub = new UpdateBuilder().setWithdrawnRoutes(extractWithdrawnRoutes(withdrawn)) - .setNlri(extractNlris(advertised)); - ub.setAttributes(attr); - return ub.build(); - } - - private List extractNlris(final Collection routes) { - return routes.stream().map(ipv4Route -> new NlriBuilder().setPrefix(new Ipv4Prefix(extractPrefix(ipv4Route))) - .setPathId(extractPathId(ipv4Route)).build()).collect(Collectors.toList()); + prefixesSentCounter.increment(); + return mpSupport + ? support.buildUpdate(Collections.singleton(route), Collections.emptyList(), routeAttributes(route)) + : buildUpdate(Collections.singleton(route), Collections.emptyList(), routeAttributes(route)); } - private List extractWithdrawnRoutes(final Collection routes) { - return routes.stream().map(ipv4Route -> new WithdrawnRoutesBuilder() - .setPrefix(new Ipv4Prefix(extractPrefix(ipv4Route))).setPathId(extractPathId(ipv4Route)).build()) - .collect(Collectors.toList()); + private static Update buildUpdate( + final @NonNull Collection advertised, + final @NonNull Collection withdrawn, + final @NonNull Attributes attr) { + return new UpdateBuilder() + .setWithdrawnRoutes(withdrawn.stream() + .map(ipv4Route -> new WithdrawnRoutesBuilder() + .setPrefix(extractPrefix(ipv4Route)) + .setPathId(extractPathId(ipv4Route)) + .build()) + .collect(Collectors.toList())) + .setNlri(advertised.stream() + .map(ipv4Route -> new NlriBuilder() + .setPrefix(extractPrefix(ipv4Route)) + .setPathId(extractPathId(ipv4Route)).build()) + .collect(Collectors.toList())) + .setAttributes(attr).build(); } - private String extractPrefix(final MapEntryNode ipv4Route) { - return (String) ipv4Route.getChild(this.routeKeyPrefixLeaf).get().getValue(); + private static Ipv4Prefix extractPrefix(final MapEntryNode ipv4Route) { + return new Ipv4Prefix((String) ipv4Route.getChildByArg(ROUTE_KEY_PREFIX_LEAF).body()); } - private PathId extractPathId(final MapEntryNode ipv4Route) { - final Optional> pathId = ipv4Route - .getChild(this.routeKeyPathIdLeaf); - return pathId.isPresent() ? new PathId((Long) pathId.get().getValue()) : null; + private static PathId extractPathId(final MapEntryNode ipv4Route) { + final var pathId = ipv4Route.childByArg(ROUTE_KEY_PATHID_LEAF); + return pathId == null ? null : new PathId((Uint32) pathId.body()); } public void close() { - this.registerDataTreeChangeListener.close(); + registerDataTreeChangeListener.close(); } boolean isMpSupported() { - return this.mpSupport; + return mpSupport; } @Override public long getPrefixesSentCount() { - return this.prefixesSentCounter.longValue(); + return prefixesSentCounter.longValue(); } }