Add decoder constraint based on treat-as-withdrawn configuration
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / config / OpenConfigMappingUtil.java
index 51151fd6e7a1209f9234dc2fe3550b194a91b561..7190b1d63395cbbd061bf051cba360b43683a471 100644 (file)
 
 package org.opendaylight.protocol.bgp.rib.impl.config;
 
+import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil.INSTANCE;
+
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
+import org.opendaylight.protocol.bgp.mode.impl.add.all.paths.AllPathSelection;
+import org.opendaylight.protocol.bgp.mode.impl.add.n.paths.AddPathBestNPathSelection;
+import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
+import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandlingSupport;
+import org.opendaylight.protocol.bgp.parser.spi.pojo.RevisedErrorHandlingSupportImpl;
+import org.opendaylight.protocol.concepts.KeyMapping;
+import org.opendaylight.protocol.util.Ipv4Util;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.BgpCommonAfiSafiList;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafi;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafiBuilder;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborAddPathsConfig;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborGroup;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborTransportConfig;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.graceful.restart.GracefulRestart;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.ErrorHandling;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.RouteReflector;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Timers;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Transport;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.transport.Config;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.NeighborKey;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroup;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.IPV4UNICAST;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.PeerType;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.SendReceive;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.add.path.capability.AddressFamilies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.add.path.capability.AddressFamiliesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.GlobalAddPathsConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.GlobalConfigAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NeighborAddPathsConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NeighborPeerGroupConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NeighborTransportConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.PeerGroupTransportConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.TransportConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.ClusterIdentifier;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 final class OpenConfigMappingUtil {
 
+    static final String APPLICATION_PEER_GROUP_NAME = "application-peers";
+    static final Optional<String> APPLICATION_PEER_GROUP_NAME_OPT = Optional.of(APPLICATION_PEER_GROUP_NAME);
+    static final int HOLDTIMER = 90;
+    private static final AfiSafi IPV4_AFISAFI = new AfiSafiBuilder().setAfiSafiName(IPV4UNICAST.class).build();
+    private static final List<AfiSafi> DEFAULT_AFISAFI = ImmutableList.of(IPV4_AFISAFI);
+    private static final int CONNECT_RETRY = 30;
+    private static final PortNumber PORT = new PortNumber(179);
+
     private OpenConfigMappingUtil() {
         throw new UnsupportedOperationException();
     }
 
-    public static String getRibInstanceName(final InstanceIdentifier<?> rootIdentifier) {
+    static String getRibInstanceName(final InstanceIdentifier<?> rootIdentifier) {
         return rootIdentifier.firstKeyOf(Protocol.class).getName();
     }
 
+    @Nullable
+    private static Integer getHoldTimer(final Timers timers) {
+        if (timers == null) {
+            return null;
+        }
+        final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.timers
+                .Config config = timers.getConfig();
+        if (config != null && config.getHoldTime() != null) {
+            return config.getHoldTime().intValue();
+        }
+        return null;
+    }
+
+    @Nullable
+    private static AsNumber getRemotePeerAs(final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp
+            .rev151009.bgp.neighbor.group.Config config) {
+        if (config != null) {
+            final AsNumber peerAs = config.getPeerAs();
+            if (peerAs != null) {
+                return peerAs;
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    private static Boolean isActive(final Transport transport) {
+        if (transport != null) {
+            final Config config = transport.getConfig();
+            if (config != null && config.isPassiveMode() != null) {
+                return !config.isPassiveMode();
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    private static Integer getRetryTimer(final Timers timers) {
+        if (timers == null) {
+            return null;
+        }
+        final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.timers
+                .Config config = timers.getConfig();
+        if (config != null && config.getConnectRetry() != null) {
+            return config.getConnectRetry().intValue();
+        }
+        return null;
+    }
+
+    static KeyMapping getNeighborKey(final Neighbor neighbor) {
+        if (neighbor.getConfig() != null) {
+            final String authPassword = neighbor.getConfig().getAuthPassword();
+            if (authPassword != null) {
+                return KeyMapping.getKeyMapping(INSTANCE.inetAddressFor(neighbor.getNeighborAddress()), authPassword);
+            }
+        }
+        return null;
+    }
+
+    static InstanceIdentifier<Neighbor> getNeighborInstanceIdentifier(
+            final InstanceIdentifier<Bgp> rootIdentifier,
+            final NeighborKey neighborKey) {
+        return rootIdentifier.child(Neighbors.class).child(Neighbor.class, neighborKey);
+    }
+
+    static String getNeighborInstanceName(final InstanceIdentifier<?> rootIdentifier) {
+        return Ipv4Util.toStringIP(rootIdentifier.firstKeyOf(Neighbor.class).getNeighborAddress());
+    }
+
+    @Nullable
+    private static <T extends TransportConfig & Augmentation<Config>> PortNumber getPort(
+            @Nullable final Transport transport, final Class<T> augment) {
+        if (transport != null) {
+            final Config config = transport.getConfig();
+            if (config != null) {
+                final T peerTc = config.augmentation(augment);
+                if (peerTc != null) {
+                    return peerTc.getRemotePort();
+                }
+            }
+        }
+        return null;
+    }
+
+    //make sure IPv4 Unicast (RFC 4271) when required
+    static List<AfiSafi> getAfiSafiWithDefault(
+            final BgpCommonAfiSafiList afiSAfis, final boolean setDeafultIPv4) {
+        if (afiSAfis == null || afiSAfis.getAfiSafi() == null) {
+            return setDeafultIPv4 ? DEFAULT_AFISAFI : Collections.emptyList();
+        }
+        final List<AfiSafi> afiSafi = afiSAfis.getAfiSafi();
+        if (setDeafultIPv4) {
+            final boolean anyMatch = afiSafi.stream()
+                    .anyMatch(input -> input.getAfiSafiName().equals(IPV4UNICAST.class));
+            if (!anyMatch) {
+                afiSafi.add(IPV4_AFISAFI);
+            }
+        }
+        return afiSafi;
+    }
+
+    static ClusterIdentifier getGlobalClusterIdentifier(final org.opendaylight.yang.gen.v1.http.openconfig.net
+            .yang.bgp.rev151009.bgp.global.base.Config globalConfig) {
+        final GlobalConfigAugmentation globalConfigAugmentation
+                = globalConfig.augmentation(GlobalConfigAugmentation.class);
+        if (globalConfigAugmentation != null && globalConfigAugmentation.getRouteReflectorClusterId() != null) {
+            return new ClusterIdentifier(globalConfigAugmentation.getRouteReflectorClusterId().getIpv4Address());
+        }
+        return new ClusterIdentifier(globalConfig.getRouterId());
+    }
+
+    @Nullable
+    static ClusterIdentifier getNeighborClusterIdentifier(
+            @Nullable final RouteReflector routeReflector,
+            @Nullable final PeerGroup peerGroup) {
+        if (peerGroup != null) {
+            final ClusterIdentifier clusteriId = extractClusterId(peerGroup.getRouteReflector());
+            if (clusteriId != null) {
+                return clusteriId;
+            }
+        }
+
+        return extractClusterId(routeReflector);
+    }
+
+    private static ClusterIdentifier extractClusterId(final RouteReflector routeReflector) {
+        if (routeReflector != null) {
+            final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.route
+                    .reflector.Config config = routeReflector.getConfig();
+            if (config != null && config.getRouteReflectorClusterId() != null) {
+                return new ClusterIdentifier(config.getRouteReflectorClusterId().getIpv4Address());
+            }
+        }
+        return null;
+    }
+
+    static Map<BgpTableType, PathSelectionMode> toPathSelectionMode(final List<AfiSafi> afiSafis,
+            final BGPTableTypeRegistryConsumer tableTypeRegistry) {
+        final Map<BgpTableType, PathSelectionMode> pathSelectionModes = new HashMap<>();
+        for (final AfiSafi afiSafi : afiSafis) {
+            final BgpNeighborAddPathsConfig afiSafi2 = afiSafi.augmentation(GlobalAddPathsConfig.class);
+            if (afiSafi2 != null) {
+                final Optional<BgpTableType> bgpTableType = tableTypeRegistry.getTableType(afiSafi.getAfiSafiName());
+                if (bgpTableType.isPresent()) {
+                    final int sendMax = afiSafi2.getSendMax();
+                    final PathSelectionMode selectionMode;
+                    if (sendMax > 1) {
+                        selectionMode = new AddPathBestNPathSelection(sendMax);
+                    } else {
+                        selectionMode = new AllPathSelection();
+                    }
+                    pathSelectionModes.put(bgpTableType.get(), selectionMode);
+                }
+            }
+        }
+        return pathSelectionModes;
+    }
+
+    static boolean isApplicationPeer(final Neighbor neighbor) {
+        final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group
+                .Config config = neighbor.getConfig();
+        if (config != null) {
+            final NeighborPeerGroupConfig config1 = config.augmentation(NeighborPeerGroupConfig.class);
+            if (config1 != null) {
+                final String peerGroup = config1.getPeerGroup();
+                return peerGroup != null && peerGroup.equals(APPLICATION_PEER_GROUP_NAME);
+            }
+        }
+        return false;
+    }
+
+    static List<AddressFamilies> toAddPathCapability(final List<AfiSafi> afiSafis,
+            final BGPTableTypeRegistryConsumer tableTypeRegistry) {
+        final List<AddressFamilies> addPathCapability = new ArrayList<>();
+        for (final AfiSafi afiSafi : afiSafis) {
+            final BgpNeighborAddPathsConfig afiSafi1 = afiSafi.augmentation(NeighborAddPathsConfig.class);
+            final Optional<BgpTableType> bgpTableType = tableTypeRegistry.getTableType(afiSafi.getAfiSafiName());
+            if (afiSafi1 != null && bgpTableType.isPresent()) {
+                final AddressFamiliesBuilder builder = new AddressFamiliesBuilder(bgpTableType.get());
+                builder.setSendReceive(toSendReceiveMode(afiSafi1));
+                addPathCapability.add(builder.build());
+            }
+        }
+        return addPathCapability;
+    }
+
+    private static SendReceive toSendReceiveMode(final BgpNeighborAddPathsConfig addPath) {
+        if (addPath.isReceive() && addPath.getSendMax() != null) {
+            return SendReceive.Both;
+        }
+        if (addPath.getSendMax() != null) {
+            return SendReceive.Send;
+        }
+        return SendReceive.Receive;
+    }
+
+    static PeerRole toPeerRole(final BgpNeighborGroup neighbor) {
+        if (isRrClient(neighbor)) {
+            return PeerRole.RrClient;
+        }
+
+        if (neighbor.getConfig() != null) {
+            final PeerType peerType = neighbor.getConfig().getPeerType();
+            if (peerType == PeerType.EXTERNAL) {
+                return PeerRole.Ebgp;
+            } else if (peerType == PeerType.INTERNAL) {
+                return PeerRole.Ibgp;
+            }
+        }
+        return null;
+    }
+
+    private static boolean isRrClient(final BgpNeighborGroup neighbor) {
+        final RouteReflector routeReflector = neighbor.getRouteReflector();
+        if (routeReflector != null && routeReflector.getConfig() != null) {
+            return routeReflector.getConfig().isRouteReflectorClient();
+        }
+        return false;
+    }
+
+    static List<BgpTableType> toTableTypes(final List<AfiSafi> afiSafis,
+            final BGPTableTypeRegistryConsumer tableTypeRegistry) {
+        return afiSafis.stream()
+                .map(afiSafi -> tableTypeRegistry.getTableType(afiSafi.getAfiSafiName()))
+                .filter(Optional::isPresent)
+                .map(Optional::get)
+                .collect(Collectors.toList());
+    }
+
+    static Set<TablesKey> toTableKey(final List<AfiSafi> afiSafis, final BGPTableTypeRegistryConsumer
+            tableTypeRegistry) {
+        return afiSafis.stream()
+                .map(afiSafi -> tableTypeRegistry.getTableKey(afiSafi.getAfiSafiName()))
+                .filter(Optional::isPresent)
+                .map(Optional::get)
+                .collect(Collectors.toSet());
+    }
+
+    static boolean isActive(final Neighbor neighbor, final PeerGroup peerGroup) {
+        Boolean activeConnection = null;
+        if (peerGroup != null) {
+            activeConnection = isActive(peerGroup.getTransport());
+        }
+
+        if (activeConnection == null) {
+            activeConnection = isActive(neighbor.getTransport());
+        }
+        if (activeConnection == null) {
+            return true;
+        }
+        return activeConnection;
+    }
+
+    @Nonnull
+    static PeerRole toPeerRole(final Neighbor neighbor, final PeerGroup peerGroup) {
+        PeerRole role = null;
+        if (peerGroup != null) {
+            role = toPeerRole(peerGroup);
+        }
+
+        if (role == null) {
+            role = toPeerRole(neighbor);
+        }
+
+        if (role == null) {
+            return PeerRole.Ibgp;
+        }
+        return role;
+    }
+
+    static int getHoldTimer(final Neighbor neighbor, final PeerGroup peerGroup) {
+        Integer hold = null;
+        if (peerGroup != null) {
+            hold = getHoldTimer(peerGroup.getTimers());
+        }
+
+        if (hold == null) {
+            hold = getHoldTimer(neighbor.getTimers());
+        }
+
+        if (hold == null) {
+            return HOLDTIMER;
+        }
+
+        return hold;
+    }
+
+    static int getGracefulRestartTimer(final Neighbor neighbor, final PeerGroup peerGroup, final int holdTimer) {
+        Integer timer = null;
+        if (peerGroup != null) {
+            timer = getGracefulRestartTimer(peerGroup.getGracefulRestart());
+        }
+
+        if (timer == null) {
+            timer = getGracefulRestartTimer(neighbor.getGracefulRestart());
+        }
+
+        /*
+         * RFC4724: "A suggested default for the Restart Time is a value less than or
+         * equal to the HOLDTIME carried in the OPEN."
+         */
+        if (timer == null) {
+            timer = holdTimer;
+        }
+
+        return timer;
+    }
+
+    @Nullable
+    private static Integer getGracefulRestartTimer(final GracefulRestart gracefulRestart) {
+        if (gracefulRestart != null) {
+            final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.graceful.restart.graceful
+                    .restart.Config config = gracefulRestart.getConfig();
+            if (config != null) {
+                return config.getRestartTime();
+            }
+        }
+        return null;
+    }
+
+    @Nonnull
+    static AsNumber getRemotePeerAs(final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009
+            .bgp.neighbor.group.Config config, final PeerGroup peerGroup, final AsNumber localAs) {
+        AsNumber neighborAs = null;
+        if (peerGroup != null) {
+            neighborAs = getRemotePeerAs(peerGroup.getConfig());
+        }
+
+        if (neighborAs == null) {
+            neighborAs = getRemotePeerAs(config);
+        }
+
+        if (neighborAs == null) {
+            return localAs;
+        }
+        return neighborAs;
+    }
+
+    @Nonnull
+    static AsNumber getLocalPeerAs(@Nullable final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp
+            .rev151009.bgp.neighbor.group.Config config, @Nonnull final AsNumber globalAs) {
+        if (config != null) {
+            final AsNumber peerAs = config.getLocalAs();
+            if (peerAs != null) {
+                return peerAs;
+            }
+        }
+        return globalAs;
+    }
+
+    static int getRetryTimer(final Neighbor neighbor, final PeerGroup peerGroup) {
+        Integer retryTimer = null;
+        if (peerGroup != null) {
+            retryTimer = getRetryTimer(peerGroup.getTimers());
+        }
+
+        if (retryTimer == null) {
+            retryTimer = getRetryTimer(neighbor.getTimers());
+        }
+
+        if (retryTimer == null) {
+            return CONNECT_RETRY;
+        }
+
+        return retryTimer;
+    }
+
+    @Nonnull
+    static PortNumber getPort(final Neighbor neighbor, final PeerGroup peerGroup) {
+        PortNumber port = null;
+        if (peerGroup != null) {
+            port = getPort(peerGroup.getTransport(), PeerGroupTransportConfig.class);
+        }
+
+        if (port == null) {
+            port = getPort(neighbor.getTransport(), NeighborTransportConfig.class);
+        }
+
+        if (port == null) {
+            return PORT;
+        }
+
+        return port;
+    }
+
+    @Nullable
+    static IpAddress getLocalAddress(@Nullable final Transport transport) {
+        if (transport != null && transport.getConfig() != null) {
+            final BgpNeighborTransportConfig.LocalAddress localAddress = transport.getConfig().getLocalAddress();
+            if (localAddress != null ) {
+                return localAddress.getIpAddress();
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    static RevisedErrorHandlingSupport getRevisedErrorHandling(final PeerRole role,final PeerGroup peerGroup,
+            final Neighbor neighbor) {
+        Boolean enabled = getRevisedErrorHandling(neighbor);
+        if (enabled == null) {
+            enabled = getRevisedErrorHandling(peerGroup);
+        }
+        if (!Boolean.TRUE.equals(enabled)) {
+            return null;
+        }
+        switch (role) {
+            case Ebgp:
+                return RevisedErrorHandlingSupportImpl.forExternalPeer();
+            case Ibgp:
+            case Internal:
+            case RrClient:
+                return RevisedErrorHandlingSupportImpl.forInternalPeer();
+            default:
+                throw new IllegalStateException("Unhandled role " + role);
+        }
+    }
+
+    @Nullable
+    private static @org.eclipse.jdt.annotation.Nullable Boolean getRevisedErrorHandling(final BgpNeighborGroup group) {
+        if (group == null) {
+            return null;
+        }
+        final ErrorHandling errorHandling = group.getErrorHandling();
+        if (errorHandling == null) {
+            return null;
+        }
+        final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.error.handling
+            .Config config = errorHandling.getConfig();
+        return config == null ? null : config.isTreatAsWithdraw();
+    }
 }