BUG-185 : implemented Best Path Selection Algorithm. 62/3762/5
authorDana Kutenicsova <dkutenic@cisco.com>
Tue, 7 Jan 2014 13:55:04 +0000 (14:55 +0100)
committerDana Kutenicsova <dkutenic@cisco.com>
Tue, 7 Jan 2014 15:41:51 +0000 (16:41 +0100)
Change-Id: Iec0f6440e21f12e140606973e15901542092c63e
Signed-off-by: Dana Kutenicsova <dkutenic@cisco.com>
23 files changed:
bgp/controller-config/src/main/resources/initial/31-bgp.conf
bgp/parser-api/src/main/java/org/opendaylight/protocol/bgp/parser/BGPSession.java
bgp/rib-impl-config/src/main/java/org/opendaylight/controller/config/yang/bgp/rib/impl/BGPSessionProposalImplModule.java
bgp/rib-impl-config/src/main/java/org/opendaylight/controller/config/yang/bgp/rib/impl/RIBImplModule.java
bgp/rib-impl-config/src/main/yang/bgp-rib-impl.yang
bgp/rib-impl-config/src/test/java/org/opendaylight/controller/config/yang/bgp/rib/impl/BGPImplModuleTest.java
bgp/rib-impl-config/src/test/java/org/opendaylight/controller/config/yang/bgp/rib/impl/BGPSessionProposalImplModuleTest.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPObjectComparator.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/BGPSessionNegotiator.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPSessionProposalImpl.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBImpl.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/spi/BGPSessionPreferences.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/ApiTest.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/BGPImplTest.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/BestPathSelectionTest.java [new file with mode: 0644]
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/FSMTest.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/SynchronizationTest.java
bgp/rib-mock/src/main/java/org/opendaylight/protocol/bgp/rib/mock/EventBusRegistration.java
bgp/testtool/src/main/java/org/opendaylight/protocol/bgp/testtool/Main.java
bgp/testtool/src/test/java/org/opendaylight/protocol/bgp/testtool/BGPSpeakerMock.java
integration-tests/src/test/java/org/opendaylight/protocol/integration/bgp/ParserToSalTest.java

index 0bcab15e3c0270659bf8625e2a0e8fed9726d19d..7c0904f13de9d9a37079d1db816ae016aeddc2dc 100644 (file)
@@ -30,6 +30,8 @@
        <module>
                <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:bgp:rib:impl">prefix:base-bgp-rib</type>
                <name>base-bgp-rib</name>
+               <as-number>64496</as-number>
+               <bgp-id>192.0.2.2</bgp-id>
        </module>
         <module>
                 <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:bgp:linkstate">prefix:bgp-linkstate</type>
index ace160c813733b2d3acde0d27888e4f9aa0b0483..c284fee38e6f3170930ef5b45149e712765efff8 100644 (file)
@@ -23,4 +23,6 @@ import org.opendaylight.yangtools.yang.binding.Notification;
 public interface BGPSession extends ProtocolSession<Notification> {
 
        Set<BgpTableType> getAdvertisedTableTypes();
+
+       byte[] getBgpId();
 }
index 386ef96c26a3ce478733ea9b4ff5c0ef3873ca92..9c9a0e1e06284180dd5e8ab56d1332d7571cffe2 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.controller.config.api.JmxAttributeValidationException;
 import org.opendaylight.protocol.bgp.rib.impl.BGPSessionProposalImpl;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionProposal;
+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.linkstate.rev131125.LinkstateAddressFamily;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.LinkstateSubsequentAddressFamily;
@@ -51,7 +52,8 @@ public final class BGPSessionProposalImplModule extends
                                "value " + getBgpId() + " is not valid IPv4 address", this.bgpIdJmxAttribute);
 
                JmxAttributeValidationException.checkNotNull(getAsNumber(), "value is not set.", this.asNumberJmxAttribute);
