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