}
protected final boolean filterRoutes(final PeerId rootPeer, final PeerId destPeer, final ExportPolicyPeerTracker peerPT, final TablesKey localTK, final PeerRole destPeerRole) {
- return !rootPeer.equals(destPeer) && isTableSupported(destPeer, peerPT, localTK) && !PeerRole.Internal.equals(destPeerRole);
+ return !rootPeer.equals(destPeer) && isTableSupportedAndReady(destPeer, peerPT, localTK) && !PeerRole.Internal.equals(destPeerRole);
}
- private boolean isTableSupported(final PeerId destPeer, final ExportPolicyPeerTracker peerPT, final TablesKey localTK) {
- if (!peerPT.isTableSupported(destPeer)) {
+ private boolean isTableSupportedAndReady(final PeerId destPeer, final ExportPolicyPeerTracker peerPT, final TablesKey localTK) {
+ if (!peerPT.isTableSupported(destPeer) || !peerPT.isTableStructureInitialized(destPeer)) {
LOG.trace("Route rejected, peer {} does not support this table type {}", destPeer, localTK);
return false;
}
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
import static org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectorTest.ATTRS_EXTENSION_Q;
import static org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectorTest.SEGMENTS_NID;
protected void setUp() {
MockitoAnnotations.initMocks(this);
this.yIIChanges = new ArrayList<>();
- this.peerPT = mock(ExportPolicyPeerTracker.class);
this.attributes = createAttr();
this.locRibTargetYii = LOC_RIB_TARGET.node(ROUTES_IDENTIFIER);
this.locRibOutTargetYii = PEER_YII.node(AdjRibOut.QNAME).node(Tables.QNAME).node(RibSupportUtils.toYangTablesKey(TABLES_KEY)).node(ROUTES_IDENTIFIER);
}
private void mockExportPolicies() {
+ doReturn(true).when(this.peerPT).isTableStructureInitialized(any(PeerId.class));
doReturn(true).when(this.peerPT).isTableSupported(PEER_ID);
doReturn(false).when(this.peerPT).isTableSupported(PEER_ID2);
doAnswer(invocation -> {
import com.google.common.base.Preconditions;
import java.util.EnumMap;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
-import java.util.Set;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import org.opendaylight.protocol.bgp.rib.impl.spi.PeerExportGroupRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * There is one ExportPolicyPeerTracker per table
+ * - peerTables: keep track of registered peers, the ones which support this table.
+ * - peerTables: flag indicates whether the structure of the peer has been created, and therefore it can start
+ * to be updated.
+ * - peerAddPathTables: keeps track of peer which supports Additional Path for this table and which Add Path
+ * configuration they are using.
+ * - groups: Contains peers grouped by peerRole and therefore sharing the same export policy.
+ */
@ThreadSafe
final class ExportPolicyPeerTrackerImpl implements ExportPolicyPeerTracker {
private static final Logger LOG = LoggerFactory.getLogger(ExportPolicyPeerTrackerImpl.class);
@GuardedBy("this")
private final Map<PeerId, SendReceive> peerAddPathTables = new HashMap<>();
@GuardedBy("this")
- private final Set<PeerId> peerTables = new HashSet<>();
+ private final Map<PeerId, Boolean> peerTables = new HashMap<>();
private final PolicyDatabase policyDatabase;
private final TablesKey localTableKey;
@GuardedBy("this")
final PeerExportGroupRegistry peerExp = this.groups.computeIfAbsent(peerRole,
k -> new PeerExportGroupImpl(this.policyDatabase.exportPolicyForRole(peerRole)));
- final AbstractRegistration registration = peerExp.registerPeer(peerId, new PeerExporTuple(peerPath, peerRole));
+ final AbstractRegistration registration = peerExp.registerPeer(peerId, new PeerExporTuple(peerPath, peerRole));
return new AbstractRegistration() {
@Override
protected void removeRegistration() {
registration.close();
- if(ExportPolicyPeerTrackerImpl.this.groups.get(peerRole).isEmpty()) {
+ if (ExportPolicyPeerTrackerImpl.this.groups.get(peerRole).isEmpty()) {
ExportPolicyPeerTrackerImpl.this.groups.remove(peerRole);
}
}
}
final SimpleRoutingPolicy simpleRoutingPolicy = optSimpleRoutingPolicy.orElse(null);
if (SimpleRoutingPolicy.AnnounceNone != simpleRoutingPolicy) {
- this.peerTables.add(peerId);
+ this.peerTables.put(peerId, false);
}
this.peerRoles.put(peerPath, peerRole);
LOG.debug("Supported table {} added to peer {} role {}", this.localTableKey, peerId, peerRole);
@Override
public synchronized boolean isTableSupported(final PeerId peerId) {
- return this.peerTables.contains(peerId);
+ return this.peerTables.containsKey(peerId);
}
@Override
final SendReceive sendReceive = this.peerAddPathTables.get(peerId);
return sendReceive != null && (sendReceive.equals(SendReceive.Both) || sendReceive.equals(SendReceive.Receive));
}
+
+ @Override
+ public synchronized void registerPeerAsInitialized(final PeerId peerId) {
+ this.peerTables.computeIfPresent(peerId, (k, v) -> true);
+ }
+
+ @Override
+ public synchronized boolean isTableStructureInitialized(final PeerId peerId) {
+ return this.peerTables.get(peerId);
+ }
}
\ No newline at end of file
private void initializeTableWithExistentRoutes(final DataTreeCandidateNode table, final PeerId peerIdOfNewPeer, final YangInstanceIdentifier rootPath,
final DOMDataWriteTransaction tx) {
if (!table.getDataBefore().isPresent() && this.exportPolicyPeerTracker.isTableSupported(peerIdOfNewPeer)) {
+ this.exportPolicyPeerTracker.registerPeerAsInitialized(peerIdOfNewPeer);
LOG.debug("Peer {} table has been created, inserting existent routes", peerIdOfNewPeer);
final PeerRole newPeerRole = this.exportPolicyPeerTracker.getRole(IdentifierUtils.peerPath(rootPath));
final PeerExportGroup peerGroup = this.exportPolicyPeerTracker.getPeerGroup(newPeerRole);
this.routeEntries.entrySet().forEach(entry -> entry.getValue().writeRoute(peerIdOfNewPeer, entry.getKey(),
- rootPath.getParent().getParent().getParent(), peerGroup, this.localTablesKey, this.exportPolicyPeerTracker, this.ribSupport, tx));
+ rootPath.getParent().getParent().getParent(), peerGroup, this.localTablesKey,
+ this.exportPolicyPeerTracker, this.ribSupport, tx));
}
}
/**
* Check whether Peer supports Add Path
- * @param peerId
+ * @param peerId of peer
* @return true if add-path is supported
*/
boolean isAddPathSupportedByPeer(@Nonnull PeerId peerId);
@Deprecated
default void peerRoleChanged(@Nonnull YangInstanceIdentifier peerPath, @Nullable PeerRole role) {
}
+
+ /**
+ * Flags peers once empty structure has been created, then changes under it can
+ * be applied
+ *
+ * @param peerId of peer
+ */
+ void registerPeerAsInitialized(PeerId peerId);
+
+ /**
+ * check whether the peer supports the table
+ * @param peerId of peer
+ * @return true if peer supports table
+ */
+ boolean isTableStructureInitialized(@Nonnull PeerId peerId);
}