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;
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;
@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;
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);
}
}
}
@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;
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) {
--- /dev/null
+/*
+ * 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();
+ }
+
+}
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 {
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);
+ }
+
}
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;
<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"/>
<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
* @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());
}
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();
+ }
}