-               JmxAttributeValidationException.checkCondition(getAsNumber() >= 0, "value must be greather than 0", this.asNumberJmxAttribute);
+               JmxAttributeValidationException.checkCondition(getAsNumber().intValue() > 0, "value must be greater than 0",
+                               this.asNumberJmxAttribute);
 
                JmxAttributeValidationException.checkNotNull(getHoldtimer(), "value is not set.", this.holdtimerJmxAttribute);
                JmxAttributeValidationException.checkCondition((getHoldtimer() == 0) || (getHoldtimer() >= 3), "value must be 0 or 3 and more",
@@ -64,7 +66,7 @@ public final class BGPSessionProposalImplModule extends
                final Map<Class<? extends AddressFamily>, Class<? extends SubsequentAddressFamily>> tables = new HashMap<>();
                tables.put(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class);
                tables.put(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
-               final BGPSessionProposalImpl bgpSessionProposal = new BGPSessionProposalImpl(getHoldtimer(), getAsNumber(), bgpId, tables);
+               final BGPSessionProposalImpl bgpSessionProposal = new BGPSessionProposalImpl(getHoldtimer(), new AsNumber(getAsNumber()), bgpId, tables);
                return new BgpSessionProposalCloseable(bgpSessionProposal);
        }
 
index 3fdcfcbd15bba8e59a0a409bb9b1eb4383164ca8..c37a1d07caf43b98cd83aea84e56e148e246c2a4 100644 (file)
@@ -23,6 +23,7 @@ import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
 import org.opendaylight.protocol.concepts.ListenerRegistration;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
 
 import com.google.common.base.Preconditions;
@@ -30,47 +31,41 @@ import com.google.common.base.Preconditions;
 /**
  *
  */
-public final class RIBImplModule
-extends
-org.opendaylight.controller.config.yang.bgp.rib.impl.AbstractRIBImplModule {
+public final class RIBImplModule extends org.opendaylight.controller.config.yang.bgp.rib.impl.AbstractRIBImplModule {
 
-       public RIBImplModule(
-                       final org.opendaylight.controller.config.api.ModuleIdentifier name,
+       public RIBImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier name,
                        final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
                super(name, dependencyResolver);
        }
 
-       public RIBImplModule(
-                       final org.opendaylight.controller.config.api.ModuleIdentifier name,
-                       final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
-                       final RIBImplModule oldModule, final java.lang.AutoCloseable oldInstance) {
+       public RIBImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier name,
+                       final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final RIBImplModule oldModule,
+                       final java.lang.AutoCloseable oldInstance) {
                super(name, dependencyResolver, oldModule, oldInstance);
        }
 
        @Override
        public void validate() {
                super.validate();
-               JmxAttributeValidationException.checkNotNull(getExtensions(),
-                               "is not set.", extensionsJmxAttribute);
-               JmxAttributeValidationException.checkNotNull(getRibId(),
-                               "is not set.", ribIdJmxAttribute);
+               JmxAttributeValidationException.checkNotNull(getExtensions(), "is not set.", this.extensionsJmxAttribute);
+               JmxAttributeValidationException.checkNotNull(getRibId(), "is not set.", this.ribIdJmxAttribute);
+               JmxAttributeValidationException.checkNotNull(getLocalAs(), "is not set.", this.localAsJmxAttribute);
+               JmxAttributeValidationException.checkNotNull(getBgpId(), "is not set.", this.localAsJmxAttribute);
        }
 
        @Override
        public java.lang.AutoCloseable createInstance() {
-               final RibImplCloseable rib = new RibImplCloseable(getRibId(), getExtensionsDependency(), getDataProviderDependency());
+               final RibImplCloseable rib = new RibImplCloseable(getRibId(), new AsNumber(getLocalAs()), getBgpId().getBytes(), getExtensionsDependency(), getDataProviderDependency());
                final List<ListenerRegistration<BGPSessionListener>> regs = new ArrayList<>();
                for (final BGP bgp : getBgpDependency()) {
                        final BGPPeer peer = new BGPPeer(rib, "peer-" + bgp.toString());
 
-                       regs.add(Preconditions.checkNotNull(bgp
-                                       .registerUpdateListener(peer,
-                                                       new ReconnectStrategyFactory() {
-                                               @Override
-                                               public ReconnectStrategy createReconnectStrategy() {
-                                                       return getTcpReconnectStrategyDependency();
-                                               }
-                                       }, getSessionReconnectStrategyDependency())));
+                       regs.add(Preconditions.checkNotNull(bgp.registerUpdateListener(peer, new ReconnectStrategyFactory() {
+                               @Override
+                               public ReconnectStrategy createReconnectStrategy() {
+                                       return getTcpReconnectStrategyDependency();
+                               }
+                       }, getSessionReconnectStrategyDependency())));
                }
                rib.setListenerRegistrations(regs);
                return rib;
@@ -79,8 +74,9 @@ org.opendaylight.controller.config.yang.bgp.rib.impl.AbstractRIBImplModule {
        private static final class RibImplCloseable extends RIBImpl implements AutoCloseable {
                private List<ListenerRegistration<BGPSessionListener>> regs;
 
-               private RibImplCloseable(final RibId ribId, final RIBExtensionConsumerContext extensions, final DataProviderService dps) {
-                       super(ribId, extensions, dps);
+               private RibImplCloseable(final RibId ribId, final AsNumber localAs, final byte[] bgpId,
+                               final RIBExtensionConsumerContext extensions, final DataProviderService dps) {
+                       super(ribId, localAs, bgpId, extensions, dps);
                }
 
                @Override
@@ -88,7 +84,7 @@ org.opendaylight.controller.config.yang.bgp.rib.impl.AbstractRIBImplModule {
                        try {
                                super.close();
                        } finally {
-                               for (ListenerRegistration<BGPSessionListener> r : regs) {
+                               for (final ListenerRegistration<BGPSessionListener> r : this.regs) {
                                        r.close();
                                }
                        }
index c669a5497a3197f7d93405c2963e061e5ae4b043..849e4ad64b7488a079ddbcee15d25793cc4e86d2 100644 (file)
@@ -76,7 +76,7 @@ module bgp-rib-impl {
 
             leaf as-number {
                 mandatory true;
-                type int32;
+                type uint32;
             }
         }
     }
@@ -235,6 +235,18 @@ module bgp-rib-impl {
                 }
             }
 
+            leaf local-as {
+               description "Our local AS number. Needed by best selection path attribute.";
+                type uint32;
+                mandatory true;
+            }
+
+            leaf bgp-id {
+                       description "Our local BGP identifier. Needed by best selection path attribute.";
+                mandatory true;
+                type string;
+            }
+
             leaf rib-id {
                 type rib:rib-id;
                 mandatory true;
index 17a244652f23a96e93b68849e32c0a54654cc7d8..bdcba48327394e3821094c27232219c888e4c756 100644 (file)
@@ -50,108 +50,111 @@ public class BGPImplModuleTest extends AbstractConfigTest {
                this.threadgropFactory = new NettyThreadgroupModuleFactory();
                this.messageFactory = new RIBExtensionsImplModuleFactory();
                this.extensionFactory = new SimpleBGPExtensionProviderContextModuleFactory();
-               super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(this.factory, this.dispactherFactory,
-                               this.sessionFacotry, this.messageFactory, this.threadgropFactory, this.extensionFactory));
+               super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(this.factory, this.dispactherFactory, this.sessionFacotry, this.messageFactory, this.threadgropFactory, this.extensionFactory));
        }
 
        @Test
-       public void testValidationExceptionPortNotSet()
-                       throws InstanceAlreadyExistsException {
+       public void testValidationExceptionPortNotSet() throws InstanceAlreadyExistsException {
                try {
-                       ConfigTransactionJMXClient transaction = configRegistryClient
-                                       .createTransaction();
-                       createInstance(transaction, this.factory.getImplementationName(), instanceName, "localhost", null, sessionFacotry.getImplementationName(),
-                                       dispactherFactory.getImplementationName(), threadgropFactory.getImplementationName(),
-                                       messageFactory.getImplementationName(), this.extensionFactory.getImplementationName());
+                       final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+                       createInstance(transaction, this.factory.getImplementationName(), this.instanceName, "localhost", null,
+                                       this.sessionFacotry.getImplementationName(), this.dispactherFactory.getImplementationName(),
+                                       this.threadgropFactory.getImplementationName(), this.messageFactory.getImplementationName(),
+                                       this.extensionFactory.getImplementationName());
                        transaction.validateConfig();
                        fail();
-               } catch (ValidationException e) {
+               } catch (final ValidationException e) {
                        assertTrue(e.getMessage().contains("Port value is not set."));
                }
        }
 
        @Test
-       public void testValidationExceptionPortOutOfRange()
-                       throws InstanceAlreadyExistsException {
+       public void testValidationExceptionPortOutOfRange() throws InstanceAlreadyExistsException {
                try {
-                       ConfigTransactionJMXClient transaction = configRegistryClient
-                                       .createTransaction();
-                       createInstance(transaction, this.factory.getImplementationName(), instanceName, "localhost", -1, sessionFacotry.getImplementationName(), dispactherFactory.getImplementationName(), threadgropFactory.getImplementationName(), messageFactory.getImplementationName(), this.extensionFactory.getImplementationName());
+                       final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+                       createInstance(transaction, this.factory.getImplementationName(), this.instanceName, "localhost", -1,
+                                       this.sessionFacotry.getImplementationName(), this.dispactherFactory.getImplementationName(),
+                                       this.threadgropFactory.getImplementationName(), this.messageFactory.getImplementationName(),
+                                       this.extensionFactory.getImplementationName());
                        transaction.validateConfig();
                        fail();
-               } catch (ValidationException e) {
+               } catch (final ValidationException e) {
                        assertTrue(e.getMessage().contains("is out of range (0-65535)."));
                }
        }
 
        @Test
-       public void testValidationExceptionHostNotSet()
-                       throws InstanceAlreadyExistsException {
+       public void testValidationExceptionHostNotSet() throws InstanceAlreadyExistsException {
                try {
-                       ConfigTransactionJMXClient transaction = configRegistryClient
-                                       .createTransaction();
-                       createInstance(transaction, this.factory.getImplementationName(), instanceName, null, 1, sessionFacotry.getImplementationName(), dispactherFactory.getImplementationName(), threadgropFactory.getImplementationName(), messageFactory.getImplementationName(), this.extensionFactory.getImplementationName());
+                       final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+                       createInstance(transaction, this.factory.getImplementationName(), this.instanceName, null, 1,
+                                       this.sessionFacotry.getImplementationName(), this.dispactherFactory.getImplementationName(),
+                                       this.threadgropFactory.getImplementationName(), this.messageFactory.getImplementationName(),
+                                       this.extensionFactory.getImplementationName());
                        transaction.validateConfig();
                        fail();
-               } catch (ValidationException e) {
+               } catch (final ValidationException e) {
                        assertTrue(e.getMessage().contains("Host value is not set."));
                }
        }
 
        @Test
        public void testCreateBean() throws Exception {
-               ConfigTransactionJMXClient transaction = configRegistryClient
-                               .createTransaction();
-               createInstance(transaction, this.factory.getImplementationName(), instanceName, "localhost", 1, sessionFacotry.getImplementationName(), dispactherFactory.getImplementationName(), threadgropFactory.getImplementationName(), messageFactory.getImplementationName(), this.extensionFactory.getImplementationName());
+               final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+               createInstance(transaction, this.factory.getImplementationName(), this.instanceName, "localhost", 1,
+                               this.sessionFacotry.getImplementationName(), this.dispactherFactory.getImplementationName(),
+                               this.threadgropFactory.getImplementationName(), this.messageFactory.getImplementationName(),
+                               this.extensionFactory.getImplementationName());
                transaction.validateConfig();
-               CommitStatus status = transaction.commit();
-               assertBeanCount(1, factory.getImplementationName());
+               final CommitStatus status = transaction.commit();
+               assertBeanCount(1, this.factory.getImplementationName());
                assertStatus(status, 6, 0, 0);
        }
 
        @Test
-       public void testReusingOldInstance() throws InstanceAlreadyExistsException,
-       ConflictingVersionException, ValidationException {
-               ConfigTransactionJMXClient transaction = configRegistryClient
-                               .createTransaction();
-               createInstance(transaction, this.factory.getImplementationName(), instanceName, "localhost", 1, sessionFacotry.getImplementationName(), dispactherFactory.getImplementationName(), threadgropFactory.getImplementationName(), messageFactory.getImplementationName(), this.extensionFactory.getImplementationName());
+       public void testReusingOldInstance() throws InstanceAlreadyExistsException, ConflictingVersionException, ValidationException {
+               ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+               createInstance(transaction, this.factory.getImplementationName(), this.instanceName, "localhost", 1,
+                               this.sessionFacotry.getImplementationName(), this.dispactherFactory.getImplementationName(),
+                               this.threadgropFactory.getImplementationName(), this.messageFactory.getImplementationName(),
+                               this.extensionFactory.getImplementationName());
                transaction.commit();
-               transaction = configRegistryClient.createTransaction();
-               assertBeanCount(1, factory.getImplementationName());
-               CommitStatus status = transaction.commit();
-               assertBeanCount(1, factory.getImplementationName());
+               transaction = this.configRegistryClient.createTransaction();
+               assertBeanCount(1, this.factory.getImplementationName());
+               final CommitStatus status = transaction.commit();
+               assertBeanCount(1, this.factory.getImplementationName());
                assertStatus(status, 0, 0, 6);
        }
 
        @Test
-       public void testReconfigure() throws InstanceAlreadyExistsException,
-       ConflictingVersionException, ValidationException,
-       InstanceNotFoundException {
-               ConfigTransactionJMXClient transaction = configRegistryClient
-                               .createTransaction();
-               createInstance(transaction, this.factory.getImplementationName(), instanceName, "localhost", 1, sessionFacotry.getImplementationName(), dispactherFactory.getImplementationName(), threadgropFactory.getImplementationName(), messageFactory.getImplementationName(), this.extensionFactory.getImplementationName());
+       public void testReconfigure() throws InstanceAlreadyExistsException, ConflictingVersionException, ValidationException,
+                       InstanceNotFoundException {
+               ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+               createInstance(transaction, this.factory.getImplementationName(), this.instanceName, "localhost", 1,
+                               this.sessionFacotry.getImplementationName(), this.dispactherFactory.getImplementationName(),
+                               this.threadgropFactory.getImplementationName(), this.messageFactory.getImplementationName(),
+                               this.extensionFactory.getImplementationName());
                transaction.commit();
-               transaction = configRegistryClient.createTransaction();
-               assertBeanCount(1, factory.getImplementationName());
-               BGPImplModuleMXBean mxBean = transaction
-                               .newMBeanProxy(transaction.lookupConfigBean(
-                                               factory.getImplementationName(),
-                                               instanceName), BGPImplModuleMXBean.class);
+               transaction = this.configRegistryClient.createTransaction();
+               assertBeanCount(1, this.factory.getImplementationName());
+               final BGPImplModuleMXBean mxBean = transaction.newMBeanProxy(
+                               transaction.lookupConfigBean(this.factory.getImplementationName(), this.instanceName), BGPImplModuleMXBean.class);
                mxBean.setPort(10);
-               CommitStatus status = transaction.commit();
-               assertBeanCount(1, factory.getImplementationName());
+               final CommitStatus status = transaction.commit();
+               assertBeanCount(1, this.factory.getImplementationName());
                assertStatus(status, 0, 1, 5);
        }
 
        public static ObjectName createInstance(final ConfigTransactionJMXClient transaction, final String moduleName,
-                       final String instanceName, final String host, final Integer port, final String sessionModuleName, final String dispatcherModuleName, final String threadgroupModuleName, final String messageFactoryModuleName, final String extensionModuleName) throws InstanceAlreadyExistsException {
-               ObjectName nameCreated = transaction.createModule(
-                               moduleName, instanceName);
-               BGPImplModuleMXBean mxBean = transaction.newMBeanProxy(
-                               nameCreated, BGPImplModuleMXBean.class);
+                       final String instanceName, final String host, final Integer port, final String sessionModuleName,
+                       final String dispatcherModuleName, final String threadgroupModuleName, final String messageFactoryModuleName,
+                       final String extensionModuleName) throws InstanceAlreadyExistsException {
+               final ObjectName nameCreated = transaction.createModule(moduleName, instanceName);
+               final BGPImplModuleMXBean mxBean = transaction.newMBeanProxy(nameCreated, BGPImplModuleMXBean.class);
                mxBean.setHost(host);
                mxBean.setPort(port);
-               mxBean.setBgpProposal(BGPSessionProposalImplModuleTest.createInstance(transaction, sessionModuleName, "bgp-session1", 1, (short)30, "128.0.0.1"));
+               mxBean.setBgpProposal(BGPSessionProposalImplModuleTest.createInstance(transaction, sessionModuleName, "bgp-session1", 1L,
+                               (short) 30, "128.0.0.1"));
                mxBean.setBgpDispatcher(BGPDispatcherImplModuleTest.createInstance(transaction, dispatcherModuleName, "bgp-dispatcher1"));
                return nameCreated;
        }
index a5b0ee7862547bde682fd49275947a3696dc09b6..07230d0110bef9c9c54ccffc35062231dcfa9e8b 100644 (file)
@@ -28,152 +28,133 @@ public class BGPSessionProposalImplModuleTest extends AbstractConfigTest {
        private final String instanceName = "bgp-session-prop";
 
        private BGPSessionProposalImplModuleFactory factory;
-       
+
        @Before
        public void setUp() throws Exception {
                this.factory = new BGPSessionProposalImplModuleFactory();
                super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(this.factory));
        }
-       
+
        @Test
-       public void testValidationExceptionAsNumberNotSet()
-                       throws InstanceAlreadyExistsException {
+       public void testValidationExceptionAsNumberNotSet() throws InstanceAlreadyExistsException {
                try {
-                       ConfigTransactionJMXClient transaction = configRegistryClient
-                                       .createTransaction();
-                       createInstance(transaction, this.factory.getImplementationName(), instanceName, null, (short)180, "192.168.1.1");
+                       final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+                       createInstance(transaction, this.factory.getImplementationName(), this.instanceName, null, (short) 180, "192.168.1.1");
                        transaction.validateConfig();
                        fail();
-               } catch (ValidationException e) {
+               } catch (final ValidationException e) {
                        assertTrue(e.getMessage().contains("AsNumber value is not set."));
                }
        }
-       
+
        @Test
-       public void testValidationExceptionAsNumberMinValue()
-                       throws InstanceAlreadyExistsException {
+       public void testValidationExceptionAsNumberMinValue() throws InstanceAlreadyExistsException {
                try {
-                       ConfigTransactionJMXClient transaction = configRegistryClient
-                                       .createTransaction();
-                       createInstance(transaction, this.factory.getImplementationName(), instanceName, -1, (short)180, "192.168.1.1");
+                       final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+                       createInstance(transaction, this.factory.getImplementationName(), this.instanceName, (long) 0, (short) 180, "192.168.1.1");
                        transaction.validateConfig();
                        fail();
-               } catch (ValidationException e) {
-                       assertTrue(e.getMessage().contains("AsNumber value must be greather than 0"));
+               } catch (final ValidationException e) {
+                       assertTrue(e.getMessage().contains("AsNumber value must be greater than 0"));
                }
        }
-       
+
        @Test
-       public void testValidationExceptionHoldtimerNotSet()
-                       throws InstanceAlreadyExistsException {
+       public void testValidationExceptionHoldtimerNotSet() throws InstanceAlreadyExistsException {
                try {
-                       ConfigTransactionJMXClient transaction = configRegistryClient
-                                       .createTransaction();
-                       createInstance(transaction, this.factory.getImplementationName(), instanceName, 1, null, "192.168.1.1");
+                       final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+                       createInstance(transaction, this.factory.getImplementationName(), this.instanceName, 1L, null, "192.168.1.1");
                        transaction.validateConfig();
                        fail();
-               } catch (ValidationException e) {
+               } catch (final ValidationException e) {
                        assertTrue(e.getMessage().contains("Holdtimer value is not set."));
                }
        }
-       
+
        @Test
-       public void testValidationExceptionHoldtimerMinValue()
-                       throws InstanceAlreadyExistsException {
+       public void testValidationExceptionHoldtimerMinValue() throws InstanceAlreadyExistsException {
                try {
-                       ConfigTransactionJMXClient transaction = configRegistryClient
-                                       .createTransaction();
-                       createInstance(transaction, this.factory.getImplementationName(), instanceName, 1, (short)2, "192.168.1.1");
+                       final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+                       createInstance(transaction, this.factory.getImplementationName(), this.instanceName, 1L, (short) 2, "192.168.1.1");
                        transaction.validateConfig();
                        fail();
-               } catch (ValidationException e) {
+               } catch (final ValidationException e) {
                        assertTrue(e.getMessage().contains("Holdtimer value must be"));
                }
        }
-       
+
        @Test
-       public void testValidationExceptionBgpIdNotSet()
-                       throws InstanceAlreadyExistsException {
+       public void testValidationExceptionBgpIdNotSet() throws InstanceAlreadyExistsException {
                try {
-                       ConfigTransactionJMXClient transaction = configRegistryClient
-                                       .createTransaction();
-                       createInstance(transaction, this.factory.getImplementationName(), instanceName, 1, (short)180, null);
+                       final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+                       createInstance(transaction, this.factory.getImplementationName(), this.instanceName, 1L, (short) 180, null);
                        transaction.validateConfig();
                        fail();
-               } catch (ValidationException e) {
+               } catch (final ValidationException e) {
                        assertTrue(e.getMessage().contains("BgpId value is not set."));
                }
        }
-       
+
        @Test
-       public void testValidationExceptionBgpIdNotIpv4()
-                       throws InstanceAlreadyExistsException {
+       public void testValidationExceptionBgpIdNotIpv4() throws InstanceAlreadyExistsException {
                try {
-                       ConfigTransactionJMXClient transaction = configRegistryClient
-                                       .createTransaction();
-                       createInstance(transaction, this.factory.getImplementationName(), instanceName, 1, (short)180, "192.168.1.500");
+                       final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+                       createInstance(transaction, this.factory.getImplementationName(), this.instanceName, 1L, (short) 180, "192.168.1.500");
                        transaction.validateConfig();
                        fail();
-               } catch (ValidationException e) {
+               } catch (final ValidationException e) {
                        assertTrue(e.getMessage().contains("is not valid IPv4 address"));
                }
        }
-       
+
        @Test
        public void testCreateBean() throws Exception {
-               ConfigTransactionJMXClient transaction = configRegistryClient
-                               .createTransaction();
-               createInstance(transaction, this.factory.getImplementationName(), instanceName, 1, (short)180, "192.168.1.1");
+               final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+               createInstance(transaction, this.factory.getImplementationName(), this.instanceName, 1L, (short) 180, "192.168.1.1");
                transaction.validateConfig();
-               CommitStatus status = transaction.commit();
-               assertBeanCount(1, factory.getImplementationName());
+               final CommitStatus status = transaction.commit();
+               assertBeanCount(1, this.factory.getImplementationName());
                assertStatus(status, 1, 0, 0);
        }
-       
+
        @Test
-       public void testReusingOldInstance() throws InstanceAlreadyExistsException,
-                       ConflictingVersionException, ValidationException {
-               ConfigTransactionJMXClient transaction = configRegistryClient
-                               .createTransaction();
-               createInstance(transaction, this.factory.getImplementationName(), instanceName, 1, (short)180, "192.168.1.1");
+       public void testReusingOldInstance() throws InstanceAlreadyExistsException, ConflictingVersionException, ValidationException {
+               ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+               createInstance(transaction, this.factory.getImplementationName(), this.instanceName, 1L, (short) 180, "192.168.1.1");
                transaction.commit();
-               transaction = configRegistryClient.createTransaction();
-               assertBeanCount(1, factory.getImplementationName());
-               CommitStatus status = transaction.commit();
-               assertBeanCount(1, factory.getImplementationName());
+               transaction = this.configRegistryClient.createTransaction();
+               assertBeanCount(1, this.factory.getImplementationName());
+               final CommitStatus status = transaction.commit();
+               assertBeanCount(1, this.factory.getImplementationName());
                assertStatus(status, 0, 0, 1);
        }
 
        @Test
-       public void testReconfigure() throws InstanceAlreadyExistsException,
-                       ConflictingVersionException, ValidationException,
+       public void testReconfigure() throws InstanceAlreadyExistsException, ConflictingVersionException, ValidationException,
                        InstanceNotFoundException {
-               ConfigTransactionJMXClient transaction = configRegistryClient
-                               .createTransaction();
-               createInstance(transaction, this.factory.getImplementationName(), instanceName, 1, (short)180, "192.168.1.1");
+               ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+               createInstance(transaction, this.factory.getImplementationName(), this.instanceName, 1L, (short) 180, "192.168.1.1");
                transaction.commit();
-               transaction = configRegistryClient.createTransaction();
-               assertBeanCount(1, factory.getImplementationName());
-               BGPSessionProposalImplModuleMXBean mxBean = transaction
-                               .newMBeanProxy(transaction.lookupConfigBean(
-                                               factory.getImplementationName(),
-                                               instanceName), BGPSessionProposalImplModuleMXBean.class);
+               transaction = this.configRegistryClient.createTransaction();
+               assertBeanCount(1, this.factory.getImplementationName());
+               final BGPSessionProposalImplModuleMXBean mxBean = transaction.newMBeanProxy(
+                               transaction.lookupConfigBean(this.factory.getImplementationName(), this.instanceName),
+                               BGPSessionProposalImplModuleMXBean.class);
                mxBean.setBgpId("192.168.10.10");
-               CommitStatus status = transaction.commit();
-               assertBeanCount(1, factory.getImplementationName());
+               final CommitStatus status = transaction.commit();
+               assertBeanCount(1, this.factory.getImplementationName());
                assertStatus(status, 0, 1, 0);
        }
-       
+
        public static ObjectName createInstance(final ConfigTransactionJMXClient transaction, final String moduleName,
-                       final String instanceName, final Integer asNumber, final Short holdtimer, final String bgpId) throws InstanceAlreadyExistsException {
-               ObjectName nameCreated = transaction.createModule(
-                               moduleName, instanceName);
-               BGPSessionProposalImplModuleMXBean mxBean = transaction.newMBeanProxy(
-                               nameCreated, BGPSessionProposalImplModuleMXBean.class);
+                       final String instanceName, final Long asNumber, final Short holdtimer, final String bgpId)
+                       throws InstanceAlreadyExistsException {
+               final ObjectName nameCreated = transaction.createModule(moduleName, instanceName);
+               final BGPSessionProposalImplModuleMXBean mxBean = transaction.newMBeanProxy(nameCreated, BGPSessionProposalImplModuleMXBean.class);
                mxBean.setAsNumber(asNumber);
                mxBean.setBgpId(bgpId);
                mxBean.setHoldtimer(holdtimer);
                return nameCreated;
-               
+
        }
 }
index d252af29e4d6338bf091be290a1d7f3babc5e540..2bc654f417943601ef94c1d05046a044f53667eb 100644 (file)
@@ -7,9 +7,18 @@
  */
 package org.opendaylight.protocol.bgp.rib.impl;
 
+import java.util.Arrays;
 import java.util.Comparator;
+import java.util.List;
 
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
 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.path.attributes.as.path.Segments;
+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.bgp.types.rev130919.as.path.segment.c.segment.AListCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCase;
+
+import com.google.common.annotations.VisibleForTesting;
 
 /**
  * This comparator is intended to implement BGP Best Path Selection algorithm, as described at
@@ -19,9 +28,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mess
  * @param <T> Actual object state reference
  */
 final class BGPObjectComparator implements Comparator<PathAttributes> {
-       public static final BGPObjectComparator INSTANCE = new BGPObjectComparator();
 
-       private BGPObjectComparator() {
+       private final AsNumber ourAS;
+
+       private final byte[] id1;
+
+       private final byte[] id2;
+
+       public BGPObjectComparator(final AsNumber ourAs, final byte[] id1, final byte[] id2) {
+               this.ourAS = ourAs;
+               this.id1 = id1;
+               this.id2 = id2;
        }
 
        @Override
@@ -32,12 +49,134 @@ final class BGPObjectComparator implements Comparator<PathAttributes> {
                if (o2 == null) {
                        return -1;
                }
-               if (o1.equals(o2)) {
+               if (o1.equals(o2) && Arrays.equals(this.id1, this.id2)) {
                        return 0;
                }
+               // 1. prefer path with accessible nexthop
+               // - we assume that all nexthops are accessible
+
+               // 2. prefer path with higher LOCAL_PREF
+               if (!o1.getLocalPref().equals(o2.getLocalPref())) {
+                       return o1.getLocalPref().getPref().compareTo(o2.getLocalPref().getPref());
+               }
+
+               // 3. prefer learned path
+               // - we assume that all paths are learned
+
+               // 4. prefer the path with the shortest AS_PATH.
+               if (!o1.getAsPath().equals(o2.getAsPath())) {
+                       final Integer i1 = countAsPath(o1.getAsPath().getSegments());
+                       final Integer i2 = countAsPath(o2.getAsPath().getSegments());
+                       return i2.compareTo(i1);
+               }
+
+               // 5. prefer the path with the lowest origin type
+               // - IGP is lower than Exterior Gateway Protocol (EGP), and EGP is lower than INCOMPLETE
+               if (!o1.getOrigin().equals(o2.getOrigin())) {
+                       if (o1.getOrigin().getValue().equals(BgpOrigin.Igp)) {
+                               return 1;
+                       }
+                       if (o2.getOrigin().getValue().equals(BgpOrigin.Igp)) {
+                               return -1;
+                       }
+                       if (o1.getOrigin().getValue().equals(BgpOrigin.Egp)) {
+                               return 1;
+                       } else {
+                               return -1;
+                       }
+               }
+
+               // 6. prefer the path with the lowest multi-exit discriminator (MED)
+               if (!o1.getMultiExitDisc().equals(o2.getMultiExitDisc())) {
+                       return o2.getMultiExitDisc().getMed().compareTo(o1.getMultiExitDisc().getMed());
+               }
+
+               // 7. prefer eBGP over iBGP paths
+               // EBGP is peering between two different AS, whereas IBGP is between same AS (Autonomous System).
+               final AsNumber first = getPeerAs(o1.getAsPath().getSegments());
+               final AsNumber second = getPeerAs(o2.getAsPath().getSegments());
+               if ((first != null || second != null) && (first != null && !first.equals(second))) {
+                       if (first == null || first.equals(this.ourAS)) {
+                               return -1;
+                       }
+                       if (second == null || second.equals(this.ourAS)) {
+                               return 1;
+                       }
+               }
+
+               // 8. Prefer the path with the lowest IGP metric to the BGP next hop.
+               // - no next hop metric is advertized
+
+               // 9. When both paths are external, prefer the path that was received first (the oldest one).
+               // if (first.equals(this.ourAS) && second.equals(this.ourAS)) {
+               // FIXME: do we have a way how to determine which one was received first?
+               // }
+
+               // 10. Prefer the route that comes from the BGP router with the lowest router ID.
+               // The router ID is the highest IP address on the router, with preference given to loopback addresses.
+               // If a path contains route reflector (RR) attributes, the originator ID is substituted for the router ID in the
+               // path selection process.
+               byte[] oid1 = this.id1;
+               byte[] oid2 = this.id2;
+               if (o1.getOriginatorId() != null) {
+                       oid1 = o1.getOriginatorId();
+               }
+               if (o2.getOriginatorId() != null) {
+                       oid2 = o2.getOriginatorId();
+               }
+               if (!Arrays.equals(oid1, oid2)) {
+                       return compareByteArrays(oid1, oid2);
+               }
+               // 11. prefer the path with the minimum cluster list length
+               int cluster1 = 0;
+               int cluster2 = 0;
+               if (o1.getClusterId() != null) {
+                       cluster1 = o1.getClusterId().size();
+               }
+               if (o2.getClusterId() != null) {
+                       cluster2 = o2.getClusterId().size();
+               }
+               if (cluster1 != cluster2) {
+                       return ((Integer) cluster1).compareTo(cluster2);
+               }
 
-               // FIXME: BUG-185: implement here
+               // 12. Prefer the path that comes from the lowest neighbor address.
+               // FIXME: do we know this?
 
                return 0;
        }
+
+       private static int countAsPath(final List<Segments> segments) {
+               // an AS_SET counts as 1, no matter how many ASs are in the set.
+               int count = 0;
+               boolean setPresent = false;
+               for (final Segments s : segments) {
+                       if (s.getCSegment() instanceof ASetCase) {
+                               setPresent = true;
+                       } else {
+                               final AListCase list = (AListCase) s.getCSegment();
+                               count += list.getAList().getAsSequence().size();
+                       }
+               }
+               return (setPresent) ? ++count : count;
+       }
+
+       private static AsNumber getPeerAs(final List<Segments> segments) {
+               if (segments.size() == 0) {
+                       return null;
+               }
+               final AListCase first = (AListCase) segments.get(0).getCSegment();
+               return first.getAList().getAsSequence().get(0).getAs();
+       }
+
+       @VisibleForTesting
+       public static int compareByteArrays(final byte[] byteOne, final byte[] byteTwo) {
+               for (int i = 0; i < byteOne.length; i++) {
+                       final int res = Byte.compare(byteOne[i], byteTwo[i]);
+                       if (res != 0) {
+                               return res;
+                       }
+               }
+               return 0;
+       }
 }
index b91ad204690f3b842973f17d0901b6217cabeb93..c729b8384b6cf6d54cec85f413971f87342565bd 100644 (file)
@@ -56,6 +56,8 @@ public final class BGPPeer implements BGPSessionListener, Peer {
                for (final BgpTableType t : session.getAdvertisedTableTypes()) {
                        this.tables.add(new TablesKey(t.getAfi(), t.getSafi()));
                }
+               this.rib.initTables(session.getBgpId());
+
        }
 
        private void cleanup() {
index e37130dfb4c41087248ca79f26c675ac66fafc58..1f13e13f3e9a930e6a26d42dde74f8e5c08d8af6 100644 (file)
@@ -25,6 +25,7 @@ import org.opendaylight.protocol.bgp.parser.BGPSessionListener;
 import org.opendaylight.protocol.bgp.parser.BGPTerminationReason;
 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
 import org.opendaylight.protocol.framework.AbstractProtocolSession;
+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.message.rev130919.Keepalive;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.KeepaliveBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Notify;
@@ -111,6 +112,8 @@ public class BGPSessionImpl extends AbstractProtocolSession<Notification> implem
 
        private final Set<BgpTableType> tableTypes;
 
+       private final Ipv4Address bgpId;
+
        BGPSessionImpl(final Timer timer, final BGPSessionListener listener, final Channel channel, final Open remoteOpen) {
                this.listener = Preconditions.checkNotNull(listener);
                this.stateTimer = Preconditions.checkNotNull(timer);
@@ -151,6 +154,7 @@ public class BGPSessionImpl extends AbstractProtocolSession<Notification> implem
                                }
                        }, this.keepAlive, TimeUnit.SECONDS);
                }
+               this.bgpId = remoteOpen.getBgpIdentifier();
        }
 
        @Override
@@ -311,4 +315,8 @@ public class BGPSessionImpl extends AbstractProtocolSession<Notification> implem
        public synchronized State getState() {
                return this.state;
        }
+
+       public byte[] getBgpId() {
+               return this.bgpId.getValue().getBytes();
+       }
 }
index aa4bda4f5489700656a3d7f3e857946f77de915e..d02247919338ec7085d151925dace956a8d7f47f 100644 (file)
@@ -102,8 +102,8 @@ public final class BGPSessionNegotiator extends AbstractSessionNegotiator<Notifi
        @Override
        protected void startNegotiation() {
                Preconditions.checkState(this.state == State.Idle);
-               this.writeMessage(new OpenBuilder().setMyAsNumber(this.localPref.getMyAs()).setHoldTimer(this.localPref.getHoldTime()).setBgpIdentifier(
-                               this.localPref.getBgpId()).setBgpParameters(this.localPref.getParams()).build());
+               this.writeMessage(new OpenBuilder().setMyAsNumber(this.localPref.getMyAs().getValue().intValue()).setHoldTimer(
+                               this.localPref.getHoldTime()).setBgpIdentifier(this.localPref.getBgpId()).setBgpParameters(this.localPref.getParams()).build());
                this.state = State.OpenSent;
 
                final Object lock = this;
index bbff88737813f59c2d491b6b3240a8b3292c1479..fe65b8ca02dfc5afd5f2de438a459f64738e02cb 100644 (file)
@@ -33,13 +33,13 @@ public final class BGPSessionProposalImpl implements BGPSessionProposal {
 
        private final short holdTimer;
 
-       private final int as;
+       private final AsNumber as;
 
        private final Ipv4Address bgpId;
 
        private final BGPSessionPreferences prefs;
 
-       public BGPSessionProposalImpl(final short holdTimer, final int as, final Ipv4Address bgpId,
+       public BGPSessionProposalImpl(final short holdTimer, final AsNumber as, final Ipv4Address bgpId,
                        final Map<Class<? extends AddressFamily>, Class<? extends SubsequentAddressFamily>> tables) {
                this.holdTimer = holdTimer;
                this.as = as;
@@ -52,8 +52,7 @@ public final class BGPSessionProposalImpl implements BGPSessionProposal {
                                                        new MultiprotocolCapabilityBuilder().setAfi(e.getKey()).setSafi(e.getValue()).build()).build()).build());
                }
                tlvs.add(new BgpParametersBuilder().setCParameters(
-                               new As4BytesCaseBuilder().setAs4BytesCapability(
-                                               new As4BytesCapabilityBuilder().setAsNumber(new AsNumber((long) as)).build()).build()).build());
+                               new As4BytesCaseBuilder().setAs4BytesCapability(new As4BytesCapabilityBuilder().setAsNumber(as).build()).build()).build());
                this.prefs = new BGPSessionPreferences(as, holdTimer, bgpId, tlvs);
        }
 
@@ -72,7 +71,7 @@ public final class BGPSessionProposalImpl implements BGPSessionProposal {
        /**
         * @return the as
         */
-       public int getAs() {
+       public AsNumber getAs() {
                return this.as;
        }
 
index 27ee4f083df28fd2b0c79a2dbb8f0dcf06bbc09d..c8a2b9db4cf21d49edad0aad58727553562ed009 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
 import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn;
 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
 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.Nlri;
@@ -60,12 +61,18 @@ public class RIBImpl extends DefaultRibReference implements AutoCloseable {
        private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
        private static final Update EOR = new UpdateBuilder().build();
        private final DataProviderService dps;
-       private final RIBTables tables;
+       private RIBTables tables;
+       private final RIBExtensionConsumerContext extensions;
+       private final AsNumber localAs;
+       private final byte[] localBgpId;
 
-       public RIBImpl(final RibId ribId, final RIBExtensionConsumerContext extensions, final DataProviderService dps) {
+       public RIBImpl(final RibId ribId, final AsNumber localAs, final byte[] localBgpId, final RIBExtensionConsumerContext extensions,
+                       final DataProviderService dps) {
                super(InstanceIdentifier.builder(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))).toInstance());
                this.dps = Preconditions.checkNotNull(dps);
-               this.tables = new RIBTables(BGPObjectComparator.INSTANCE, extensions);
+               this.extensions = extensions;
+               this.localAs = Preconditions.checkNotNull(localAs);
+               this.localBgpId = localBgpId;
 
                LOG.debug("Instantiating RIB table {} at {}", ribId, getInstanceIdentifier());
 
@@ -73,9 +80,10 @@ public class RIBImpl extends DefaultRibReference implements AutoCloseable {
                final Object o = t.readOperationalData(getInstanceIdentifier());
                Preconditions.checkState(o == null, "Data provider conflict detected on object {}", getInstanceIdentifier());
 
-               t.putOperationalData(getInstanceIdentifier(),
+               t.putOperationalData(
+                               getInstanceIdentifier(),
                                new RibBuilder().setKey(new RibKey(ribId)).setId(ribId).setLocRib(
-                                               new LocRibBuilder().setTables(Collections.<Tables>emptyList()).build()).build());
+                                               new LocRibBuilder().setTables(Collections.<Tables> emptyList()).build()).build());
                Futures.addCallback(JdkFutureAdapters.listenInPoolThread(t.commit()), new FutureCallback<RpcResult<TransactionStatus>>() {
                        @Override
                        public void onSuccess(final RpcResult<TransactionStatus> result) {
@@ -89,6 +97,10 @@ public class RIBImpl extends DefaultRibReference implements AutoCloseable {
                });
        }
 
+       synchronized void initTables(final byte[] remoteBgpId) {
+               this.tables = new RIBTables(new BGPObjectComparator(this.localAs, this.localBgpId, remoteBgpId), this.extensions);
+       }
+
        synchronized void updateTables(final BGPPeer peer, final Update message) {
                final DataModificationTransaction trans = this.dps.beginTransaction();
 
@@ -133,10 +145,10 @@ public class RIBImpl extends DefaultRibReference implements AutoCloseable {
                                                        peer,
                                                        new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).setCNextHop(
                                                                        attrs.getCNextHop()).setAdvertizedRoutes(
-                                                                                       new AdvertizedRoutesBuilder().setDestinationType(
-                                                                                                       new DestinationIpv4CaseBuilder().setDestinationIpv4(
-                                                                                                                       new DestinationIpv4Builder().setIpv4Prefixes(ar.getNlri()).build()).build()).build()).build(),
-                                                                                                                       attrs);
+                                                                       new AdvertizedRoutesBuilder().setDestinationType(
+                                                                                       new DestinationIpv4CaseBuilder().setDestinationIpv4(
+                                                                                                       new DestinationIpv4Builder().setIpv4Prefixes(ar.getNlri()).build()).build()).build()).build(),
+                                                       attrs);
                                } else {
                                        LOG.debug("Not adding objects from unhandled IPv4 Unicast");
                                }
@@ -211,7 +223,7 @@ public class RIBImpl extends DefaultRibReference implements AutoCloseable {
 
        @Override
        public void close() throws InterruptedException, ExecutionException {
-               final DataModificationTransaction t = dps.beginTransaction();
+               final DataModificationTransaction t = this.dps.beginTransaction();
                t.removeOperationalData(getInstanceIdentifier());
                t.commit().get();
        }
index 44725a8a18806d92f1f5d75ce77cbefff786666e..53e84d4ca9f921de576fd7b842b3b0fe1d909dc9 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.protocol.bgp.rib.impl.spi;
 
 import java.util.List;
 
+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.message.rev130919.open.BgpParameters;
 
@@ -17,7 +18,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mess
  */
 public final class BGPSessionPreferences {
 
-       private final int as;
+       private final AsNumber as;
 
        private final int hold;
 
@@ -30,7 +31,7 @@ public final class BGPSessionPreferences {
         * 
         * @param prefs BGP Open message
         */
-       public BGPSessionPreferences(final int as, final int hold, final Ipv4Address bgpId, final List<BgpParameters> params) {
+       public BGPSessionPreferences(final AsNumber as, final int hold, final Ipv4Address bgpId, final List<BgpParameters> params) {
                this.as = as;
                this.hold = hold;
                this.bgpId = bgpId;
@@ -42,7 +43,7 @@ public final class BGPSessionPreferences {
         * 
         * @return AS number
         */
-       public int getMyAs() {
+       public AsNumber getMyAs() {
                return this.as;
        }
 
index d08fd6ab9ca986cd378f2472bb150a30d4161fcb..9df8a317502bf658e986153bcd83e54809fd1ac8 100644 (file)
@@ -12,14 +12,15 @@ import static org.junit.Assert.assertNull;
 
 import org.junit.Test;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
 
 public class ApiTest {
 
        @Test
        public void testBGPSessionPreferences() {
-               final BGPSessionPreferences sp = new BGPSessionPreferences(58, (short) 5, null, null);
+               final BGPSessionPreferences sp = new BGPSessionPreferences(new AsNumber(58L), (short) 5, null, null);
                assertNull(sp.getBgpId());
                assertEquals((short) 5, sp.getHoldTime());
-               assertEquals(58, sp.getMyAs());
+               assertEquals(new AsNumber(58L), sp.getMyAs());
        }
 }
index be828758e0e70b1743424e863614a0b9cb4d3b1d..47b90b7e2fcf58d83022d4de085530bbf6aee9b4 100644 (file)
@@ -30,6 +30,7 @@ import org.opendaylight.protocol.concepts.ListenerRegistration;
 import org.opendaylight.protocol.framework.NeverReconnectStrategy;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParameters;
 
 public class BGPImplTest {
@@ -54,10 +55,9 @@ public class BGPImplTest {
 
        @Test
        public void testBgpImpl() throws Exception {
-               doReturn(new BGPSessionPreferences(0, 0, null, Collections.<BgpParameters> emptyList())).when(this.prop).getProposal();
+               doReturn(new BGPSessionPreferences(new AsNumber(0L), 0, null, Collections.<BgpParameters> emptyList())).when(this.prop).getProposal();
                this.bgp = new BGPImpl(this.disp, new InetSocketAddress(InetAddress.getLoopbackAddress(), 2000), this.prop);
-               final ListenerRegistration<?> reg = this.bgp.registerUpdateListener(new SimpleSessionListener(),
-                               new ReconnectStrategyFactory() {
+               final ListenerRegistration<?> reg = this.bgp.registerUpdateListener(new SimpleSessionListener(), new ReconnectStrategyFactory() {
                        @Override
                        public ReconnectStrategy createReconnectStrategy() {
                                return new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000);
diff --git a/bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/BestPathSelectionTest.java b/bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/BestPathSelectionTest.java
new file mode 100644 (file)
index 0000000..0dac242
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
+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.path.attributes.AsPathBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.LocalPrefBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.MultiExitDiscBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.OriginBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.as.path.Segments;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.as.path.SegmentsBuilder;
+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.types.rev130919.BgpOrigin;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.AListCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.AListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequence;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequenceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.set._case.ASetBuilder;
+
+import com.google.common.collect.Lists;
+
+/**
+ * @see <a href="http://www.cisco.com/c/en/us/support/docs/ip/border-gateway-protocol-bgp/13753-25.html">BGP Best Path
+ *      Selection</a>
+ */
+public class BestPathSelectionTest {
+
+       private final BGPObjectComparator comparator = new BGPObjectComparator(new AsNumber(40L), new byte[] { (byte) 192, (byte) 150, 20, 38 }, new byte[] {
+                       (byte) 192, (byte) 150, 20, 38 });
+
+       private PathAttributes attr1;
+       private PathAttributes attr2;
+       private PathAttributes attr3;
+       private PathAttributes attr4;
+       private PathAttributes attr5;
+       private PathAttributes attr6;
+       private PathAttributes attr7;
+
+       @Before
+       public void setUp() {
+               final AsPathBuilder asBuilder1 = new AsPathBuilder();
+               final AsPathBuilder asBuilder2 = new AsPathBuilder();
+               List<Segments> segs = new ArrayList<>();
+               final List<AsNumber> ases = Lists.newArrayList(new AsNumber(100L), new AsNumber(30L));
+               final List<AsSequence> seqs = Lists.newArrayList(new AsSequenceBuilder().setAs(new AsNumber(50L)).build());
+               segs.add(new SegmentsBuilder().setCSegment(new AListCaseBuilder().setAList(new AListBuilder().setAsSequence(seqs).build()).build()).build());
+               asBuilder1.setSegments(segs);
+               segs = new ArrayList<>();
+               segs.add(new SegmentsBuilder().setCSegment(new AListCaseBuilder().setAList(new AListBuilder().setAsSequence(seqs).build()).build()).build());
+               segs.add(new SegmentsBuilder().setCSegment(new ASetCaseBuilder().setASet(new ASetBuilder().setAsSet(ases).build()).build()).build());
+               asBuilder2.setSegments(segs);
+
+               final List<ClusterIdentifier> clusters = new ArrayList<>();
+               clusters.add(new ClusterIdentifier(new byte[4]));
+               clusters.add(new ClusterIdentifier(new byte[4]));
+
+               final PathAttributesBuilder builder = new PathAttributesBuilder();
+               builder.setLocalPref(new LocalPrefBuilder().setPref(100L).build());
+               this.attr1 = builder.build();
+               builder.setLocalPref(new LocalPrefBuilder().setPref(230L).build());
+               builder.setAsPath(asBuilder2.build());
+               this.attr2 = builder.build();
+               builder.setAsPath(asBuilder1.build());
+               builder.setOrigin(new OriginBuilder().setValue(BgpOrigin.Incomplete).build());
+               this.attr3 = builder.build();
+               builder.setOrigin(new OriginBuilder().setValue(BgpOrigin.Egp).build());
+               builder.setMultiExitDisc(new MultiExitDiscBuilder().setMed(15L).build());
+               this.attr4 = builder.build();
+               builder.setMultiExitDisc(new MultiExitDiscBuilder().setMed(12L).build());
+               this.attr5 = builder.build();
+               builder.setAsPath(new AsPathBuilder().setSegments(new ArrayList<Segments>()).build());
+               builder.setClusterId(new ArrayList<ClusterIdentifier>());
+               this.attr6 = builder.build();
+               builder.setClusterId(clusters);
+               this.attr7 = builder.build();
+       }
+
+       @Test
+       public void testCompare() {
+               assertTrue(this.comparator.compare(this.attr1, this.attr2) < 0);
+               assertTrue(this.comparator.compare(this.attr2, this.attr1) > 0);
+
+               assertTrue(this.comparator.compare(this.attr2, this.attr3) < 0);
+               assertTrue(this.comparator.compare(this.attr3, this.attr2) > 0);
+
+               assertTrue(this.comparator.compare(this.attr3, this.attr4) < 0);
+               assertTrue(this.comparator.compare(this.attr4, this.attr3) > 0);
+
+               assertTrue(this.comparator.compare(this.attr4, this.attr5) < 0);
+               assertTrue(this.comparator.compare(this.attr5, this.attr4) > 0);
+
+               assertTrue(this.comparator.compare(this.attr5, this.attr6) < 0);
+               assertTrue(this.comparator.compare(this.attr6, this.attr5) > 0);
+
+               assertTrue(this.comparator.compare(this.attr6, this.attr7) < 0);
+               assertTrue(this.comparator.compare(this.attr7, this.attr6) > 0);
+       }
+
+       @Test
+       public void testByteCompare() {
+               assertTrue(BGPObjectComparator.compareByteArrays(new byte[] { (byte) 192, (byte) 150, 20, 38 }, new byte[] { (byte) 192,
+                               (byte) 168, 25, 1 }) < 0);
+               assertTrue(BGPObjectComparator.compareByteArrays(new byte[] { (byte) 192, (byte) 168, 25, 1 }, new byte[] { (byte) 192, (byte) 150,
+                               20, 38 }) > 0);
+       }
+}
index bcf1ac5c4133df2348860381d798dc7c292500ae..12d986e9614e1137737fe787eb814da952cb3810 100644 (file)
@@ -35,6 +35,7 @@ import org.mockito.stubbing.Answer;
 import org.opendaylight.protocol.bgp.parser.BGPError;
 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
 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;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Keepalive;
@@ -83,7 +84,7 @@ public class FSMTest {
                tlvs.add(new BgpParametersBuilder().setCParameters(
                                new MultiprotocolCaseBuilder().setMultiprotocolCapability(
                                                new MultiprotocolCapabilityBuilder().setAfi(this.linkstatett.getAfi()).setSafi(this.linkstatett.getSafi()).build()).build()).build());
-               final BGPSessionPreferences prefs = new BGPSessionPreferences(30, (short) 3, null, tlvs);
+               final BGPSessionPreferences prefs = new BGPSessionPreferences(new AsNumber(30L), (short) 3, null, tlvs);
 
                final ChannelFuture f = mock(ChannelFuture.class);
                doReturn(null).when(f).addListener(any(GenericFutureListener.class));
index e5bc1d5a1c5a589bdfebe925c5e3315b2c355281..85e46cded97a2bb3cd84f299ffead65ea6e066af 100644 (file)
@@ -89,6 +89,11 @@ public class SynchronizationTest {
                                types.add(new BgpTableTypeImpl(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class));
                                return types;
                        }
+
+                       @Override
+                       public byte[] getBgpId() {
+                               return new byte[] { (byte) 127, 0, 0, 1 };
+                       }
                }, this.listener, types);
        }
 
index 695653b10984772ed6bf875287d1f2a64be538be..cfe180bec35288411e23f6abf86d9c223619234d 100644 (file)
@@ -87,6 +87,11 @@ final class EventBusRegistration extends ListenerRegistration<BGPSessionListener
                                public Set<BgpTableType> getAdvertisedTableTypes() {
                                        return tts;
                                }
+
+                               @Override
+                               public byte[] getBgpId() {
+                                       return new byte[] { (byte) 127, 0, 0, 1 };
+                               }
                        });
                } else if (!(message instanceof Keepalive)) {
                        listener.onMessage(null, message);
index 873329909694af0ef8e779d2fa3ddd31101b40ec..89ff6642a1f28d16640fa4dce2e73773b613d370 100644 (file)
@@ -101,7 +101,7 @@ public final class Main {
                tables.put(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
                tables.put(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class);
 
-               final BGPSessionProposalImpl prop = new BGPSessionProposalImpl(holdTimerValue, as.getValue().intValue(), new Ipv4Address("25.25.25.2"), tables);
+               final BGPSessionProposalImpl prop = new BGPSessionProposalImpl(holdTimerValue, as, new Ipv4Address("25.25.25.2"), tables);
 
                final BGPSessionPreferences proposal = prop.getProposal();
 
index 3700ea664eb661b1721ddeb88f82edbacdd9b3a9..5ccd87819e3cd9b1c4f052bd80c0b360931a70f4 100644 (file)
@@ -30,6 +30,7 @@ import org.opendaylight.protocol.framework.ProtocolSession;
 import org.opendaylight.protocol.framework.SessionListener;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
+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.linkstate.rev131125.LinkstateAddressFamily;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.LinkstateSubsequentAddressFamily;
@@ -79,7 +80,7 @@ public class BGPSpeakerMock<M, S extends ProtocolSession<M>, L extends SessionLi
                tables.put(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
                tables.put(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class);
 
-               final BGPSessionPreferences prefs = new BGPSessionProposalImpl((short) 90, 72, new Ipv4Address("127.0.0.2"), tables).getProposal();
+               final BGPSessionPreferences prefs = new BGPSessionProposalImpl((short) 90, new AsNumber(72L), new Ipv4Address("127.0.0.2"), tables).getProposal();
 
                final SessionNegotiatorFactory<Notification, BGPSessionImpl, BGPSessionListener> snf = new BGPSessionNegotiatorFactory(new HashedWheelTimer(), prefs);
 
index 1f8874dcd248c33ef8b8528cacf66b85517f326b..1a1f5f4a9cc0da6b3bcbf47efeaf10933dd64b49 100644 (file)
@@ -38,6 +38,7 @@ import org.opendaylight.protocol.bgp.rib.spi.SimpleRIBExtensionProviderContext;
 import org.opendaylight.protocol.bgp.util.HexDumpBGPFileParser;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -100,7 +101,7 @@ public class ParserToSalTest {
 
                        @Override
                        public RpcResult<TransactionStatus> get(final long timeout, final TimeUnit unit) throws InterruptedException,
-                       ExecutionException, TimeoutException {
+                                       ExecutionException, TimeoutException {
                                return null;
                        }
                }).when(this.mockedTransaction).commit();
@@ -135,7 +136,7 @@ public class ParserToSalTest {
                final RIBExtensionProviderContext ext = new SimpleRIBExtensionProviderContext();
                new RIBActivator().startRIBExtensionProvider(ext);
                new org.opendaylight.protocol.bgp.linkstate.RIBActivator().startRIBExtensionProvider(ext);
-               final RIBImpl rib = new RIBImpl(new RibId("testRib"), ext, this.providerService);
+               final RIBImpl rib = new RIBImpl(new RibId("testRib"), new AsNumber(72L), new byte[] { (byte) 127, 0, 0, 1 }, ext, this.providerService);
                final BGPPeer peer = new BGPPeer(rib, "peer-" + this.mock.toString());
 
                this.mock.registerUpdateListener(peer, new ReconnectStrategyFactory() {