Bug-2064: Implementation of RFC5492 Error handling.
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / controller / config / yang / bgp / rib / impl / BGPPeerModule.java
1 /*
2  * Copyright (c) 2013 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  * Generated file
10
11  * Generated from: yang module name: bgp-rib-impl  yang module local name: bgp-peer
12  * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
13  * Generated at: Sat Jan 25 11:00:14 CET 2014
14  *
15  * Do not modify this file unless it is present under src/main directory
16  */
17 package org.opendaylight.controller.config.yang.bgp.rib.impl;
18
19 import com.google.common.base.Charsets;
20 import com.google.common.collect.Lists;
21 import com.google.common.net.InetAddresses;
22 import io.netty.util.concurrent.Future;
23 import java.net.InetSocketAddress;
24 import java.util.List;
25 import org.opendaylight.controller.config.api.JmxAttributeValidationException;
26 import org.opendaylight.protocol.bgp.rib.impl.BGPPeer;
27 import org.opendaylight.protocol.bgp.rib.impl.StrictBGPPeerRegistry;
28 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPPeerRegistry;
29 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
30 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
31 import org.opendaylight.tcpmd5.api.KeyMapping;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParameters;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParametersBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.bgp.parameters.OptionalCapabilitiesBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.As4BytesCaseBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.as4.bytes._case.As4BytesCapabilityBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.MultiprotocolCaseBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.optional.capabilities.c.parameters.multiprotocol._case.MultiprotocolCapabilityBuilder;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  *
47  */
48 public final class BGPPeerModule extends org.opendaylight.controller.config.yang.bgp.rib.impl.AbstractBGPPeerModule {
49     private static final Logger LOG = LoggerFactory.getLogger(BGPPeerModule.class);
50
51     public BGPPeerModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
52         final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
53         super(identifier, dependencyResolver);
54     }
55
56     public BGPPeerModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
57         final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final BGPPeerModule oldModule,
58         final java.lang.AutoCloseable oldInstance) {
59
60         super(identifier, dependencyResolver, oldModule, oldInstance);
61     }
62
63     @Override
64     protected void customValidation() {
65         JmxAttributeValidationException.checkNotNull(getHost(), "value is not set.", hostJmxAttribute);
66         JmxAttributeValidationException.checkNotNull(getPort(), "value is not set.", portJmxAttribute);
67
68         if (getPassword() != null) {
69             /*
70              *  This is a nasty hack, but we don't have another clean solution. We cannot allow
71              *  password being set if the injected dispatcher does not have the optional
72              *  md5-server-channel-factory set.
73              *
74              *  FIXME: this is a use case for Module interfaces, e.g. RibImplModule
75              *         should something like isMd5ServerSupported()
76              */
77
78             final RIBImplModuleMXBean ribProxy = this.dependencyResolver.newMXBeanProxy(getRib(), RIBImplModuleMXBean.class);
79             final BGPDispatcherImplModuleMXBean bgpDispatcherProxy = this.dependencyResolver.newMXBeanProxy(
80                 ribProxy.getBgpDispatcher(), BGPDispatcherImplModuleMXBean.class);
81             final boolean isMd5Supported = bgpDispatcherProxy.getMd5ChannelFactory() != null;
82
83             JmxAttributeValidationException.checkCondition(isMd5Supported,
84                 "Underlying dispatcher does not support MD5 clients", passwordJmxAttribute);
85
86         }
87     }
88
89     private InetSocketAddress createAddress() {
90         final IpAddress ip = getHost();
91         if (ip.getIpv4Address() != null) {
92             return new InetSocketAddress(InetAddresses.forString(ip.getIpv4Address().getValue()), getPort().getValue());
93         } else if (ip.getIpv6Address() != null) {
94             return new InetSocketAddress(InetAddresses.forString(ip.getIpv6Address().getValue()), getPort().getValue());
95         } else {
96             throw new IllegalStateException("Failed to handle host " + getHost());
97         }
98     }
99
100     @Override
101     public java.lang.AutoCloseable createInstance() {
102         final RIB r = getRibDependency();
103
104         final List<BgpParameters> tlvs = getTlvs(r);
105         final AsNumber remoteAs = getAsOrDefault(r);
106         final String password = getPasswordOrNull();
107
108         final BGPSessionPreferences prefs = new BGPSessionPreferences(r.getLocalAs(), getHoldtimer(), r.getBgpIdentifier(), tlvs);
109         final BGPPeer bgpClientPeer = new BGPPeer(peerName(getHostWithoutValue()), r);
110         bgpClientPeer.registerRootRuntimeBean(getRootRuntimeBeanRegistratorWrapper());
111
112         getPeerRegistryBackwards().addPeer(getHostWithoutValue(), bgpClientPeer, prefs);
113
114         final CloseableNoEx peerCloseable = new CloseableNoEx() {
115             @Override
116             public void close() {
117                 bgpClientPeer.close();
118                 getPeerRegistryBackwards().removePeer(getHostWithoutValue());
119             }
120         };
121
122         // Initiate connection
123         if(getInitiateConnection()) {
124             final Future<Void> cf = initiateConnection(createAddress(), password, remoteAs, getPeerRegistryBackwards());
125             return new CloseableNoEx() {
126                 @Override
127                 public void close() {
128                     cf.cancel(true);
129                     peerCloseable.close();
130                 }
131             };
132         } else {
133             return peerCloseable;
134         }
135     }
136
137     private interface CloseableNoEx extends AutoCloseable {
138         @Override
139         void close();
140     }
141
142     private String getPasswordOrNull() {
143         final String password;
144         if (getPassword() != null) {
145             password = getPassword().getValue();
146         } else {
147             password = null;
148         }
149         return password;
150     }
151
152     private AsNumber getAsOrDefault(final RIB r) {
153         // Remote AS number defaults to our local AS
154         final AsNumber remoteAs;
155         if (getRemoteAs() != null) {
156             remoteAs = new AsNumber(getRemoteAs());
157         } else {
158             remoteAs = r.getLocalAs();
159         }
160         return remoteAs;
161     }
162
163     private List<BgpParameters> getTlvs(final RIB r) {
164         final List<BgpParameters> tlvs = Lists.newArrayList();
165         tlvs.add(new BgpParametersBuilder().setOptionalCapabilities(Lists.newArrayList(new OptionalCapabilitiesBuilder().setCParameters(
166             new As4BytesCaseBuilder().setAs4BytesCapability(new As4BytesCapabilityBuilder().setAsNumber(r.getLocalAs()).build()).build()).build())).build());
167
168         for (final BgpTableType t : getAdvertizedTableDependency()) {
169             if (!r.getLocalTables().contains(t)) {
170                 LOG.info("RIB instance does not list {} in its local tables. Incoming data will be dropped.", t);
171             }
172
173             tlvs.add(new BgpParametersBuilder().setOptionalCapabilities(Lists.newArrayList(new OptionalCapabilitiesBuilder().setCParameters(
174                 new MultiprotocolCaseBuilder().setMultiprotocolCapability(new MultiprotocolCapabilityBuilder(t).build()).build()).build())).build());
175         }
176         return tlvs;
177     }
178
179     public IpAddress getHostWithoutValue() {
180         // FIXME we need to remove field "value" from IpAddress since equals does not work as expected when value being present
181         // Remove after this bug is fixed https://bugs.opendaylight.org/show_bug.cgi?id=1276
182         final IpAddress host = super.getHost();
183         if(host.getIpv4Address() != null) {
184             return new IpAddress(host.getIpv4Address());
185         } else if(host.getIpv6Address() != null){
186             return new IpAddress(host.getIpv6Address());
187         }
188
189         throw new IllegalArgumentException("Unexpected host " + host);
190     }
191
192     private io.netty.util.concurrent.Future<Void> initiateConnection(final InetSocketAddress address, final String password, final AsNumber remoteAs, final BGPPeerRegistry registry) {
193         final KeyMapping keys;
194         if (password != null) {
195             keys = new KeyMapping();
196             keys.put(address.getAddress(), password.getBytes(Charsets.US_ASCII));
197         } else {
198             keys = null;
199         }
200
201         final RIB rib = getRibDependency();
202         return rib.getDispatcher().createReconnectingClient(address, remoteAs, registry, rib.getTcpStrategyFactory(),
203             rib.getSessionStrategyFactory(), keys);
204     }
205
206     private BGPPeerRegistry getPeerRegistryBackwards() {
207         return getPeerRegistry() == null ? StrictBGPPeerRegistry.GLOBAL : getPeerRegistryDependency();
208     }
209
210     private static String peerName(final IpAddress host) {
211         if (host.getIpv4Address() != null) {
212             return host.getIpv4Address().getValue();
213         }
214         if (host.getIpv6Address() != null) {
215             return host.getIpv6Address().getValue();
216         }
217
218         return null;
219     }
220
221 }