BUG-4827: Introduce add path tables support and Path Id to rib support 99/36099/10
authorClaudio D. Gasparini <cgaspari@cisco.com>
Sat, 5 Mar 2016 21:18:27 +0000 (22:18 +0100)
committerMilos Fabian <milfabia@cisco.com>
Thu, 17 Mar 2016 00:16:17 +0000 (00:16 +0000)
On session up peer will advertise supported add path tables,
we store them on data store and introduce them to ribsupport
for future filtering of route advertise.
Also we introduce a method for extract Path Id from prefix received routes,
which will be used by Add Path selection modes.

Change-Id: I118e40913086aef71f1f72600c9b66de65b858b5
Signed-off-by: Claudio D. Gasparini <cgaspari@cisco.com>
22 files changed:
bgp/controller-config/src/main/resources/initial/41-bgp-example.xml
bgp/parser-api/src/main/yang/bgp-multiprotocol.yang
bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/impl/base/BaseAbstractRouteEntry.java
bgp/rib-api/src/main/yang/bgp-rib.yang
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibInWriter.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/ApplicationPeer.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPPeer.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPSessionImpl.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPSessionStats.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/ExportPolicyPeerTrackerImpl.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/IPv4RIBSupport.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/LocRibWriter.java
bgp/rib-impl/src/main/yang/odl-bgp-rib-impl-cfg.yang
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibsInWriterTest.java
bgp/rib-mock/src/main/java/org/opendaylight/protocol/bgp/rib/mock/EventBusRegistration.java
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/AbstractRIBSupport.java
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/AddPathRibSupport.java [new file with mode: 0644]
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/BGPSession.java
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/ExportPolicyPeerTracker.java
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RIBSupport.java
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RibSupportUtils.java
bgp/rib-spi/src/test/java/org/opendaylight/protocol/bgp/rib/spi/AbstractRIBSupportTest.java

index 2659fa1e06598d6606eb98254b5b6222dbf488ba..4ced005c6b140f9adf047786fc1de317a1f0715f 100755 (executable)
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:bgp:rib:impl">prefix:bgp-table-type</type>
                         <name>ipv4-l3vpn</name>
                     </advertized-table>
+                    <add-path>
+                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:bgp:rib:impl">prefix:add-path</type>
+                        <name>ipv4-unicast-both</name>
+                    </add-path>
                 </module>
                 -->
 
index c50a2bf4afc7bc3b44fa20f603fea2efc0bc57f2..b1fe925ee88f85d8214e0e41cbdcd52e8784f8f8 100644 (file)
@@ -55,6 +55,13 @@ module bgp-multiprotocol {
         }
     }
 
