2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.protocol.bgp.peer.acceptor;
11 import com.google.common.base.Preconditions;
12 import io.netty.channel.Channel;
13 import io.netty.channel.ChannelConfig;
14 import io.netty.channel.ChannelFuture;
15 import io.netty.channel.epoll.Epoll;
16 import io.netty.channel.epoll.EpollChannelOption;
17 import io.netty.util.internal.PlatformDependent;
18 import java.net.InetAddress;
19 import java.net.InetSocketAddress;
20 import java.net.UnknownHostException;
21 import java.security.AccessControlException;
22 import javax.annotation.Nonnull;
23 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
24 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
25 import org.opendaylight.protocol.bgp.rib.impl.spi.PeerRegistryListener;
26 import org.opendaylight.protocol.concepts.KeyMapping;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
33 public final class BGPPeerAcceptorImpl implements AutoCloseable {
34 private static final Logger LOG = LoggerFactory.getLogger(BGPPeerAcceptorImpl.class);
35 private static final int PRIVILEGED_PORTS = 1024;
36 private final BGPDispatcher bgpDispatcher;
37 private final InetSocketAddress address;
38 private ChannelFuture futureChannel;
39 private AutoCloseable listenerRegistration;
41 public BGPPeerAcceptorImpl(final IpAddress bindingAddress, final PortNumber portNumber,
42 final BGPDispatcher bgpDispatcher) {
43 this.bgpDispatcher = Preconditions.checkNotNull(bgpDispatcher);
44 this.address = getAddress(Preconditions.checkNotNull(bindingAddress), Preconditions.checkNotNull(portNumber));
45 if (!PlatformDependent.isWindows() && !PlatformDependent.isRoot()
46 && portNumber.getValue() < PRIVILEGED_PORTS) {
47 throw new AccessControlException("Unable to bind port " + portNumber.getValue() +
48 " while running as non-root user.");
53 LOG.debug("Instantiating BGP Peer Acceptor : {}", this.address);
55 this.futureChannel = this.bgpDispatcher.createServer(this.address);
56 // Validate future success
57 this.futureChannel.addListener(future -> {
58 Preconditions.checkArgument(future.isSuccess(), "Unable to start bgp server on %s",
59 this.address, future.cause());
60 final Channel channel = this.futureChannel.channel();
61 if (Epoll.isAvailable()) {
62 this.listenerRegistration = this.bgpDispatcher.getBGPPeerRegistry().registerPeerRegisterListener(
63 new BGPPeerAcceptorImpl.PeerRegistryListenerImpl(channel.config()));
68 private static InetSocketAddress getAddress(final IpAddress ipAddress, final PortNumber portNumber) {
69 final InetAddress inetAddr;
71 inetAddr = InetAddress.getByName(ipAddress.getIpv4Address() != null ?
72 ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue());
73 } catch (final UnknownHostException e) {
74 throw new IllegalArgumentException("Illegal binding address " + ipAddress, e);
76 return new InetSocketAddress(inetAddr, portNumber.getValue());
80 * This closes the acceptor and no new bgp connections will be accepted
81 * Connections already established will be preserved
86 public void close() throws Exception {
87 this.futureChannel.cancel(true);
88 this.futureChannel.channel().close();
89 if (this.listenerRegistration != null) {
90 this.listenerRegistration.close();
94 private static final class PeerRegistryListenerImpl implements PeerRegistryListener {
95 private final ChannelConfig channelConfig;
96 private final KeyMapping keys;
98 PeerRegistryListenerImpl(final ChannelConfig channelConfig) {
99 this.channelConfig = channelConfig;
100 this.keys = KeyMapping.getKeyMapping();
104 public void onPeerAdded(@Nonnull final IpAddress ip, @Nonnull final BGPSessionPreferences prefs) {
105 if (prefs.getMd5Password().isPresent()) {
106 this.keys.put(IetfInetUtil.INSTANCE.inetAddressFor(ip), prefs.getMd5Password().get());
107 this.channelConfig.setOption(EpollChannelOption.TCP_MD5SIG, this.keys);
112 public void onPeerRemoved(@Nonnull final IpAddress ip) {
113 if (this.keys.remove(IetfInetUtil.INSTANCE.inetAddressFor(ip)) != null) {
114 this.channelConfig.setOption(EpollChannelOption.TCP_MD5SIG, this.keys);