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 static java.util.Objects.requireNonNull;
13 import com.google.common.base.Preconditions;
14 import io.netty.channel.Channel;
15 import io.netty.channel.ChannelConfig;
16 import io.netty.channel.ChannelFuture;
17 import io.netty.channel.epoll.Epoll;
18 import io.netty.channel.epoll.EpollChannelOption;
19 import io.netty.util.internal.PlatformDependent;
20 import java.net.InetAddress;
21 import java.net.InetSocketAddress;
22 import java.net.UnknownHostException;
23 import java.util.HashMap;
25 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
26 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
27 import org.opendaylight.protocol.bgp.rib.impl.spi.PeerRegistryListener;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressNoZone;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
31 import org.opendaylight.yangtools.concepts.Registration;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
35 public final class BGPPeerAcceptorImpl implements AutoCloseable {
36 private static final Logger LOG = LoggerFactory.getLogger(BGPPeerAcceptorImpl.class);
37 private static final int PRIVILEGED_PORTS = 1024;
38 private final BGPDispatcher bgpDispatcher;
39 private final InetSocketAddress address;
40 private ChannelFuture futureChannel;
41 private Registration listenerRegistration;
43 public BGPPeerAcceptorImpl(final IpAddressNoZone bindingAddress, final PortNumber portNumber,
44 final BGPDispatcher bgpDispatcher) {
45 this.bgpDispatcher = requireNonNull(bgpDispatcher);
46 address = getAddress(requireNonNull(bindingAddress), requireNonNull(portNumber));
47 if (!PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()
48 && portNumber.getValue().toJava() < PRIVILEGED_PORTS) {
49 throw new SecurityException("Unable to bind port " + portNumber.getValue()
50 + " while running as non-root user.");
55 LOG.debug("Instantiating BGP Peer Acceptor : {}", address);
57 futureChannel = bgpDispatcher.createServer(address);
58 // Validate future success
59 futureChannel.addListener(future -> {
60 Preconditions.checkArgument(future.isSuccess(), "Unable to start bgp server on %s",
61 address, future.cause());
62 final Channel channel = futureChannel.channel();
63 if (Epoll.isAvailable()) {
64 listenerRegistration = bgpDispatcher.getBGPPeerRegistry().registerPeerRegisterListener(
65 new BGPPeerAcceptorImpl.PeerRegistryListenerImpl(channel.config()));
70 private static InetSocketAddress getAddress(final IpAddressNoZone ipAddress, final PortNumber portNumber) {
71 final InetAddress inetAddr;
73 inetAddr = InetAddress.getByName(ipAddress.getIpv4AddressNoZone() != null
74 ? ipAddress.getIpv4AddressNoZone().getValue() : ipAddress.getIpv6AddressNoZone().getValue());
75 } catch (final UnknownHostException e) {
76 throw new IllegalArgumentException("Illegal binding address " + ipAddress, e);
78 return new InetSocketAddress(inetAddr, portNumber.getValue().toJava());
82 * This closes the acceptor and no new bgp connections will be accepted. Connections already established will be
87 futureChannel.cancel(true);
88 futureChannel.channel().close();
89 if (listenerRegistration != null) {
90 listenerRegistration.close();
94 private static final class PeerRegistryListenerImpl implements PeerRegistryListener {
95 private final Map<InetAddress, byte[]> keys = new HashMap<>();
96 private final ChannelConfig channelConfig;
98 PeerRegistryListenerImpl(final ChannelConfig channelConfig) {
99 this.channelConfig = channelConfig;
103 public void onPeerAdded(final IpAddressNoZone ip, final BGPSessionPreferences prefs) {
104 prefs.getMd5Password().ifPresent(password -> {
105 keys.put(IetfInetUtil.INSTANCE.inetAddressForNoZone(ip), password);
106 channelConfig.setOption(EpollChannelOption.TCP_MD5SIG, keys);
111 public void onPeerRemoved(final IpAddressNoZone ip) {
112 if (keys.remove(IetfInetUtil.INSTANCE.inetAddressForNoZone(ip)) != null) {
113 channelConfig.setOption(EpollChannelOption.TCP_MD5SIG, keys);