+    grouping bgp-add-path-table-type {
+        uses bgp-table-type;
+        leaf send-receive {
+            type send-receive;
+        }
+    }
+
     grouping destination {
         choice destination-type {
             // to be augmented
@@ -103,10 +110,7 @@ module bgp-multiprotocol {
         container add-path-capability {
             reference "http://tools.ietf.org/html/draft-ietf-idr-add-paths-13#section-4";
             list address-families {
-                uses bgp-table-type;
-                leaf send-receive {
-                    type send-receive;
-                }
+                uses bgp-add-path-table-type;
             }
         }
         container route-refresh-capability {
index bc4b6c6acce04c77f69a8193c3e673ab0a263b70..7ba5acc7b1b9abf44b419b79e6f75bbd61f96a9e 100644 (file)
@@ -215,7 +215,7 @@ abstract class BaseAbstractRouteEntry implements RouteEntry {
     }
 
     private boolean isTableSupported(final PeerId destPeer, final ExportPolicyPeerTracker peerPT, final TablesKey localTK) {
-        if (!peerPT.isTableSupported(destPeer, localTK)) {
+        if (!peerPT.isTableSupported(destPeer)) {
             LOG.trace("Route rejected, peer {} does not support this table type {}", destPeer, localTK);
             return false;
         }
index 543b273dd92a9fa669fc860db5e3e5f2a9f50da4..3432241a29463a7c99ab2978503a3f99ff7de551 100644 (file)
@@ -106,7 +106,7 @@ module bgp-rib {
                 }
                 list supported-tables {
                     key "afi safi";
-                    uses bgp-mp:bgp-table-type;
+                    uses bgp-mp:bgp-add-path-table-type;
                 }
                 container adj-rib-in {
                     description "Routes as we have received them from the peer.";
index 9da50a9a2d6f17e55787414619b98c3689bedbe6..b01cd978f6f46fa6e321bc0efd5c79fd78717480 100644 (file)
@@ -12,9 +12,11 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import javax.annotation.concurrent.NotThreadSafe;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -25,6 +27,8 @@ import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContext;
 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
 import org.opendaylight.protocol.bgp.rib.spi.IdentifierUtils;
 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.SendReceive;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.add.path.capability.AddressFamilies;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
@@ -73,6 +77,7 @@ final class AdjRibInWriter {
     private static final NodeIdentifier PEER_ROLE = new NodeIdentifier(PEER_ROLE_QNAME);
     private static final NodeIdentifier PEER_TABLES = new NodeIdentifier(SupportedTables.QNAME);
     private static final NodeIdentifier TABLES = new NodeIdentifier(Tables.QNAME);
+    private static final QName SEND_RECEIVE = QName.create(SupportedTables.QNAME, "send-receive").intern();
 
     // FIXME: is there a utility method to construct this?
     private static final ContainerNode EMPTY_ADJRIBIN = Builders.containerBuilder().withNodeIdentifier(ADJRIBIN).addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build()).build();
@@ -130,14 +135,16 @@ final class AdjRibInWriter {
      * @param newPeerId new peer BGP identifier
      * @param registry RIB extension registry
      * @param tableTypes New tables, must not be null
+     * @param addPathTablesType
      * @return New writer
      */
-    AdjRibInWriter transform(final PeerId newPeerId, final RIBSupportContextRegistry registry, final Set<TablesKey> tableTypes, final boolean isAppPeer) {
+    AdjRibInWriter transform(final PeerId newPeerId, final RIBSupportContextRegistry registry, final Set<TablesKey> tableTypes,
+        final List<AddressFamilies> addPathTablesType, final boolean isAppPeer) {
         final DOMDataWriteTransaction tx = this.chain.newWriteOnlyTransaction();
 
         final YangInstanceIdentifier newPeerPath;
         newPeerPath = createEmptyPeerStructure(newPeerId, isAppPeer, tx);
-        final ImmutableMap<TablesKey, TableContext> tb = createNewTableInstances(newPeerPath, isAppPeer, registry, tableTypes, tx);
+        final ImmutableMap<TablesKey, TableContext> tb = createNewTableInstances(newPeerPath, isAppPeer, registry, tableTypes, addPathTablesType, tx);
         tx.submit();
 
         return new AdjRibInWriter(this.ribPath, this.chain, newPeerId, this.role, newPeerPath, tb);
@@ -149,12 +156,15 @@ final class AdjRibInWriter {
      * @param isAppPeer
      * @param registry
      * @param tableTypes
+     * @param addPathTablesType
      * @param tx
      * @return
      */
     private ImmutableMap<TablesKey, TableContext> createNewTableInstances(final YangInstanceIdentifier newPeerPath, final boolean isAppPeer,
-        final RIBSupportContextRegistry registry, final Set<TablesKey> tableTypes, final DOMDataWriteTransaction tx) {
+        final RIBSupportContextRegistry registry, final Set<TablesKey> tableTypes, final List<AddressFamilies> addPathTablesType,
+        final DOMDataWriteTransaction tx) {
 
+        final Map<TablesKey, SendReceive> addPathTableMaps = mapTableTypesFamilies(addPathTablesType);
         final Builder<TablesKey, TableContext> tb = ImmutableMap.builder();
         for (final TablesKey tableKey : tableTypes) {
             final RIBSupportContext rs = registry.getRIBSupportContext(tableKey);
@@ -164,12 +174,17 @@ final class AdjRibInWriter {
                 LOG.warn("No support for table type {}, skipping it", tableKey);
                 continue;
             }
-            installAdjRibsOutTables(isAppPeer, newPeerPath, rs, instanceIdentifierKey, tableKey, tx);
+            installAdjRibsOutTables(isAppPeer, newPeerPath, rs, instanceIdentifierKey, tableKey, addPathTableMaps.get(tableKey), tx);
             installAdjRibInTables(newPeerPath, tableKey, rs, instanceIdentifierKey, tx, tb);
         }
         return tb.build();
     }
 
+    private Map<TablesKey, SendReceive> mapTableTypesFamilies(final List<AddressFamilies> addPathTablesType) {
+        return Collections.unmodifiableMap(addPathTablesType.stream().collect(Collectors.toMap(af -> new TablesKey(af.getAfi(), af.getSafi()),
+            af -> af.getSendReceive())));
+    }
+
     private void installAdjRibInTables(final YangInstanceIdentifier newPeerPath, final TablesKey tableKey, final RIBSupportContext rs,
         final NodeIdentifierWithPredicates instanceIdentifierKey, final DOMDataWriteTransaction tx, final Builder<TablesKey, TableContext> tb) {
         // We will use table keys very often, make sure they are optimized
@@ -185,13 +200,17 @@ final class AdjRibInWriter {
     }
 
     private void installAdjRibsOutTables(final boolean isAppPeer, final YangInstanceIdentifier newPeerPath, final RIBSupportContext rs,
-        final NodeIdentifierWithPredicates instanceIdentifierKey, final TablesKey tableKey, final DOMDataWriteTransaction tx) {
+        final NodeIdentifierWithPredicates instanceIdentifierKey, final TablesKey tableKey, final SendReceive sendReceive,
+        final DOMDataWriteTransaction tx) {
         if (!isAppPeer) {
             final NodeIdentifierWithPredicates supTablesKey = RibSupportUtils.toYangKey(SupportedTables.QNAME, tableKey);
             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> tt = Builders.mapEntryBuilder().withNodeIdentifier(supTablesKey);
             for (final Entry<QName, Object> e : supTablesKey.getKeyValues().entrySet()) {
                 tt.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
             }
+            if(sendReceive != null) {
+                tt.withChild(ImmutableNodes.leafNode(SEND_RECEIVE, sendReceive.toString().toLowerCase()));
+            }
             tx.put(LogicalDatastoreType.OPERATIONAL, newPeerPath.node(PEER_TABLES).node(supTablesKey), tt.build());
             rs.createEmptyTableStructure(tx, newPeerPath.node(EMPTY_ADJRIBOUT.getIdentifier()).node(TABLES).node(instanceIdentifierKey));
         }
index 5d1a01676a1578065350d82ae9418922b2021d94..f7bd571353dba4f8306ca7aee9cc8476af7940f5 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.Verify;
 import com.google.common.net.InetAddresses;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
@@ -60,7 +61,6 @@ public class ApplicationPeer implements AutoCloseable, org.opendaylight.protocol
     private final DOMTransactionChain chain;
     private final DOMTransactionChain writerChain;
     private final BGPConfigModuleTracker moduleTracker;
-
     private AdjRibInWriter writer;
 
     public ApplicationPeer(final ApplicationRibId applicationRibId, final Ipv4Address ipAddress, final RIBImpl rib, final BGPConfigModuleTracker
@@ -73,7 +73,8 @@ public class ApplicationPeer implements AutoCloseable, org.opendaylight.protocol
         this.chain = targetRib.createPeerChain(this);
         this.writerChain = targetRib.createPeerChain(this);
         this.writer = AdjRibInWriter.create(targetRib.getYangRibId(), PeerRole.Internal, this.writerChain);
-        this.writer = this.writer.transform(RouterIds.createPeerId(ipAddress), targetRib.getRibSupportContext(), targetRib.getLocalTablesKeys(), true);
+        this.writer = this.writer.transform(RouterIds.createPeerId(ipAddress), targetRib.getRibSupportContext(), targetRib.getLocalTablesKeys(),
+            Collections.emptyList(), true);
         this.moduleTracker = moduleTracker;
         if (moduleTracker != null) {
             moduleTracker.onInstanceCreate();
index 1233d21c7848f8fd73b8cb927072b58de811aa27..a7dc2161c258355b9442e76d25e78de22a39238f 100644 (file)
@@ -50,6 +50,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mult
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.RouteRefresh;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.add.path.capability.AddressFamilies;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlri;
@@ -220,13 +221,15 @@ public class BGPPeer implements BGPSessionListener, Peer, AutoCloseable, BGPPeer
 
     @Override
     public synchronized void onSessionUp(final BGPSession session) {
-        LOG.info("Session with peer {} went up with tables: {}", this.name, session.getAdvertisedTableTypes());
+        final List<AddressFamilies> addPathTablesType = session.getAdvertisedAddPathTableTypes();
+        LOG.info("Session with peer {} went up with tables {} and Add Path tables {}", this.name, addPathTablesType,
+            session.getAdvertisedAddPathTableTypes());
         this.session = session;
         this.rawIdentifier = InetAddresses.forString(session.getBgpId().getValue()).getAddress();
         final PeerId peerId = RouterIds.createPeerId(session.getBgpId());
         createAdjRibOutListener(peerId);
 
-        this.ribWriter = this.ribWriter.transform(peerId, this.rib.getRibSupportContext(), this.tables, false);
+        this.ribWriter = this.ribWriter.transform(peerId, this.rib.getRibSupportContext(), this.tables, addPathTablesType, false);
         this.sessionEstablishedCounter++;
         if (this.registrator != null) {
             this.runtimeReg = this.registrator.register(this);
index 0a04aaa28d39efb0c011f2cd3e1ab693469b84c5..9f42cae002448e189c9deb0a2cb425add83ff61d 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.MoreObjects;
 import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
@@ -20,6 +21,7 @@ import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.SimpleChannelInboundHandler;
 import java.io.IOException;
 import java.util.Date;
+import java.util.List;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import javax.annotation.concurrent.GuardedBy;
@@ -48,7 +50,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mess
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.CParameters1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.RouteRefresh;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.AddPathCapability;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.MultiprotocolCapability;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.add.path.capability.AddressFamilies;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.slf4j.Logger;
@@ -110,6 +114,7 @@ public class BGPSessionImpl extends SimpleChannelInboundHandler<Notification> im
     private State state = State.OPEN_CONFIRM;
 
     private final Set<BgpTableType> tableTypes;
+    private final List<AddressFamilies> addPathTypes;
     private final int holdTimerValue;
     private final int keepAlive;
     private final AsNumber asNumber;
@@ -122,7 +127,7 @@ public class BGPSessionImpl extends SimpleChannelInboundHandler<Notification> im
     public BGPSessionImpl(final BGPSessionListener listener, final Channel channel, final Open remoteOpen, final BGPSessionPreferences localPreferences,
             final BGPPeerRegistry peerRegistry) {
         this(listener, channel, remoteOpen, localPreferences.getHoldTime(), peerRegistry);
-        this.sessionStats = new BGPSessionStats(remoteOpen, this.holdTimerValue, this.keepAlive, channel, Optional.of(localPreferences), this.tableTypes);
+        this.sessionStats = new BGPSessionStats(remoteOpen, this.holdTimerValue, this.keepAlive, channel, Optional.of(localPreferences), this.tableTypes, this.addPathTypes);
     }
 
     public BGPSessionImpl(final BGPSessionListener listener, final Channel channel, final Open remoteOpen, final int localHoldTimer,
@@ -143,25 +148,31 @@ public class BGPSessionImpl extends SimpleChannelInboundHandler<Notification> im
 
         final Set<TablesKey> tts = Sets.newHashSet();
         final Set<BgpTableType> tats = Sets.newHashSet();
+        final List<AddressFamilies> addPathCapabilitiesList = Lists.newArrayList();
         if (remoteOpen.getBgpParameters() != null) {
             for (final BgpParameters param : remoteOpen.getBgpParameters()) {
                 for (final OptionalCapabilities optCapa : param.getOptionalCapabilities()) {
                     final CParameters cParam = optCapa.getCParameters();
-                    if ( cParam.getAugmentation(CParameters1.class) == null ||
-                            cParam.getAugmentation(CParameters1.class).getMultiprotocolCapability() == null ) {
+                    if ( cParam.getAugmentation(CParameters1.class) == null) {
                         continue;
                     }
-                    final MultiprotocolCapability multi = cParam.getAugmentation(CParameters1.class).getMultiprotocolCapability();
-                    final TablesKey tt = new TablesKey(multi.getAfi(), multi.getSafi());
-                    LOG.trace("Added table type to sync {}", tt);
-                    tts.add(tt);
-                    tats.add(new BgpTableTypeImpl(tt.getAfi(), tt.getSafi()));
+                    if(cParam.getAugmentation(CParameters1.class).getMultiprotocolCapability() != null) {
+                        final MultiprotocolCapability multi = cParam.getAugmentation(CParameters1.class).getMultiprotocolCapability();
+                        final TablesKey tt = new TablesKey(multi.getAfi(), multi.getSafi());
+                        LOG.trace("Added table type to sync {}", tt);
+                        tts.add(tt);
+                        tats.add(new BgpTableTypeImpl(tt.getAfi(), tt.getSafi()));
+                    } else if (cParam.getAugmentation(CParameters1.class).getAddPathCapability() != null) {
+                        final AddPathCapability addPathCap = cParam.getAugmentation(CParameters1.class).getAddPathCapability();
+                        addPathCapabilitiesList.addAll(addPathCap.getAddressFamilies());
+                    }
                 }
             }
         }
 
         this.sync = new BGPSynchronization(this.listener, tts);
         this.tableTypes = tats;
+        this.addPathTypes = addPathCapabilitiesList;
 
         if (this.holdTimerValue != 0) {
             channel.eventLoop().schedule(new Runnable() {
@@ -180,7 +191,7 @@ public class BGPSessionImpl extends SimpleChannelInboundHandler<Notification> im
         }
         this.bgpId = remoteOpen.getBgpIdentifier();
         this.sessionStats = new BGPSessionStats(remoteOpen, this.holdTimerValue, this.keepAlive, channel, Optional.<BGPSessionPreferences>absent(),
-                this.tableTypes);
+                this.tableTypes, this.addPathTypes);
     }
 
     @Override
@@ -373,6 +384,11 @@ public class BGPSessionImpl extends SimpleChannelInboundHandler<Notification> im
         return this.tableTypes;
     }
 
+    @Override
+    public List<AddressFamilies> getAdvertisedAddPathTableTypes() {
+        return this.addPathTypes;
+    }
+
     protected synchronized void sessionUp() {
         this.sessionStats.startSessionStopwatch();
         this.state = State.UP;
index 2e78f7245356ac3e4c1013a9ab3a359052e37a14..4888c03eb4835b6b374a7bab969817246d75ff44 100644 (file)
@@ -17,6 +17,8 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import org.opendaylight.controller.config.yang.bgp.rib.impl.AdvertisedAddPathTableTypes;
 import org.opendaylight.controller.config.yang.bgp.rib.impl.AdvertizedTableTypes;
 import org.opendaylight.controller.config.yang.bgp.rib.impl.BgpSessionState;
 import org.opendaylight.controller.config.yang.bgp.rib.impl.ErrorMsgs;
@@ -42,6 +44,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mess
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.CParameters1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.MultiprotocolCapability;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.add.path.capability.AddressFamilies;
 
 final class BGPSessionStats {
     private final Stopwatch sessionStopwatch;
@@ -53,12 +56,12 @@ final class BGPSessionStats {
     private final ErrorMsgs errMsgs = new ErrorMsgs();
 
     public BGPSessionStats(final Open remoteOpen, final int holdTimerValue, final int keepAlive, final Channel channel,
-            final Optional<BGPSessionPreferences> localPreferences, final Collection<BgpTableType> tableTypes) {
+        final Optional<BGPSessionPreferences> localPreferences, final Collection<BgpTableType> tableTypes, final List<AddressFamilies> addPathTypes) {
         this.sessionStopwatch = Stopwatch.createUnstarted();
         this.stats = new BgpSessionState();
         this.stats.setHoldtimeCurrent(holdTimerValue);
         this.stats.setKeepaliveCurrent(keepAlive);
-        this.stats.setPeerPreferences(setPeerPref(remoteOpen, channel, tableTypes));
+        this.stats.setPeerPreferences(setPeerPref(remoteOpen, channel, tableTypes, addPathTypes));
         this.stats.setSpeakerPreferences(setSpeakerPref(channel, localPreferences));
         initMsgs();
     }
@@ -168,6 +171,15 @@ final class BGPSessionStats {
         return att;
     }
 
+    private static AdvertisedAddPathTableTypes addAddPathTableType(final AddressFamilies addressFamilies) {
+        Preconditions.checkNotNull(addressFamilies);
+        final AdvertisedAddPathTableTypes att = new AdvertisedAddPathTableTypes();
+        att.setAfi(addressFamilies.getAfi().getSimpleName());
+        att.setSafi(addressFamilies.getSafi().getSimpleName());
+        att.setSendReceive(addressFamilies.getSendReceive().toString());
+        return att;
+    }
+
     private static SpeakerPreferences setSpeakerPref(final Channel channel, final Optional<BGPSessionPreferences> localPreferences) {
         Preconditions.checkNotNull(channel);
         final SpeakerPreferences pref = new SpeakerPreferences();
@@ -219,7 +231,8 @@ final class BGPSessionStats {
         return pref;
     }
 
-    private static PeerPreferences setPeerPref(final Open remoteOpen, final Channel channel, final Collection<BgpTableType> tableTypes) {
+    private static PeerPreferences setPeerPref(final Open remoteOpen, final Channel channel, final Collection<BgpTableType> tableTypes,
+        final List<AddressFamilies> addPathTypes) {
         Preconditions.checkNotNull(remoteOpen);
         Preconditions.checkNotNull(channel);
         final PeerPreferences pref = new PeerPreferences();
@@ -229,10 +242,11 @@ final class BGPSessionStats {
         pref.setBgpId(remoteOpen.getBgpIdentifier().getValue());
         pref.setAs(remoteOpen.getMyAsNumber().longValue());
         pref.setHoldtime(remoteOpen.getHoldTimer());
-        final List<AdvertizedTableTypes> tt = new ArrayList<>();
-        for (final BgpTableType t : tableTypes) {
-            tt.add(addTableType(t));
-        }
+
+        final List<AdvertizedTableTypes> tt = tableTypes.stream().map(BGPSessionStats::addTableType).collect(Collectors.toList());
+        final List<AdvertisedAddPathTableTypes> addPathTableTypeList = addPathTypes.stream().map(BGPSessionStats::addAddPathTableType)
+            .collect(Collectors.toList());
+
         if (remoteOpen.getBgpParameters() != null) {
             for (final BgpParameters param : remoteOpen.getBgpParameters()) {
                 for (final OptionalCapabilities capa : param.getOptionalCapabilities()) {
@@ -260,6 +274,7 @@ final class BGPSessionStats {
             }
         }
         pref.setAdvertizedTableTypes(tt);
+        pref.setAdvertisedAddPathTableTypes(addPathTableTypeList);
         return pref;
     }
 }
index bf09d30caec202db058693872367f6e2f1db6145..480c0690114be6095fbda07cbd7c736ccf14ffff 100644 (file)
@@ -8,13 +8,14 @@
 package org.opendaylight.protocol.bgp.rib.impl;
 
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Collections2;
-import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
 import java.util.AbstractMap;
 import java.util.Collection;
 import java.util.Collections;
@@ -22,37 +23,48 @@ import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
 import org.opendaylight.protocol.bgp.rib.spi.IdentifierUtils;
 import org.opendaylight.protocol.bgp.rib.spi.PeerExportGroup;
 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.SendReceive;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.peer.SupportedTables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+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.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 final class ExportPolicyPeerTrackerImpl extends AbstractPeerRoleTracker implements ExportPolicyPeerTracker {
     private static final Logger LOG = LoggerFactory.getLogger(ExportPolicyPeerTrackerImpl.class);
-    private static final Function<YangInstanceIdentifier, Entry<PeerId, YangInstanceIdentifier>> GENERATE_PEERID = new Function<YangInstanceIdentifier, Entry<PeerId, YangInstanceIdentifier>>() {
+    private static final Function<YangInstanceIdentifier, Entry<PeerId, YangInstanceIdentifier>> GENERATE_PEER_ID = new Function<YangInstanceIdentifier, Entry<PeerId, YangInstanceIdentifier>>() {
         @Override
         public Entry<PeerId, YangInstanceIdentifier> apply(final YangInstanceIdentifier input) {
             final PeerId peerId = IdentifierUtils.peerId((NodeIdentifierWithPredicates) input.getLastPathArgument());
             return new AbstractMap.SimpleImmutableEntry<>(peerId, input);
         }
     };
-
+    private static final QName SEND_RECEIVE = QName.create(SupportedTables.QNAME, "send-receive").intern();
+    private static final NodeIdentifier SEND_RECEIVE_NID = new YangInstanceIdentifier.NodeIdentifier(SEND_RECEIVE);
     private final Map<YangInstanceIdentifier, PeerRole> peerRoles = new HashMap<>();
-    private final HashMultimap<PeerId, NodeIdentifierWithPredicates> peerTables = HashMultimap.create();
-    private volatile Map<PeerRole, PeerExportGroup> groups = Collections.emptyMap();
+    private final Set<PeerId> peerTables = Sets.newHashSet();
     private final PolicyDatabase policyDatabase;
+    private final Map<PeerId, SendReceive> peerAddPathTables = new HashMap<>();
+    private final TablesKey localTableKey;
+    private volatile Map<PeerRole, PeerExportGroup> groups = Collections.emptyMap();
 
-    ExportPolicyPeerTrackerImpl(final PolicyDatabase policyDatabase) {
+    ExportPolicyPeerTrackerImpl(final PolicyDatabase policyDatabase, final TablesKey localTablesKey) {
         this.policyDatabase = Preconditions.checkNotNull(policyDatabase);
+        this.localTableKey = localTablesKey;
     }
 
     private Map<PeerRole, PeerExportGroup> createGroups(final Map<YangInstanceIdentifier, PeerRole> peerPathRoles) {
@@ -74,7 +86,7 @@ final class ExportPolicyPeerTrackerImpl extends AbstractPeerRoleTracker implemen
         final Map<PeerRole, PeerExportGroup> ret = new EnumMap<>(PeerRole.class);
         for (final Entry<PeerRole, Collection<YangInstanceIdentifier>> e : roleToIds.asMap().entrySet()) {
             final AbstractExportPolicy policy = this.policyDatabase.exportPolicyForRole(e.getKey());
-            final Collection<Entry<PeerId, YangInstanceIdentifier>> peers = ImmutableList.copyOf(Collections2.transform(e.getValue(), GENERATE_PEERID));
+            final Collection<Entry<PeerId, YangInstanceIdentifier>> peers = ImmutableList.copyOf(Collections2.transform(e.getValue(), GENERATE_PEER_ID));
 
             ret.put(e.getKey(), new PeerExportGroupImpl(peers, allPeerRoles, policy));
         }
@@ -101,32 +113,64 @@ final class ExportPolicyPeerTrackerImpl extends AbstractPeerRoleTracker implemen
         }
     }
 
+    @Override
+    public void onTablesChanged(final PeerId peerId, final DataTreeCandidateNode tablesChange) {
+        final NodeIdentifierWithPredicates supTablesKey = RibSupportUtils.toYangKey(SupportedTables.QNAME, this.localTableKey);
+        final DataTreeCandidateNode localTableNode = tablesChange.getModifiedChild(supTablesKey);
+        if (localTableNode != null) {
+            final Optional<NormalizedNode<?, ?>> dataAfter = localTableNode.getDataAfter();
+            processSupportedSendReceiveTables(localTableNode.getModifiedChild(SEND_RECEIVE_NID), peerId);
+            if (dataAfter.isPresent()) {
+                final boolean added = this.peerTables.add(peerId);
+                if (added) {
+                    LOG.debug("Supported table {} added to peer {}", this.localTableKey, peerId);
+                }
+            } else {
+                final NodeIdentifierWithPredicates value = (NodeIdentifierWithPredicates) localTableNode.getIdentifier();
+                this.peerTables.remove(peerId);
+                LOG.debug("Removed tables {} from peer {}", value, peerId);
+            }
+        }
+    }
+
     @Override
     public PeerExportGroup getPeerGroup(final PeerRole role) {
         return this.groups.get(Preconditions.checkNotNull(role));
     }
 
     @Override
-    public void onTablesChanged(final PeerId peerId, final DataTreeCandidateNode node) {
-        if (node.getDataAfter().isPresent()) {
-            final NodeIdentifierWithPredicates value = (NodeIdentifierWithPredicates) node.getDataAfter().get().getIdentifier();
-            final boolean added = this.peerTables.put(peerId, value);
-            if (added) {
-                LOG.debug("Supported table {} added to peer {}", value, peerId);
+    public PeerRole getRole(final YangInstanceIdentifier peerId) {
+        return this.peerRoles.get(peerId);
+    }
+
+    private void processSupportedSendReceiveTables(final DataTreeCandidateNode sendReceiveModChild, final PeerId peerId) {
+        if (sendReceiveModChild != null) {
+            if (sendReceiveModChild.getModificationType().equals(ModificationType.DELETE)) {
+                final Optional<NormalizedNode<?, ?>> sendReceiveNode = sendReceiveModChild.getDataBefore();
+                if (sendReceiveNode.isPresent()) {
+                    final SendReceive sendReceiveValue = SendReceive.valueOf(BindingMapping.getClassName((String) sendReceiveNode.get().getValue()));
+                    this.peerAddPathTables.remove(peerId);
+                    LOG.debug("Supported Add BestPath table {} removed to peer {}", sendReceiveValue, peerId);
+                }
+            } else {
+                final Optional<NormalizedNode<?, ?>> sendReceiveNode = sendReceiveModChild.getDataAfter();
+                if (sendReceiveNode.isPresent()) {
+                    final SendReceive sendReceiveValue = SendReceive.valueOf(BindingMapping.getClassName((String) sendReceiveNode.get().getValue()));
+                    this.peerAddPathTables.put(peerId, sendReceiveValue);
+                    LOG.debug("Supported Add BestPath table {} added to peer {}", sendReceiveValue, peerId);
+                }
             }
-        } else {
-            final NodeIdentifierWithPredicates value = (NodeIdentifierWithPredicates) node.getIdentifier();
-            this.peerTables.remove(peerId,value);
-            LOG.debug("Removed tables {} from peer {}", value, peerId);
         }
     }
 
     @Override
-    public boolean isTableSupported(final PeerId peerId, final TablesKey tablesKey) {
-        return this.peerTables.get(peerId).contains(RibSupportUtils.toYangKey(SupportedTables.QNAME, tablesKey));
+    public boolean isTableSupported(final PeerId peerId) {
+        return this.peerTables.contains(peerId);
     }
 
-    public PeerRole getRole(final YangInstanceIdentifier peerId) {
-        return this.peerRoles.get(peerId);
+    @Override
+    public boolean isAddPathSupportedByPeer(final PeerId peerId) {
+        final SendReceive sendReceive = this.peerAddPathTables.get(peerId);
+        return sendReceive != null && (sendReceive.equals(SendReceive.Both) || sendReceive.equals(SendReceive.Receive));
     }
 }
\ No newline at end of file
index 1bb3ce9a05f339b1a5250350e97c1831310a7752..b2245121f7ffc696032f0a99856016e04e6250e9 100644 (file)
@@ -9,10 +9,12 @@ package org.opendaylight.protocol.bgp.rib.impl;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import javax.annotation.Nonnull;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv4RoutesCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.DestinationIpv4;
@@ -35,8 +37,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.type
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.common.QName;
 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.ChoiceNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 
@@ -46,6 +52,7 @@ import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 final class IPv4RIBSupport extends AbstractIPRIBSupport {
     @VisibleForTesting
     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 IPv4RIBSupport SINGLETON = new IPv4RIBSupport();
     private static final ImmutableCollection<Class<? extends DataObject>> CACHEABLE_NLRI_OBJECTS =
             ImmutableSet.<Class<? extends DataObject>>of(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.Ipv4Prefix.class);
@@ -58,6 +65,7 @@ final class IPv4RIBSupport extends AbstractIPRIBSupport {
     private final NodeIdentifier ipv4Route = new NodeIdentifier(Ipv4Route.QNAME);
     private final NodeIdentifier nlriRoutesList = new NodeIdentifier(Ipv4Prefixes.QNAME);
     private final NodeIdentifier routeKeyLeaf = new NodeIdentifier(PREFIX_QNAME);
+    private final NodeIdentifier pathIdLeaf = new NodeIdentifier(PATHID_QNAME);
 
     private IPv4RIBSupport() {
         super(Ipv4RoutesCase.class, Ipv4Routes.class, Ipv4Route.class);
@@ -107,6 +115,24 @@ final class IPv4RIBSupport extends AbstractIPRIBSupport {
         return CACHEABLE_NLRI_OBJECTS;
     }
 
+    @Nonnull
+    @Override
+    public PathArgument getRouteIdAddPath(final long pathId, final PathArgument routeId) {
+        final String prefix = (String) (((NodeIdentifierWithPredicates) routeId).getKeyValues()).get(PREFIX_QNAME);
+        final ImmutableMap<QName, Object> keyValues = ImmutableMap.of(PATHID_QNAME, pathId, PREFIX_QNAME, prefix);
+
+        return new NodeIdentifierWithPredicates(Ipv4Route.QNAME, keyValues);
+    }
+
+    @Override
+    public long extractPathId(final NormalizedNode<?, ?> data) {
+        final NormalizedNode<?, ?> pathId = NormalizedNodes.findNode(data, pathIdLeaf).orNull();
+        if (pathId == null) {
+            return 0;
+        }
+        return (Long) pathId.getValue();
+    }
+
     private List<Ipv4Prefixes> extractPrefixes(final Collection<MapEntryNode> routes) {
         final List<Ipv4Prefixes> prefs = new ArrayList<>(routes.size());
         for (final MapEntryNode route : routes) {
index e64ea404cf2154b615bb3553315fd83190998548..9b20e8314f205ffac827ec012c8df4d998bff4f1 100644 (file)
@@ -37,7 +37,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.peer.EffectiveRibIn;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.peer.SupportedTables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Attributes;
@@ -89,7 +88,7 @@ final class LocRibWriter implements AutoCloseable, DOMDataTreeChangeListener {
         this.ourAs = Preconditions.checkNotNull(ourAs);
         this.ribSupport = registry.getRIBSupportContext(tablesKey).getRibSupport();
         this.attributesIdentifier = this.ribSupport.routeAttributesIdentifier();
-        this.peerPolicyTracker = new ExportPolicyPeerTrackerImpl(pd);
+        this.peerPolicyTracker = new ExportPolicyPeerTrackerImpl(pd, this.localTablesKey);
         this.cacheDisconnectedPeers = cacheDisconnectedPeers;
         this.pathSelectionMode = pathSelectionMode;
 
@@ -173,24 +172,20 @@ final class LocRibWriter implements AutoCloseable, DOMDataTreeChangeListener {
             LOG.trace("Skipping change {}", rootNode.getIdentifier());
             return;
         }
-        initializeTableWithExistenRoutes(table, peerId, rootPath, tx);
+        initializeTableWithExistentRoutes(table, peerId, rootPath, tx);
         updateNodes(table, peerId, tx, ret);
     }
 
     private void filterOutChangesToSupportedTables(final PeerId peerIdOfNewPeer, final DataTreeCandidateNode rootNode) {
         final DataTreeCandidateNode tablesChange = rootNode.getModifiedChild(AbstractPeerRoleTracker.PEER_TABLES);
         if (tablesChange != null) {
-            final NodeIdentifierWithPredicates supTablesKey = RibSupportUtils.toYangKey(SupportedTables.QNAME, this.localTablesKey);
-            final DataTreeCandidateNode containsLocalKeyTable = tablesChange.getModifiedChild(supTablesKey);
-            if (containsLocalKeyTable != null) {
-                this.peerPolicyTracker.onTablesChanged(peerIdOfNewPeer, containsLocalKeyTable);
-            }
+            this.peerPolicyTracker.onTablesChanged(peerIdOfNewPeer, tablesChange);
         }
     }
 
-    private void initializeTableWithExistenRoutes(final DataTreeCandidateNode table, final PeerId peerIdOfNewPeer, final YangInstanceIdentifier rootPath,
+    private void initializeTableWithExistentRoutes(final DataTreeCandidateNode table, final PeerId peerIdOfNewPeer, final YangInstanceIdentifier rootPath,
         final DOMDataWriteTransaction tx) {
-        if (!table.getDataBefore().isPresent() && this.peerPolicyTracker.isTableSupported(peerIdOfNewPeer, this.localTablesKey)) {
+        if (!table.getDataBefore().isPresent() && this.peerPolicyTracker.isTableSupported(peerIdOfNewPeer)) {
             LOG.debug("Peer {} table has been created, inserting existent routes", peerIdOfNewPeer);
             final PeerRole newPeerRole = this.peerPolicyTracker.getRole(IdentifierUtils.peerPath(rootPath));
             final PeerExportGroup peerGroup = this.peerPolicyTracker.getPeerGroup(newPeerRole);
index d00e6fde1907218af684b95580a7ae8ab70b8e71..b1f66565689165b442b98a48f734843feb5db0b2 100644 (file)
@@ -453,6 +453,19 @@ module odl-bgp-rib-impl-cfg {
         }
     }
 
+    grouping afi-safi {
+        leaf afi {
+            description "Address Family Identifier.";
+            type string;
+            default "";
+        }
+        leaf safi {
+            description "Subsequent Address Family Identifier.";
+            type string;
+            default "";
+        }
+    }
+
     grouping preferences {
         leaf bgp-id {
             description "The BGP Identifier.";
@@ -515,13 +528,14 @@ module odl-bgp-rib-impl-cfg {
 
         list advertized-table-types {
             description "The BGP Table-type capabilities advertized by the BGP peer.";
-            leaf afi {
-                description "Address Family Identifier.";
-                type string;
-                default "";
-            }
-            leaf safi {
-                description "Subsequent Address Family Identifier.";
+            uses afi-safi;
+        }
+
+        list advertised-add-path-table-types {
+            description "The BGP Table-type capabilities advertized by the BGP peer.";
+            uses afi-safi;
+            leaf send-receive {
+                description "Send Receive Add Path Configuration.";
                 type string;
                 default "";
             }
index 6b7c05fc67b5c6073211fd46427c61bcc0f392e2..51d60dd11c8e2010ab1d934dd0067e97f838337a 100644 (file)
@@ -11,6 +11,8 @@ import static org.junit.Assert.assertNotNull;
 
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.CheckedFuture;
+import java.util.Collections;
+import java.util.List;
 import java.util.Set;
 import org.junit.Before;
 import org.junit.Test;
@@ -24,6 +26,9 @@ import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContext;
 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
 import org.opendaylight.protocol.bgp.rib.spi.IdentifierUtils;
 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.SendReceive;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.add.path.capability.AddressFamilies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.add.path.capability.AddressFamiliesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Rib;
@@ -56,6 +61,10 @@ public class AdjRibsInWriterTest {
 
     private static final TablesKey k4 = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
     private final Set<TablesKey> tableTypes = Sets.newHashSet(k4);
+
+    private static final AddressFamilies addressFamilies = new AddressFamiliesBuilder().setAfi(Ipv4AddressFamily.class)
+        .setSafi(UnicastSubsequentAddressFamily.class).setSendReceive(SendReceive.Both).build();
+    private final List<AddressFamilies> addPathTablesType = Collections.singletonList(addressFamilies);
     private final String peerIp = "12.34.56.78";
 
     @Before
@@ -76,7 +85,7 @@ public class AdjRibsInWriterTest {
         Mockito.doReturn(this.context).when(this.registry).getRIBSupportContext(Mockito.any(TablesKey.class));
         Mockito.doNothing().when(this.context).createEmptyTableStructure(Mockito.eq(this.tx), Mockito.any(YangInstanceIdentifier.class));
 
-        this.writer.transform(new PeerId(this.peerIp), this.registry, this.tableTypes, false);
+        this.writer.transform(new PeerId(this.peerIp), this.registry, this.tableTypes, this.addPathTablesType, false);
 
         // verify peer skeleton was inserted correctly
         Mockito.verify(this.tx).put(Mockito.eq(LogicalDatastoreType.OPERATIONAL), Mockito.eq(peerPath), Mockito.eq(this.writer.peerSkeleton(IdentifierUtils.peerKey(peerPath), this.peerIp, false)));
index 8ca478e5f332039fc362b76f349309277d2ebeed..01c8a78242fc2b0a38c4978c067ea087eb08465d 100644 (file)
@@ -7,10 +7,12 @@
  */
 package org.opendaylight.protocol.bgp.rib.mock;
 
+import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import com.google.common.eventbus.EventBus;
 import com.google.common.eventbus.Subscribe;
 import io.netty.channel.ChannelHandlerContext;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
@@ -25,7 +27,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mess
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.optional.capabilities.CParameters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.CParameters1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.AddPathCapability;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.MultiprotocolCapability;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.add.path.capability.AddressFamilies;
 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.slf4j.Logger;
@@ -71,15 +75,21 @@ final class EventBusRegistration extends AbstractListenerRegistration<BGPSession
             listener.onSessionTerminated(null, null);
         } else if (message instanceof Open) {
             final Set<BgpTableType> tts = Sets.newHashSet();
+            final List<AddressFamilies> addPathCapabilitiesList = Lists.newArrayList();
             for (final BgpParameters param : ((Open) message).getBgpParameters()) {
                 for (final OptionalCapabilities capa : param.getOptionalCapabilities()) {
                     final CParameters cParam = capa.getCParameters();
-                    if (cParam.getAugmentation(CParameters1.class) != null && cParam.getAugmentation(CParameters1.class)
-                        .getMultiprotocolCapability() != null) {
+                    if (cParam.getAugmentation(CParameters1.class) == null) {
+                        continue;
+                    }
+                    if (cParam.getAugmentation(CParameters1.class).getMultiprotocolCapability() != null) {
                         final MultiprotocolCapability p = cParam.getAugmentation(CParameters1.class).getMultiprotocolCapability();
                         LOG.debug("Adding open parameter {}", p);
                         final BgpTableType type = new BgpTableTypeImpl(p.getAfi(), p.getSafi());
                         tts.add(type);
+                    } else if (cParam.getAugmentation(CParameters1.class).getAddPathCapability() != null) {
+                        final AddPathCapability addPathCap = cParam.getAugmentation(CParameters1.class).getAddPathCapability();
+                        addPathCapabilitiesList.addAll(addPathCap.getAddressFamilies());
                     }
                 }
             }
@@ -157,6 +167,11 @@ final class EventBusRegistration extends AbstractListenerRegistration<BGPSession
                 return new AsNumber(AS);
             }
 
+            @Override
+            public List<AddressFamilies> getAdvertisedAddPathTableTypes() {
+                return Collections.emptyList();
+            }
+
         });
     }
 }
index 6706b770411419f2ba09fd06c3ea6c109c337f7f..913ca65b0457ba9c8466dd742e953345a9a03348 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.base.Preconditions;
 import java.util.Collection;
 import java.util.Collections;
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.UpdateBuilder;
@@ -40,6 +41,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
 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.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -277,4 +279,17 @@ public abstract class AbstractRIBSupport implements RIBSupport {
         }
     }
 
+    @Nullable
+    @Override
+    /**
+     * Return null for non supporting Add path models
+     */
+    public PathArgument getRouteIdAddPath(final long pathId, final PathArgument routeId) {
+        return null;
+    }
+
+    @Override
+    public long extractPathId(final NormalizedNode<?, ?> data) {
+        return 0;
+    }
 }
diff --git a/bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/AddPathRibSupport.java b/bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/AddPathRibSupport.java
new file mode 100644 (file)
index 0000000..815593a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.rib.spi;
+
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Interface implemented to be extended by RibSupport.
+ * This interface exposes methods to access to Add Path information
+ */
+public interface AddPathRibSupport {
+    /**
+     * Extract PathId from route change received
+     *
+     * @param normalizedNode
+     * @return pathId  The path identifier from data change, in case its not provided or supported return 0 by default
+     */
+    long extractPathId(NormalizedNode<?, ?> normalizedNode);
+
+    /**
+     * Construct a PathArgument to an AddPathRoute
+     *
+     * @param pathId  The path identifier
+     * @param routeId PathArgument leaf path
+     * @return routeId PathArgument + pathId or Null in case Add-path is not supported
+     */
+    @Nullable PathArgument getRouteIdAddPath(long pathId, PathArgument routeId);
+}
index 185c1cc1e548d4a21c6f8e98984f34cf9bf9e61f..a01b197579bad7abffcf41002ccf21fbafb2b5d4 100644 (file)
@@ -8,10 +8,12 @@
 package org.opendaylight.protocol.bgp.rib.spi;
 
 import io.netty.channel.ChannelInboundHandler;
+import java.util.List;
 import java.util.Set;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.add.path.capability.AddressFamilies;
 
 /**
  * BGP Session represents the finite state machine in BGP, including timers and its purpose is to create a BGP
@@ -41,4 +43,11 @@ public interface BGPSession extends AutoCloseable, ChannelInboundHandler {
      * @return Peer's AS Number
      */
     AsNumber getAsNumber();
+    /**
+     * Return a list with Add Path tables supported advertised and corresponding SendReceive mode.
+     *
+     * @return AddPathTables supported
+     */
+    List<AddressFamilies> getAdvertisedAddPathTableTypes();
+
 }
index a4c10b50dfe06eeb248765a7b438365219cd6080..fc505a7892f74fee5fc90ceaa0b369e7c405fd00 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.protocol.bgp.rib.spi;
 
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
 
@@ -35,10 +34,9 @@ public interface ExportPolicyPeerTracker {
     /**
      * check whether the peer supports the table
      * @param peerId of peer
-     * @param tablesKey to be checked
      * @return true if peer supports table
      */
-    boolean isTableSupported(PeerId peerId, TablesKey tablesKey);
+    boolean isTableSupported(PeerId peerId);
 
     /**
      * @param peerId of peer
@@ -51,4 +49,11 @@ public interface ExportPolicyPeerTracker {
      * @param peerPath YII of peer
      */
     void onDataTreeChanged(DataTreeCandidateNode change, YangInstanceIdentifier peerPath);
+
+    /**
+     * Check whether Peer supports Add Path
+     * @param peerId
+     * @return true if add-path is supported
+     */
+    boolean isAddPathSupportedByPeer(PeerId peerId);
 }
index 6be31c19f9572e5e4f3b9507ab39649e11796fc6..b022cb421f9dbff0388f2f4552ac4cf9d717ef00 100644 (file)
@@ -29,7 +29,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNod
  * to register an implementation of this class and the RIB core then calls into it
  * to inquire about details specific to that particular model.
  */
-public interface RIBSupport {
+public interface RIBSupport extends AddPathRibSupport {
     /**
      * Return the table-type-specific empty routes container, as augmented into the
      * bgp-rib model under /rib/tables/routes choice node. This needs to include all
index c40c3098fee314a93c76642e939b445b4ea1deaa..51dbeb111b50761a3e63369e2419a7f24c040b17 100644 (file)
@@ -8,6 +8,8 @@
 package org.opendaylight.protocol.bgp.rib.spi;
 
 import com.google.common.collect.ImmutableMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpAddPathTableType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.peer.SupportedTablesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AddressFamily;
@@ -20,6 +22,8 @@ public final class RibSupportUtils {
 
     private static final QName AFI_QNAME = QName.create(Tables.QNAME, "afi").intern();
     private static final QName SAFI_QNAME = QName.create(Tables.QNAME, "safi").intern();
+    private static final QName ADD_PATH_AFI_QNAME = QName.create(BgpAddPathTableType.QNAME, "afi").intern();
+    private static final QName ADD_PATH_SAFI_QNAME = QName.create(BgpAddPathTableType.QNAME, "safi").intern();
 
     private RibSupportUtils() {
         throw new UnsupportedOperationException("Utility class");
@@ -52,6 +56,23 @@ public final class RibSupportUtils {
         return new NodeIdentifierWithPredicates(id, keyValues);
     }
 
+
+    /**
+     * Creates Yang Instance Identifier path argument from supplied AFI and SAFI
+     *
+     * @param id QNAME representing node
+     * @param afi Class representing AFI
+     * @param safi Class representing SAFI
+     * @return NodeIdentifierWithPredicates of 'id' for specified AFI, SAFI combination.
+     */
+    public static NodeIdentifierWithPredicates toYangPathKey(final QName id, final Class<? extends AddressFamily> afi,
+        final Class<? extends SubsequentAddressFamily> safi) {
+        final ImmutableMap<QName, Object> keyValues = ImmutableMap.<QName, Object>of(
+            ADD_PATH_AFI_QNAME, BindingReflections.findQName(afi),
+            ADD_PATH_SAFI_QNAME, BindingReflections.findQName(safi));
+        return new NodeIdentifierWithPredicates(id, keyValues);
+    }
+
     /**
      * Creates Yang Instance Identifier path argument from supplied {@link TablesKey}
      *
@@ -63,6 +84,17 @@ public final class RibSupportUtils {
         return toYangKey(id, k.getAfi(), k.getSafi());
     }
 
+    /**
+     * Creates Yang Instance Identifier path argument from supplied {@link TablesKey}
+     *
+     * @param id QNAME representing node
+     * @param k  Add PAth Tables key representing table.
+     * @return NodeIdentifierWithPredicates of 'id' for specified AFI, SAFI combination.
+     */
+    public static NodeIdentifierWithPredicates toYangKey(final QName id, final SupportedTablesKey k) {
+        return toYangPathKey(id, k.getAfi(), k.getSafi());
+    }
+
     /**
      * Creates Yang Instance Identifier path argument from supplied {@link TablesKey}
      *
index 865a7a3a976a35d016cf5a2ca3fbbfbd32385eb9..f57e88ae4ba8c7ca9589e893c71865099cee89a5 100644 (file)
@@ -33,11 +33,13 @@ 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.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 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.api.schema.tree.DataTreeCandidates;
@@ -69,6 +71,11 @@ public class AbstractRIBSupportTest {
             return null;
         }
 
+        @Override
+        public PathArgument getRouteIdAddPath(final long pathId, final PathArgument routeId) {
+            throw new UnsupportedOperationException();
+        }
+
         @Override
         protected NodeIdentifier destinationContainerIdentifier() {
             return new NodeIdentifier(DestinationIpv4.QNAME);
@@ -91,6 +98,11 @@ public class AbstractRIBSupportTest {
             return false;
         }
 
+        @Override
+        public long extractPathId(final NormalizedNode<?, ?> normalizedNode) {
+            throw new UnsupportedOperationException();
+        }
+
         @Override
         protected MpReachNlri buildReach(final Collection<MapEntryNode> routes, final CNextHop hop) {
             return null;