837fbefb05ca4c227b64e5c967f7d3201c3745c2
[bgpcep.git] / bgp / peer-acceptor / src / main / java / org / opendaylight / protocol / bgp / peer / acceptor / BGPPeerAcceptorImpl.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.protocol.bgp.peer.acceptor;
10
11 import static java.util.Objects.requireNonNull;
12
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;
24 import java.util.Map;
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.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 public final class BGPPeerAcceptorImpl implements AutoCloseable {
35     private static final Logger LOG = LoggerFactory.getLogger(BGPPeerAcceptorImpl.class);
36     private static final int PRIVILEGED_PORTS = 1024;
37     private final BGPDispatcher bgpDispatcher;
38     private final InetSocketAddress address;
39     private ChannelFuture futureChannel;
40     private AutoCloseable listenerRegistration;
41
42     public BGPPeerAcceptorImpl(final IpAddressNoZone bindingAddress, final PortNumber portNumber,
43             final BGPDispatcher bgpDispatcher) {
44         this.bgpDispatcher = requireNonNull(bgpDispatcher);
45         address = getAddress(requireNonNull(bindingAddress), requireNonNull(portNumber));
46         if (!PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()
47                 && portNumber.getValue().toJava() < PRIVILEGED_PORTS) {
48             throw new SecurityException("Unable to bind port " + portNumber.getValue()
49                     + " while running as non-root user.");
50         }
51     }
52
53     public void start() {
54         LOG.debug("Instantiating BGP Peer Acceptor : {}", address);
55
56         futureChannel = bgpDispatcher.createServer(address);
57         // Validate future success
58         futureChannel.addListener(future -> {
59             Preconditions.checkArgument(future.isSuccess(), "Unable to start bgp server on %s",
60                 address, future.cause());
61             final Channel channel = futureChannel.channel();
62             if (Epoll.isAvailable()) {
63                 listenerRegistration = bgpDispatcher.getBGPPeerRegistry().registerPeerRegisterListener(
64                     new BGPPeerAcceptorImpl.PeerRegistryListenerImpl(channel.config()));
65             }
66         });
67     }
68
69     private static InetSocketAddress getAddress(final IpAddressNoZone ipAddress, final PortNumber portNumber) {
70         final InetAddress inetAddr;
71         try {
72             inetAddr = InetAddress.getByName(ipAddress.getIpv4AddressNoZone() != null
73                     ? ipAddress.getIpv4AddressNoZone().getValue() : ipAddress.getIpv6AddressNoZone().getValue());
74         } catch (final UnknownHostException e) {
75             throw new IllegalArgumentException("Illegal binding address " + ipAddress, e);
76         }
77         return new InetSocketAddress(inetAddr, portNumber.getValue().toJava());
78     }
79
80     /**
81      * This closes the acceptor and no new bgp connections will be accepted
82      * Connections already established will be preserved.
83      **/
84     @Override
85     public void close() throws Exception {
86         futureChannel.cancel(true);
87         futureChannel.channel().close();
88         if (listenerRegistration != null) {
89             listenerRegistration.close();
90         }
91     }
92
93     private static final class PeerRegistryListenerImpl implements PeerRegistryListener {
94         private final Map<InetAddress, byte[]> keys = new HashMap<>();
95         private final ChannelConfig channelConfig;
96
97         PeerRegistryListenerImpl(final ChannelConfig channelConfig) {
98             this.channelConfig = channelConfig;
99         }
100
101         @Override
102         public void onPeerAdded(final IpAddressNoZone ip, final BGPSessionPreferences prefs) {
103             prefs.getMd5Password().ifPresent(password -> {
104                 keys.put(IetfInetUtil.INSTANCE.inetAddressForNoZone(ip), password);
105                 channelConfig.setOption(EpollChannelOption.TCP_MD5SIG, keys);
106             });
107         }
108
109         @Override
110         public void onPeerRemoved(final IpAddressNoZone ip) {
111             if (keys.remove(IetfInetUtil.INSTANCE.inetAddressForNoZone(ip)) != null) {
112                 channelConfig.setOption(EpollChannelOption.TCP_MD5SIG, keys);
113             }
114         }
115     }
116 }