introduce graceful restart listener capability
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / config / OpenConfigMappingUtil.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 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil.INSTANCE;
12
13 import com.google.common.collect.ImmutableList;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Optional;
20 import java.util.Set;
21 import java.util.stream.Collectors;
22 import javax.annotation.Nonnull;
23 import javax.annotation.Nullable;
24 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
25 import org.opendaylight.protocol.bgp.mode.impl.add.all.paths.AllPathSelection;
26 import org.opendaylight.protocol.bgp.mode.impl.add.n.paths.AddPathBestNPathSelection;
27 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
28 import org.opendaylight.protocol.concepts.KeyMapping;
29 import org.opendaylight.protocol.util.Ipv4Util;
30 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.BgpCommonAfiSafiList;
31 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafi;
32 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafiBuilder;
33 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborAddPathsConfig;
34 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborGroup;
35 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborTransportConfig;
36 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.graceful.restart.GracefulRestart;
37 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.RouteReflector;
38 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Timers;
39 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Transport;
40 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.transport.Config;
41 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
42 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.NeighborKey;
43 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroup;
44 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
45 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
46 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.IPV4UNICAST;
47 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.PeerType;
48 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.SendReceive;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.add.path.capability.AddressFamilies;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.add.path.capability.AddressFamiliesBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.GlobalAddPathsConfig;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.GlobalConfigAugmentation;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NeighborAddPathsConfig;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NeighborPeerGroupConfig;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NeighborTransportConfig;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.PeerGroupTransportConfig;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.TransportConfig;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.ClusterIdentifier;
66 import org.opendaylight.yangtools.yang.binding.Augmentation;
67 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
68
69 final class OpenConfigMappingUtil {
70
71     static final String APPLICATION_PEER_GROUP_NAME = "application-peers";
72     static final Optional<String> APPLICATION_PEER_GROUP_NAME_OPT = Optional.of(APPLICATION_PEER_GROUP_NAME);
73     static final int HOLDTIMER = 90;
74     private static final AfiSafi IPV4_AFISAFI = new AfiSafiBuilder().setAfiSafiName(IPV4UNICAST.class).build();
75     private static final List<AfiSafi> DEFAULT_AFISAFI = ImmutableList.of(IPV4_AFISAFI);
76     private static final int CONNECT_RETRY = 30;
77     private static final PortNumber PORT = new PortNumber(179);
78
79     private OpenConfigMappingUtil() {
80         throw new UnsupportedOperationException();
81     }
82
83     static String getRibInstanceName(final InstanceIdentifier<?> rootIdentifier) {
84         return rootIdentifier.firstKeyOf(Protocol.class).getName();
85     }
86
87     @Nullable
88     private static Integer getHoldTimer(final Timers timers) {
89         if (timers == null) {
90             return null;
91         }
92         final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.timers
93                 .Config config = timers.getConfig();
94         if (config != null && config.getHoldTime() != null) {
95             return config.getHoldTime().intValue();
96         }
97         return null;
98     }
99
100     @Nullable
101     private static AsNumber getRemotePeerAs(final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp
102             .rev151009.bgp.neighbor.group.Config config) {
103         if (config != null) {
104             final AsNumber peerAs = config.getPeerAs();
105             if (peerAs != null) {
106                 return peerAs;
107             }
108         }
109         return null;
110     }
111
112     @Nullable
113     private static Boolean isActive(final Transport transport) {
114         if (transport != null) {
115             final Config config = transport.getConfig();
116             if (config != null && config.isPassiveMode() != null) {
117                 return !config.isPassiveMode();
118             }
119         }
120         return null;
121     }
122
123     @Nullable
124     private static Integer getRetryTimer(final Timers timers) {
125         if (timers == null) {
126             return null;
127         }
128         final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.timers
129                 .Config config = timers.getConfig();
130         if (config != null && config.getConnectRetry() != null) {
131             return config.getConnectRetry().intValue();
132         }
133         return null;
134     }
135
136     static KeyMapping getNeighborKey(final Neighbor neighbor) {
137         if (neighbor.getConfig() != null) {
138             final String authPassword = neighbor.getConfig().getAuthPassword();
139             if (authPassword != null) {
140                 return KeyMapping.getKeyMapping(INSTANCE.inetAddressFor(neighbor.getNeighborAddress()), authPassword);
141             }
142         }
143         return null;
144     }
145
146     static InstanceIdentifier<Neighbor> getNeighborInstanceIdentifier(
147             final InstanceIdentifier<Bgp> rootIdentifier,
148             final NeighborKey neighborKey) {
149         return rootIdentifier.child(Neighbors.class).child(Neighbor.class, neighborKey);
150     }
151
152     static String getNeighborInstanceName(final InstanceIdentifier<?> rootIdentifier) {
153         return Ipv4Util.toStringIP(rootIdentifier.firstKeyOf(Neighbor.class).getNeighborAddress());
154     }
155
156     @Nullable
157     private static <T extends TransportConfig & Augmentation<Config>> PortNumber getPort(
158             @Nullable final Transport transport, final Class<T> augment) {
159         if (transport != null) {
160             final Config config = transport.getConfig();
161             if (config != null) {
162                 final T peerTc = config.augmentation(augment);
163                 if (peerTc != null) {
164                     return peerTc.getRemotePort();
165                 }
166             }
167         }
168         return null;
169     }
170
171     //make sure IPv4 Unicast (RFC 4271) when required
172     static List<AfiSafi> getAfiSafiWithDefault(
173             final BgpCommonAfiSafiList afiSAfis, final boolean setDeafultIPv4) {
174         if (afiSAfis == null || afiSAfis.getAfiSafi() == null) {
175             return setDeafultIPv4 ? DEFAULT_AFISAFI : Collections.emptyList();
176         }
177         final List<AfiSafi> afiSafi = afiSAfis.getAfiSafi();
178         if (setDeafultIPv4) {
179             final boolean anyMatch = afiSafi.stream()
180                     .anyMatch(input -> input.getAfiSafiName().equals(IPV4UNICAST.class));
181             if (!anyMatch) {
182                 afiSafi.add(IPV4_AFISAFI);
183             }
184         }
185         return afiSafi;
186     }
187
188     static ClusterIdentifier getGlobalClusterIdentifier(final org.opendaylight.yang.gen.v1.http.openconfig.net
189             .yang.bgp.rev151009.bgp.global.base.Config globalConfig) {
190         final GlobalConfigAugmentation globalConfigAugmentation
191                 = globalConfig.augmentation(GlobalConfigAugmentation.class);
192         if (globalConfigAugmentation != null && globalConfigAugmentation.getRouteReflectorClusterId() != null) {
193             return new ClusterIdentifier(globalConfigAugmentation.getRouteReflectorClusterId().getIpv4Address());
194         }
195         return new ClusterIdentifier(globalConfig.getRouterId());
196     }
197
198     @Nullable
199     static ClusterIdentifier getNeighborClusterIdentifier(
200             @Nullable final RouteReflector routeReflector,
201             @Nullable final PeerGroup peerGroup) {
202         if (peerGroup != null) {
203             final ClusterIdentifier clusteriId = extractClusterId(peerGroup.getRouteReflector());
204             if (clusteriId != null) {
205                 return clusteriId;
206             }
207         }
208
209         return extractClusterId(routeReflector);
210     }
211
212     private static ClusterIdentifier extractClusterId(final RouteReflector routeReflector) {
213         if (routeReflector != null) {
214             final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.route
215                     .reflector.Config config = routeReflector.getConfig();
216             if (config != null && config.getRouteReflectorClusterId() != null) {
217                 return new ClusterIdentifier(config.getRouteReflectorClusterId().getIpv4Address());
218             }
219         }
220         return null;
221     }
222
223     static Map<BgpTableType, PathSelectionMode> toPathSelectionMode(final List<AfiSafi> afiSafis,
224             final BGPTableTypeRegistryConsumer tableTypeRegistry) {
225         final Map<BgpTableType, PathSelectionMode> pathSelectionModes = new HashMap<>();
226         for (final AfiSafi afiSafi : afiSafis) {
227             final BgpNeighborAddPathsConfig afiSafi2 = afiSafi.augmentation(GlobalAddPathsConfig.class);
228             if (afiSafi2 != null) {
229                 final Optional<BgpTableType> bgpTableType = tableTypeRegistry.getTableType(afiSafi.getAfiSafiName());
230                 if (bgpTableType.isPresent()) {
231                     final Short sendMax = afiSafi2.getSendMax();
232                     final PathSelectionMode selectionMode;
233                     if (sendMax > 1) {
234                         selectionMode = new AddPathBestNPathSelection(sendMax.longValue());
235                     } else {
236                         selectionMode = new AllPathSelection();
237                     }
238                     pathSelectionModes.put(bgpTableType.get(), selectionMode);
239                 }
240             }
241         }
242         return pathSelectionModes;
243     }
244
245     static boolean isApplicationPeer(final Neighbor neighbor) {
246         final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group
247                 .Config config = neighbor.getConfig();
248         if (config != null) {
249             final NeighborPeerGroupConfig config1 = config.augmentation(NeighborPeerGroupConfig.class);
250             if (config1 != null) {
251                 final String peerGroup = config1.getPeerGroup();
252                 return peerGroup != null && peerGroup.equals(APPLICATION_PEER_GROUP_NAME);
253             }
254         }
255         return false;
256     }
257
258     static List<AddressFamilies> toAddPathCapability(final List<AfiSafi> afiSafis,
259             final BGPTableTypeRegistryConsumer tableTypeRegistry) {
260         final List<AddressFamilies> addPathCapability = new ArrayList<>();
261         for (final AfiSafi afiSafi : afiSafis) {
262             final BgpNeighborAddPathsConfig afiSafi1 = afiSafi.augmentation(NeighborAddPathsConfig.class);
263             final Optional<BgpTableType> bgpTableType = tableTypeRegistry.getTableType(afiSafi.getAfiSafiName());
264             if (afiSafi1 != null && bgpTableType.isPresent()) {
265                 final AddressFamiliesBuilder builder = new AddressFamiliesBuilder(bgpTableType.get());
266                 builder.setSendReceive(toSendReceiveMode(afiSafi1));
267                 addPathCapability.add(builder.build());
268             }
269         }
270         return addPathCapability;
271     }
272
273     private static SendReceive toSendReceiveMode(final BgpNeighborAddPathsConfig addPath) {
274         if (addPath.isReceive() && addPath.getSendMax() != null) {
275             return SendReceive.Both;
276         }
277         if (addPath.getSendMax() != null) {
278             return SendReceive.Send;
279         }
280         return SendReceive.Receive;
281     }
282
283     static PeerRole toPeerRole(final BgpNeighborGroup neighbor) {
284         if (isRrClient(neighbor)) {
285             return PeerRole.RrClient;
286         }
287
288         if (neighbor.getConfig() != null) {
289             final PeerType peerType = neighbor.getConfig().getPeerType();
290             if (peerType == PeerType.EXTERNAL) {
291                 return PeerRole.Ebgp;
292             } else if (peerType == PeerType.INTERNAL) {
293                 return PeerRole.Ibgp;
294             }
295         }
296         return null;
297     }
298
299     private static boolean isRrClient(final BgpNeighborGroup neighbor) {
300         final RouteReflector routeReflector = neighbor.getRouteReflector();
301         if (routeReflector != null && routeReflector.getConfig() != null) {
302             return routeReflector.getConfig().isRouteReflectorClient();
303         }
304         return false;
305     }
306
307     static List<BgpTableType> toTableTypes(final List<AfiSafi> afiSafis,
308             final BGPTableTypeRegistryConsumer tableTypeRegistry) {
309         return afiSafis.stream()
310                 .map(afiSafi -> tableTypeRegistry.getTableType(afiSafi.getAfiSafiName()))
311                 .filter(Optional::isPresent)
312                 .map(Optional::get)
313                 .collect(Collectors.toList());
314     }
315
316     static Set<TablesKey> toTableKey(final List<AfiSafi> afiSafis, final BGPTableTypeRegistryConsumer
317             tableTypeRegistry) {
318         return afiSafis.stream()
319                 .map(afiSafi -> tableTypeRegistry.getTableKey(afiSafi.getAfiSafiName()))
320                 .filter(Optional::isPresent)
321                 .map(Optional::get)
322                 .collect(Collectors.toSet());
323     }
324
325     static boolean isActive(final Neighbor neighbor, final PeerGroup peerGroup) {
326         Boolean activeConnection = null;
327         if (peerGroup != null) {
328             activeConnection = isActive(peerGroup.getTransport());
329         }
330
331         if (activeConnection == null) {
332             activeConnection = isActive(neighbor.getTransport());
333         }
334         if (activeConnection == null) {
335             return true;
336         }
337         return activeConnection;
338     }
339
340     @Nonnull
341     static PeerRole toPeerRole(final Neighbor neighbor, final PeerGroup peerGroup) {
342         PeerRole role = null;
343         if (peerGroup != null) {
344             role = toPeerRole(peerGroup);
345         }
346
347         if (role == null) {
348             role = toPeerRole(neighbor);
349         }
350
351         if (role == null) {
352             return PeerRole.Ibgp;
353         }
354         return role;
355     }
356
357     static int getHoldTimer(final Neighbor neighbor, final PeerGroup peerGroup) {
358         Integer hold = null;
359         if (peerGroup != null) {
360             hold = getHoldTimer(peerGroup.getTimers());
361         }
362
363         if (hold == null) {
364             hold = getHoldTimer(neighbor.getTimers());
365         }
366
367         if (hold == null) {
368             return HOLDTIMER;
369         }
370
371         return hold;
372     }
373
374     static int getGracefulRestartTimer(final Neighbor neighbor, final PeerGroup peerGroup, final int holdTimer) {
375         Integer timer = null;
376         if (peerGroup != null) {
377             timer = getGracefulRestartTimer(peerGroup.getGracefulRestart());
378         }
379
380         if (timer == null) {
381             timer = getGracefulRestartTimer(neighbor.getGracefulRestart());
382         }
383
384         /*
385          * RFC4724: "A suggested default for the Restart Time is a value less than or
386          * equal to the HOLDTIME carried in the OPEN."
387          */
388         if (timer == null) {
389             timer = holdTimer;
390         }
391
392         return timer;
393     }
394
395     @Nullable
396     private static Integer getGracefulRestartTimer(final GracefulRestart gracefulRestart) {
397         if (gracefulRestart != null) {
398             final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.graceful.restart.graceful
399                     .restart.Config config = gracefulRestart.getConfig();
400             if (config != null) {
401                 return config.getRestartTime();
402             }
403         }
404         return null;
405     }
406
407     @Nonnull
408     static AsNumber getRemotePeerAs(final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009
409             .bgp.neighbor.group.Config config, final PeerGroup peerGroup, final AsNumber localAs) {
410         AsNumber neighborAs = null;
411         if (peerGroup != null) {
412             neighborAs = getRemotePeerAs(peerGroup.getConfig());
413         }
414
415         if (neighborAs == null) {
416             neighborAs = getRemotePeerAs(config);
417         }
418
419         if (neighborAs == null) {
420             return localAs;
421         }
422         return neighborAs;
423     }
424
425     @Nonnull
426     static AsNumber getLocalPeerAs(@Nullable final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp
427             .rev151009.bgp.neighbor.group.Config config, @Nonnull final AsNumber globalAs) {
428         if (config != null) {
429             final AsNumber peerAs = config.getLocalAs();
430             if (peerAs != null) {
431                 return peerAs;
432             }
433         }
434         return globalAs;
435     }
436
437     static int getRetryTimer(final Neighbor neighbor, final PeerGroup peerGroup) {
438         Integer retryTimer = null;
439         if (peerGroup != null) {
440             retryTimer = getRetryTimer(peerGroup.getTimers());
441         }
442
443         if (retryTimer == null) {
444             retryTimer = getRetryTimer(neighbor.getTimers());
445         }
446
447         if (retryTimer == null) {
448             return CONNECT_RETRY;
449         }
450
451         return retryTimer;
452     }
453
454     @Nonnull
455     static PortNumber getPort(final Neighbor neighbor, final PeerGroup peerGroup) {
456         PortNumber port = null;
457         if (peerGroup != null) {
458             port = getPort(peerGroup.getTransport(), PeerGroupTransportConfig.class);
459         }
460
461         if (port == null) {
462             port = getPort(neighbor.getTransport(), NeighborTransportConfig.class);
463         }
464
465         if (port == null) {
466             return PORT;
467         }
468
469         return port;
470     }
471
472     @Nullable
473     static IpAddress getLocalAddress(@Nullable final Transport transport) {
474         if (transport != null && transport.getConfig() != null) {
475             final BgpNeighborTransportConfig.LocalAddress localAddress = transport.getConfig().getLocalAddress();
476             if (localAddress != null ) {
477                 return localAddress.getIpAddress();
478             }
479         }
480         return null;
481     }
482 }