Bug 5061: Bgp Peer deployer 67/42267/14
authorMilos Fabian <milfabia@cisco.com>
Wed, 20 Jul 2016 14:20:39 +0000 (16:20 +0200)
committerRobert Varga <nite@hq.sk>
Wed, 10 Aug 2016 13:44:48 +0000 (13:44 +0000)
Extends BGP deployer to be capable to
instantiate BGPPeer instances based on
current OpenConfig Neighbor configurations.

Change-Id: If27e4551b7fc6db4c3c5dcf07028e5563d61e0dd
Signed-off-by: Milos Fabian <milfabia@cisco.com>
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/config/BgpDeployerImpl.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/config/BgpPeer.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/config/OpenConfigMappingUtil.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/spi/InstanceType.java
bgp/rib-impl/src/main/resources/org/opendaylight/blueprint/bgp-rib.xml
util/src/main/java/org/opendaylight/protocol/util/Ipv4Util.java

index 34348a46e587ec6479148c047e74fd1a5b881c71..b509eacd163921190a92be19a40d74b58104241a 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.protocol.bgp.rib.impl.config;
 
+import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getNeighborInstanceIdentifier;
 import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getRibInstanceName;
 
 import com.google.common.base.Optional;
@@ -35,8 +36,10 @@ import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFaile
 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigMappingService;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
 import org.opendaylight.protocol.bgp.rib.impl.spi.InstanceType;
+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.Global;
+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.NetworkInstanceBuilder;
@@ -66,6 +69,8 @@ public final class BgpDeployerImpl implements BgpDeployer, DataTreeChangeListene
     @GuardedBy("this")
     private final Map<InstanceIdentifier<Bgp>, RibImpl> ribs = new HashMap<>();
     @GuardedBy("this")
+    private final Map<InstanceIdentifier<Neighbor>, BgpPeer> peers = new HashMap<>();
+    @GuardedBy("this")
     private boolean closed;
 
     private final DataBroker dataBroker;
@@ -109,6 +114,8 @@ public final class BgpDeployerImpl implements BgpDeployer, DataTreeChangeListene
             for (final DataObjectModification<? extends DataObject> dataObjectModification : rootNode.getModifiedChildren()) {
                 if (dataObjectModification.getDataType().equals(Global.class)) {
                     onGlobalChanged((DataObjectModification<Global>) dataObjectModification, rootIdentifier);
+                } else if (dataObjectModification.getDataType().equals(Neighbors.class)) {
+                    onNeighborsChanged((DataObjectModification<Neighbors>) dataObjectModification, rootIdentifier);
                 }
             }
         }
@@ -122,6 +129,8 @@ public final class BgpDeployerImpl implements BgpDeployer, DataTreeChangeListene
     @Override
     public synchronized void close() throws Exception {
         this.registration.close();
+        this.peers.values().forEach(bgpPeer -> bgpPeer.close());
+        this.peers.clear();
         this.ribs.values().forEach(rib -> rib.close());
         this.ribs.clear();
         this.closed = true;
@@ -197,6 +206,56 @@ public final class BgpDeployerImpl implements BgpDeployer, DataTreeChangeListene
         registerRibInstance(ribImpl, ribInstanceName);
     }
 
