<artifactId>bgp-parser-spi</artifactId>
<type>test-jar</type>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <scope>test</scope>
+ <type>test-jar</type>
+ </dependency>
</dependencies>
<build>
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.opendaylight.protocol.bgp.rib.spi.AbstractAdjRIBs;
-import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsInTransaction;
+import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsTransaction;
import org.opendaylight.protocol.bgp.rib.spi.Peer;
import org.opendaylight.protocol.util.ByteArray;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
}
@Override
- public void addRoutes(final AdjRIBsInTransaction trans, final Peer peer, final MpReachNlri nlri,
+ public void addRoutes(final AdjRIBsTransaction trans, final Peer peer, final MpReachNlri nlri,
final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes attributes) {
LOG.debug("Passed nlri {}", nlri);
final LinkstateDestination keys = ((DestinationLinkstateCase) nlri.getAdvertizedRoutes().getDestinationType()).getDestinationLinkstate();
}
@Override
- public void removeRoutes(final AdjRIBsInTransaction trans, final Peer peer, final MpUnreachNlri nlri) {
+ public void removeRoutes(final AdjRIBsTransaction trans, final Peer peer, final MpUnreachNlri nlri) {
final DestinationLinkstate keys = ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationLinkstateCase) nlri.getWithdrawnRoutes().getDestinationType()).getDestinationLinkstate();
for (final CLinkstateDestination key : keys.getCLinkstateDestination()) {
import java.util.List;
import org.opendaylight.protocol.bgp.rib.spi.AbstractRIBExtensionProviderActivator;
+import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsFactory;
import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn;
-import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsInFactory;
import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionProviderContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.LinkstateAddressFamily;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.LinkstateSubsequentAddressFamily;
public final class RIBActivator extends AbstractRIBExtensionProviderActivator {
@Override
protected List<AutoCloseable> startRIBExtensionProviderImpl(final RIBExtensionProviderContext context) {
- return Lists.newArrayList(context.registerAdjRIBsInFactory(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class, new AdjRIBsInFactory() {
+ return Lists.newArrayList(context.registerAdjRIBsInFactory(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class, new AdjRIBsFactory() {
@Override
- public AdjRIBsIn createAdjRIBsIn(final KeyedInstanceIdentifier<Tables, TablesKey> basePath) {
+ public AdjRIBsIn<?, ?> createAdjRIBs(final KeyedInstanceIdentifier<Tables, TablesKey> basePath) {
return new LinkstateAdjRIBsIn(basePath);
}
}));
*/
package org.opendaylight.protocol.bgp.linkstate;
-import static org.junit.Assert.assertEquals;
-
import java.math.BigInteger;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.protocol.bgp.rib.RibReference;
-import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsInTransaction;
+import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsTransaction;
import org.opendaylight.protocol.bgp.rib.spi.BGPObjectComparator;
import org.opendaylight.protocol.bgp.rib.spi.Peer;
+import org.opendaylight.protocol.bgp.rib.spi.RouteEncoder;
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.IpPrefix;
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.update.path.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
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.rib.Tables;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesBuilder;
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;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.AttributesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpOrigin;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.IsoSystemIdentifier;
-import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
-public class LinkstateAdjRIBsInTest {
+public class LinkstateAdjRIBsInTest extends AbstractDataBrokerTest {
private static final AsNumber TEST_AS_NUMBER = new AsNumber(35L);
private Peer peer;
@Mock
- private AdjRIBsInTransaction adjRibTx;
+ private AdjRIBsTransaction adjRibTx;
+
+ @Mock
+ private RouteEncoder encoder;
private LinkstateAdjRIBsIn lrib;
private final List<CLinkstateDestination> destinations = new ArrayList<>();
- private final HashMap<InstanceIdentifier<?>, DataObject> data = new HashMap<>();
-
private final BGPObjectComparator bgpComparator = new BGPObjectComparator(TEST_AS_NUMBER);
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ final WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
final InstanceIdentifier<Rib> iid = InstanceIdentifier.builder(BgpRib.class).child(Rib.class, new RibKey(new RibId("test-rib"))).toInstance();
final KeyedInstanceIdentifier<Tables, TablesKey> key = iid.child(LocRib.class).child(Tables.class, new TablesKey(LinkstateAddressFamily.class,
LinkstateSubsequentAddressFamily.class));
+
Mockito.doAnswer(new Answer<Void>() {
+ @SuppressWarnings("unchecked")
@Override
public Void answer(final InvocationOnMock invocation) throws Throwable {
final Object[] args = invocation.getArguments();
- LinkstateAdjRIBsInTest.this.data.put((InstanceIdentifier<?>)args[0], (DataObject)args[1]);
+ final InstanceIdentifier<Route> ii = (InstanceIdentifier<Route>) args[2];
+ final Route data = (Route) args[4];
+ wTx.put(LogicalDatastoreType.OPERATIONAL, ii, data, true);
return null;
}
- }).when(this.adjRibTx).advertise(Mockito.<InstanceIdentifier<DataObject>>any(), Mockito.any(DataObject.class));
+ }).when(this.adjRibTx).advertise(Mockito.<RouteEncoder>any(), Mockito.any(), Mockito.<InstanceIdentifier<Route>>any(), Mockito.<Peer>any(), Mockito.any(Route.class));
Mockito.doAnswer(new Answer<Void>() {
+ @SuppressWarnings("unchecked")
@Override
public Void answer(final InvocationOnMock invocation) throws Throwable {
final Object[] args = invocation.getArguments();
- LinkstateAdjRIBsInTest.this.data.remove(args[0]);
+ final InstanceIdentifier<Route> ii = (InstanceIdentifier<Route>) args[2];
+ wTx.delete(LogicalDatastoreType.OPERATIONAL, ii);
return null;
}
- }).when(this.adjRibTx).withdraw(Matchers.any(InstanceIdentifier.class));
+ }).when(this.adjRibTx).withdraw(Mockito.<RouteEncoder>any(), Mockito.any(), Mockito.<InstanceIdentifier<Route>>any());
Mockito.doAnswer(new Answer<Void>() {
@SuppressWarnings("unchecked")
@Override
public Void answer(final InvocationOnMock invocation) throws Throwable {
final Object[] args = invocation.getArguments();
- final InstanceIdentifier<Tables> base = (InstanceIdentifier<Tables>) args[0];
- final Tables tables = (Tables) LinkstateAdjRIBsInTest.this.data.get(key);
- if(tables != null) {
- LinkstateAdjRIBsInTest.this.data.put(base,
- new TablesBuilder(tables).setAttributes(new AttributesBuilder().setUptodate((Boolean) args[1]).build()).build());
- }
+ final InstanceIdentifier<Tables> basePath = (InstanceIdentifier<Tables>) args[0];
+ final Boolean uptodate = (Boolean) args[1];
+ final InstanceIdentifier<Attributes> aid = basePath.child(Attributes.class);
+ wTx.merge(LogicalDatastoreType.OPERATIONAL, aid, new AttributesBuilder().setUptodate(uptodate).build());
return null;
}
}).when(this.adjRibTx).setUptodate(Matchers.<InstanceIdentifier<Tables>>any(), Mockito.anyBoolean());
this.lrib.addRoutes(this.adjRibTx, this.peer, this.builder.build(), pa.build());
- Mockito.verify(this.adjRibTx, Mockito.times(1)).advertise(Matchers.<InstanceIdentifier<DataObject>>any(), Matchers.any(DataObject.class));
+ Mockito.verify(this.adjRibTx, Mockito.times(1)).advertise(Mockito.<RouteEncoder>any(), Mockito.any(), Mockito.<InstanceIdentifier<Route>>any(), Mockito.<Peer>any(), Mockito.any(Route.class));
Mockito.verify(this.adjRibTx, Mockito.times(1)).setUptodate(Matchers.<InstanceIdentifier<Tables>>any(), Matchers.anyBoolean());
-
- assertEquals(1, this.data.size());
}
@Test
this.lrib.addRoutes(this.adjRibTx, this.peer, this.builder.build(), pa.build());
- Mockito.verify(this.adjRibTx, Mockito.times(1)).advertise(Matchers.<InstanceIdentifier<DataObject>>any(), Matchers.any(DataObject.class));
+ Mockito.verify(this.adjRibTx, Mockito.times(1)).advertise(Mockito.<RouteEncoder>any(), Mockito.any(), Mockito.<InstanceIdentifier<Route>>any(), Mockito.<Peer>any(), Mockito.any(Route.class));
Mockito.verify(this.adjRibTx, Mockito.times(1)).setUptodate(Matchers.<InstanceIdentifier<Tables>>any(), Matchers.anyBoolean());
- assertEquals(1, this.data.size());
}
@Test
this.lrib.addRoutes(this.adjRibTx, this.peer, this.builder.build(), pa.build());
- Mockito.verify(this.adjRibTx, Mockito.times(1)).advertise(Matchers.<InstanceIdentifier<DataObject>>any(), Matchers.any(DataObject.class));
+ Mockito.verify(this.adjRibTx, Mockito.times(1)).advertise(Mockito.<RouteEncoder>any(), Mockito.any(), Mockito.<InstanceIdentifier<Route>>any(), Mockito.<Peer>any(), Mockito.any(Route.class));
Mockito.verify(this.adjRibTx, Mockito.times(1)).setUptodate(Matchers.<InstanceIdentifier<Tables>>any(), Matchers.anyBoolean());
- assertEquals(1, this.data.size());
-
final MpUnreachNlriBuilder builder = new MpUnreachNlriBuilder();
builder.setAfi(LinkstateAddressFamily.class);
builder.setSafi(LinkstateSubsequentAddressFamily.class);
this.destinations).build()).build()).build());
this.lrib.removeRoutes(this.adjRibTx, this.peer, builder.build());
- Mockito.verify(this.adjRibTx, Mockito.times(1)).withdraw(Matchers.any(InstanceIdentifier.class));
- assertEquals(0, this.data.size());
+ Mockito.verify(this.adjRibTx, Mockito.times(1)).withdraw(Mockito.<RouteEncoder>any(), Mockito.any(), Matchers.<InstanceIdentifier<Route>>any());
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.impl;
+
+import com.google.common.base.Preconditions;
+
+import java.util.Queue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOut;
+import org.opendaylight.protocol.bgp.rib.spi.RouteEncoder;
+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.rib.rev130925.Route;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+
+/**
+ * A per-peer collection of data which needs to be sent out. This class is kept lockfree
+ * on purpose.
+ */
+abstract class AbstractAdjRIBsOut implements AdjRIBsOut {
+ private final ConcurrentMap<Object, AdjRIBOutEntry<Object, Route>> data = new ConcurrentHashMap<>();
+ private final Queue<Object> queue = new ConcurrentLinkedQueue<>();
+
+ /**
+ * Callback invoked from RIB backend when new data becomes available. Implementations
+ * are expected to be able to handle multiple notifications and perform state
+ * compression as appropriate.
+ */
+ protected abstract void wantWrite();
+
+ /**
+ * Write a single PDU onto the peer. This callback is issued from {@link #process()}.
+ *
+ * @param pdu Update message
+ * @return True if the peer is ready to accept another PDU.
+ */
+ protected abstract boolean writePDU(Update pdu);
+
+ @Override
+ public void put(final RouteEncoder ribOut, final Object key, final Route newValue) {
+ AdjRIBOutEntry<Object, Route> e = data.get(key);
+ if (e == null) {
+ if (newValue == null) {
+ // Already not advertised, nothing to do
+ return;
+ }
+
+ e = new AdjRIBOutEntry<Object, Route>(ribOut);
+ }
+
+ // Make sure the new value is visible to the advertiser thread
+ final DataObject oldValue = e.getAndSetCurrent(newValue);
+
+ // Now read what is being currently advertised
+ final DataObject advValue = e.getAdverised();
+
+ if (advValue == newValue) {
+ /*
+ * We raced with the advertiser, which has sent out the this advertisement.
+ * This means our job is done.
+ */
+ return;
+ }
+
+ if (newValue != null && AdjRIBOutEntry.isNone(advValue)) {
+ /*
+ * We are advertising a new value and this is not a entry: need to put
+ * it into the map.
+ */
+ data.put(key, e);
+ }
+
+ if (oldValue == advValue) {
+ /*
+ * The old value was being advertised, so the advertiser is not aware that
+ * this key needs updating. Enqueue the key, so it will see it.
+ */
+ queue.add(key);
+ wantWrite();
+ }
+ }
+
+ /**
+ * Call this method from superclass when you are ready to process outgoing PDUs.
+ */
+ protected final void process() {
+ boolean writable = true;
+
+ while (writable) {
+ final Object key = queue.poll();
+ if (key == null) {
+ break;
+ }
+
+ final AdjRIBOutEntry<Object, Route> e = data.get(key);
+ if (e == null) {
+ /*
+ * This was a notification for a value which has already been withdrawn,
+ * nothing to do, continue to next key.
+ */
+ continue;
+ }
+
+ // First read what is it that we are advertising
+ final DataObject oldValue = e.getAdverised();
+ Preconditions.checkState(oldValue != null, "Unexpected withdrawn entry %s for %s", e, key);
+
+ // Now read what we should be advertising
+ final Route newValue = e.getCurrent();
+
+ if (!oldValue.equals(newValue)) {
+ /*
+ * The advertised value is not the same as what we want to advertise,
+ * so we need to send it out.
+ */
+ writable = writePDU(e.getRibOut().updateMessageFor(key, newValue));
+ }
+
+ /*
+ * Save what we are advertising. We need to store this even for withdrawals,
+ * as the entry may have been picked up again.
+ */
+ e.setAdverised(newValue);
+
+ /*
+ * Ready to clean the entry. Just a tiny check first: has the new value
+ * changed? If it has, we need to keep the entry, as there is an incoming
+ * update.
+ */
+ if (newValue == null && e.getCurrent() == newValue) {
+ data.remove(key, e);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.impl;
+
+import com.google.common.base.Preconditions;
+
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+import org.opendaylight.protocol.bgp.rib.spi.RouteEncoder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.route.Attributes;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+
+final class AdjRIBOutEntry<K, V extends Route> {
+ @SuppressWarnings("rawtypes")
+ private static final AtomicReferenceFieldUpdater<AdjRIBOutEntry, Route> NLRIENTRY_ADV_UPDATER = AtomicReferenceFieldUpdater.newUpdater(AdjRIBOutEntry.class, Route.class, "advertisedValue");
+ @SuppressWarnings("rawtypes")
+ private static final AtomicReferenceFieldUpdater<AdjRIBOutEntry, Route> NLRIENTRY_CUR_UPDATER = AtomicReferenceFieldUpdater.newUpdater(AdjRIBOutEntry.class, Route.class, "currentValue");
+
+ /*
+ * Marker object for uninitialized value. Distinct from null.
+ */
+ private static final Route NLRIENTRY_NONE_VALUE = new Route() {
+ @Override
+ public Class<? extends DataContainer> getImplementedInterface() {
+ throw new IllegalStateException("This method should never be invoked");
+ }
+
+ @Override
+ public Attributes getAttributes() {
+ throw new IllegalStateException("This method should never be invoked");
+ }
+ };
+
+ // Referenced via AtomicReferenceFieldUpdaters
+ @SuppressWarnings("unused")
+ private volatile Route currentValue = NLRIENTRY_NONE_VALUE;
+ @SuppressWarnings("unused")
+ private volatile Route advertisedValue = NLRIENTRY_NONE_VALUE;
+ private final RouteEncoder ribOut;
+
+ AdjRIBOutEntry(final RouteEncoder ribOut) {
+ this.ribOut = Preconditions.checkNotNull(ribOut);
+ }
+
+ Route getAdverised() {
+ return NLRIENTRY_ADV_UPDATER.get(this);
+ }
+
+ void setAdverised(final V value) {
+ NLRIENTRY_ADV_UPDATER.set(this, value);
+ }
+
+ @SuppressWarnings("unchecked")
+ V getCurrent() {
+ final Route o = NLRIENTRY_CUR_UPDATER.get(this);
+ Preconditions.checkState(!isNone(o), "Value cannot be NONE here");
+ return (V) o;
+ }
+
+ Route getAndSetCurrent(final V value) {
+ return NLRIENTRY_CUR_UPDATER.getAndSet(this, value);
+ }
+
+ RouteEncoder getRibOut() {
+ return ribOut;
+ }
+
+ static final boolean isNone(final Object o) {
+ return o == NLRIENTRY_NONE_VALUE;
+ }
+}
\ No newline at end of file
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.CheckedFuture;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsInTransaction;
+import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOut;
+import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsTransaction;
import org.opendaylight.protocol.bgp.rib.spi.BGPObjectComparator;
+import org.opendaylight.protocol.bgp.rib.spi.Peer;
+import org.opendaylight.protocol.bgp.rib.spi.RouteEncoder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Attributes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.AttributesBuilder;
-import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-class AdjRIBsInTransactionImpl implements AdjRIBsInTransaction {
- private static final Logger LOG = LoggerFactory.getLogger(AdjRIBsInTransactionImpl.class);
+class AdjRIBsTransactionImpl implements AdjRIBsTransaction {
+ private static final Logger LOG = LoggerFactory.getLogger(AdjRIBsTransactionImpl.class);
private final BGPObjectComparator comparator;
private final WriteTransaction trans;
+ private final Map<Peer, AdjRIBsOut> ribs;
- AdjRIBsInTransactionImpl(final BGPObjectComparator comparator, final WriteTransaction writeTransaction) {
+ AdjRIBsTransactionImpl(final Map<Peer, AdjRIBsOut> ribs, final BGPObjectComparator comparator, final WriteTransaction writeTransaction) {
this.comparator = Preconditions.checkNotNull(comparator);
this.trans = Preconditions.checkNotNull(writeTransaction);
+ this.ribs = Preconditions.checkNotNull(ribs);
}
@Override
}
@Override
- public <T extends DataObject> void advertise(final InstanceIdentifier<T> id, final T obj) {
- trans.put(LogicalDatastoreType.OPERATIONAL, id, obj, true);
+ public BGPObjectComparator comparator() {
+ return comparator;
}
@Override
- public void withdraw(final InstanceIdentifier<?> id) {
- trans.delete(LogicalDatastoreType.OPERATIONAL, id);
+ public <K, V extends Route> void advertise(final RouteEncoder ribOut, final K key, final InstanceIdentifier<V> id, final Peer peer, final V obj) {
+ trans.put(LogicalDatastoreType.OPERATIONAL, id, obj, true);
+ for (Entry<Peer, AdjRIBsOut> e : ribs.entrySet()) {
+ if (e.getKey() != peer) {
+ e.getValue().put(ribOut, key, obj);
+ }
+ }
}
@Override
- public BGPObjectComparator comparator() {
- return comparator;
+ public <K, V extends Route> void withdraw(final RouteEncoder ribOut, final K key, final InstanceIdentifier<V> id) {
+ trans.delete(LogicalDatastoreType.OPERATIONAL, id);
+ for (AdjRIBsOut r : ribs.values()) {
+ r.put(ribOut, key, null);
+ }
}
}
import javax.annotation.concurrent.GuardedBy;
+import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOutRegistration;
import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
import org.opendaylight.protocol.bgp.rib.impl.spi.ReusableBGPPeer;
import org.opendaylight.protocol.bgp.rib.spi.BGPSession;
private final RIB rib;
private final String name;
+ @GuardedBy("this")
private BGPSession session;
+ @GuardedBy("this")
private byte[] rawIdentifier;
+ @GuardedBy("this")
+ private AdjRIBsOutRegistration reg;
public BGPPeer(final String name, final RIB rib) {
this.rib = Preconditions.checkNotNull(rib);
this.tables.add(key);
this.rib.initTable(this, key);
}
+
+ // Not particularly nice, but what can
+ if (session instanceof BGPSessionImpl) {
+ reg = rib.registerRIBsOut(this, new SessionRIBsOut((BGPSessionImpl) session));
+ }
}
private synchronized void cleanup() {
this.rib.clearTable(this, key);
}
+ if (reg != null) {
+ reg.close();
+ reg = null;
+ }
+
this.tables.clear();
this.session = null;
}
cleanup();
}
+ @GuardedBy("this")
private void dropConnection() {
if (this.session != null) {
this.session.close();
}
@Override
- public byte[] getRawIdentifier() {
+ public synchronized byte[] getRawIdentifier() {
return rawIdentifier;
}
}
} else if (msg instanceof Notify) {
// Notifications are handled internally
LOG.info("Session closed because Notification message received: {} / {}", ((Notify) msg).getErrorCode(),
- ((Notify) msg).getErrorSubcode());
+ ((Notify) msg).getErrorSubcode());
this.closeWithoutMessage();
this.listener.onSessionTerminated(this, new BGPTerminationReason(BGPError.forValue(((Notify) msg).getErrorCode(),
- ((Notify) msg).getErrorSubcode())));
+ ((Notify) msg).getErrorSubcode())));
} else if (msg instanceof Keepalive) {
// Keepalives are handled internally
LOG.trace("Received KeepAlive messsage.");
public final AsNumber getAsNumber() {
return this.asNumber;
}
+
+ synchronized boolean isWritable() {
+ return channel != null && channel.isWritable();
+ }
+
+ synchronized void schedule(final Runnable task) {
+ Preconditions.checkState(channel != null);
+ channel.eventLoop().submit(task);
+
+ }
}
import com.google.common.collect.Lists;
import org.opendaylight.protocol.bgp.rib.spi.AbstractAdjRIBs;
-import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsInTransaction;
+import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsTransaction;
import org.opendaylight.protocol.bgp.rib.spi.Peer;
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.multiprotocol.rev130919.destination.destination.type.DestinationIpv4Case;
}
@Override
- public void addRoutes(final AdjRIBsInTransaction trans, final Peer peer, final MpReachNlri nlri,
+ public void addRoutes(final AdjRIBsTransaction trans, final Peer peer, final MpReachNlri nlri,
final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes attributes) {
final RIBEntryData<Ipv4Prefix, Ipv4Route, Ipv4RouteKey> data = new RIBEntryData<Ipv4Prefix, Ipv4Route, Ipv4RouteKey>(peer, attributes) {
@Override
}
@Override
- public void removeRoutes(final AdjRIBsInTransaction trans, final Peer peer, final MpUnreachNlri nlri) {
+ public void removeRoutes(final AdjRIBsTransaction trans, final Peer peer, final MpUnreachNlri nlri) {
for (final Ipv4Prefix id : ((DestinationIpv4Case) nlri.getWithdrawnRoutes().getDestinationType()).getDestinationIpv4().getIpv4Prefixes()) {
super.remove(trans, peer, id);
}
import com.google.common.collect.Lists;
import org.opendaylight.protocol.bgp.rib.spi.AbstractAdjRIBs;
-import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsInTransaction;
+import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsTransaction;
import org.opendaylight.protocol.bgp.rib.spi.Peer;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.destination.type.DestinationIpv6Case;
}
@Override
- public void addRoutes(final AdjRIBsInTransaction trans, final Peer peer, final MpReachNlri nlri,
+ public void addRoutes(final AdjRIBsTransaction trans, final Peer peer, final MpReachNlri nlri,
final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes attributes) {
final RIBEntryData<Ipv6Prefix, Ipv6Route, Ipv6RouteKey> data = new RIBEntryData<Ipv6Prefix, Ipv6Route, Ipv6RouteKey>(peer, attributes) {
@Override
}
@Override
- public void removeRoutes(final AdjRIBsInTransaction trans, final Peer peer, final MpUnreachNlri nlri) {
+ public void removeRoutes(final AdjRIBsTransaction trans, final Peer peer, final MpUnreachNlri nlri) {
for (final Ipv6Prefix id : ((DestinationIpv6) nlri.getWithdrawnRoutes().getDestinationType()).getIpv6Prefixes()) {
super.remove(trans, peer, id);
}
import java.util.List;
import org.opendaylight.protocol.bgp.rib.spi.AbstractRIBExtensionProviderActivator;
+import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsFactory;
import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn;
-import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsInFactory;
import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionProviderContext;
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;
@Override
protected List<AutoCloseable> startRIBExtensionProviderImpl(final RIBExtensionProviderContext context) {
- AdjRIBsInFactory adj1 = new AdjRIBsInFactory() {
+ AdjRIBsFactory adj1 = new AdjRIBsFactory() {
@Override
- public AdjRIBsIn createAdjRIBsIn(final KeyedInstanceIdentifier<Tables, TablesKey> basePath) {
+ public AdjRIBsIn<?, ?> createAdjRIBs(final KeyedInstanceIdentifier<Tables, TablesKey> basePath) {
return new Ipv4AdjRIBsIn(basePath);
}
};
- AdjRIBsInFactory adj2 = new AdjRIBsInFactory() {
+ AdjRIBsFactory adj2 = new AdjRIBsFactory() {
@Override
- public AdjRIBsIn createAdjRIBsIn(final KeyedInstanceIdentifier<Tables, TablesKey> basePath) {
+ public AdjRIBsIn<?, ?> createAdjRIBs(final KeyedInstanceIdentifier<Tables, TablesKey> basePath) {
return new Ipv6AdjRIBsIn(basePath);
}
};
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import javax.annotation.concurrent.ThreadSafe;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
+import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOut;
+import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOutRegistration;
import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn;
private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
private static final Update EOR = new UpdateBuilder().build();
private static final TablesKey IPV4_UNICAST_TABLE = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
+ private final ConcurrentMap<Peer, AdjRIBsOut> ribOuts = new ConcurrentHashMap<>();
private final ReconnectStrategyFactory tcpStrategyFactory;
private final ReconnectStrategyFactory sessionStrategyFactory;
private final BGPObjectComparator comparator;
@Override
public synchronized void updateTables(final Peer peer, final Update message) {
- final AdjRIBsInTransactionImpl trans = new AdjRIBsInTransactionImpl(this.comparator, this.dps.newWriteOnlyTransaction());
+ final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(ribOuts, this.comparator, this.dps.newWriteOnlyTransaction());
if (!EOR.equals(message)) {
final WithdrawnRoutes wr = message.getWithdrawnRoutes();
if (wr != null) {
- final AdjRIBsIn ari = this.tables.get(IPV4_UNICAST_TABLE);
+ final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
if (ari != null) {
ari.removeRoutes(
trans,
if (mpu != null) {
final MpUnreachNlri nlri = mpu.getMpUnreachNlri();
- final AdjRIBsIn ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
+ final AdjRIBsIn<?, ?> ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
if (ari != null) {
ari.removeRoutes(trans, peer, nlri);
} else {
final Nlri ar = message.getNlri();
if (ar != null) {
- final AdjRIBsIn ari = this.tables.get(IPV4_UNICAST_TABLE);
+ final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
if (ari != null) {
final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
if (mpr != null) {
final MpReachNlri nlri = mpr.getMpReachNlri();
- final AdjRIBsIn ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
+ final AdjRIBsIn<?, ?> ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
if (ari != null) {
if (message.equals(ari.endOfRib())) {
ari.markUptodate(trans, peer);
}
}
} else {
- final AdjRIBsIn ari = this.tables.get(IPV4_UNICAST_TABLE);
+ final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
if (ari != null) {
ari.markUptodate(trans, peer);
} else {
@Override
public synchronized void clearTable(final Peer peer, final TablesKey key) {
- final AdjRIBsIn ari = this.tables.get(key);
+ final AdjRIBsIn<?, ?> ari = this.tables.get(key);
if (ari != null) {
- final AdjRIBsInTransactionImpl trans = new AdjRIBsInTransactionImpl(comparator, this.dps.newWriteOnlyTransaction());
+ final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(ribOuts, comparator, this.dps.newWriteOnlyTransaction());
ari.clear(trans, peer);
Futures.addCallback(trans.commit(), new FutureCallback<Void>() {
public void initTable(final Peer bgpPeer, final TablesKey key) {
// FIXME: BUG-196: support graceful restart
}
+
+ @Override
+ public AdjRIBsOutRegistration registerRIBsOut(final Peer peer, final AdjRIBsOut aro) {
+ final AdjRIBsOutRegistration reg = new AdjRIBsOutRegistration(aro) {
+ @Override
+ protected void removeRegistration() {
+ ribOuts.remove(peer, aro);
+ }
+ };
+
+ ribOuts.put(peer, aro);
+ // FIXME: schedule a walk over all the tables
+ return reg;
+ }
}
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.protocol.bgp.rib.RibReference;
+import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsFactory;
import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn;
-import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsInFactory;
import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
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.rib.Tables;
private static final Logger LOG = LoggerFactory.getLogger(RIBTables.class);
- private final Map<TablesKey, AdjRIBsIn> tables = new HashMap<>();
+ private final Map<TablesKey, AdjRIBsIn<?, ?>> tables = new HashMap<>();
private final RIBExtensionConsumerContext registry;
RIBTables(final RIBExtensionConsumerContext extensions) {
this.registry = Preconditions.checkNotNull(extensions);
}
- public synchronized AdjRIBsIn get(final TablesKey key) {
+ public synchronized AdjRIBsIn<?, ?> get(final TablesKey key) {
LOG.debug("Looking for key {} in tables {}", key, this.tables);
- final AdjRIBsIn ret = this.tables.get(key);
+ final AdjRIBsIn<?, ?> ret = this.tables.get(key);
LOG.trace("Key found {}", ret);
return ret;
}
- public synchronized AdjRIBsIn create(final WriteTransaction trans, final RibReference rib, final TablesKey key) {
+ public synchronized AdjRIBsIn<?, ?> create(final WriteTransaction trans, final RibReference rib, final TablesKey key) {
if (this.tables.containsKey(key)) {
LOG.warn("Duplicate create request for key {}", key);
return this.tables.get(key);
}
- final AdjRIBsInFactory f = this.registry.getAdjRIBsInFactory(key.getAfi(), key.getSafi());
+ final AdjRIBsFactory f = this.registry.getAdjRIBsInFactory(key.getAfi(), key.getSafi());
if (f == null) {
LOG.debug("RIBsInFactory not found for key {}, returning null", key);
return null;
}
final KeyedInstanceIdentifier<Tables, TablesKey> basePath = rib.getInstanceIdentifier().child(LocRib.class).child(Tables.class, key);
- final AdjRIBsIn table = Preconditions.checkNotNull(f.createAdjRIBsIn(basePath));
+ final AdjRIBsIn<?, ?> table = Preconditions.checkNotNull(f.createAdjRIBs(basePath));
LOG.debug("Table {} created for key {}", table, key);
this.tables.put(key, table);
--- /dev/null
+/*
+ * Copyright (c) 2014 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.impl;
+
+import com.google.common.base.Preconditions;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
+
+final class SessionRIBsOut extends AbstractAdjRIBsOut implements Runnable {
+ private final AtomicBoolean scheduled = new AtomicBoolean(false);
+ private final BGPSessionImpl session;
+
+ SessionRIBsOut(final BGPSessionImpl session) {
+ this.session = Preconditions.checkNotNull(session);
+ }
+
+ @Override
+ protected void wantWrite() {
+ if (scheduled.compareAndSet(false, true)) {
+ session.schedule(this);
+ }
+ }
+
+ @Override
+ protected boolean writePDU(final Update pdu) {
+ session.sendMessage(pdu);
+ return session.isWritable();
+ }
+
+ @Override
+ public void run() {
+ process();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 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.impl.spi;
+
+import org.opendaylight.protocol.bgp.rib.spi.RouteEncoder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
+
+public interface AdjRIBsOut {
+ public void put(final RouteEncoder ribOut, final Object key, final Route newValue);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.impl.spi;
+
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+
+public abstract class AdjRIBsOutRegistration extends AbstractObjectRegistration<AdjRIBsOut> {
+ protected AdjRIBsOutRegistration(final AdjRIBsOut instance) {
+ super(instance);
+ }
+}
ReconnectStrategyFactory getTcpStrategyFactory();
ReconnectStrategyFactory getSessionStrategyFactory();
+
+ AdjRIBsOutRegistration registerRIBsOut(Peer bgpPeer, AdjRIBsOut aro);
}
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.opendaylight.protocol.bgp.rib.spi.AbstractAdjRIBs;
-import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsInTransaction;
+import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsTransaction;
import org.opendaylight.protocol.bgp.rib.spi.BGPObjectComparator;
import org.opendaylight.protocol.bgp.rib.spi.Peer;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
}
@Override
- public void addRoutes(final AdjRIBsInTransaction trans, final Peer peer, final MpReachNlri nlri,
+ public void addRoutes(final AdjRIBsTransaction trans, final Peer peer, final MpReachNlri nlri,
final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes attributes) {
return;
}
@Override
- public void removeRoutes(final AdjRIBsInTransaction trans, final Peer peer, final MpUnreachNlri nlri) {
+ public void removeRoutes(final AdjRIBsTransaction trans, final Peer peer, final MpUnreachNlri nlri) {
return;
}
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
+import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathAttributes;
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;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributesBuilder;
+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.PathAttributes1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes2Builder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlriBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
import org.slf4j.LoggerFactory;
@ThreadSafe
-public abstract class AbstractAdjRIBs<I, D extends Identifiable<K> & Route, K extends Identifier<D>> implements AdjRIBsIn {
+public abstract class AbstractAdjRIBs<I, D extends Identifiable<K> & Route, K extends Identifier<D>> implements AdjRIBsIn<I, D>, RouteEncoder {
protected abstract static class RIBEntryData<I, D extends Identifiable<K> & Route, K extends Identifier<D>> {
private final PathAttributes attributes;
private final Peer peer;
return newState;
}
- private void electCandidate(final AdjRIBsInTransaction transaction, final RIBEntryData<I, D, K> candidate) {
+ private void electCandidate(final AdjRIBsTransaction transaction, final RIBEntryData<I, D, K> candidate) {
LOG.trace("Electing state {} to supersede {}", candidate, this.currentState);
if (this.currentState == null || !this.currentState.equals(candidate)) {
LOG.trace("Elected new state for {}: {}", getName(), candidate);
- transaction.advertise(getName(), candidate.getDataObject(this.key, getName().getKey()));
+ transaction.advertise(AbstractAdjRIBs.this, this.key, getName(), candidate.getPeer(), candidate.getDataObject(this.key, getName().getKey()));
this.currentState = candidate;
}
}
- synchronized boolean removeState(final AdjRIBsInTransaction transaction, final Peer peer) {
+ synchronized boolean removeState(final AdjRIBsTransaction transaction, final Peer peer) {
final RIBEntryData<I, D, K> data = this.candidates.remove(peer);
LOG.trace("Removed data {}", data);
electCandidate(transaction, candidate);
} else {
LOG.trace("Final candidate disappeared, removing entry {}", getName());
- transaction.withdraw(getName());
+ transaction.withdraw(AbstractAdjRIBs.this, this.key, getName());
}
return this.candidates.isEmpty();
}
- synchronized void setState(final AdjRIBsInTransaction transaction, final Peer peer, final RIBEntryData<I, D, K> state) {
+ synchronized void setState(final AdjRIBsTransaction transaction, final Peer peer, final RIBEntryData<I, D, K> state) {
this.candidates.put(Preconditions.checkNotNull(peer), Preconditions.checkNotNull(state));
electCandidate(transaction, findCandidate(transaction.comparator(), state));
}
}
private static final Logger LOG = LoggerFactory.getLogger(AbstractAdjRIBs.class);
- private final InstanceIdentifier<Tables> basePath;
+ private final KeyedInstanceIdentifier<Tables, TablesKey> basePath;
+ private final BgpTableType tableType;
private final Update eor;
@GuardedBy("this")
protected AbstractAdjRIBs(final KeyedInstanceIdentifier<Tables, TablesKey> basePath) {
this.basePath = Preconditions.checkNotNull(basePath);
+ this.tableType = new BgpTableTypeImpl(basePath.getKey().getAfi(), basePath.getKey().getSafi());
this.eor = new UpdateBuilder().setPathAttributes(new PathAttributesBuilder().addAugmentation(
- PathAttributes1.class, new PathAttributes1Builder().setMpReachNlri(new MpReachNlriBuilder()
- .setAfi(basePath.getKey().getAfi()).setSafi(basePath.getKey().getSafi()).build()).build()).build()).build();
+ PathAttributes1.class, new PathAttributes1Builder().setMpReachNlri(new MpReachNlriBuilder(this.tableType)
+ .build()).build()).build()).build();
+
}
@Override
- public final synchronized void clear(final AdjRIBsInTransaction trans, final Peer peer) {
+ public final synchronized void clear(final AdjRIBsTransaction trans, final Peer peer) {
final Iterator<Map.Entry<I, RIBEntry>> i = this.entries.entrySet().iterator();
while (i.hasNext()) {
final Map.Entry<I, RIBEntry> e = i.next();
* @param id Data store instance identifier
* @param data Data object to be written
*/
- protected final synchronized void add(final AdjRIBsInTransaction trans, final Peer peer, final I id, final RIBEntryData<I, D, K> data) {
+ protected final synchronized void add(final AdjRIBsTransaction trans, final Peer peer, final I id, final RIBEntryData<I, D, K> data) {
LOG.debug("Adding state {} for {} peer {}", data, id, peer);
RIBEntry e = this.entries.get(Preconditions.checkNotNull(id));
* @param peer Originating peer
* @param id Data store instance identifier
*/
- protected final synchronized void remove(final AdjRIBsInTransaction trans, final Peer peer, final I id) {
+ protected final synchronized void remove(final AdjRIBsTransaction trans, final Peer peer, final I id) {
final RIBEntry e = this.entries.get(id);
if (e != null && e.removeState(trans, peer)) {
LOG.debug("Removed last state, removing entry for {}", id);
}
@Override
- public final void markUptodate(final AdjRIBsInTransaction trans, final Peer peer) {
+ public final void markUptodate(final AdjRIBsTransaction trans, final Peer peer) {
this.peers.put(peer, Boolean.TRUE);
trans.setUptodate(this.basePath, !this.peers.values().contains(Boolean.FALSE));
}
public final Update endOfRib() {
return this.eor;
}
+
+ @Override
+ public Update updateMessageFor(final Object key, final Route route) {
+ final UpdateBuilder ub = new UpdateBuilder();
+ final PathAttributesBuilder pab = new PathAttributesBuilder();
+
+ if (route != null) {
+ final MpReachNlriBuilder reach = new MpReachNlriBuilder(this.tableType);
+
+ addAdvertisement(reach, (D)route);
+ pab.fieldsFrom(route.getAttributes());
+ pab.addAugmentation(PathAttributes1.class, new PathAttributes1Builder().setMpReachNlri(reach.build()).build()).build();
+ } else {
+ final MpUnreachNlriBuilder unreach = new MpUnreachNlriBuilder(tableType);
+ addWithdrawal(unreach, (I)key);
+ pab.addAugmentation(PathAttributes2.class, new PathAttributes2Builder().setMpUnreachNlri(unreach.build()).build()).build();
+ }
+
+ ub.setPathAttributes(pab.build());
+ return ub.build();
+ }
+
}
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
-public interface AdjRIBsInFactory {
- AdjRIBsIn createAdjRIBsIn(final KeyedInstanceIdentifier<Tables, TablesKey> basePath);
+public interface AdjRIBsFactory {
+ AdjRIBsIn<?, ?> createAdjRIBs(final KeyedInstanceIdentifier<Tables, TablesKey> basePath);
}
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlri;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
-public interface AdjRIBsIn {
- void addRoutes(AdjRIBsInTransaction trans, Peer peer, MpReachNlri nlri, PathAttributes attributes);
+public interface AdjRIBsIn<K, V extends Route> {
+ void addRoutes(AdjRIBsTransaction trans, Peer peer, MpReachNlri nlri, PathAttributes attributes);
- void removeRoutes(AdjRIBsInTransaction trans, Peer peer, MpUnreachNlri nlri);
+ void removeRoutes(AdjRIBsTransaction trans, Peer peer, MpUnreachNlri nlri);
- void clear(AdjRIBsInTransaction trans, Peer peer);
+ void clear(AdjRIBsTransaction trans, Peer peer);
- void markUptodate(AdjRIBsInTransaction trans, Peer peer);
+ void markUptodate(AdjRIBsTransaction trans, Peer peer);
Update endOfRib();
}
*/
package org.opendaylight.protocol.bgp.rib.spi;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
-import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
/**
* An execution context for a single LocRib transaction.
*/
-public interface AdjRIBsInTransaction {
+public interface AdjRIBsTransaction {
BGPObjectComparator comparator();
void setUptodate(InstanceIdentifier<Tables> basePath, boolean uptodate);
- <T extends DataObject> void advertise(final InstanceIdentifier<T> id, final T obj);
- void withdraw(final InstanceIdentifier<?> id);
-
+ <K, T extends Route> void advertise(RouteEncoder ribOut, K key, InstanceIdentifier<T> id, Peer peer, T obj);
+ <K, T extends Route> void withdraw(RouteEncoder ribOut, K key, InstanceIdentifier<T> id);
}
* exposes an interface for registration of factories for creating AdjRIBsIn instances, which handle the specifics.
*/
public interface RIBExtensionConsumerContext {
- AdjRIBsInFactory getAdjRIBsInFactory(Class<? extends AddressFamily> afi, Class<? extends SubsequentAddressFamily> safi);
+ AdjRIBsFactory getAdjRIBsInFactory(Class<? extends AddressFamily> afi, Class<? extends SubsequentAddressFamily> safi);
}
\ No newline at end of file
* @return Registration handle. Call its close() method to remove it.
*/
AutoCloseable registerAdjRIBsInFactory(Class<? extends AddressFamily> afi, Class<? extends SubsequentAddressFamily> safi,
- AdjRIBsInFactory factory);
+ AdjRIBsFactory factory);
}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2013 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 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.rib.rev130925.Route;
+
+public interface RouteEncoder {
+ Update updateMessageFor(Object key, Route route);
+}
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.SubsequentAddressFamily;
public class SimpleRIBExtensionProviderContext implements RIBExtensionProviderContext {
- private final Map<TablesKey, AdjRIBsInFactory> factories = new ConcurrentHashMap<>();
+ private final Map<TablesKey, AdjRIBsFactory> factories = new ConcurrentHashMap<>();
@Override
public final synchronized AbstractRegistration registerAdjRIBsInFactory(final Class<? extends AddressFamily> afi,
- final Class<? extends SubsequentAddressFamily> safi, final AdjRIBsInFactory factory) {
+ final Class<? extends SubsequentAddressFamily> safi, final AdjRIBsFactory factory) {
final TablesKey key = new TablesKey(afi, safi);
if (this.factories.containsKey(key)) {
}
@Override
- public final synchronized AdjRIBsInFactory getAdjRIBsInFactory(final Class<? extends AddressFamily> afi,
+ public final synchronized AdjRIBsFactory getAdjRIBsInFactory(final Class<? extends AddressFamily> afi,
final Class<? extends SubsequentAddressFamily> safi) {
return this.factories.get(new TablesKey(afi, safi));
}