summaryrefslogtreecommitdiffstats
path: root/infra/bgp-distribution
diff options
context:
space:
mode:
Diffstat (limited to 'infra/bgp-distribution')
-rw-r--r--infra/bgp-distribution/asciidoc/Readme.adoc3
-rw-r--r--infra/bgp-distribution/bgp_postman_collection.json136
-rw-r--r--infra/bgp-distribution/pom.xml118
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BGPDispatcherImplProvider.java36
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BGPExtensionConsumerContextProvider.java46
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BGPPeerRegistryProvider.java123
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpConfiguration.java68
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpConfigurationModule.java33
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpExtensionsModule.java64
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpModule.java82
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpNettyThreadGroupProvider.java34
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpRIBProvider.java121
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpReaderFactoryProvider.java60
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpReadersModule.java33
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpServerProvider.java107
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpWriterFactoryProvider.java90
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpWritersModule.java33
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/RIBExtensionConsumerContextProvider.java45
-rw-r--r--infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/distro/Main.java73
-rw-r--r--infra/bgp-distribution/src/main/resources/honeycomb-minimal-resources/config/bgp-peers.json48
-rw-r--r--infra/bgp-distribution/src/main/resources/honeycomb-minimal-resources/config/bgp.json9
-rw-r--r--infra/bgp-distribution/src/test/java/io/fd/honeycomb/infra/bgp/distro/BgpDistributionTest.java125
-rw-r--r--infra/bgp-distribution/src/test/resources/WEB-INF/web.xml74
-rw-r--r--infra/bgp-distribution/src/test/resources/bgp-peers.json90
-rw-r--r--infra/bgp-distribution/src/test/resources/bgp.json9
-rw-r--r--infra/bgp-distribution/src/test/resources/honeycomb-keystorebin0 -> 2392 bytes
-rw-r--r--infra/bgp-distribution/src/test/resources/honeycomb.json40
-rw-r--r--infra/bgp-distribution/src/test/resources/logback.xml31
28 files changed, 1731 insertions, 0 deletions
diff --git a/infra/bgp-distribution/asciidoc/Readme.adoc b/infra/bgp-distribution/asciidoc/Readme.adoc
new file mode 100644
index 000000000..f6222d4d0
--- /dev/null
+++ b/infra/bgp-distribution/asciidoc/Readme.adoc
@@ -0,0 +1,3 @@
+= bgp-distribution
+
+Honeycomb distribution that adds BGP to NETCONF and RESTCONF northbound intrerfaces provided by minimal-distribution. \ No newline at end of file
diff --git a/infra/bgp-distribution/bgp_postman_collection.json b/infra/bgp-distribution/bgp_postman_collection.json
new file mode 100644
index 000000000..1e7602a2d
--- /dev/null
+++ b/infra/bgp-distribution/bgp_postman_collection.json
@@ -0,0 +1,136 @@
+{
+ "id": "866862e9-5b18-cf86-e8a3-c121422e38e6",
+ "name": "Honeycomb BGP RESTCONF calls",
+ "description": "Examples of BGP configration based on \nhttp://docs.opendaylight.org/en/stable-boron/user-guide/bgp-user-guide.html",
+ "order": [
+ "aed706f7-b83c-93b2-552b-831c1576a0c6",
+ "830e5608-4b7e-fbcf-e1b6-057af48570a7",
+ "62045d77-ce19-7e74-468b-74843c20b5ce",
+ "2632240a-42ce-126e-11a5-b7f8e16a0a28",
+ "4f5f4d00-2bd6-6f23-5f19-d15130f7cdb8",
+ "3af97a8b-b9f3-7a20-6ce8-5d492954d3c2"
+ ],
+ "folders": [],
+ "timestamp": 1494477000331,
+ "owner": "567303",
+ "public": false,
+ "requests": [
+ {
+ "id": "2632240a-42ce-126e-11a5-b7f8e16a0a28",
+ "headers": "Content-Type: application/xml\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8183/restconf/config/bgp-rib:application-rib/10.25.1.9/tables/bgp-types:ipv4-address-family/bgp-types:unicast-subsequent-address-family/bgp-inet:ipv4-routes",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "POST",
+ "data": [],
+ "dataMode": "raw",
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1494502752142,
+ "name": "add ipv4unicast route",
+ "description": "",
+ "collectionId": "866862e9-5b18-cf86-e8a3-c121422e38e6",
+ "responses": [],
+ "rawModeData": "<ipv4-route xmlns=\"urn:opendaylight:params:xml:ns:yang:bgp-inet\">\n <path-id>0</path-id>\n <prefix>10.0.0.11/32</prefix>\n <attributes>\n <as-path></as-path>\n <origin>\n <value>igp</value>\n </origin>\n <local-pref>\n <pref>100</pref>\n </local-pref>\n <ipv4-next-hop>\n <global>10.11.1.1</global>\n </ipv4-next-hop>\n </attributes>\n</ipv4-route>"
+ },
+ {
+ "id": "3af97a8b-b9f3-7a20-6ce8-5d492954d3c2",
+ "headers": "Content-Type: application/xml\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8183/restconf/operational/bgp-rib:bgp-rib/rib/hc-bgp-instance/peer/bgp:%2F%2F127.0.0.2/adj-rib-out/tables/bgp-types:ipv4-address-family/bgp-types:unicast-subsequent-address-family/bgp-inet:ipv4-routes",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1495009639185,
+ "name": "show 127.0.0.2 peer's adj-rib-out",
+ "description": "",
+ "collectionId": "866862e9-5b18-cf86-e8a3-c121422e38e6",
+ "responses": [],
+ "rawModeData": "<neighbor xmlns=\"urn:opendaylight:params:xml:ns:yang:bgp:openconfig-extensions\">\n <neighbor-address>192.0.2.1</neighbor-address>\n <timers>\n <config>\n <hold-time>90</hold-time>\n <connect-retry>10</connect-retry>\n </config>\n </timers>\n <transport>\n <config>\n <remote-port>179</remote-port>\n <passive-mode>false</passive-mode>\n </config>\n </transport>\n <config>\n <peer-type>INTERNAL</peer-type>\n </config>\n</neighbor>"
+ },
+ {
+ "id": "4f5f4d00-2bd6-6f23-5f19-d15130f7cdb8",
+ "headers": "Content-Type: application/xml\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8183/restconf/operational/bgp-rib:bgp-rib/rib/hc-bgp-instance/loc-rib",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1495009616064,
+ "name": "show speeker's Loc-RIB",
+ "description": "",
+ "collectionId": "866862e9-5b18-cf86-e8a3-c121422e38e6",
+ "responses": [],
+ "rawModeData": "<neighbor xmlns=\"urn:opendaylight:params:xml:ns:yang:bgp:openconfig-extensions\">\n <neighbor-address>10.25.1.9</neighbor-address>\n <config>\n <peer-group>application-peers</peer-group>\n </config>\n</neighbor>"
+ },
+ {
+ "id": "62045d77-ce19-7e74-468b-74843c20b5ce",
+ "headers": "Content-Type: application/xml\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8183/restconf/operational/bgp-rib:bgp-rib/rib/hc-bgp-instance/peer/bgp:%2F%2F10.25.1.9",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1495116619841,
+ "name": "show 127.0.0.3 app peer state",
+ "description": "",
+ "collectionId": "866862e9-5b18-cf86-e8a3-c121422e38e6",
+ "responses": [],
+ "rawModeData": "<neighbor xmlns=\"urn:opendaylight:params:xml:ns:yang:bgp:openconfig-extensions\">\n <neighbor-address>192.0.2.1</neighbor-address>\n <timers>\n <config>\n <hold-time>90</hold-time>\n <connect-retry>10</connect-retry>\n </config>\n </timers>\n <transport>\n <config>\n <remote-port>179</remote-port>\n <passive-mode>false</passive-mode>\n </config>\n </transport>\n <config>\n <peer-type>INTERNAL</peer-type>\n </config>\n</neighbor>"
+ },
+ {
+ "id": "830e5608-4b7e-fbcf-e1b6-057af48570a7",
+ "headers": "Content-Type: application/xml\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8183/restconf/operational/bgp-rib:bgp-rib/rib/hc-bgp-instance/peer/bgp:%2F%2F127.0.0.2",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1495009591745,
+ "name": "show 127.0.0.2 peer state",
+ "description": "",
+ "collectionId": "866862e9-5b18-cf86-e8a3-c121422e38e6",
+ "responses": [],
+ "rawModeData": "<neighbor xmlns=\"urn:opendaylight:params:xml:ns:yang:bgp:openconfig-extensions\">\n <neighbor-address>192.0.2.1</neighbor-address>\n <timers>\n <config>\n <hold-time>90</hold-time>\n <connect-retry>10</connect-retry>\n </config>\n </timers>\n <transport>\n <config>\n <remote-port>179</remote-port>\n <passive-mode>false</passive-mode>\n </config>\n </transport>\n <config>\n <peer-type>INTERNAL</peer-type>\n </config>\n</neighbor>"
+ },
+ {
+ "id": "aed706f7-b83c-93b2-552b-831c1576a0c6",
+ "headers": "Content-Type: application/xml\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8183/restconf/operational/bgp-rib:bgp-rib/rib/hc-bgp-instance",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1495116911838,
+ "name": "show hc-bgp-instance",
+ "description": "",
+ "collectionId": "866862e9-5b18-cf86-e8a3-c121422e38e6",
+ "responses": [],
+ "rawModeData": "<neighbor xmlns=\"urn:opendaylight:params:xml:ns:yang:bgp:openconfig-extensions\">\n <neighbor-address>192.0.2.1</neighbor-address>\n <timers>\n <config>\n <hold-time>90</hold-time>\n <connect-retry>10</connect-retry>\n </config>\n </timers>\n <transport>\n <config>\n <remote-port>179</remote-port>\n <passive-mode>false</passive-mode>\n </config>\n </transport>\n <config>\n <peer-type>INTERNAL</peer-type>\n </config>\n</neighbor>"
+ }
+ ]
+} \ No newline at end of file
diff --git a/infra/bgp-distribution/pom.xml b/infra/bgp-distribution/pom.xml
new file mode 100644
index 000000000..c70d03017
--- /dev/null
+++ b/infra/bgp-distribution/pom.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>minimal-distribution-parent</artifactId>
+ <version>1.17.07-SNAPSHOT</version>
+ <relativePath>../../common/minimal-distribution-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>bgp-distribution</artifactId>
+ <name>${project.artifactId}</name>
+ <version>1.17.07-SNAPSHOT</version>
+
+ <properties>
+ <main.class>io.fd.honeycomb.infra.bgp.distro.Main</main.class>
+ <sonar.skip>true</sonar.skip>
+ <distribution.modules>
+ io.fd.honeycomb.infra.bgp.BgpModule,
+ io.fd.honeycomb.infra.bgp.BgpExtensionsModule,
+ io.fd.honeycomb.infra.bgp.BgpReadersModule,
+ io.fd.honeycomb.infra.bgp.BgpWritersModule,
+ io.fd.honeycomb.infra.bgp.BgpConfigurationModule
+ </distribution.modules>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.gmaven</groupId>
+ <artifactId>groovy-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>minimal-distribution</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- ODL-BGP -->
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>bgp-rib-impl</artifactId>
+ <!-- TODO remove exclusion after bumping to Boron-SR4 -->
+ <exclusions>
+ <exclusion>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>bgp-openconfig-impl</artifactId>
+ </dependency>
+ <!-- BGP extensions -->
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>bgp-evpn</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>bgp-inet</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>bgp-labeled-unicast</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>bgp-linkstate</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>bgp-l3vpn</artifactId>
+ </dependency>
+
+ <!-- test dependencies -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.mashape.unirest</groupId>
+ <artifactId>unirest-java</artifactId>
+ <version>1.4.9</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.jcraft</groupId>
+ <artifactId>jsch</artifactId>
+ <version>0.1.54</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project> \ No newline at end of file
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BGPDispatcherImplProvider.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BGPDispatcherImplProvider.java
new file mode 100644
index 000000000..c9ec39f35
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BGPDispatcherImplProvider.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.inject.Inject;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+import io.netty.channel.EventLoopGroup;
+import org.opendaylight.protocol.bgp.parser.spi.BGPExtensionConsumerContext;
+import org.opendaylight.protocol.bgp.rib.impl.BGPDispatcherImpl;
+import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
+
+final class BGPDispatcherImplProvider extends ProviderTrait<BGPDispatcher> {
+ @Inject
+ private BGPExtensionConsumerContext consumerContext;
+ @Inject
+ private EventLoopGroup threadGroup;
+
+ @Override
+ protected BGPDispatcher create() {
+ return new BGPDispatcherImpl(consumerContext.getMessageRegistry(), threadGroup, threadGroup);
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BGPExtensionConsumerContextProvider.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BGPExtensionConsumerContextProvider.java
new file mode 100644
index 000000000..00e99ab99
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BGPExtensionConsumerContextProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.inject.Inject;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+import java.util.ArrayList;
+import java.util.Set;
+import org.opendaylight.protocol.bgp.parser.spi.BGPExtensionConsumerContext;
+import org.opendaylight.protocol.bgp.parser.spi.BGPExtensionProviderActivator;
+import org.opendaylight.protocol.bgp.parser.spi.BGPExtensionProviderContext;
+import org.opendaylight.protocol.bgp.parser.spi.pojo.SimpleBGPExtensionProviderContext;
+import org.opendaylight.protocol.bgp.parser.spi.pojo.SimpleBGPExtensionProviderContextActivator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class BGPExtensionConsumerContextProvider extends ProviderTrait<BGPExtensionConsumerContext> {
+ private static final Logger LOG = LoggerFactory.getLogger(BGPExtensionConsumerContextProvider.class);
+
+ @Inject
+ private Set<BGPExtensionProviderActivator> activators;
+
+ @Override
+ protected BGPExtensionConsumerContext create() {
+ final BGPExtensionProviderContext ctx = new SimpleBGPExtensionProviderContext();
+ final SimpleBGPExtensionProviderContextActivator activator =
+ new SimpleBGPExtensionProviderContextActivator(ctx, new ArrayList<>(activators));
+ LOG.debug("Starting BGPExtensionConsumerContext with activators: {}", activators);
+ activator.start();
+ return ctx;
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BGPPeerRegistryProvider.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BGPPeerRegistryProvider.java
new file mode 100644
index 000000000..217c43823
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BGPPeerRegistryProvider.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.translate.util.JsonUtils.readContainerEntryJson;
+import static org.opendaylight.protocol.bgp.openconfig.impl.util.OpenConfigUtil.APPLICATION_PEER_GROUP_NAME;
+import static org.opendaylight.yangtools.sal.binding.generator.impl.BindingSchemaContextUtils.findDataNodeContainer;
+
+import com.google.common.base.Optional;
+import com.google.inject.Inject;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+import java.io.InputStream;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigMappingService;
+import org.opendaylight.protocol.bgp.rib.impl.StrictBGPPeerRegistry;
+import org.opendaylight.protocol.bgp.rib.impl.config.AppPeer;
+import org.opendaylight.protocol.bgp.rib.impl.config.BgpPeer;
+import org.opendaylight.protocol.bgp.rib.impl.spi.BGPPeerRegistry;
+import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborPeerGroupConfig;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.NetworkInstances;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceKey;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.Protocols;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.ProtocolKey;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.policy.types.rev151009.BGP;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Config2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Protocol1;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class BGPPeerRegistryProvider extends ProviderTrait<BGPPeerRegistry> {
+ private static final Logger LOG = LoggerFactory.getLogger(BGPPeerRegistryProvider.class);
+ private static final String PEERS_CFG = "/bgp-peers.json";
+ @Inject
+ private BindingToNormalizedNodeCodec codec;
+ @Inject
+ private RIB globalRib;
+ @Inject
+ private BGPOpenConfigMappingService mappingService;
+ @Inject
+ private SchemaService schemaService;
+
+ @Override
+ protected BGPPeerRegistry create() {
+ final BGPPeerRegistry peerRegistry = StrictBGPPeerRegistry.instance();
+ final Neighbors neighbors = readNeighbours();
+ for (final Neighbor neighbor : neighbors.getNeighbor()) {
+ if (isApplicationPeer(neighbor)) {
+ LOG.trace("Starting AppPeer for {}", neighbor);
+ new AppPeer().start(globalRib, neighbor, mappingService, null);
+ } else {
+ LOG.trace("Starting BgpPeer for {}", neighbor);
+ new BgpPeer(null, peerRegistry).start(globalRib, neighbor, mappingService, null);
+ }
+ }
+ LOG.debug("Created BGPPeerRegistry with neighbours {}", neighbors);
+ return peerRegistry;
+ }
+
+ private Neighbors readNeighbours() {
+ LOG.debug("Reading BGP neighbours from {}", PEERS_CFG);
+ final InputStream resourceStream = this.getClass().getResourceAsStream(PEERS_CFG);
+ checkState(resourceStream != null, "Resource %s not found", PEERS_CFG);
+
+ final InstanceIdentifier<Bgp> bgpII = InstanceIdentifier.create(NetworkInstances.class)
+ .child(NetworkInstance.class, new NetworkInstanceKey("dummy-value")).child(Protocols.class)
+ .child(Protocol.class, new ProtocolKey(BGP.class, "dummy-value")).augmentation(Protocol1.class)
+ .child(Bgp.class);
+ final InstanceIdentifier<Neighbors> neighborsII = bgpII.child(Neighbors.class);
+
+ final YangInstanceIdentifier neighborsYII = codec.toYangInstanceIdentifier(neighborsII);
+ final SchemaContext schemaContext = schemaService.getGlobalContext();
+ final Optional<DataNodeContainer> parentNode = findDataNodeContainer(schemaContext, bgpII);
+ final ContainerNode parentContainer = readContainerEntryJson(schemaContext, resourceStream,
+ (SchemaNode) parentNode.get(),
+ (YangInstanceIdentifier.NodeIdentifier) neighborsYII.getLastPathArgument());
+ final NormalizedNode<?, ?> neighborsContainer = parentContainer.getValue().iterator().next();
+
+ final Map.Entry<InstanceIdentifier<?>, DataObject> entry = codec.fromNormalizedNode(neighborsYII, neighborsContainer);
+ checkNotNull(entry, "Failed to deserialize neighbours configuration at %s", PEERS_CFG);
+ return (Neighbors) entry.getValue();
+ }
+
+ private static boolean isApplicationPeer(@Nonnull final Neighbor neighbor) {
+ return java.util.Optional.of(neighbor.getConfig())
+ .map(config -> config.getAugmentation(Config2.class))
+ .map(BgpNeighborPeerGroupConfig::getPeerGroup)
+ .map(APPLICATION_PEER_GROUP_NAME::equals)
+ .orElse(false);
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpConfiguration.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpConfiguration.java
new file mode 100644
index 000000000..9182dd3a0
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpConfiguration.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.common.base.MoreObjects;
+import java.util.Optional;
+import net.jmob.guice.conf.core.BindConfig;
+import net.jmob.guice.conf.core.InjectConfig;
+import net.jmob.guice.conf.core.Syntax;
+
+/**
+ * This is the Java equivalent for bgp.json file. We use guice-config library to load all the config attributes
+ * into this class instance.
+ *
+ * The BindConfig annotation tells that bgp.json file should be looked up on classpath root.
+ */
+@BindConfig(value = "bgp", syntax = Syntax.JSON)
+public class BgpConfiguration {
+
+ public boolean isBgpEnabled() {
+ return Boolean.valueOf(bgpEnabled);
+ }
+
+ public boolean isBgpMultiplePathsEnabled() {
+ return Boolean.valueOf(bgpMultiplePaths.get());
+ }
+
+ @InjectConfig("bgp-enabled")
+ public String bgpEnabled;
+ @InjectConfig("bgp-binding-address")
+ public Optional<String> bgpBindingAddress;
+ @InjectConfig("bgp-port")
+ public Optional<Integer> bgpPort;
+ @InjectConfig("bgp-as-number")
+ public Optional<Integer> bgpAsNumber;
+ @InjectConfig("bgp-receive-multiple-paths")
+ public Optional<String> bgpMultiplePaths;
+ @InjectConfig("bgp-send-max-paths")
+ public Optional<Integer> bgpSendMaxMaths;
+ @InjectConfig("bgp-netty-threads")
+ public Integer bgpNettyThreads;
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("bgpEnabled", bgpEnabled)
+ .add("bgpBindingAddress", bgpBindingAddress)
+ .add("bgpPort", bgpPort)
+ .add("bgp-as-number", bgpAsNumber)
+ .add("bgp-netty-threads", bgpNettyThreads)
+ .add("bgp-receive-multiple-paths", bgpMultiplePaths)
+ .add("bgp-send-max-paths", bgpSendMaxMaths)
+ .toString();
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpConfigurationModule.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpConfigurationModule.java
new file mode 100644
index 000000000..a1c2e765b
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpConfigurationModule.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.inject.AbstractModule;
+import net.jmob.guice.conf.core.ConfigurationModule;
+
+/**
+ * Load the configuration from json into HoneycombConfiguration and make it available.
+ */
+public class BgpConfigurationModule extends AbstractModule {
+
+ protected void configure() {
+ install(ConfigurationModule.create());
+ // Inject non-dependency configuration
+ requestInjection(BgpConfiguration.class);
+ }
+
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpExtensionsModule.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpExtensionsModule.java
new file mode 100644
index 000000000..461fb8918
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpExtensionsModule.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import org.opendaylight.protocol.bgp.parser.spi.BGPExtensionConsumerContext;
+import org.opendaylight.protocol.bgp.parser.spi.BGPExtensionProviderActivator;
+import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
+import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionProviderActivator;
+
+/**
+ * Registers BGP extensions provided by ODL implementation.
+ * TODO add support for flowspec (requires some special initialization)
+ */
+public final class BgpExtensionsModule extends AbstractModule {
+
+ protected void configure() {
+ // This should be part of BgpModule, but that one is Private and Multibinders + private BASE_MODULES
+ // do not work together, that's why there's a dedicated module here
+ // https://github.com/google/guice/issues/906
+ configureRIBExtensions();
+ configureBGPExtensions();
+ }
+
+ private void configureRIBExtensions() {
+ final Multibinder<RIBExtensionProviderActivator> ribExtensionBinder = Multibinder.newSetBinder(binder(),
+ RIBExtensionProviderActivator.class);
+ ribExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.evpn.impl.RIBActivator.class);
+ ribExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.inet.RIBActivator.class);
+ ribExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.labeled.unicast.RIBActivator.class);
+ ribExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.linkstate.impl.RIBActivator.class);
+ ribExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.l3vpn.ipv4.RibIpv4Activator.class);
+ ribExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.l3vpn.ipv6.RibIpv6Activator.class);
+ bind(RIBExtensionConsumerContext.class).toProvider(RIBExtensionConsumerContextProvider.class);
+ }
+
+ private void configureBGPExtensions() {
+ final Multibinder<BGPExtensionProviderActivator> bgpExtensionBinder = Multibinder.newSetBinder(binder(),
+ BGPExtensionProviderActivator.class);
+ bgpExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.parser.impl.BGPActivator.class);
+ bgpExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.evpn.impl.BGPActivator.class);
+ bgpExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.inet.BGPActivator.class);
+ bgpExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.labeled.unicast.BGPActivator.class);
+ bgpExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.linkstate.impl.BGPActivator.class);
+ bgpExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.l3vpn.ipv4.BgpIpv4Activator.class);
+ bgpExtensionBinder.addBinding().to(org.opendaylight.protocol.bgp.l3vpn.ipv6.BgpIpv6Activator.class);
+ bind(BGPExtensionConsumerContext.class).toProvider(BGPExtensionConsumerContextProvider.class);
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpModule.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpModule.java
new file mode 100644
index 000000000..128e9f0de
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpModule.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import static io.fd.honeycomb.infra.distro.data.InmemoryDOMDataBrokerProvider.CONFIG;
+import static io.fd.honeycomb.infra.distro.data.InmemoryDOMDataBrokerProvider.OPERATIONAL;
+
+import com.google.inject.PrivateModule;
+import com.google.inject.Singleton;
+import com.google.inject.name.Names;
+import io.fd.honeycomb.infra.distro.data.BindingDataBrokerProvider;
+import io.fd.honeycomb.infra.distro.data.DataStoreProvider;
+import io.fd.honeycomb.infra.distro.data.InmemoryDOMDataBrokerProvider;
+import io.netty.channel.EventLoopGroup;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
+import org.opendaylight.protocol.bgp.openconfig.impl.BGPOpenConfigMappingServiceImpl;
+import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigMappingService;
+import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
+import org.opendaylight.protocol.bgp.rib.impl.spi.BGPPeerRegistry;
+import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
+
+public final class BgpModule extends PrivateModule {
+
+ static final String HONEYCOMB_BGP = "honeycomb-bgp";
+
+ protected void configure() {
+ // Create BGPDispatcher BGPDispatcher for creating BGP clients
+ bind(EventLoopGroup.class).toProvider(BgpNettyThreadGroupProvider.class).in(Singleton.class);
+ bind(BGPDispatcher.class).toProvider(BGPDispatcherImplProvider.class).in(Singleton.class);
+
+ configureRIB();
+
+ // Configure peer registry
+ bind(BGPOpenConfigMappingService.class).toInstance(new BGPOpenConfigMappingServiceImpl());
+ bind(BGPPeerRegistry.class).toProvider(BGPPeerRegistryProvider.class);
+
+ // Create BGP server instance
+ bind(BgpServerProvider.BgpServer.class).toProvider(BgpServerProvider.class).in(Singleton.class);
+ expose(BgpServerProvider.BgpServer.class);
+ }
+
+ private void configureRIB() {
+ // Create inmemory config data store for HONEYCOMB_BGP
+ bind(InMemoryDOMDataStore.class).annotatedWith(Names.named(CONFIG))
+ .toProvider(new DataStoreProvider(CONFIG, LogicalDatastoreType.CONFIGURATION))
+ .in(Singleton.class);
+
+ // Create inmemory operational data store for HONEYCOMB_BGP
+ bind(InMemoryDOMDataStore.class).annotatedWith(Names.named(OPERATIONAL))
+ .toProvider(new DataStoreProvider(OPERATIONAL, LogicalDatastoreType.OPERATIONAL))
+ .in(Singleton.class);
+
+ // Wrap datastores as DOMDataBroker
+ // TODO make executor service configurable
+ bind(DOMDataBroker.class).toProvider(InmemoryDOMDataBrokerProvider.class).in(Singleton.class);
+
+ // Wrap DOMDataBroker as BA data broker (required by BgpReaderFactoryProvider)
+ bind(DataBroker.class).annotatedWith(Names.named(HONEYCOMB_BGP)).toProvider(BindingDataBrokerProvider.class)
+ .in(Singleton.class);
+ expose(DataBroker.class).annotatedWith(Names.named(HONEYCOMB_BGP));
+
+ // Create RIB instance
+ bind(RIB.class).toProvider(BgpRIBProvider.class).in(Singleton.class);
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpNettyThreadGroupProvider.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpNettyThreadGroupProvider.java
new file mode 100644
index 000000000..8208a4320
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpNettyThreadGroupProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.google.inject.Inject;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+import io.netty.channel.nio.NioEventLoopGroup;
+
+final class BgpNettyThreadGroupProvider extends ProviderTrait<NioEventLoopGroup> {
+
+ @Inject
+ private BgpConfiguration cfgAttributes;
+
+ @Override
+ protected NioEventLoopGroup create() {
+ return new NioEventLoopGroup(cfgAttributes.bgpNettyThreads,
+ new ThreadFactoryBuilder().setNameFormat("bgp-netty-%d").build());
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpRIBProvider.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpRIBProvider.java
new file mode 100644
index 000000000..11ee4cf8d
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpRIBProvider.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.common.collect.ImmutableList;
+import com.google.inject.Inject;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.broker.impl.PingPongDataBroker;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
+import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigMappingService;
+import org.opendaylight.protocol.bgp.rib.impl.RIBImpl;
+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.RIBExtensionConsumerContext;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafi;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafiBuilder;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.IPV4UNICAST;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.AfiSafi2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.AfiSafi2Builder;
+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.rib.TablesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class BgpRIBProvider extends ProviderTrait<RIB> {
+ private static final Logger LOG = LoggerFactory.getLogger(BgpRIBProvider.class);
+ private static final String HC_BGP_INSTANCE_NAME = "hc-bgp-instance";
+
+ @Inject
+ private BgpConfiguration cfg;
+ @Inject
+ private RIBExtensionConsumerContext extensions;
+ @Inject
+ private BGPDispatcher dispatcher;
+ @Inject
+ private BindingToNormalizedNodeCodec codec;
+ @Inject
+ private DOMDataBroker domBroker;
+ @Inject
+ private BGPOpenConfigMappingService mappingService;
+ @Inject
+ private SchemaService schemaService;
+
+ @Override
+ protected RIB create() {
+ final AsNumber asNumber = new AsNumber(cfg.bgpAsNumber.get().longValue());
+ final Ipv4Address routerId = new Ipv4Address(cfg.bgpBindingAddress.get());
+ final ClusterIdentifier clusterId = new ClusterIdentifier(routerId);
+ LOG.debug("Creating BGP RIB: routerId={}, asNumber={}", routerId, asNumber);
+ // TODO configure other BGP Multiprotocol extensions:
+ final List<AfiSafi> afiSafi = ImmutableList.of(new AfiSafiBuilder().setAfiSafiName(IPV4UNICAST.class)
+ .addAugmentation(AfiSafi2.class,
+ new AfiSafi2Builder().setReceive(cfg.isBgpMultiplePathsEnabled())
+ .setSendMax(cfg.bgpSendMaxMaths.get().shortValue()).build())
+ .build());
+ final Map<TablesKey, PathSelectionMode> pathSelectionModes = mappingService.toPathSelectionMode(afiSafi)
+ .entrySet().stream().collect(Collectors.toMap(entry ->
+ new TablesKey(entry.getKey().getAfi(), entry.getKey().getSafi()), Map.Entry::getValue));
+ // based on RIBImpl.createRib
+ final RIBImpl rib =
+ new RIBImpl(new NoopClusterSingletonServiceProvider(), new RibId(HC_BGP_INSTANCE_NAME), asNumber,
+ new BgpId(routerId), clusterId, extensions, dispatcher, codec, new PingPongDataBroker(domBroker),
+ mappingService.toTableTypes(afiSafi), pathSelectionModes, extensions.getClassLoadingStrategy(), null);
+
+ // required for proper RIB's CodecRegistry initialization (based on RIBImpl.start)
+ schemaService.registerSchemaContextListener(rib);
+
+ LOG.debug("BGP RIB created successfully: {}", rib);
+ return rib;
+ }
+
+ /**
+ * HC does not support clustering, but BGP uses {@link ClusterSingletonServiceProvider}
+ * to initialize {@link RIBImpl}. Therefore we provide this dummy implementation.
+ */
+ private static final class NoopClusterSingletonServiceProvider implements ClusterSingletonServiceProvider {
+ private static final Logger LOG = LoggerFactory.getLogger(NoopClusterSingletonServiceProvider.class);
+
+ private static final ClusterSingletonServiceRegistration REGISTRATION =
+ () -> LOG.debug("Closing ClusterSingletonServiceRegistration");
+
+ @Override
+ public ClusterSingletonServiceRegistration registerClusterSingletonService(
+ final ClusterSingletonService clusterSingletonService) {
+ clusterSingletonService.instantiateServiceInstance();
+ return REGISTRATION;
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.debug("Closing NoopClusterSingletonServiceProvider");
+ }
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpReaderFactoryProvider.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpReaderFactoryProvider.java
new file mode 100644
index 000000000..b79074f10
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpReaderFactoryProvider.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.honeycomb.translate.util.read.BindingBrokerReader;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+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.BgpRibBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+final class BgpReaderFactoryProvider extends ProviderTrait<ReaderFactory> {
+
+ @Inject
+ @Named(BgpModule.HONEYCOMB_BGP)
+ private DataBroker bgpDataBroker;
+
+ @Override
+ protected BgpReaderFactory create() {
+ return new BgpReaderFactory(bgpDataBroker);
+ }
+
+ /**
+ * {@link ReaderFactory} provides reader form BGP's dedicated data store.
+ * Makes BGP operational data available over NETCONF/RESTCONF.
+ */
+ private static final class BgpReaderFactory implements ReaderFactory {
+
+ private final DataBroker bgpDataBroker;
+
+ BgpReaderFactory(final DataBroker bgpDataBroker) {
+ this.bgpDataBroker = bgpDataBroker;
+ }
+
+ @Override
+ public void init(final ModifiableReaderRegistryBuilder registry) {
+ registry.add(new BindingBrokerReader<>(InstanceIdentifier.create(BgpRib.class),
+ bgpDataBroker, LogicalDatastoreType.OPERATIONAL, BgpRibBuilder.class));
+ }
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpReadersModule.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpReadersModule.java
new file mode 100644
index 000000000..745a94269
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpReadersModule.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Singleton;
+import com.google.inject.multibindings.Multibinder;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+
+public class BgpReadersModule extends AbstractModule {
+
+ protected void configure() {
+ // This should be part of BgpModule, but that one is Private and Multibinders + private BASE_MODULES
+ // do not work together, that's why there's a dedicated module here
+ // https://github.com/google/guice/issues/906
+ final Multibinder<ReaderFactory> binder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
+ binder.addBinding().toProvider(BgpReaderFactoryProvider.class).in(Singleton.class);
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpServerProvider.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpServerProvider.java
new file mode 100644
index 000000000..27dad8840
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpServerProvider.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.common.base.Preconditions;
+import com.google.inject.Inject;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelConfig;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.epoll.Epoll;
+import io.netty.channel.epoll.EpollChannelOption;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
+import org.opendaylight.protocol.bgp.rib.impl.spi.BGPPeerRegistry;
+import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
+import org.opendaylight.protocol.bgp.rib.impl.spi.PeerRegistryListener;
+import org.opendaylight.protocol.concepts.KeyMapping;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class BgpServerProvider extends ProviderTrait<BgpServerProvider.BgpServer> {
+ private static final Logger LOG = LoggerFactory.getLogger(BgpServerProvider.class);
+ @Inject
+ private BgpConfiguration cfg;
+ @Inject
+ private BGPPeerRegistry peerRegistry;
+ @Inject
+ private BGPDispatcher dispatcher;
+
+ @Override
+ protected BgpServer create() {
+ // code based on org.opendaylight.controller.config.yang.bgp.rib.impl.BGPPeerAcceptorModule from Boron-SR3
+ final InetAddress bindingAddress;
+ try {
+ bindingAddress = InetAddress.getByName(cfg.bgpBindingAddress.get());
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Illegal BGP binding address", e);
+ }
+ final InetSocketAddress address = new InetSocketAddress(bindingAddress, cfg.bgpPort.get());
+ LOG.debug("Creating BgpServer for {}", address);
+ final ChannelFuture localServer = dispatcher.createServer(peerRegistry, address);
+ localServer.addListener(future -> {
+ Preconditions.checkArgument(future.isSuccess(), "Unable to start bgp server on %s", address, future.cause());
+ final Channel channel = localServer.channel();
+ if (Epoll.isAvailable()) {
+ peerRegistry.registerPeerRegisterListener(new PeerRegistryListenerImpl(channel.config()));
+ }
+ });
+ final BgpServer server = new BgpServer(localServer);
+ LOG.debug("BgpServer successfully created.");
+ return server;
+ }
+
+ public static final class BgpServer {
+ private ChannelFuture localServer;
+
+ BgpServer(final ChannelFuture localServer) {
+ this.localServer = localServer;
+ }
+
+ public ChannelFuture getLocalServer() {
+ return localServer;
+ }
+ }
+
+ private static final class PeerRegistryListenerImpl implements PeerRegistryListener {
+ private final ChannelConfig channelConfig;
+ private final KeyMapping keys;
+
+ PeerRegistryListenerImpl(final ChannelConfig channelConfig) {
+ this.channelConfig = channelConfig;
+ this.keys = KeyMapping.getKeyMapping();
+ }
+ @Override
+ public void onPeerAdded(final IpAddress ip, final BGPSessionPreferences prefs) {
+ if (prefs.getMd5Password().isPresent()) {
+ this.keys.put(IetfInetUtil.INSTANCE.inetAddressFor(ip), prefs.getMd5Password().get());
+ this.channelConfig.setOption(EpollChannelOption.TCP_MD5SIG, this.keys);
+ }
+ }
+ @Override
+ public void onPeerRemoved(final IpAddress ip) {
+ if (this.keys.remove(IetfInetUtil.INSTANCE.inetAddressFor(ip)) != null) {
+ this.channelConfig.setOption(EpollChannelOption.TCP_MD5SIG, this.keys);
+ }
+ }
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpWriterFactoryProvider.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpWriterFactoryProvider.java
new file mode 100644
index 000000000..081fbd782
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpWriterFactoryProvider.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+import io.fd.honeycomb.translate.util.write.BindingBrokerWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.routes.Ipv4Routes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.routes.ipv4.routes.Ipv4Route;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Attributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.LocalPref;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.Origin;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.ApplicationRib;
+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.types.rev130919.next.hop.c.next.hop.ipv4.next.hop._case.Ipv4NextHop;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+final class BgpWriterFactoryProvider extends ProviderTrait<WriterFactory> {
+ @Inject
+ @Named(BgpModule.HONEYCOMB_BGP)
+ private DataBroker bgpDataBroker;
+ @Override
+ protected BgpWriterFactory create() {
+ return new BgpWriterFactory(bgpDataBroker);
+ }
+
+ /**
+ * {@link WriterFactory} for BGP cfg write integration with HC writer registry.
+ * Using BindingBrokerWriter to write BGP configuration data via dedicated broker that, unlike
+ * {@link io.fd.honeycomb.data.impl.DataBroker}, supports tx chains and DOMDataChangeListener registration
+ * extensively used by ODL's bgp.
+ *
+ * As a bonus BGP route configuration is persisted and available for read via RESTCONF/NETCONF.
+ */
+ private static final class BgpWriterFactory implements WriterFactory {
+ private final DataBroker dataBroker;
+
+ private static final InstanceIdentifier<ApplicationRib> AR_IID =
+ InstanceIdentifier.create(ApplicationRib.class);
+ private static final InstanceIdentifier<Tables> TABLES_IID = AR_IID.child(Tables.class);
+ private static final InstanceIdentifier<Ipv4Routes> IPV4_ROUTES_IID = TABLES_IID.child((Class) Ipv4Routes.class);
+ private static final InstanceIdentifier<Ipv4Route> IPV4_ROUTE_IID = IPV4_ROUTES_IID.child(Ipv4Route.class);
+
+ private BgpWriterFactory(final DataBroker dataBroker) {
+ this.dataBroker = dataBroker;
+ }
+
+ // TODO (HONEYCOMB-359):
+ // BGP models are huge, we need some kind of wildcarded subtree writer, that works for whole subtree.
+ // 1) we can either move checking handledTypes to writers (getHandledTypes, isAffected, writer.getHandedTypes, ...)
+ // but then precondition check in flatWriterRegistry might be slower (we need to check if we have all writers
+ // in order to avoid unnecessary reverts).
+ //
+ // 2) alternative is to compute all child nodes during initialization (might introduce some footprint penalty).
+ @Override
+ public void init(final ModifiableWriterRegistryBuilder registry) {
+ registry.subtreeAdd(
+ Sets.newHashSet(
+ TABLES_IID,
+ IPV4_ROUTES_IID,
+ IPV4_ROUTES_IID.child(Ipv4Route.class),
+ IPV4_ROUTE_IID.child(Attributes.class),
+ IPV4_ROUTE_IID.child(Attributes.class).child(Origin.class),
+ IPV4_ROUTE_IID.child(Attributes.class).child(LocalPref.class),
+ IPV4_ROUTE_IID.child(Attributes.class).child(Ipv4NextHop.class)
+ ),
+ new BindingBrokerWriter<>(InstanceIdentifier.create(ApplicationRib.class), dataBroker)
+ );
+ }
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpWritersModule.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpWritersModule.java
new file mode 100644
index 000000000..f1e92c4ba
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/BgpWritersModule.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Singleton;
+import com.google.inject.multibindings.Multibinder;
+import io.fd.honeycomb.translate.write.WriterFactory;
+
+public class BgpWritersModule extends AbstractModule {
+
+ protected void configure() {
+ // This should be part of BgpModule, but that one is Private and Multibinders + private BASE_MODULES
+ // do not work together, that's why there's a dedicated module here
+ // https://github.com/google/guice/issues/906
+ final Multibinder<WriterFactory> binder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+ binder.addBinding().toProvider(BgpWriterFactoryProvider.class).in(Singleton.class);
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/RIBExtensionConsumerContextProvider.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/RIBExtensionConsumerContextProvider.java
new file mode 100644
index 000000000..b90b7880c
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/RIBExtensionConsumerContextProvider.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp;
+
+import com.google.inject.Inject;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+import java.util.ArrayList;
+import java.util.Set;
+import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
+import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionProviderActivator;
+import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionProviderContext;
+import org.opendaylight.protocol.bgp.rib.spi.SimpleRIBExtensionProviderContext;
+import org.opendaylight.protocol.bgp.rib.spi.SimpleRIBExtensionProviderContextActivator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RIBExtensionConsumerContextProvider extends ProviderTrait<RIBExtensionConsumerContext> {
+ private static final Logger LOG = LoggerFactory.getLogger(RIBExtensionConsumerContextProvider.class);
+ @Inject
+ private Set<RIBExtensionProviderActivator> activators;
+
+ @Override
+ protected RIBExtensionConsumerContext create() {
+ final RIBExtensionProviderContext ctx = new SimpleRIBExtensionProviderContext();
+ final SimpleRIBExtensionProviderContextActivator activator =
+ new SimpleRIBExtensionProviderContextActivator(ctx, new ArrayList<>(activators));
+ LOG.debug("Starting RIBExtensionConsumerContext with activators: {}", activators);
+ activator.start();
+ return ctx;
+ }
+}
diff --git a/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/distro/Main.java b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/distro/Main.java
new file mode 100644
index 000000000..0204e1f5c
--- /dev/null
+++ b/infra/bgp-distribution/src/main/java/io/fd/honeycomb/infra/bgp/distro/Main.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp.distro;
+
+import static io.fd.honeycomb.infra.distro.ActiveModuleProvider.STANDARD_MODULES_RELATIVE_PATH;
+import static io.fd.honeycomb.infra.distro.ActiveModuleProvider.aggregateResources;
+import static io.fd.honeycomb.infra.distro.ActiveModuleProvider.loadActiveModules;
+
+import com.google.inject.ConfigurationException;
+import com.google.inject.CreationException;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.ProvisionException;
+import io.fd.honeycomb.infra.bgp.BgpConfiguration;
+import io.fd.honeycomb.infra.bgp.BgpServerProvider;
+import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class Main {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Main.class);
+
+ private Main() {
+ }
+
+ public static void main(String[] args) {
+ final ClassLoader classLoader = Main.class.getClassLoader();
+ init(loadActiveModules(aggregateResources(STANDARD_MODULES_RELATIVE_PATH, classLoader)));
+ }
+
+ /**
+ * Initialize the Honeycomb with provided modules
+ */
+ public static Injector init(final Set<? extends Module> modules) {
+ try {
+ Injector injector = io.fd.honeycomb.infra.distro.Main.init(modules);
+ final BgpConfiguration bgpAttributes = injector.getInstance(BgpConfiguration.class);
+
+ if (bgpAttributes.isBgpEnabled()) {
+ LOG.info("Starting BGP");
+ injector.getInstance(BgpServerProvider.BgpServer.class);
+ LOG.info("BGP started successfully!");
+ }
+
+ return injector;
+ } catch (CreationException | ProvisionException | ConfigurationException e) {
+ LOG.error("Failed to initialize Honeycomb components", e);
+ throw e;
+ } catch (RuntimeException e) {
+ LOG.error("Unexpected initialization failure", e);
+ throw e;
+ } finally {
+ // Trigger gc to force collect initial garbage + dedicated classloader
+ System.gc();
+ }
+ }
+
+}
diff --git a/infra/bgp-distribution/src/main/resources/honeycomb-minimal-resources/config/bgp-peers.json b/infra/bgp-distribution/src/main/resources/honeycomb-minimal-resources/config/bgp-peers.json
new file mode 100644
index 000000000..6de2065b8
--- /dev/null
+++ b/infra/bgp-distribution/src/main/resources/honeycomb-minimal-resources/config/bgp-peers.json
@@ -0,0 +1,48 @@
+{
+ "bgp-openconfig-extensions:neighbors": {
+ "neighbor": [
+ {
+ "neighbor-address": "10.25.1.9",
+ "config": {
+ "peer-group": "application-peers"
+ },
+ "afi-safis": {
+ "afi-safi": [
+ {
+ "afi-safi-name": "openconfig-bgp-types:IPV4-UNICAST",
+ "receive": true,
+ "send-max": 0
+ }
+ ]
+ }
+ },
+ {
+ "neighbor-address": "127.0.0.2",
+ "config": {
+ "peer-type": "INTERNAL"
+ },
+ "timers": {
+ "config": {
+ "connect-retry": 10,
+ "hold-time": 90
+ }
+ },
+ "transport": {
+ "config": {
+ "remote-port": 17900,
+ "passive-mode": false
+ }
+ },
+ "afi-safis": {
+ "afi-safi": [
+ {
+ "afi-safi-name": "openconfig-bgp-types:IPV4-UNICAST",
+ "receive": true,
+ "send-max": 0
+ }
+ ]
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/infra/bgp-distribution/src/main/resources/honeycomb-minimal-resources/config/bgp.json b/infra/bgp-distribution/src/main/resources/honeycomb-minimal-resources/config/bgp.json
new file mode 100644
index 000000000..2664c9ed6
--- /dev/null
+++ b/infra/bgp-distribution/src/main/resources/honeycomb-minimal-resources/config/bgp.json
@@ -0,0 +1,9 @@
+{
+ "bgp-enabled": "true",
+ "bgp-binding-address": "127.0.0.1",
+ "bgp-port": 1790,
+ "bgp-as-number": 65000,
+ "bgp-receive-multiple-paths": "true",
+ "bgp-send-max-paths": 0,
+ "bgp-netty-threads": 2
+} \ No newline at end of file
diff --git a/infra/bgp-distribution/src/test/java/io/fd/honeycomb/infra/bgp/distro/BgpDistributionTest.java b/infra/bgp-distribution/src/test/java/io/fd/honeycomb/infra/bgp/distro/BgpDistributionTest.java
new file mode 100644
index 000000000..095d61c39
--- /dev/null
+++ b/infra/bgp-distribution/src/test/java/io/fd/honeycomb/infra/bgp/distro/BgpDistributionTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.infra.bgp.distro;
+
+import static com.google.common.collect.ImmutableSet.of;
+
+import com.google.common.io.ByteStreams;
+import com.google.inject.Module;
+import com.mashape.unirest.http.Unirest;
+import io.fd.honeycomb.infra.bgp.BgpConfigurationModule;
+import io.fd.honeycomb.infra.bgp.BgpExtensionsModule;
+import io.fd.honeycomb.infra.bgp.BgpModule;
+import io.fd.honeycomb.infra.bgp.BgpReadersModule;
+import io.fd.honeycomb.infra.bgp.BgpWritersModule;
+import io.fd.honeycomb.infra.distro.cfgattrs.CfgAttrsModule;
+import io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule;
+import io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule;
+import io.fd.honeycomb.infra.distro.initializer.InitializerPipelineModule;
+import io.fd.honeycomb.infra.distro.netconf.NetconfModule;
+import io.fd.honeycomb.infra.distro.netconf.NetconfReadersModule;
+import io.fd.honeycomb.infra.distro.restconf.RestconfModule;
+import io.fd.honeycomb.infra.distro.schema.SchemaModule;
+import io.fd.honeycomb.infra.distro.schema.YangBindingProviderModule;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.Set;
+import javax.net.ssl.SSLContext;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.ssl.SSLContexts;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BgpDistributionTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(BgpDistributionTest.class);
+ private static final String CERT_PASSWORD = "testing";
+ private static final int HELLO_WAIT = 2500;
+
+ private static final int BGP_MSG_TYPE_OFFSET = 18; // 16 (MARKER) + 2 (LENGTH);
+ private static final byte BGP_OPEN_MSG_TYPE = 1;
+ private static final int BGP_PORT = 1790;
+
+ public static final Set<Module> BASE_MODULES = of(
+ new YangBindingProviderModule(),
+ new SchemaModule(),
+ new ConfigAndOperationalPipelineModule(),
+ new ContextPipelineModule(),
+ new InitializerPipelineModule(),
+ new NetconfModule(),
+ new NetconfReadersModule(),
+ new RestconfModule(),
+ new CfgAttrsModule(),
+ new BgpModule(),
+ new BgpExtensionsModule(),
+ new BgpReadersModule(),
+ new BgpWritersModule(),
+ new BgpConfigurationModule());
+
+ @Before
+ public void setUp() throws Exception {
+ SSLContext sslcontext = SSLContexts.custom()
+ .loadTrustMaterial(getClass().getResource("/honeycomb-keystore"),
+ CERT_PASSWORD.toCharArray(), new TrustSelfSignedStrategy())
+ .build();
+
+ SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext);
+ CloseableHttpClient httpclient = HttpClients.custom()
+ .setSSLSocketFactory(sslsf)
+ .build();
+ Unirest.setHttpClient(httpclient);
+ }
+
+ @Test(timeout = 60000)
+ public void test() throws Exception {
+ io.fd.honeycomb.infra.bgp.distro.Main.init(BASE_MODULES);
+ LOG.info("Testing Honeycomb BGP distribution");
+ assertBgp();
+ }
+
+ private byte[] readMessage(final InputStream inputStream) throws IOException {
+ final int available = inputStream.available();
+ final byte[] msg = new byte[available];
+ ByteStreams.read(inputStream, msg, 0, available);
+ return msg;
+ }
+
+ private void assertBgp() throws Exception {
+ // Wait until BGP server is started
+ Thread.sleep(HELLO_WAIT);
+ final InetAddress bgpHost = InetAddress.getByName("127.0.0.1");
+ final InetAddress bgpPeerAddress = InetAddress.getByName("127.0.0.2");
+ try (final Socket localhost = new Socket(bgpHost, BGP_PORT, bgpPeerAddress, 0);
+ final InputStream inputStream = localhost.getInputStream()) {
+ // Wait until bgp message is sent
+ Thread.sleep(HELLO_WAIT);
+
+ final byte[] msg = readMessage(inputStream);
+ LOG.info("Received BGP message: {}", msg);
+
+ Assert.assertEquals(BGP_OPEN_MSG_TYPE, msg[BGP_MSG_TYPE_OFFSET]);
+ }
+ }
+} \ No newline at end of file
diff --git a/infra/bgp-distribution/src/test/resources/WEB-INF/web.xml b/infra/bgp-distribution/src/test/resources/WEB-INF/web.xml
new file mode 100644
index 000000000..6cf487170
--- /dev/null
+++ b/infra/bgp-distribution/src/test/resources/WEB-INF/web.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ ~ Copyright (c) 2016 Cisco and/or its affiliates.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <servlet>
+ <servlet-name>JAXRSRestconf</servlet-name>
+ <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>javax.ws.rs.Application</param-name>
+ <param-value>org.opendaylight.netconf.sal.rest.impl.RestconfApplication</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>JAXRSRestconf</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+ <filter>
+ <filter-name>cross-origin-restconf</filter-name>
+ <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
+ <init-param>
+ <param-name>allowedOrigins</param-name>
+ <param-value>*</param-value>
+ </init-param>
+ <init-param>
+ <param-name>allowedMethods</param-name>
+ <param-value>GET,POST,OPTIONS,DELETE,PUT,HEAD</param-value>
+ </init-param>
+ <init-param>
+ <param-name>allowedHeaders</param-name>
+ <param-value>origin, content-type, accept, authorization</param-value>
+ </init-param>
+ <init-param>
+ <param-name>exposedHeaders</param-name>
+ <param-value>location</param-value>
+ </init-param>
+ </filter>
+ <filter-mapping>
+ <filter-name>cross-origin-restconf</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>NB api</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ <http-method>POST</http-method>
+ <http-method>GET</http-method>
+ <http-method>PUT</http-method>
+ <http-method>PATCH</http-method>
+ <http-method>DELETE</http-method>
+ <http-method>HEAD</http-method>
+ </web-resource-collection>
+ </security-constraint>
+
+</web-app>
diff --git a/infra/bgp-distribution/src/test/resources/bgp-peers.json b/infra/bgp-distribution/src/test/resources/bgp-peers.json
new file mode 100644
index 000000000..3a7e01060
--- /dev/null
+++ b/infra/bgp-distribution/src/test/resources/bgp-peers.json
@@ -0,0 +1,90 @@
+{
+ "bgp-openconfig-extensions:neighbors": {
+ "neighbor": [
+ {
+ "neighbor-address": "10.25.1.9",
+ "config": {
+ "peer-group": "application-peers"
+ },
+ "afi-safis": {
+ "afi-safi": [
+ {
+ "afi-safi-name": "openconfig-bgp-types:IPV4-UNICAST",
+ "receive": true,
+ "send-max": 0
+ }
+ ]
+ }
+ },
+ {
+ "neighbor-address": "10.25.1.10",
+ "config": {
+ "peer-group": "application-peers"
+ },
+ "afi-safis": {
+ "afi-safi": [
+ {
+ "afi-safi-name": "openconfig-bgp-types:IPV4-UNICAST",
+ "receive": true,
+ "send-max": 0
+ }
+ ]
+ }
+ },
+ {
+ "neighbor-address": "127.0.0.2",
+ "config": {
+ "peer-type": "INTERNAL"
+ },
+ "timers": {
+ "config": {
+ "connect-retry": 10,
+ "hold-time": 90
+ }
+ },
+ "transport": {
+ "config": {
+ "remote-port": 17900,
+ "passive-mode": false
+ }
+ },
+ "afi-safis": {
+ "afi-safi": [
+ {
+ "afi-safi-name": "openconfig-bgp-types:IPV4-UNICAST",
+ "receive": true,
+ "send-max": 0
+ }
+ ]
+ }
+ },
+ {
+ "neighbor-address": "127.0.0.3",
+ "config": {
+ "peer-type": "EXTERNAL"
+ },
+ "timers": {
+ "config": {
+ "connect-retry": 10,
+ "hold-time": 90
+ }
+ },
+ "transport": {
+ "config": {
+ "remote-port": 17900,
+ "passive-mode": false
+ }
+ },
+ "afi-safis": {
+ "afi-safi": [
+ {
+ "afi-safi-name": "openconfig-bgp-types:IPV4-UNICAST",
+ "receive": true,
+ "send-max": 0
+ }
+ ]
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/infra/bgp-distribution/src/test/resources/bgp.json b/infra/bgp-distribution/src/test/resources/bgp.json
new file mode 100644
index 000000000..494b6a965
--- /dev/null
+++ b/infra/bgp-distribution/src/test/resources/bgp.json
@@ -0,0 +1,9 @@
+ {
+ "bgp-enabled": "true",
+ "bgp-binding-address": "127.0.0.1",
+ "bgp-port": 1790,
+ "bgp-as-number": 65000,
+ "bgp-receive-multiple-paths": "true",
+ "bgp-send-max-paths": 0,
+ "bgp-netty-threads": 2
+} \ No newline at end of file
diff --git a/infra/bgp-distribution/src/test/resources/honeycomb-keystore b/infra/bgp-distribution/src/test/resources/honeycomb-keystore
new file mode 100644
index 000000000..44093dc09
--- /dev/null
+++ b/infra/bgp-distribution/src/test/resources/honeycomb-keystore
Binary files differ
diff --git a/infra/bgp-distribution/src/test/resources/honeycomb.json b/infra/bgp-distribution/src/test/resources/honeycomb.json
new file mode 100644
index 000000000..a0b2a633c
--- /dev/null
+++ b/infra/bgp-distribution/src/test/resources/honeycomb.json
@@ -0,0 +1,40 @@
+ {
+ "persisted-context-path": "/tmp/honeycomb/persist/context/data.json",
+ "persisted-context-restoration-type": "Merge",
+ "persisted-config-path": "/tmp/honeycomb/persist/config/data.json",
+ "persisted-config-restoration-type": "Merge",
+
+ "notification-service-queue-depth": 1,
+
+ "restconf-http-enabled": "true",
+ "restconf-root-path": "/restconf",
+ "restconf-binding-address": "127.0.0.1",
+ "restconf-port": 8182,
+ "restconf-https-enabled": "true",
+ "restconf-https-binding-address": "127.0.0.1",
+ "restconf-https-port": 8444,
+ "restconf-keystore": "/honeycomb-keystore",
+ "restconf-keystore-password": "testing",
+ "restconf-keystore-manager-password": "testing",
+ "restconf-truststore": "/honeycomb-keystore",
+ "restconf-truststore-password": "testing",
+ "restconf-websocket-port": 7780,
+ "restconf-pool-max-size": 10,
+ "restconf-pool-min-size": 1,
+ "restconf-acceptors-size": 1,
+ "restconf-selectors-size": 1,
+ "restconf-https-acceptors-size": 1,
+ "restconf-https-selectors-size": 1,
+
+ "netconf-netty-threads": 2,
+ "netconf-tcp-enabled" : "true",
+ "netconf-tcp-binding-address": "127.0.0.1",
+ "netconf-tcp-binding-port": 7778,
+ "netconf-ssh-enabled" : "true",
+ "netconf-ssh-binding-address": "127.0.0.1",
+ "netconf-ssh-binding-port": 2832,
+ "netconf-notification-stream-name": "honeycomb",
+
+ "username": "admin",
+ "password": "admin"
+} \ No newline at end of file
diff --git a/infra/bgp-distribution/src/test/resources/logback.xml b/infra/bgp-distribution/src/test/resources/logback.xml
new file mode 100644
index 000000000..2ee89db4e
--- /dev/null
+++ b/infra/bgp-distribution/src/test/resources/logback.xml
@@ -0,0 +1,31 @@
+ <!--
+ ~ Copyright (c) 2016 Cisco and/or its affiliates.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<configuration scan="true">
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{36} - %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <root level="warn">
+ <appender-ref ref="STDOUT" />
+ </root>
+
+ <logger name="org.opendaylight" level="INFO"/>
+ <logger name="io.fd" level="INFO"/>
+</configuration>