Bug 5566: BGP listener TCP MD5 support is not working
[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.base.Optional;
21 import com.google.common.base.Preconditions;
22 import com.google.common.net.InetAddresses;
23 import io.netty.channel.epoll.Epoll;
24 import io.netty.util.concurrent.Future;
25 import java.net.InetSocketAddress;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import org.opendaylight.controller.config.api.JmxAttributeValidationException;
31 import org.opendaylight.protocol.bgp.openconfig.spi.BGPConfigModuleTracker;
32 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
33 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenconfigMapper;
34 import org.opendaylight.protocol.bgp.openconfig.spi.InstanceConfigurationIdentifier;
35 import org.opendaylight.protocol.bgp.openconfig.spi.pojo.BGPPeerInstanceConfiguration;
36 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
37 import org.opendaylight.protocol.bgp.parser.spi.MultiprotocolCapabilitiesUtil;
38 import org.opendaylight.protocol.bgp.rib.impl.BGPPeer;
39 import org.opendaylight.protocol.bgp.rib.impl.StrictBGPPeerRegistry;
40 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPPeerRegistry;
41 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
43 import org.opendaylight.protocol.concepts.KeyMapping;
44 import org.opendaylight.protocol.util.Ipv6Util;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.BgpParameters;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.BgpParametersBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.OptionalCapabilities;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.OptionalCapabilitiesBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.optional.capabilities.CParametersBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.optional.capabilities.c.parameters.As4BytesCapabilityBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.CParameters1;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.CParameters1Builder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.AddPathCapabilityBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.GracefulRestartCapabilityBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.MultiprotocolCapabilityBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.add.path.capability.AddressFamilies;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.rfc2385.cfg.rev160324.Rfc2385Key;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 /**
66  *
67  */
68 public final class BGPPeerModule extends org.opendaylight.controller.config.yang.bgp.rib.impl.AbstractBGPPeerModule {
69     private static final Logger LOG = LoggerFactory.getLogger(BGPPeerModule.class);
70
71     public BGPPeerModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
72             final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
73         super(identifier, dependencyResolver);
74     }
75
76     public BGPPeerModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
77             final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final BGPPeerModule oldModule,
78             final java.lang.AutoCloseable oldInstance) {
79
80         super(identifier, dependencyResolver, oldModule, oldInstance);
81     }
82
83     @Override
84     protected void customValidation() {
85         final IpAddress host = getHost();
86         JmxAttributeValidationException.checkNotNull(host, "value is not set.", hostJmxAttribute);
87         JmxAttributeValidationException.checkCondition(host.getIpv4Address() != null || host.getIpv6Address() != null,
88                 "Unexpected host", hostJmxAttribute);
89
90         JmxAttributeValidationException.checkNotNull(getPort(), "value is not set.", portJmxAttribute);
91
92         if (getPeerRole() != null) {
93             final boolean isNotPeerRoleInternal= getPeerRole() != PeerRole.Internal;
94             JmxAttributeValidationException.checkCondition(isNotPeerRoleInternal,
95                     "Internal Peer Role is reserved for Application Peer use.", peerRoleJmxAttribute);
96         }
97
98         if (getOptionalPassword(getPassword()).isPresent()) {
99             JmxAttributeValidationException.checkCondition(Epoll.isAvailable(),
100                     "BGP Peer is configured with password but native transport is not available", passwordJmxAttribute);
101         }
102
103     }
104
105     private InetSocketAddress createAddress() {
106         final IpAddress ip = getHost();
107         Preconditions.checkArgument(ip.getIpv4Address() != null || ip.getIpv6Address() != null, "Failed to handle host %s", ip);
108         if (ip.getIpv4Address() != null) {
109             return new InetSocketAddress(InetAddresses.forString(ip.getIpv4Address().getValue()), getPort().getValue());
110         }
111         return new InetSocketAddress(InetAddresses.forString(ip.getIpv6Address().getValue()), getPort().getValue());
112     }
113
114     @Override
115     public java.lang.AutoCloseable createInstance() {
116         final RIB r = getRibDependency();
117
118         final List<BgpParameters> tlvs = getTlvs(r);
119         final AsNumber remoteAs = getAsOrDefault(r);
120         final BGPSessionPreferences prefs = new BGPSessionPreferences(r.getLocalAs(), getHoldtimer(), r.getBgpIdentifier(), remoteAs, tlvs,
121                 getMD5Password(getPassword()));
122         final BGPPeer bgpClientPeer;
123         final IpAddress host = getNormalizedHost();
124         if (getPeerRole() != null) {
125             bgpClientPeer = new BGPPeer(peerName(host), r, getPeerRole(), getSimpleRoutingPolicy(), getRpcRegistryDependency());
126         } else {
127             bgpClientPeer = new BGPPeer(peerName(host), r, PeerRole.Ibgp, getSimpleRoutingPolicy(), getRpcRegistryDependency());
128         }
129
130         bgpClientPeer.registerRootRuntimeBean(getRootRuntimeBeanRegistratorWrapper());
131
132         getPeerRegistryBackwards().addPeer(host, bgpClientPeer, prefs);
133
134         final BGPPeerModuleTracker moduleTracker = new BGPPeerModuleTracker(r.getOpenConfigProvider());
135         moduleTracker.onInstanceCreate();
136
137         final CloseableNoEx peerCloseable = () -> {
138             bgpClientPeer.close();
139             getPeerRegistryBackwards().removePeer(host);
140             moduleTracker.onInstanceClose();
141         };
142
143         // Initiate connection
144         if(getInitiateConnection()) {
145             final Future<Void> cf = initiateConnection(createAddress(), getOptionalPassword(getPassword()), getPeerRegistryBackwards());
146             return () -> {
147                 cf.cancel(true);
148                 peerCloseable.close();
149             };
150         } else {
151             return peerCloseable;
152         }
153     }
154
155     private interface CloseableNoEx extends AutoCloseable {
156         @Override
157         void close();
158     }
159
160     private AsNumber getAsOrDefault(final RIB r) {
161         // Remote AS number defaults to our local AS
162         final AsNumber remoteAs;
163         if (getRemoteAs() != null) {
164             remoteAs = new AsNumber(getRemoteAs());
165         } else {
166             remoteAs = r.getLocalAs();
167         }
168         return remoteAs;
169     }
170
171     private List<BgpParameters> getTlvs(final RIB r) {
172         final List<BgpParameters> tlvs = new ArrayList<>();
173         final List<OptionalCapabilities> caps = new ArrayList<>();
174         caps.add(new OptionalCapabilitiesBuilder().setCParameters(new CParametersBuilder().setAs4BytesCapability(
175                 new As4BytesCapabilityBuilder().setAsNumber(r.getLocalAs()).build()).build()).build());
176         caps.add(new OptionalCapabilitiesBuilder().setCParameters(new CParametersBuilder().addAugmentation(CParameters1.class,
177                 new CParameters1Builder().setGracefulRestartCapability(new GracefulRestartCapabilityBuilder().build()).build()).build()).build());
178
179         if (getRouteRefresh()) {
180             caps.add(new OptionalCapabilitiesBuilder().setCParameters(MultiprotocolCapabilitiesUtil.RR_CAPABILITY).build());
181         }
182
183         if (!getAddPathDependency().isEmpty()) {
184             final List<AddressFamilies> addPathFamilies = filterAddPathDependency(getAddPathDependency());
185             caps.add(new OptionalCapabilitiesBuilder().setCParameters(new CParametersBuilder().addAugmentation(CParameters1.class,
186                     new CParameters1Builder().setAddPathCapability(new AddPathCapabilityBuilder().setAddressFamilies(addPathFamilies).build()).build()).build()).build());
187         }
188
189         for (final BgpTableType t : getAdvertizedTableDependency()) {
190             if (!r.getLocalTables().contains(t)) {
191                 LOG.info("RIB instance does not list {} in its local tables. Incoming data will be dropped.", t);
192             }
193
194             caps.add(new OptionalCapabilitiesBuilder().setCParameters(new CParametersBuilder().addAugmentation(CParameters1.class,
195                     new CParameters1Builder().setMultiprotocolCapability(new MultiprotocolCapabilityBuilder(t).build()).build()).build()).build());
196         }
197         tlvs.add(new BgpParametersBuilder().setOptionalCapabilities(caps).build());
198         return tlvs;
199     }
200
201     private List<AddressFamilies> filterAddPathDependency(final List<AddressFamilies> addPathDependency) {
202         final Map<BgpTableType, AddressFamilies> filteredFamilies = new HashMap<BgpTableType, AddressFamilies>();
203         for (final AddressFamilies family : addPathDependency) {
204             final BgpTableType key = new BgpTableTypeImpl(family.getAfi(), family.getSafi());
205             if (!filteredFamilies.containsKey(key)) {
206                 filteredFamilies.put(key, family);
207             } else {
208                 LOG.info("Ignoring Add-path dependency {}", family);
209             }
210         }
211         return new ArrayList<AddressFamilies>(filteredFamilies.values());
212     }
213
214     public IpAddress getNormalizedHost() {
215         final IpAddress host = getHost();
216         if(host.getIpv6Address() != null){
217             return new IpAddress(Ipv6Util.getFullForm(host.getIpv6Address()));
218         }
219         return host;
220     }
221
222     private io.netty.util.concurrent.Future<Void> initiateConnection(final InetSocketAddress address, final Optional<Rfc2385Key> password, final BGPPeerRegistry registry) {
223         final KeyMapping keys = KeyMapping.getKeyMapping(address.getAddress(), password);
224         final RIB rib = getRibDependency();
225         final Optional<KeyMapping> optionalKey = Optional.fromNullable(keys);
226         return rib.getDispatcher().createReconnectingClient(address, registry, getRetrytimer(), optionalKey);
227     }
228
229     private BGPPeerRegistry getPeerRegistryBackwards() {
230         return getPeerRegistry() == null ? StrictBGPPeerRegistry.GLOBAL : getPeerRegistryDependency();
231     }
232
233     private static String peerName(final IpAddress host) {
234         if (host.getIpv4Address() != null) {
235             return host.getIpv4Address().getValue();
236         }
237         if (host.getIpv6Address() != null) {
238             return host.getIpv6Address().getValue();
239         }
240
241         return null;
242     }
243
244     private final class BGPPeerModuleTracker implements BGPConfigModuleTracker {
245
246         private final BGPOpenconfigMapper<BGPPeerInstanceConfiguration> neighborProvider;
247         private final BGPPeerInstanceConfiguration bgpPeerInstanceConfiguration;
248
249         public BGPPeerModuleTracker(final Optional<BGPOpenConfigProvider> openconfigProvider) {
250             if (openconfigProvider.isPresent()) {
251                 this.neighborProvider = openconfigProvider.get().getOpenConfigMapper(BGPPeerInstanceConfiguration.class);
252             } else {
253                 this.neighborProvider = null;
254             }
255             final InstanceConfigurationIdentifier identifier = new InstanceConfigurationIdentifier(getIdentifier().getInstanceName());
256             this.bgpPeerInstanceConfiguration = new BGPPeerInstanceConfiguration(identifier, getNormalizedHost(),
257                     getPort(), getHoldtimer(), getPeerRole(), getInitiateConnection(),
258                     getAdvertizedTableDependency(), getAsOrDefault(getRibDependency()),
259                     getOptionalPassword(getPassword()), getAddPathDependency());
260         }
261
262         @Override
263         public void onInstanceCreate() {
264             if (this.neighborProvider != null) {
265                 this.neighborProvider.writeConfiguration(this.bgpPeerInstanceConfiguration);
266             }
267         }
268
269         @Override
270         public void onInstanceClose() {
271             if (this.neighborProvider != null) {
272                 this.neighborProvider.removeConfiguration(this.bgpPeerInstanceConfiguration);
273             }
274         }
275
276     }
277
278     private static Optional<Rfc2385Key> getOptionalPassword(final Rfc2385Key password) {
279         return password != null && ! password.getValue().isEmpty() ? Optional.of(password) : Optional.<Rfc2385Key>absent();
280     }
281
282     private static Optional<byte[]> getMD5Password(final Rfc2385Key password) {
283         return getOptionalPassword(password).isPresent() ? Optional.of(password.getValue().getBytes(Charsets.US_ASCII)) : Optional.absent();
284     }
285
286 }