Bump to odlparent-3.0.2 and yangtools-2.0.0
[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.security.AccessControlException;
24 import javax.annotation.Nonnull;
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.protocol.concepts.KeyMapping;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
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 AutoCloseable listenerRegistration;
42
43     public BGPPeerAcceptorImpl(final IpAddress bindingAddress, final PortNumber portNumber,
44             final BGPDispatcher bgpDispatcher) {
45         this.bgpDispatcher = requireNonNull(bgpDispatcher);
46         this.address = getAddress(requireNonNull(bindingAddress), requireNonNull(portNumber));
47         if (!PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()
48                 && portNumber.getValue() < PRIVILEGED_PORTS) {
49             throw new AccessControlException("Unable to bind port " + portNumber.getValue()
50                     + " while running as non-root user.");
51         }
52     }
53
54     public void start() {
55         LOG.debug("Instantiating BGP Peer Acceptor : {}", this.address);
56
57         this.futureChannel = this.bgpDispatcher.createServer(this.address);
58         // Validate future success
59         this.futureChannel.addListener(future -> {
60             Preconditions.checkArgument(future.isSuccess(), "Unable to start bgp server on %s",
61                 this.address, future.cause());
62             final Channel channel = this.futureChannel.channel();
63             if (Epoll.isAvailable()) {
64                 this.listenerRegistration = this.bgpDispatcher.getBGPPeerRegistry().registerPeerRegisterListener(
65                     new BGPPeerAcceptorImpl.PeerRegistryListenerImpl(channel.config()));
66             }
67         });
68     }
69
70     private static InetSocketAddress getAddress(final IpAddress ipAddress, final PortNumber portNumber) {
71         final InetAddress inetAddr;
72         try {
73             inetAddr = InetAddress.getByName(ipAddress.getIpv4Address() != null
74                     ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue());
75         } catch (final UnknownHostException e) {
76             throw new IllegalArgumentException("Illegal binding address " + ipAddress, e);
77         }
78         return new InetSocketAddress(inetAddr, portNumber.getValue());
79     }
80
81     /**
82      * This closes the acceptor and no new bgp connections will be accepted
83      * Connections already established will be preserved.
84      **/
85     @Override
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();
91         }
92     }
93
94     private static final class PeerRegistryListenerImpl implements PeerRegistryListener {
95         private final ChannelConfig channelConfig;
96         private final KeyMapping keys;
97
98         PeerRegistryListenerImpl(final ChannelConfig channelConfig) {
99             this.channelConfig = channelConfig;
100             this.keys = KeyMapping.getKeyMapping();
101         }
102
103         @Override
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);
108             }
109         }
110
111         @Override
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);
115             }
116         }
117     }
118 }