From c68ba9fedd2bed167d1271be894c98b1aa1b4040 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Wed, 5 Dec 2018 19:18:57 +0100 Subject: [PATCH] Prepare EffRibInWriter for LLGR_STALE handling When a peer configured with Long-Lived Graceful Restart goes down, we need to process all tables which it advertised as LLGR-enabled and mark all routes as being tagged with LLGR_STALE. LLGR_STALE community must be added to routes behind import policy processing since policies can also add this community. This patch should provide procedures necessary to add LLGR_STALE community to routes. JIRA: BGPCEP-495 Change-Id: If921e378f998109b073c628f9913f395496b3139 Signed-off-by: Robert Varga Signed-off-by: Matej Perina --- .../bgp/rib/impl/EffectiveRibInWriter.java | 84 ++++++++++++++----- .../bgp/rib/impl/StaleCommunities.java | 53 ++++++++++++ 2 files changed, 117 insertions(+), 20 deletions(-) create mode 100644 bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/StaleCommunities.java diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/EffectiveRibInWriter.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/EffectiveRibInWriter.java index 932b1eeb14..a7c6258b76 100644 --- a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/EffectiveRibInWriter.java +++ b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/EffectiveRibInWriter.java @@ -10,6 +10,7 @@ package org.opendaylight.protocol.bgp.rib.impl; import static com.google.common.base.Verify.verify; import static java.util.Objects.requireNonNull; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.FluentFuture; @@ -35,6 +36,7 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.mdsal.common.api.CommitInfo; import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer; +import org.opendaylight.protocol.bgp.parser.impl.message.update.CommunityUtil; import org.opendaylight.protocol.bgp.rib.impl.spi.RIB; import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry; import org.opendaylight.protocol.bgp.rib.impl.spi.RibOutRefresh; @@ -46,6 +48,7 @@ import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryImportParameter import org.opendaylight.protocol.bgp.route.targetcontrain.spi.ClientRouteTargetContrainCache; import org.opendaylight.protocol.bgp.route.targetcontrain.spi.RouteTargetMembeshipUtil; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.Communities; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.Peer; @@ -95,6 +98,13 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn MplsLabeledVpnSubsequentAddressFamily.class); private static final TablesKey IVP6_VPN_TABLE_KEY = new TablesKey(Ipv6AddressFamily.class, MplsLabeledVpnSubsequentAddressFamily.class); + private static final ImmutableList STALE_LLGR_COMMUNUTIES = ImmutableList.of( + StaleCommunities.STALE_LLGR); + private static final Attributes STALE_LLGR_ATTRIBUTES = new org.opendaylight.yang.gen.v1.urn.opendaylight.params + .xml.ns.yang.bgp.message.rev180329.path.attributes.AttributesBuilder() + .setCommunities(STALE_LLGR_COMMUNUTIES) + .build(); + private final RIBSupportContextRegistry registry; private final KeyedInstanceIdentifier peerIId; private final InstanceIdentifier effRibTables; @@ -260,7 +270,7 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn switch (routeChanged.getModificationType()) { case SUBTREE_MODIFIED: case WRITE: - writeRoutes(tx, tableKey, ribSupport, tablePath, routeKey, routeChanged.getDataAfter()); + writeRoutes(tx, tableKey, ribSupport, tablePath, routeKey, routeChanged.getDataAfter(), false); break; case DELETE: final InstanceIdentifier routeIID = ribSupport.createRouteIdentifier(tablePath, routeKey); @@ -271,32 +281,66 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn } private , S extends ChildOf, - R extends Route & ChildOf & Identifiable, I extends Identifier> void writeRoutes( - final WriteTransaction tx, final TablesKey tk, final RIBSupport ribSupport, + R extends Route & ChildOf & Identifiable, I extends Identifier> void writeRoutes( + final WriteTransaction tx, final TablesKey tk, final RIBSupport ribSupport, final KeyedInstanceIdentifier tablePath, final I routeKey, - final R route) { + final R route, final boolean longLivedStale) { final InstanceIdentifier routeIID = ribSupport.createRouteIdentifier(tablePath, routeKey); CountersUtil.increment(this.prefixesReceived.get(tk), tk); - final Optional effAtt = this.ribPolicies - .applyImportPolicies(this.peerImportParameters, route.getAttributes(), - tableTypeRegistry.getAfiSafiType(ribSupport.getTablesKey()).get()); - if (effAtt.isPresent()) { - final Optional rtMembership = RouteTargetMembeshipUtil.getRT(route); - if (rtMembership.isPresent()) { - final RouteTarget rt = rtMembership.get(); - if(PeerRole.Ebgp != this.peerImportParameters.getFromPeerRole()) { - this.rtCache.cacheRoute(route); - } - this.rtMemberships.add(rt); - this.rtMembershipsUpdated = true; + + final Attributes routeAttrs = route.getAttributes(); + final Optional optEffAtt; + // In case we want to add LLGR_STALE we do not process route through policies since it may be + // considered as received with LLGR_STALE from peer which is not true. + if (longLivedStale) { + // LLGR procedures are in effect. If the route is tagged with NO_LLGR, it needs to be removed. + final List effCommunities = routeAttrs.getCommunities(); + if (effCommunities != null && effCommunities.contains(CommunityUtil.NO_LLGR)) { + deleteRoutes(routeIID, route, tx); + return; } - CountersUtil.increment(this.prefixesInstalled.get(tk), tk); - tx.put(LogicalDatastoreType.OPERATIONAL, routeIID, route); - tx.put(LogicalDatastoreType.OPERATIONAL, routeIID.child(Attributes.class), effAtt.get()); + optEffAtt = Optional.of(wrapLongLivedStale(routeAttrs)); } else { + optEffAtt = this.ribPolicies.applyImportPolicies(this.peerImportParameters, routeAttrs, + tableTypeRegistry.getAfiSafiType(ribSupport.getTablesKey()).get()); + } + if (!optEffAtt.isPresent()) { deleteRoutes(routeIID, route, tx); + return; + } + final Optional rtMembership = RouteTargetMembeshipUtil.getRT(route); + if (rtMembership.isPresent()) { + final RouteTarget rt = rtMembership.get(); + if (PeerRole.Ebgp != this.peerImportParameters.getFromPeerRole()) { + this.rtCache.cacheRoute(route); + } + this.rtMemberships.add(rt); + this.rtMembershipsUpdated = true; } + CountersUtil.increment(this.prefixesInstalled.get(tk), tk); + tx.put(LogicalDatastoreType.OPERATIONAL, routeIID, route); + tx.put(LogicalDatastoreType.OPERATIONAL, routeIID.child(Attributes.class), optEffAtt.get()); + } + + private static Attributes wrapLongLivedStale(final Attributes attrs) { + if (attrs == null) { + return STALE_LLGR_ATTRIBUTES; + } + + final List oldCommunities = attrs.getCommunities(); + final List newCommunities; + if (oldCommunities != null) { + if (oldCommunities.contains(StaleCommunities.STALE_LLGR)) { + return attrs; + } + newCommunities = StaleCommunities.create(oldCommunities); + } else { + newCommunities = STALE_LLGR_COMMUNUTIES; + } + + return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329 + .path.attributes.AttributesBuilder(attrs).setCommunities(newCommunities).build(); } private void deleteRoutes(final InstanceIdentifier routeIID, @@ -326,7 +370,7 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn LOG.trace("Create Empty table at {}", tablePath); if (table.getDataBefore() == null) { tx.put(LogicalDatastoreType.OPERATIONAL, tablePath, new TablesBuilder() - .setAfi(tableKey.getAfi()).setSafi(tableKey.getSafi()) + .withKey(tableKey).setAfi(tableKey.getAfi()).setSafi(tableKey.getSafi()) .setAttributes(newTable.getAttributes()).build()); } diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/StaleCommunities.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/StaleCommunities.java new file mode 100644 index 0000000000..e04738c32b --- /dev/null +++ b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/StaleCommunities.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018 AT&T Intellectual Property. 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.rib.impl; + +import static java.util.Objects.requireNonNull; + +import java.util.AbstractList; +import java.util.List; +import org.opendaylight.protocol.bgp.parser.impl.message.update.CommunityUtil; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.Communities; + +/** + * Utility class which prepends {@code LLGR_STALE} community in front of some other communities. + */ +class StaleCommunities extends AbstractList { + private static final class RandomAccess extends StaleCommunities implements java.util.RandomAccess { + RandomAccess(final List orig) { + super(orig); + } + } + + static final Communities STALE_LLGR = (Communities) CommunityUtil.LLGR_STALE; + + private final List orig; + + StaleCommunities(final List orig) { + this.orig = requireNonNull(orig); + } + + static StaleCommunities create(final List orig) { + return orig instanceof java.util.RandomAccess ? new RandomAccess(orig) : new StaleCommunities(orig); + } + + @Override + public final boolean contains(final Object obj) { + return STALE_LLGR.equals(obj) || orig.contains(obj); + } + + @Override + public final Communities get(final int index) { + return index == 0 ? STALE_LLGR : orig.get(index - 1); + } + + @Override + public final int size() { + return orig.size() + 1; + } +} -- 2.36.6