1cdf75052777f6099ab6ae7b388fd4e2299e1dc4
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / config / BgpPeer.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.rib.impl.config;
10
11 import static java.util.Objects.requireNonNull;
12 import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getHoldTimer;
13 import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getPeerAs;
14 import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getSimpleRoutingPolicy;
15
16 import com.google.common.base.Optional;
17 import com.google.common.base.Preconditions;
18 import com.google.common.collect.Iterables;
19 import com.google.common.util.concurrent.Futures;
20 import com.google.common.util.concurrent.ListenableFuture;
21 import io.netty.util.concurrent.Future;
22 import java.net.InetSocketAddress;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Objects;
27 import java.util.Set;
28 import javax.annotation.concurrent.GuardedBy;
29 import org.opendaylight.controller.config.yang.bgp.rib.impl.BGPPeerRuntimeMXBean;
30 import org.opendaylight.controller.config.yang.bgp.rib.impl.BgpPeerState;
31 import org.opendaylight.controller.config.yang.bgp.rib.impl.BgpSessionState;
32 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
33 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
34 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
35 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
36 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
37 import org.opendaylight.protocol.bgp.parser.BgpExtendedMessageUtil;
38 import org.opendaylight.protocol.bgp.parser.spi.MultiprotocolCapabilitiesUtil;
39 import org.opendaylight.protocol.bgp.rib.impl.BGPPeer;
40 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
41 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer.WriteConfiguration;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
44 import org.opendaylight.protocol.bgp.rib.spi.state.BGPPeerState;
45 import org.opendaylight.protocol.bgp.rib.spi.state.BGPPeerStateConsumer;
46 import org.opendaylight.protocol.concepts.KeyMapping;
47 import org.opendaylight.protocol.util.Ipv4Util;
48 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafi;
49 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.AfiSafis;
50 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.BgpParameters;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.BgpParametersBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.OptionalCapabilities;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.OptionalCapabilitiesBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.optional.capabilities.CParametersBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.optional.capabilities.c.parameters.As4BytesCapabilityBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.CParameters1;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.CParameters1Builder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.AddPathCapabilityBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.MultiprotocolCapabilityBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.add.path.capability.AddressFamilies;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
65 import org.osgi.framework.ServiceRegistration;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68
69
70 public final class BgpPeer implements PeerBean, BGPPeerStateConsumer, BGPPeerRuntimeMXBean {
71
72     private static final Logger LOG = LoggerFactory.getLogger(BgpPeer.class);
73
74     private final RpcProviderRegistry rpcRegistry;
75     @GuardedBy("this")
76     private ServiceRegistration<?> serviceRegistration;
77     @GuardedBy("this")
78     private Neighbor currentConfiguration;
79     @GuardedBy("this")
80     private BgpPeerSingletonService bgpPeerSingletonService;
81
82     public BgpPeer(final RpcProviderRegistry rpcRegistry) {
83         this.rpcRegistry = rpcRegistry;
84     }
85
86     @Override
87     public synchronized void start(final RIB rib, final Neighbor neighbor, final BGPTableTypeRegistryConsumer tableTypeRegistry,
88         final WriteConfiguration configurationWriter) {
89         Preconditions.checkState(this.bgpPeerSingletonService == null, "Previous peer instance was not closed.");
90         this.bgpPeerSingletonService = new BgpPeerSingletonService(rib, neighbor, tableTypeRegistry, configurationWriter);
91         this.currentConfiguration = neighbor;
92     }
93
94     @Override
95     public synchronized void restart(final RIB rib, final BGPTableTypeRegistryConsumer tableTypeRegistry) {
96         Preconditions.checkState(this.currentConfiguration != null);
97         start(rib, this.currentConfiguration, tableTypeRegistry, null);
98     }
99
100     @Override
101     public synchronized void close() {
102         closeSingletonService();
103         if (this.serviceRegistration != null) {
104             this.serviceRegistration.unregister();
105             this.serviceRegistration = null;
106         }
107     }
108
109     @Override
110     public synchronized ListenableFuture<Void> closeServiceInstance() {
111         if (this.bgpPeerSingletonService != null) {
112             return this.bgpPeerSingletonService.closeServiceInstance();
113         }
114         return Futures.immediateFuture(null);
115     }
116
117     private void closeSingletonService() {
118         if (this.bgpPeerSingletonService != null) {
119             try {
120                 this.bgpPeerSingletonService.close();
121                 this.bgpPeerSingletonService = null;
122             } catch (final Exception e) {
123                 LOG.warn("Failed to close peer instance", e);
124             }
125         }
126     }
127
128     @Override
129     public Boolean containsEqualConfiguration(final Neighbor neighbor) {
130         final AfiSafis actAfiSafi = this.currentConfiguration.getAfiSafis();
131         final AfiSafis extAfiSafi = neighbor.getAfiSafis();
132         final List<AfiSafi> actualSafi = actAfiSafi != null ? actAfiSafi.getAfiSafi() : Collections.emptyList();
133         final List<AfiSafi> extSafi = extAfiSafi != null ? extAfiSafi.getAfiSafi() : Collections.emptyList();
134         return actualSafi.containsAll(extSafi) && extSafi.containsAll(actualSafi)
135         && Objects.equals(this.currentConfiguration.getConfig(), neighbor.getConfig())
136         && Objects.equals(this.currentConfiguration.getNeighborAddress(), neighbor.getNeighborAddress())
137         && Objects.equals(this.currentConfiguration.getAddPaths(),neighbor.getAddPaths())
138         && Objects.equals(this.currentConfiguration.getApplyPolicy(), neighbor.getApplyPolicy())
139         && Objects.equals(this.currentConfiguration.getAsPathOptions(), neighbor.getAsPathOptions())
140         && Objects.equals(this.currentConfiguration.getEbgpMultihop(), neighbor.getEbgpMultihop())
141         && Objects.equals(this.currentConfiguration.getGracefulRestart(), neighbor.getGracefulRestart())
142         && Objects.equals(this.currentConfiguration.getErrorHandling(), neighbor.getErrorHandling())
143         && Objects.equals(this.currentConfiguration.getLoggingOptions(), neighbor.getLoggingOptions())
144         && Objects.equals(this.currentConfiguration.getRouteReflector(), neighbor.getRouteReflector())
145         && Objects.equals(this.currentConfiguration.getState(), neighbor.getState())
146         && Objects.equals(this.currentConfiguration.getTimers(), neighbor.getTimers())
147         && Objects.equals(this.currentConfiguration.getTransport(), neighbor.getTransport());
148     }
149
150     private static List<BgpParameters> getBgpParameters(final Neighbor neighbor, final RIB rib,
151             final BGPTableTypeRegistryConsumer tableTypeRegistry) {
152         final List<BgpParameters> tlvs = new ArrayList<>();
153         final List<OptionalCapabilities> caps = new ArrayList<>();
154         caps.add(new OptionalCapabilitiesBuilder().setCParameters(new CParametersBuilder().setAs4BytesCapability(
155                 new As4BytesCapabilityBuilder().setAsNumber(rib.getLocalAs()).build()).build()).build());
156
157         caps.add(new OptionalCapabilitiesBuilder().setCParameters(BgpExtendedMessageUtil.EXTENDED_MESSAGE_CAPABILITY).build());
158         caps.add(new OptionalCapabilitiesBuilder().setCParameters(MultiprotocolCapabilitiesUtil.RR_CAPABILITY).build());
159
160         final List<AfiSafi> afiSafi = OpenConfigMappingUtil.getAfiSafiWithDefault(neighbor.getAfiSafis(), false);
161         final List<AddressFamilies> addPathCapability = OpenConfigMappingUtil.toAddPathCapability(afiSafi, tableTypeRegistry);
162         if (!addPathCapability.isEmpty()) {
163             caps.add(new OptionalCapabilitiesBuilder().setCParameters(new CParametersBuilder().addAugmentation(CParameters1.class,
164                     new CParameters1Builder().setAddPathCapability(
165                             new AddPathCapabilityBuilder().setAddressFamilies(addPathCapability).build()).build()).build()).build());
166         }
167
168         final List<BgpTableType> tableTypes = OpenConfigMappingUtil.toTableTypes(afiSafi, tableTypeRegistry);
169         for (final BgpTableType tableType : tableTypes) {
170             if (!rib.getLocalTables().contains(tableType)) {
171                 LOG.info("RIB instance does not list {} in its local tables. Incoming data will be dropped.", tableType);
172             }
173
174             caps.add(new OptionalCapabilitiesBuilder().setCParameters(
175                     new CParametersBuilder().addAugmentation(CParameters1.class,
176                             new CParameters1Builder().setMultiprotocolCapability(
177                                     new MultiprotocolCapabilityBuilder(tableType).build()).build()).build()).build());
178         }
179         tlvs.add(new BgpParametersBuilder().setOptionalCapabilities(caps).build());
180         return tlvs;
181     }
182
183     private static Optional<byte[]> getPassword(final KeyMapping key) {
184         if (key != null) {
185             return Optional.of(Iterables.getOnlyElement(key.values()));
186         }
187         return Optional.absent();
188     }
189
190     @Override
191     public BgpPeerState getBgpPeerState() {
192         return this.bgpPeerSingletonService.getPeer().getBgpPeerState();
193     }
194
195     @Override
196     public BgpSessionState getBgpSessionState() {
197         return this.bgpPeerSingletonService.getPeer().getBgpSessionState();
198     }
199
200     @Override
201     public void resetSession() {
202         this.bgpPeerSingletonService.getPeer().resetSession();
203     }
204
205     @Override
206     public void resetStats() {
207         this.bgpPeerSingletonService.getPeer().resetStats();
208     }
209
210     @Override
211     public BGPPeerState getPeerState() {
212         if (this.bgpPeerSingletonService == null) {
213             return null;
214         }
215         return this.bgpPeerSingletonService.getPeerState();
216     }
217
218     synchronized void setServiceRegistration(final ServiceRegistration<?> serviceRegistration) {
219         this.serviceRegistration = serviceRegistration;
220     }
221
222     private final class BgpPeerSingletonService implements BGPPeerStateConsumer, ClusterSingletonService,
223         AutoCloseable {
224         private final ServiceGroupIdentifier serviceGroupIdentifier;
225         private final boolean activeConnection;
226         private final BGPDispatcher dispatcher;
227         private final InetSocketAddress inetAddress;
228         private final int retryTimer;
229         private final KeyMapping keys;
230         private final WriteConfiguration configurationWriter;
231         private ClusterSingletonServiceRegistration registration;
232         private final BGPPeer bgpPeer;
233         private final IpAddress neighborAddress;
234         private final BGPSessionPreferences prefs;
235         private Future<Void> connection;
236         @GuardedBy("this")
237         private boolean isServiceInstantiated;
238
239         private BgpPeerSingletonService(final RIB rib, final Neighbor neighbor,
240             final BGPTableTypeRegistryConsumer tableTypeRegistry, final WriteConfiguration configurationWriter) {
241             this.neighborAddress = neighbor.getNeighborAddress();
242             final AfiSafis afisSAfis = requireNonNull(neighbor.getAfiSafis());
243             final Set<TablesKey> afiSafisAdvertized = OpenConfigMappingUtil
244                 .toTableKey(afisSAfis.getAfiSafi(), tableTypeRegistry);
245             this.bgpPeer = new BGPPeer(Ipv4Util.toStringIP(this.neighborAddress), rib,
246                 OpenConfigMappingUtil.toPeerRole(neighbor), getSimpleRoutingPolicy(neighbor), BgpPeer.this.rpcRegistry,
247                 afiSafisAdvertized, Collections.emptySet());
248             final List<BgpParameters> bgpParameters = getBgpParameters(neighbor, rib, tableTypeRegistry);
249             final KeyMapping keyMapping = OpenConfigMappingUtil.getNeighborKey(neighbor);
250             this.prefs = new BGPSessionPreferences(rib.getLocalAs(), getHoldTimer(neighbor), rib.getBgpIdentifier(),
251                 getPeerAs(neighbor, rib), bgpParameters, getPassword(keyMapping));
252             this.activeConnection = OpenConfigMappingUtil.isActive(neighbor);
253             this.dispatcher = rib.getDispatcher();
254             this.inetAddress = Ipv4Util.toInetSocketAddress(this.neighborAddress, OpenConfigMappingUtil.getPort(neighbor));
255             this.retryTimer = OpenConfigMappingUtil.getRetryTimer(neighbor);
256             this.keys = keyMapping;
257             this.configurationWriter = configurationWriter;
258             this.serviceGroupIdentifier = rib.getRibIServiceGroupIdentifier();
259             LOG.info("Peer Singleton Service {} registered", this.serviceGroupIdentifier.getValue());
260             //this need to be always the last step
261             this.registration = rib.registerClusterSingletonService(this);
262         }
263
264         @Override
265         public void close() throws Exception {
266             if (this.registration != null) {
267                 this.registration.close();
268                 this.registration = null;
269             }
270         }
271
272         @Override
273         public synchronized void instantiateServiceInstance() {
274             this.isServiceInstantiated = true;
275             if(this.configurationWriter != null) {
276                 this.configurationWriter.apply();
277             }
278             LOG.info("Peer Singleton Service {} instantiated, Peer {}", getIdentifier().getValue(), this.neighborAddress);
279             this.bgpPeer.instantiateServiceInstance();
280             this.dispatcher.getBGPPeerRegistry().addPeer(this.neighborAddress, this.bgpPeer, this.prefs);
281             if (this.activeConnection) {
282                 this.connection = this.dispatcher.createReconnectingClient(this.inetAddress, this.retryTimer, this.keys);
283             }
284         }
285
286         @Override
287         public synchronized ListenableFuture<Void> closeServiceInstance() {
288             if(!this.isServiceInstantiated) {
289                 LOG.info("Peer Singleton Service {} already closed, Peer {}", getIdentifier().getValue(),
290                     this.neighborAddress);
291                 return Futures.immediateFuture(null);
292             }
293             LOG.info("Close Peer Singleton Service {}, Peer {}", getIdentifier().getValue(), this.neighborAddress);
294             this.isServiceInstantiated = false;
295             if (this.connection != null) {
296                 this.connection.cancel(true);
297                 this.connection = null;
298             }
299             final ListenableFuture<Void> future = this.bgpPeer.close();
300             if(BgpPeer.this.currentConfiguration != null) {
301                 this.dispatcher.getBGPPeerRegistry().removePeer(BgpPeer.this.currentConfiguration.getNeighborAddress());
302             }
303             return future;
304         }
305
306         @Override
307         public ServiceGroupIdentifier getIdentifier() {
308             return this.serviceGroupIdentifier;
309         }
310
311         BGPPeerRuntimeMXBean getPeer() {
312             return this.bgpPeer;
313         }
314
315         @Override
316         public BGPPeerState getPeerState() {
317             return this.bgpPeer.getPeerState();
318         }
319     }
320 }