2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.protocol.bgp.rib.impl.config;
10 import static com.google.common.base.Preconditions.checkState;
11 import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil.INSTANCE;
13 import com.google.common.collect.ImmutableMap;
14 import com.google.common.collect.Maps;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.List;
21 import java.util.Optional;
23 import java.util.function.Function;
24 import java.util.stream.Collectors;
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
28 import org.opendaylight.protocol.bgp.mode.impl.add.all.paths.AllPathSelection;
29 import org.opendaylight.protocol.bgp.mode.impl.add.n.paths.AddPathBestNPathSelection;
30 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
31 import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandlingSupport;
32 import org.opendaylight.protocol.bgp.parser.spi.pojo.RevisedErrorHandlingSupportImpl;
33 import org.opendaylight.protocol.concepts.KeyMapping;
34 import org.opendaylight.protocol.util.Ipv4Util;
35 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.BgpCommonAfiSafiList;
36 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafi;
37 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafiBuilder;
38 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafiKey;
39 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborAddPathsConfig;
40 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborGroup;
41 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborTransportConfig;
42 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.graceful.restart.GracefulRestart;
43 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.ErrorHandling;
44 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.RouteReflector;
45 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Timers;
46 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Transport;
47 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.transport.Config;
48 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
49 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.NeighborKey;
50 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroup;
51 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
52 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
53 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.IPV4UNICAST;
54 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.PeerType;
55 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressNoZone;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.SendReceive;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.add.path.capability.AddressFamilies;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.add.path.capability.AddressFamiliesBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.GlobalAddPathsConfig;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.GlobalConfigAugmentation;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NeighborAddPathsConfig;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NeighborPeerGroupConfig;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NeighborTransportConfig;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.PeerGroupTransportConfig;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.TransportConfig;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.ClusterIdentifier;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
78 import org.opendaylight.yangtools.yang.common.Uint16;
80 final class OpenConfigMappingUtil {
81 static final String APPLICATION_PEER_GROUP_NAME = "application-peers";
82 static final Optional<String> APPLICATION_PEER_GROUP_NAME_OPT = Optional.of(APPLICATION_PEER_GROUP_NAME);
83 static final int HOLDTIMER = 90;
84 private static final AfiSafi IPV4_AFISAFI = new AfiSafiBuilder().setAfiSafiName(IPV4UNICAST.class).build();
85 private static final Map<AfiSafiKey, AfiSafi> DEFAULT_AFISAFI = ImmutableMap.of(IPV4_AFISAFI.key(), IPV4_AFISAFI);
86 private static final int CONNECT_RETRY = 30;
87 private static final PortNumber PORT = new PortNumber(Uint16.valueOf(179).intern());
89 private OpenConfigMappingUtil() {
93 static String getRibInstanceName(final InstanceIdentifier<?> rootIdentifier) {
94 return rootIdentifier.firstKeyOf(Protocol.class).getName();
97 static KeyMapping getNeighborKey(final Neighbor neighbor) {
98 if (neighbor.getConfig() != null) {
99 final String authPassword = neighbor.getConfig().getAuthPassword();
100 if (authPassword != null) {
101 return KeyMapping.getKeyMapping(INSTANCE.inetAddressFor(neighbor.getNeighborAddress()), authPassword);
107 static InstanceIdentifier<Neighbor> getNeighborInstanceIdentifier(
108 final InstanceIdentifier<Bgp> rootIdentifier,
109 final NeighborKey neighborKey) {
110 return rootIdentifier.child(Neighbors.class).child(Neighbor.class, neighborKey);
113 static IpAddressNoZone convertIpAddress(final IpAddress addr) {
117 final Ipv4Address ipv4 = addr.getIpv4Address();
119 return new IpAddressNoZone(INSTANCE.ipv4AddressNoZoneFor(ipv4));
121 final Ipv6Address ipv6 = addr.getIpv6Address();
122 checkState(ipv6 != null, "Unexpected address %s", addr);
123 return new IpAddressNoZone(INSTANCE.ipv6AddressNoZoneFor(ipv6));
126 static String getNeighborInstanceName(final InstanceIdentifier<?> rootIdentifier) {
127 return Ipv4Util.toStringIP(convertIpAddress(rootIdentifier.firstKeyOf(Neighbor.class).getNeighborAddress()));
130 //make sure IPv4 Unicast (RFC 4271) when required
131 static Map<AfiSafiKey, AfiSafi> getAfiSafiWithDefault(
132 final BgpCommonAfiSafiList afiSAfis, final boolean setDeafultIPv4) {
133 if (afiSAfis == null || afiSAfis.getAfiSafi() == null) {
134 return setDeafultIPv4 ? DEFAULT_AFISAFI : Collections.emptyMap();
136 final Map<AfiSafiKey, AfiSafi> afiSafi = afiSAfis.nonnullAfiSafi();
137 if (setDeafultIPv4 && !afiSafi.containsKey(IPV4_AFISAFI.key())) {
138 final Map<AfiSafiKey, AfiSafi> newAfiSafi = Maps.newHashMapWithExpectedSize(afiSafi.size() + 1);
139 newAfiSafi.putAll(afiSafi);
140 newAfiSafi.put(IPV4_AFISAFI.key(), IPV4_AFISAFI);
146 static ClusterIdentifier getGlobalClusterIdentifier(final org.opendaylight.yang.gen.v1.http.openconfig.net
147 .yang.bgp.rev151009.bgp.global.base.Config globalConfig) {
148 final GlobalConfigAugmentation globalConfigAugmentation
149 = globalConfig.augmentation(GlobalConfigAugmentation.class);
150 final Ipv4Address addr;
151 if (globalConfigAugmentation != null && globalConfigAugmentation.getRouteReflectorClusterId() != null) {
152 addr = globalConfigAugmentation.getRouteReflectorClusterId().getIpv4Address();
154 addr = globalConfig.getRouterId();
156 return new ClusterIdentifier(IetfInetUtil.INSTANCE.ipv4AddressNoZoneFor(addr));
159 static @Nullable ClusterIdentifier getNeighborClusterIdentifier(
160 final @Nullable RouteReflector routeReflector, final @Nullable PeerGroup peerGroup) {
161 if (peerGroup != null) {
162 final ClusterIdentifier clusteriId = extractClusterId(peerGroup.getRouteReflector());
163 if (clusteriId != null) {
168 return extractClusterId(routeReflector);
171 private static ClusterIdentifier extractClusterId(final RouteReflector routeReflector) {
172 if (routeReflector != null) {
173 final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.route
174 .reflector.Config config = routeReflector.getConfig();
175 if (config != null && config.getRouteReflectorClusterId() != null) {
176 return new ClusterIdentifier(IetfInetUtil.INSTANCE.ipv4AddressNoZoneFor(
177 config.getRouteReflectorClusterId().getIpv4Address()));
183 static Map<BgpTableType, PathSelectionMode> toPathSelectionMode(final Collection<AfiSafi> afiSafis,
184 final BGPTableTypeRegistryConsumer tableTypeRegistry) {
185 final Map<BgpTableType, PathSelectionMode> pathSelectionModes = new HashMap<>();
186 for (final AfiSafi afiSafi : afiSafis) {
187 final BgpNeighborAddPathsConfig afiSafi2 = afiSafi.augmentation(GlobalAddPathsConfig.class);
188 if (afiSafi2 != null) {
189 final Optional<BgpTableType> bgpTableType = tableTypeRegistry.getTableType(afiSafi.getAfiSafiName());
190 if (bgpTableType.isPresent()) {
191 final short sendMax = afiSafi2.getSendMax().toJava();
192 final PathSelectionMode selectionMode;
194 selectionMode = new AddPathBestNPathSelection(sendMax);
196 selectionMode = new AllPathSelection();
198 pathSelectionModes.put(bgpTableType.get(), selectionMode);
202 return pathSelectionModes;
205 static boolean isApplicationPeer(final Neighbor neighbor) {
206 final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group
207 .Config config = neighbor.getConfig();
208 if (config != null) {
209 final NeighborPeerGroupConfig config1 = config.augmentation(NeighborPeerGroupConfig.class);
210 if (config1 != null) {
211 final String peerGroup = config1.getPeerGroup();
212 return peerGroup != null && peerGroup.equals(APPLICATION_PEER_GROUP_NAME);
218 static List<AddressFamilies> toAddPathCapability(final Collection<AfiSafi> afiSafis,
219 final BGPTableTypeRegistryConsumer tableTypeRegistry) {
220 final List<AddressFamilies> addPathCapability = new ArrayList<>();
221 for (final AfiSafi afiSafi : afiSafis) {
222 final BgpNeighborAddPathsConfig afiSafi1 = afiSafi.augmentation(NeighborAddPathsConfig.class);
223 final Optional<BgpTableType> bgpTableType = tableTypeRegistry.getTableType(afiSafi.getAfiSafiName());
224 if (afiSafi1 != null && bgpTableType.isPresent()) {
225 final AddressFamiliesBuilder builder = new AddressFamiliesBuilder(bgpTableType.get());
226 builder.setSendReceive(toSendReceiveMode(afiSafi1));
227 addPathCapability.add(builder.build());
230 return addPathCapability;
233 private static SendReceive toSendReceiveMode(final BgpNeighborAddPathsConfig addPath) {
234 if (addPath.isReceive() && addPath.getSendMax() != null) {
235 return SendReceive.Both;
237 if (addPath.getSendMax() != null) {
238 return SendReceive.Send;
240 return SendReceive.Receive;
243 private static boolean isRrClient(final BgpNeighborGroup neighbor) {
244 final RouteReflector routeReflector = neighbor.getRouteReflector();
245 if (routeReflector != null && routeReflector.getConfig() != null) {
246 return routeReflector.getConfig().isRouteReflectorClient();
251 static List<BgpTableType> toTableTypes(final Collection<AfiSafi> afiSafis,
252 final BGPTableTypeRegistryConsumer tableTypeRegistry) {
253 return afiSafis.stream()
254 .map(afiSafi -> tableTypeRegistry.getTableType(afiSafi.getAfiSafiName()))
255 .filter(Optional::isPresent)
257 .collect(Collectors.toList());
260 static Set<TablesKey> toTableKey(final Map<AfiSafiKey, AfiSafi> afiSafis, final BGPTableTypeRegistryConsumer
262 return afiSafis.values().stream()
263 .map(afiSafi -> tableTypeRegistry.getTableKey(afiSafi.getAfiSafiName()))
264 .filter(Optional::isPresent)
266 .collect(Collectors.toSet());
269 static boolean isActive(final Neighbor neighbor, final PeerGroup peerGroup) {
270 Optional<Boolean> activeConnection = peerGroup == null ? Optional.empty() : isActive(peerGroup.getTransport());
271 if (!activeConnection.isPresent()) {
272 activeConnection = isActive(neighbor.getTransport());
274 return activeConnection.orElse(Boolean.TRUE);
277 private static Optional<Boolean> isActive(final Transport transport) {
278 if (transport != null) {
279 final Config config = transport.getConfig();
280 if (config != null) {
281 final Boolean passive = config.isPassiveMode();
282 if (passive != null) {
283 return Optional.of(!passive);
287 return Optional.empty();
290 static PeerRole toPeerRole(final BgpNeighborGroup neighbor) {
291 if (isRrClient(neighbor)) {
292 return PeerRole.RrClient;
295 if (neighbor.getConfig() != null) {
296 final PeerType peerType = neighbor.getConfig().getPeerType();
297 if (peerType == PeerType.EXTERNAL) {
298 return PeerRole.Ebgp;
299 } else if (peerType == PeerType.INTERNAL) {
300 return PeerRole.Ibgp;
306 static @NonNull PeerRole toPeerRole(final Neighbor neighbor, final PeerGroup peerGroup) {
307 PeerRole role = null;
308 if (peerGroup != null) {
309 role = toPeerRole(peerGroup);
313 role = toPeerRole(neighbor);
317 return PeerRole.Ibgp;
322 static int getHoldTimer(final Neighbor neighbor, final PeerGroup peerGroup) {
324 if (peerGroup != null) {
325 hold = getHoldTimer(peerGroup.getTimers());
329 hold = getHoldTimer(neighbor.getTimers());
339 private static @Nullable Integer getHoldTimer(final Timers timers) {
340 if (timers == null) {
343 final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.timers
344 .Config config = timers.getConfig();
345 if (config != null && config.getHoldTime() != null) {
346 return config.getHoldTime().intValue();
351 static int getGracefulRestartTimer(final Neighbor neighbor, final PeerGroup peerGroup, final int holdTimer) {
353 if (peerGroup != null) {
354 timer = getGracefulRestartTimer(peerGroup.getGracefulRestart());
358 timer = getGracefulRestartTimer(neighbor.getGracefulRestart());
362 * RFC4724: "A suggested default for the Restart Time is a value less than or
363 * equal to the HOLDTIME carried in the OPEN."
365 return timer == null ? holdTimer : timer.toJava();
368 private static @Nullable Uint16 getGracefulRestartTimer(final GracefulRestart gracefulRestart) {
369 if (gracefulRestart != null) {
370 final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.graceful.restart.graceful
371 .restart.Config config = gracefulRestart.getConfig();
372 if (config != null) {
373 return config.getRestartTime();
379 static @NonNull AsNumber getRemotePeerAs(final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009
380 .bgp.neighbor.group.Config config, final PeerGroup peerGroup, final AsNumber localAs) {
381 AsNumber neighborAs = null;
382 if (peerGroup != null) {
383 neighborAs = getRemotePeerAs(peerGroup.getConfig());
386 if (neighborAs == null) {
387 neighborAs = getRemotePeerAs(config);
390 if (neighborAs == null) {
396 private static AsNumber getRemotePeerAs(final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp
397 .rev151009.bgp.neighbor.group.@Nullable Config config) {
398 return config == null ? null : config.getPeerAs();
401 static @NonNull AsNumber getLocalPeerAs(final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp
402 .rev151009.bgp.neighbor.group.@Nullable Config config, final @NonNull AsNumber globalAs) {
403 if (config != null) {
404 final AsNumber peerAs = config.getLocalAs();
405 if (peerAs != null) {
412 static int getRetryTimer(final Neighbor neighbor, final PeerGroup peerGroup) {
413 Integer retryTimer = null;
414 if (peerGroup != null) {
415 retryTimer = getRetryTimer(peerGroup.getTimers());
418 if (retryTimer == null) {
419 retryTimer = getRetryTimer(neighbor.getTimers());
422 if (retryTimer == null) {
423 return CONNECT_RETRY;
429 private static @Nullable Integer getRetryTimer(final Timers timers) {
430 if (timers == null) {
433 final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.timers
434 .Config config = timers.getConfig();
435 if (config != null && config.getConnectRetry() != null) {
436 return config.getConnectRetry().intValue();
441 static @NonNull PortNumber getPort(final Neighbor neighbor, final PeerGroup peerGroup) {
442 PortNumber port = null;
443 if (peerGroup != null) {
444 port = getPort(peerGroup.getTransport(), config -> config.augmentation(PeerGroupTransportConfig.class));
448 port = getPort(neighbor.getTransport(), config -> config.augmentation(NeighborTransportConfig.class));
458 private static @Nullable PortNumber getPort(final @Nullable Transport transport,
459 final Function<Config, TransportConfig> extractConfig) {
460 if (transport != null) {
461 final Config config = transport.getConfig();
462 if (config != null) {
463 final TransportConfig peerTc = extractConfig.apply(config);
464 if (peerTc != null) {
465 return peerTc.getRemotePort();
472 static @Nullable IpAddressNoZone getLocalAddress(@Nullable final Transport transport) {
473 if (transport != null && transport.getConfig() != null) {
474 final BgpNeighborTransportConfig.LocalAddress localAddress = transport.getConfig().getLocalAddress();
475 if (localAddress != null) {
476 return convertIpAddress(localAddress.getIpAddress());
482 static @Nullable RevisedErrorHandlingSupport getRevisedErrorHandling(final PeerRole role,final PeerGroup peerGroup,
483 final Neighbor neighbor) {
484 Optional<Boolean> enabled = getRevisedErrorHandling(neighbor);
485 if (!enabled.isPresent()) {
486 enabled = getRevisedErrorHandling(peerGroup);
488 if (!enabled.orElse(Boolean.FALSE)) {
493 return RevisedErrorHandlingSupportImpl.forExternalPeer();
497 return RevisedErrorHandlingSupportImpl.forInternalPeer();
499 throw new IllegalStateException("Unhandled role " + role);
503 private static Optional<Boolean> getRevisedErrorHandling(final BgpNeighborGroup group) {
505 return Optional.empty();
507 final ErrorHandling errorHandling = group.getErrorHandling();
508 if (errorHandling == null) {
509 return Optional.empty();
511 final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.error.handling
512 .Config config = errorHandling.getConfig();
513 return config == null ? Optional.empty() : Optional.of(config.isTreatAsWithdraw());