+    private void onNeighborsChanged(final DataObjectModification<Neighbors> dataObjectModification,
+            final InstanceIdentifier<Bgp> rootIdentifier) {
+        for (final DataObjectModification<? extends DataObject> neighborModification : dataObjectModification.getModifiedChildren()) {
+            switch (neighborModification.getModificationType()) {
+            case DELETE:
+                onNeighborRemoved(rootIdentifier, (Neighbor) neighborModification.getDataBefore());
+                break;
+            case SUBTREE_MODIFIED:
+            case WRITE:
+                onNeighborModified(rootIdentifier, (Neighbor) neighborModification.getDataAfter());
+                break;
+            default:
+                break;
+            }
+        }
+    }
+
+    private void onNeighborModified(final InstanceIdentifier<Bgp> rootIdentifier, final Neighbor neighbor) {
+        LOG.debug("Modifing Peer instance with configuration: {}", neighbor);
+        //restart peer instance with a new configuration
+        final BgpPeer bgpPeer = this.peers.get(getNeighborInstanceIdentifier(rootIdentifier, neighbor.getKey()));
+        if (bgpPeer != null) {
+            bgpPeer.close();
+            bgpPeer.start(this.ribs.get(rootIdentifier), neighbor, this.mappingService);
+        } else {
+            //create new instance, if none is present
+            onNeighborCreated(rootIdentifier, neighbor);
+        }
+        LOG.debug("Peer instance modified {}", bgpPeer);
+    }
+
+    private void onNeighborCreated(final InstanceIdentifier<Bgp> rootIdentifier, final Neighbor neighbor) {
+        //create, start and register peer instance
+        LOG.debug("Creating Peer instance with configuration: {}", neighbor);
+        final BgpPeer bgpPeer = (BgpPeer) this.container.getComponentInstance(InstanceType.PEER.getBeanName());
+        bgpPeer.start(this.ribs.get(rootIdentifier), neighbor, this.mappingService);
+        this.peers.put(getNeighborInstanceIdentifier(rootIdentifier, neighbor.getKey()), bgpPeer);
+        LOG.debug("Peer instance created {}", bgpPeer);
+    }
+
+    private void onNeighborRemoved(final InstanceIdentifier<Bgp> rootIdentifier, final Neighbor neighbor) {
+        //destroy peer instance
+        LOG.debug("Removing Peer instance: {}", rootIdentifier);
+        final BgpPeer bgpPeer = this.peers.remove(getNeighborInstanceIdentifier(rootIdentifier, neighbor.getKey()));
+        if (bgpPeer != null) {
+            bgpPeer.close();
+            LOG.debug("Peer instance removed {}", bgpPeer);
+        }
+    }
+
     @Override
     public <T extends DataObject> ListenableFuture<Void> writeConfiguration(final T data,
             final InstanceIdentifier<T> identifier) {
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/config/BgpPeer.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/config/BgpPeer.java
new file mode 100644 (file)
index 0000000..6a12304
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.protocol.bgp.rib.impl.config;
+
+import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getHoldTimer;
+import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getPeerAs;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import io.netty.util.concurrent.Future;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigMappingService;
+import org.opendaylight.protocol.bgp.parser.BgpExtendedMessageUtil;
+import org.opendaylight.protocol.bgp.parser.spi.MultiprotocolCapabilitiesUtil;
+import org.opendaylight.protocol.bgp.rib.impl.BGPPeer;
+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.RIB;
+import org.opendaylight.protocol.concepts.KeyMapping;
+import org.opendaylight.protocol.util.Ipv4Util;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.BgpParameters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.BgpParametersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.OptionalCapabilities;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.OptionalCapabilitiesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.optional.capabilities.CParametersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.optional.capabilities.c.parameters.As4BytesCapabilityBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.CParameters1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.CParameters1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.AddPathCapabilityBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.MultiprotocolCapabilityBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.add.path.capability.AddressFamilies;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class BgpPeer implements AutoCloseable {
+
+    //FIXME make configurable
+    private static final PortNumber PORT = new PortNumber(179);
+
+    private static final Logger LOG = LoggerFactory.getLogger(BgpPeer.class);
+
+    private final RpcProviderRegistry rpcRegistry;
+    private final BGPPeerRegistry peerRegistry;
+    private BGPPeer bgpPeer;
+
+    private IpAddress neighborAddress;
+
+    private Future<Void> connection;
+
+    public BgpPeer(final RpcProviderRegistry rpcRegistry, final BGPPeerRegistry peerRegistry) {
+        this.rpcRegistry = rpcRegistry;
+        this.peerRegistry = peerRegistry;
+    }
+
+    public void start(final RIB rib, final Neighbor neighbor, final BGPOpenConfigMappingService mappingService) {
+        Preconditions.checkState(this.bgpPeer == null, "Previous peer instance {} was not closed.");
+        this.neighborAddress = neighbor.getNeighborAddress();
+        this.bgpPeer = new BGPPeer(Ipv4Util.toStringIP(this.neighborAddress), rib,
+                mappingService.toPeerRole(neighbor), this.rpcRegistry);
+        final List<BgpParameters> bgpParameters = getBgpParameters(neighbor, rib, mappingService);
+        final KeyMapping key = OpenConfigMappingUtil.getNeighborKey(neighbor);
+        final BGPSessionPreferences prefs = new BGPSessionPreferences(rib.getLocalAs(),
+                getHoldTimer(neighbor), rib.getBgpIdentifier(), getPeerAs(neighbor, rib), bgpParameters, getPassword(key));
+        this.peerRegistry.addPeer(this.neighborAddress, this.bgpPeer, prefs);
+        if (OpenConfigMappingUtil.isActive(neighbor)) {
+            this.connection = rib.getDispatcher().createReconnectingClient(
+                    Ipv4Util.toInetSocketAddress(this.neighborAddress, PORT), this.peerRegistry,
+                    OpenConfigMappingUtil.getRetryTimer(neighbor), Optional.fromNullable(key));
+        }
+
+    }
+
+    @Override
+    public void close() {
+        if (this.bgpPeer != null) {
+            if (this.connection != null) {
+                this.connection.cancel(true);
+                this.connection = null;
+            }
+            this.bgpPeer.close();
+            this.bgpPeer = null;
+            this.peerRegistry.removePeer(this.neighborAddress);
+            this.neighborAddress = null;
+        }
+    }
+
+    private static List<BgpParameters> getBgpParameters(final Neighbor neighbor, final RIB rib,
+            final BGPOpenConfigMappingService mappingService) {
+        final List<BgpParameters> tlvs = new ArrayList<>();
+        final List<OptionalCapabilities> caps = new ArrayList<>();
+        caps.add(new OptionalCapabilitiesBuilder().setCParameters(new CParametersBuilder().setAs4BytesCapability(
+                new As4BytesCapabilityBuilder().setAsNumber(rib.getLocalAs()).build()).build()).build());
+
+        caps.add(new OptionalCapabilitiesBuilder().setCParameters(BgpExtendedMessageUtil.EXTENDED_MESSAGE_CAPABILITY).build());
+        caps.add(new OptionalCapabilitiesBuilder().setCParameters(MultiprotocolCapabilitiesUtil.RR_CAPABILITY).build());
+
+        final List<AddressFamilies> addPathCapability = mappingService.toAddPathCapability(neighbor.getAfiSafis().getAfiSafi());
+        if (!addPathCapability.isEmpty()) {
+            caps.add(new OptionalCapabilitiesBuilder().setCParameters(new CParametersBuilder().addAugmentation(CParameters1.class,
+                    new CParameters1Builder().setAddPathCapability(
+                            new AddPathCapabilityBuilder().setAddressFamilies(addPathCapability).build()).build()).build()).build());
+        }
+
+        final List<BgpTableType> tableTypes = mappingService.toTableTypes(neighbor.getAfiSafis().getAfiSafi());
+        for (final BgpTableType tableType : tableTypes) {
+            if (!rib.getLocalTables().contains(tableType)) {
+                LOG.info("RIB instance does not list {} in its local tables. Incoming data will be dropped.", tableType);
+            }
+
+            caps.add(new OptionalCapabilitiesBuilder().setCParameters(
+                    new CParametersBuilder().addAugmentation(CParameters1.class,
+                            new CParameters1Builder().setMultiprotocolCapability(
+                                    new MultiprotocolCapabilityBuilder(tableType).build()).build()).build()).build());
+        }
+        tlvs.add(new BgpParametersBuilder().setOptionalCapabilities(caps).build());
+        return tlvs;
+    }
+
+    private static Optional<byte[]> getPassword(final KeyMapping key) {
+        if (key != null) {
+            return Optional.of(Iterables.getOnlyElement(key.values()));
+        }
+        return Optional.absent();
+    }
+
+}
index 51151fd6e7a1209f9234dc2fe3550b194a91b561..7cc62eaaab33ae065d8cd911eab82f5dbaf92ea7 100644 (file)
@@ -8,7 +8,16 @@
 
 package org.opendaylight.protocol.bgp.rib.impl.config;
 
+import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil.INSTANCE;
+
+import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
+import org.opendaylight.protocol.concepts.KeyMapping;
+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.neighbors.NeighborKey;
+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.network.instances.network.instance.protocols.Protocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 final class OpenConfigMappingUtil {
@@ -21,4 +30,37 @@ final class OpenConfigMappingUtil {
         return rootIdentifier.firstKeyOf(Protocol.class).getName();
     }
 
+    public static int getHoldTimer(final Neighbor neighbor) {
+        return neighbor.getTimers().getConfig().getHoldTime().intValue();
+    }
+
+    public static AsNumber getPeerAs(final Neighbor neighbor, final RIB rib) {
+        final AsNumber peerAs = neighbor.getConfig().getPeerAs();
+        if (peerAs != null) {
+            return peerAs;
+        }
+        return rib.getLocalAs();
+    }
+
+    public static boolean isActive(final Neighbor neighbor) {
+        return !neighbor.getTransport().getConfig().isPassiveMode();
+    }
+
+    public static int getRetryTimer(final Neighbor neighbor) {
+        return neighbor.getTimers().getConfig().getConnectRetry().intValue();
+    }
+
+    public static KeyMapping getNeighborKey(final Neighbor neighbor) {
+        final String authPassword = neighbor.getConfig().getAuthPassword();
+        if (authPassword != null) {
+            KeyMapping.getKeyMapping(INSTANCE.inetAddressFor(neighbor.getNeighborAddress()), authPassword);
+        }
+        return null;
+    }
+
+    public static InstanceIdentifier<Neighbor> getNeighborInstanceIdentifier(final InstanceIdentifier<Bgp> rootIdentifier,
+            final NeighborKey neighborKey) {
+        return rootIdentifier.child(Neighbors.class).child(Neighbor.class, neighborKey);
+    }
+
 }
index 000607216006e85920fa68ba13ca1d31c7e33500..965e86901f2ba9d820a319eb2592bee80e1b7729 100644 (file)
@@ -9,13 +9,16 @@
 package org.opendaylight.protocol.bgp.rib.impl.spi;
 
 import com.google.common.collect.Lists;
+import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 import org.opendaylight.protocol.bgp.rib.RibReference;
 
 public enum InstanceType {
 
-    RIB("ribImpl", Lists.newArrayList(RIB.class, RibReference.class));
+    RIB("ribImpl", Lists.newArrayList(RIB.class, RibReference.class)),
+
+    PEER("bgpPeer", Collections.emptyList());
 
     private final String beanName;
     private final String[] services;
index 71b14db9b9bfb006b1c2618e4610643b36897da6..ad6820fb62d144a581c04fa89347c99b9b9f4cec 100644 (file)
@@ -46,6 +46,7 @@
   <reference id="domDataBroker" interface="org.opendaylight.controller.md.sal.dom.api.DOMDataBroker"/>
   <reference id="bgpOpenConfigMappingService" interface="org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigMappingService"/>
   <reference id="schemaService" interface="org.opendaylight.controller.sal.core.api.model.SchemaService"/>
+  <reference id="rpcRegistry" interface="org.opendaylight.controller.sal.binding.api.RpcProviderRegistry"/>
 
   <bean id="bgpDeployer" class="org.opendaylight.protocol.bgp.rib.impl.config.BgpDeployerImpl">
     <argument value="global-bgp"/>
@@ -65,4 +66,9 @@
     <argument ref="schemaService"/>
   </bean>
 
-</blueprint>
+  <bean id="bgpPeer" class="org.opendaylight.protocol.bgp.rib.impl.config.BgpPeer" scope="prototype">
+    <argument ref="rpcRegistry"/>
+    <argument ref="BGPPeerRegistry"/>
+  </bean>
+
+</blueprint>
\ No newline at end of file
index 79fe31b2a149139ddb282289440e160ee68cba00..4eb674387feea4a05a4a1602af45f6282487b512 100644 (file)
@@ -219,12 +219,7 @@ public final class Ipv4Util {
      * @return InetSocketAddress
      */
     public static InetSocketAddress toInetSocketAddress(final IpAddress ipAddress, final PortNumber port) {
-        final String ipString;
-        if (ipAddress.getIpv4Address() != null) {
-            ipString = ipAddress.getIpv4Address().getValue();
-        } else {
-            ipString = ipAddress.getIpv6Address().getValue();
-        }
+        final String ipString = toStringIP(ipAddress);
         return new InetSocketAddress(InetAddresses.forString(ipString), port.getValue());
     }
 
@@ -252,4 +247,16 @@ public final class Ipv4Util {
         final Map.Entry<Ipv4Address, Integer> splitIpv4Prefix = IetfInetUtil.INSTANCE.splitIpv4Prefix(ipv4Prefix);
         return IetfInetUtil.INSTANCE.ipv4PrefixFor(incrementIpv4Address(splitIpv4Prefix.getKey()), splitIpv4Prefix.getValue());
     }
+
+    /**
+     * Get string representation of IpAddress
+     * @param ipAddress
+     * @return String value of Ipv4Address or Ipv6Address
+     */
+    public static String toStringIP(final IpAddress ipAddress) {
+        if (ipAddress.getIpv4Address() != null) {
+            return ipAddress.getIpv4Address().getValue();
+        }
+        return ipAddress.getIpv6Address().getValue();
+    }
 }