From ee6ac915446be0d46a439f4e5c3e8b644d587885 Mon Sep 17 00:00:00 2001 From: Milos Fabian Date: Thu, 14 Apr 2016 14:31:10 +0200 Subject: [PATCH] Bug-4827: BGP Add-Path OpenConfig Support II Added mapping from OpenConfig API to BGP RIB and Peer Module support BGP Add-Path configuration. In "BGPPeer" configuration per AFI/SAFI Add-Path capability is configured optionally. In "BGPRibImpl" configuration per AFI/SAFI path selection strategy is configured optionally. Change-Id: Ie88148417037ffae869c39cc067fb4b5373ca25e Signed-off-by: Milos Fabian --- .../impl/moduleconfig/AddPathFunction.java | 139 ++++++++++++++ .../impl/moduleconfig/BGPPeerProvider.java | 51 ++++-- .../impl/moduleconfig/BGPRibImplProvider.java | 22 ++- .../PathSelectionModeFunction.java | 170 ++++++++++++++++++ .../impl/moduleconfig/TableTypesFunction.java | 28 +-- .../openconfig/impl/util/OpenConfigUtil.java | 56 +++--- .../impl/util/OpenConfigUtilTest.java | 13 ++ 7 files changed, 425 insertions(+), 54 deletions(-) create mode 100644 bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/AddPathFunction.java create mode 100644 bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/PathSelectionModeFunction.java diff --git a/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/AddPathFunction.java b/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/AddPathFunction.java new file mode 100644 index 0000000000..4d9a0aab0d --- /dev/null +++ b/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/AddPathFunction.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.protocol.bgp.openconfig.impl.moduleconfig; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.ReadTransaction; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.protocol.bgp.openconfig.impl.util.OpenConfigUtil; +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.use.multiple.paths.neighbor.UseMultiplePaths; +import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.use.multiple.paths.neighbor.use.multiple.paths.Config; +import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.AfiSafi2; +import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.AfiSafiType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.SendReceive; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.AddPath; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.AddPathImpl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.BgpTableType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.BgpTableTypeImpl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.ServiceRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.Module; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.ModuleKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.services.Service; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.services.ServiceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.services.service.Instance; +import org.opendaylight.yangtools.yang.binding.ChildOf; + +final class AddPathFunction { + + private AddPathFunction() { + throw new UnsupportedOperationException(); + } + + public static > List getAddPath(final ReadOnlyTransaction rTx, final BGPConfigModuleProvider + configModuleWriter, final Function function, final List afiSafis) { + final ImmutableList afiSafisMultipath = FluentIterable.from(afiSafis).filter(new Predicate() { + @Override + public boolean apply(final AfiSafi afisafi) { + final AfiSafi2 afiSafi2 = afisafi.getAugmentation(AfiSafi2.class); + if (afiSafi2 != null) { + final UseMultiplePaths useMultiplePaths = afiSafi2.getUseMultiplePaths(); + if (useMultiplePaths != null) { + final Config useMultiplePathsConfig = useMultiplePaths.getConfig(); + if (useMultiplePathsConfig != null && useMultiplePathsConfig.isEnabled() != null) { + return useMultiplePathsConfig.isEnabled(); + } + } + } + return false; + }}).toList(); + try { + final Optional maybeService = configModuleWriter.readConfigService(new ServiceKey(AddPath.class), rTx); + if (maybeService.isPresent()) { + final Service service = maybeService.get(); + final List modules = new ArrayList<>(); + final Map moduleNameToService = new HashMap<>(); + for (final Instance instance : service.getInstance()) { + final String moduleName = OpenConfigUtil.getModuleName(instance.getProvider()); + final ModuleKey moduleKey = new ModuleKey(moduleName, AddPathImpl.class); + final Optional moduleConfig = configModuleWriter.readModuleConfiguration(moduleKey, rTx); + if (moduleConfig.isPresent()) { + modules.add(moduleConfig.get()); + } + moduleNameToService.put(moduleName, instance.getName()); + } + + return TableTypesFunction.toServices(function, afiSafisMultipath, afiSafiToModuleName(afiSafisMultipath, modules, configModuleWriter, rTx), moduleNameToService); + } + return Collections.emptyList(); + } catch (final ReadFailedException e) { + throw new IllegalStateException(OpenConfigUtil.FAILED_TO_READ_SERVICE, e); + } + } + + private static Map, String> afiSafiToModuleName(final List afiSafis, final List modules, final BGPConfigModuleProvider configModuleWriter, final ReadTransaction rTx) throws ReadFailedException { + final Map, String> afiSafiToModuleName = new HashMap<>(afiSafis.size()); + for (final Module module : modules) { + final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.AddPathImpl config = + ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.AddPathImpl) module.getConfiguration()); + if (config.getSendReceive() == SendReceive.Both) { + final Optional tryFind = Iterables.tryFind(afiSafis, new Predicate() { + @Override + public boolean apply(final AfiSafi input) { + final Optional bgpTableType = OpenConfigUtil.toBgpTableType(input.getAfiSafiName()); + return bgpTableType.isPresent() && tableTypeExists(configModuleWriter, rTx, + (String) config.getAddressFamily().getName(), bgpTableType.get()); + } + }); + if (tryFind.isPresent()) { + afiSafiToModuleName.put(tryFind.get().getAfiSafiName(), module.getName()); + } + } + } + return afiSafiToModuleName; + } + + public static boolean tableTypeExists(final BGPConfigModuleProvider configModuleWriter, final ReadTransaction rTx, + final String instanceName, final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType tableType) { + try { + final Optional maybeService = configModuleWriter.readConfigService(new ServiceKey(BgpTableType.class), rTx); + if (maybeService.isPresent()) { + for (final Instance instance : maybeService.get().getInstance()) { + final String moduleName = OpenConfigUtil.getModuleName(instance.getProvider()); + if (moduleName.equals(instanceName)) { + final ModuleKey moduleKey = new ModuleKey(moduleName, BgpTableTypeImpl.class); + final Optional moduleConfig = configModuleWriter.readModuleConfiguration(moduleKey, rTx); + if (moduleConfig.isPresent()) { + final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpTableTypeImpl tableTypeImpl = (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpTableTypeImpl)moduleConfig.get().getConfiguration(); + final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType moduleTableType = new org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl(tableTypeImpl.getAfi(), tableTypeImpl.getSafi()); + if (moduleTableType.equals(tableType)) { + return true; + } + } + } + } + } + return false; + } catch (final ReadFailedException e) { + throw new IllegalStateException(OpenConfigUtil.FAILED_TO_READ_SERVICE, e); + } + } + +} diff --git a/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/BGPPeerProvider.java b/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/BGPPeerProvider.java index 1c0c08b0f3..555d9037a8 100644 --- a/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/BGPPeerProvider.java +++ b/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/BGPPeerProvider.java @@ -32,6 +32,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controll import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.BgpTableType; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.RibInstance; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPeerBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.AddPath; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.AddPathBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.AdvertizedTable; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.AdvertizedTableBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.Rib; @@ -73,6 +75,16 @@ final class BGPPeerProvider { } }; + private static final Function ADD_PATH_FUNCTION = new Function() { + @Override + public AddPath apply(final String name) { + return new AddPathBuilder() + .setName(name) + .setType(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.AddPath.class) + .build(); + } + }; + private final BGPConfigHolder neighborState; private final BGPConfigHolder globalState; private final BGPConfigModuleProvider configModuleOp; @@ -105,22 +117,28 @@ final class BGPPeerProvider { final ModuleKey moduleKey = this.neighborState.getModuleKey(modifiedNeighbor.getKey()); final ReadOnlyTransaction rTx = this.dataBroker.newReadOnlyTransaction(); final List advertizedTables = getAdvertizedTables(modifiedNeighbor, rTx); + final List addPathCapabilities = getAddPathCapabilities(modifiedNeighbor, rTx); if (moduleKey != null) { - updateExistingPeerConfiguration(moduleKey, modifiedNeighbor, advertizedTables, rTx); + updateExistingPeerConfiguration(moduleKey, modifiedNeighbor, advertizedTables, rTx, addPathCapabilities); } else { - createNewPeerConfiguration(moduleKey, modifiedNeighbor, advertizedTables, rTx); + createNewPeerConfiguration(moduleKey, modifiedNeighbor, advertizedTables, rTx, addPathCapabilities); } } private List getAdvertizedTables(final Neighbor modifiedNeighbor, final ReadOnlyTransaction rTx) { - return TableTypesFunction.getLocalTables(rTx, this.configModuleOp, this.ADVERTIZED_TABLE_FUNCTION, modifiedNeighbor.getAfiSafis().getAfiSafi()); + return TableTypesFunction.getLocalTables(rTx, this.configModuleOp, ADVERTIZED_TABLE_FUNCTION, modifiedNeighbor.getAfiSafis().getAfiSafi()); + } + + private List getAddPathCapabilities(final Neighbor modifiedNeighbor, final ReadOnlyTransaction rTx) { + return AddPathFunction.getAddPath(rTx, this.configModuleOp, ADD_PATH_FUNCTION, modifiedNeighbor.getAfiSafis().getAfiSafi()); } - private void updateExistingPeerConfiguration(final ModuleKey moduleKey, final Neighbor modifiedNeighbor, final List advertizedTables, final ReadOnlyTransaction rTx) { - if (this.neighborState.addOrUpdate(moduleKey, modifiedNeighbor.getKey(), modifiedNeighbor)) { + private void updateExistingPeerConfiguration(final ModuleKey moduleKey, final Neighbor modifiedNeighbor, final List + advertizedTables, final ReadOnlyTransaction rTx, final List addPathCapabilities) { + if (neighborState.addOrUpdate(moduleKey, modifiedNeighbor.getKey(), modifiedNeighbor)) { final Optional maybeModule = getOldModuleConfiguration(moduleKey, rTx); if (maybeModule.isPresent()) { - final Module peerConfigModule = toPeerConfigModule(modifiedNeighbor, maybeModule.get(), advertizedTables); + final Module peerConfigModule = toPeerConfigModule(modifiedNeighbor, maybeModule.get(), advertizedTables, addPathCapabilities); putOldModuleConfigurationIntoNewModule(peerConfigModule); } } @@ -144,13 +162,14 @@ final class BGPPeerProvider { } } - private void createNewPeerConfiguration(final ModuleKey moduleKey, final Neighbor modifiedNeighbor, final List advertizedTables, final ReadOnlyTransaction rTx) { + private void createNewPeerConfiguration(final ModuleKey moduleKey, final Neighbor modifiedNeighbor, final List advertizedTables, + final ReadOnlyTransaction rTx, final List addPathCapabilities) { final ModuleKey ribImplKey = this.globalState.getModuleKey(GlobalIdentifier.GLOBAL_IDENTIFIER); if (ribImplKey != null) { try { - final Rib rib = RibInstanceFunction.getRibInstance(this.configModuleOp, this.TO_RIB_FUNCTION, ribImplKey.getName(), rTx); + final Rib rib = RibInstanceFunction.getRibInstance(this.configModuleOp, TO_RIB_FUNCTION, ribImplKey.getName(), rTx); final RpcRegistry rpcReg = RpcRegistryFunction.getRpcRegistryInstance(rTx, this.configModuleOp, RPC_REG_FUNCTION); - final Module peerConfigModule = toPeerConfigModule(modifiedNeighbor, advertizedTables, rib, rpcReg); + final Module peerConfigModule = toPeerConfigModule(modifiedNeighbor, advertizedTables, rib, rpcReg, addPathCapabilities); this.configModuleOp.putModuleConfiguration(peerConfigModule, this.dataBroker.newWriteOnlyTransaction()); this.neighborState.addOrUpdate(peerConfigModule.getKey(), modifiedNeighbor.getKey(), modifiedNeighbor); } catch (final Exception e) { @@ -160,10 +179,11 @@ final class BGPPeerProvider { } } - private static Module toPeerConfigModule(final Neighbor neighbor, final Module oldBgpPeer, final List tableTypes) { + private static Module toPeerConfigModule(final Neighbor neighbor, final Module oldBgpPeer, final List tableTypes, + final List addPathCapabilities) { final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPeer bgpPeer = (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPeer) oldBgpPeer.getConfiguration(); - final BgpPeerBuilder bgpPeerBuilder = toBgpPeerConfig(neighbor, tableTypes, bgpPeer.getRib(), bgpPeer.getRpcRegistry()); + final BgpPeerBuilder bgpPeerBuilder = toBgpPeerConfig(neighbor, tableTypes, bgpPeer.getRib(), bgpPeer.getRpcRegistry(), addPathCapabilities); bgpPeerBuilder.setPeerRegistry(((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPeer) oldBgpPeer.getConfiguration()).getPeerRegistry()); bgpPeerBuilder.setPort(((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPeer) oldBgpPeer.getConfiguration()).getPort()); @@ -172,21 +192,24 @@ final class BGPPeerProvider { return mBuilder.build(); } - private static Module toPeerConfigModule(final Neighbor neighbor, final List tableTypes, final Rib rib, final RpcRegistry rpcReg) { + private static Module toPeerConfigModule(final Neighbor neighbor, final List tableTypes, final Rib rib, final RpcRegistry rpcReg, + final List addPathCapabilities) { final ModuleBuilder mBuilder = new ModuleBuilder(); mBuilder.setName(createPeerName(neighbor.getNeighborAddress())); mBuilder.setType(BgpPeer.class); - mBuilder.setConfiguration(toBgpPeerConfig(neighbor, tableTypes, rib, rpcReg).build()); + mBuilder.setConfiguration(toBgpPeerConfig(neighbor, tableTypes, rib, rpcReg, addPathCapabilities).build()); mBuilder.setKey(new ModuleKey(mBuilder.getName(), mBuilder.getType())); return mBuilder.build(); } - private static BgpPeerBuilder toBgpPeerConfig(final Neighbor neighbor, final List tableTypes, final Rib rib, final RpcRegistry rpcReg) { + private static BgpPeerBuilder toBgpPeerConfig(final Neighbor neighbor, final List tableTypes, final Rib rib, final RpcRegistry rpcReg, + final List addPathCapabilities) { final BgpPeerBuilder bgpPeerBuilder = new BgpPeerBuilder(); if (rpcReg != null) { bgpPeerBuilder.setRpcRegistry(rpcReg); } bgpPeerBuilder.setAdvertizedTable(tableTypes); + bgpPeerBuilder.setAddPath(addPathCapabilities); bgpPeerBuilder.setRib(rib); org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress ipAdress = null; if (neighbor.getNeighborAddress().getIpv4Address() != null) { diff --git a/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/BGPRibImplProvider.java b/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/BGPRibImplProvider.java index ca260d24a3..42f2700d36 100644 --- a/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/BGPRibImplProvider.java +++ b/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/BGPRibImplProvider.java @@ -22,11 +22,14 @@ import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.t import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.BgpBuilder; import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.BgpPathSelectionMode; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.BgpTableType; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.RibImpl; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.RibImplBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.rib.impl.LocalTable; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.rib.impl.LocalTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.rib.impl.RibPathSelectionMode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.rib.impl.RibPathSelectionModeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.Module; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.ModuleBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.ModuleKey; @@ -44,6 +47,13 @@ final class BGPRibImplProvider { } }; + private static final Function PATH_SELECTION_MODE_FUNCTION = new Function() { + @Override + public RibPathSelectionMode apply(final String input) { + return new RibPathSelectionModeBuilder().setName(input).setType(BgpPathSelectionMode.class).build(); + } + }; + private final BGPConfigHolder globalState; private final BGPConfigModuleProvider configModuleWriter; private final DataBroker dataBroker; @@ -78,7 +88,8 @@ final class BGPRibImplProvider { final Optional maybeModule = this.configModuleWriter.readModuleConfiguration(moduleKey, rTx); if (maybeModule.isPresent()) { final List localTables = getAdvertizedTables(modifiedGlobal, rTx); - final Module newModule = toRibImplConfigModule(modifiedGlobal, maybeModule.get(), localTables); + final List pathSelectionModes = getPathSelectionModes(modifiedGlobal, rTx); + final Module newModule = toRibImplConfigModule(modifiedGlobal, maybeModule.get(), localTables, pathSelectionModes); this.configModuleWriter.putModuleConfiguration(newModule, dataBroker.newWriteOnlyTransaction()); } } catch (final Exception e) { @@ -92,7 +103,13 @@ final class BGPRibImplProvider { return TableTypesFunction.getLocalTables(rTx, this.configModuleWriter, this.LOCAL_TABLE_FUNCTION, modifiedGlobal.getAfiSafis().getAfiSafi()); } - private static Module toRibImplConfigModule(final Global globalConfig, final Module module, final List tableTypes) { + private List getPathSelectionModes(final Global modifiedGlobal, final ReadOnlyTransaction rTx) { + return PathSelectionModeFunction.getPathSelectionMode(rTx, this.configModuleWriter, PATH_SELECTION_MODE_FUNCTION, + modifiedGlobal.getAfiSafis().getAfiSafi()); + } + + private static Module toRibImplConfigModule(final Global globalConfig, final Module module, final List tableTypes, + final List pathSelectionModes) { final RibImpl ribImpl = (RibImpl) module.getConfiguration(); final RibImplBuilder ribImplBuilder = new RibImplBuilder(); if (globalConfig.getConfig() != null) { @@ -108,6 +125,7 @@ final class BGPRibImplProvider { ribImplBuilder.setExtensions(ribImpl.getExtensions()); ribImplBuilder.setRibId(ribImpl.getRibId()); ribImplBuilder.setOpenconfigProvider(ribImpl.getOpenconfigProvider()); + ribImplBuilder.setRibPathSelectionMode(pathSelectionModes); final ModuleBuilder mBuilder = new ModuleBuilder(module); mBuilder.setConfiguration(ribImplBuilder.build()); diff --git a/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/PathSelectionModeFunction.java b/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/PathSelectionModeFunction.java new file mode 100644 index 0000000000..1906c970d2 --- /dev/null +++ b/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/PathSelectionModeFunction.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.protocol.bgp.openconfig.impl.moduleconfig; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; +import com.google.common.collect.Iterables; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.ReadTransaction; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.protocol.bgp.openconfig.impl.util.OpenConfigUtil; +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.use.multiple.paths.use.multiple.paths.Config; +import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.use.multiple.paths.use.multiple.paths.Ibgp; +import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.AfiSafi1; +import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.AfiSafiType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.path.selection.mode.rev160301.AdvertiseAllPaths; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.path.selection.mode.rev160301.AdvertiseNPaths; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.path.selection.mode.rev160301.PathSelectionModeFactory; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.BgpPathSelectionMode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.BgpPsmImpl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.ModuleType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.ServiceRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.Module; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.ModuleKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.services.Service; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.services.ServiceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.services.service.Instance; +import org.opendaylight.yangtools.yang.binding.ChildOf; + +final class PathSelectionModeFunction { + + private static final Map> PATH_SELECTION_MODULE_TYPES; + + static { + final Builder> builder = ImmutableMap.builder(); + builder.put(AdvertiseNPaths.QNAME.getLocalName(), AdvertiseNPaths.class); + builder.put(AdvertiseAllPaths.QNAME.getLocalName(), AdvertiseAllPaths.class); + PATH_SELECTION_MODULE_TYPES = builder.build(); + } + + private PathSelectionModeFunction() { + throw new UnsupportedOperationException(); + } + + public static > List getPathSelectionMode(final ReadOnlyTransaction rTx, final BGPConfigModuleProvider + configModuleWriter, final Function function, final List afiSafis) { + final ImmutableList afiSafisMultipath = FluentIterable.from(afiSafis).filter(new Predicate() { + @Override + public boolean apply(final AfiSafi afisafi) { + final AfiSafi1 afiSafi1 = afisafi.getAugmentation(AfiSafi1.class); + if (afiSafi1 != null) { + final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.use.multiple.paths.UseMultiplePaths useMultiplePaths = afiSafi1.getUseMultiplePaths(); + if (useMultiplePaths != null) { + final Config useMultiplePathsConfig = useMultiplePaths.getConfig(); + if (useMultiplePathsConfig != null && useMultiplePathsConfig.isEnabled() != null) { + return useMultiplePathsConfig.isEnabled(); + } + } + } + return false; + }}).toList(); + try { + final Optional maybeService = configModuleWriter.readConfigService(new ServiceKey(BgpPathSelectionMode.class), rTx); + if (maybeService.isPresent()) { + final Service service = maybeService.get(); + final List modules = new ArrayList<>(); + final Map moduleNameToService = new HashMap<>(); + for (final Instance instance : service.getInstance()) { + final String moduleName = OpenConfigUtil.getModuleName(instance.getProvider()); + final ModuleKey moduleKey = new ModuleKey(moduleName, BgpPsmImpl.class); + final Optional moduleConfig = configModuleWriter.readModuleConfiguration(moduleKey, rTx); + if (moduleConfig.isPresent()) { + modules.add(moduleConfig.get()); + } + moduleNameToService.put(moduleName, instance.getName()); + } + + return TableTypesFunction.toServices(function, afiSafisMultipath, afiSafiToModuleName(afiSafisMultipath, modules, configModuleWriter, rTx), moduleNameToService); + } + return Collections.emptyList(); + } catch (final ReadFailedException e) { + throw new IllegalStateException(OpenConfigUtil.FAILED_TO_READ_SERVICE, e); + } + } + + private static Class getModuleTypeClass(final String moduleType) { + return PATH_SELECTION_MODULE_TYPES.get(moduleType); + } + + private static Map, String> afiSafiToModuleName(final List afiSafis, final List modules, final BGPConfigModuleProvider configModuleWriter, final ReadTransaction rTx) throws ReadFailedException { + final Map, String> afiSafiToModuleName = new HashMap<>(afiSafis.size()); + for (final Module module : modules) { + final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPsmImpl config = + ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPsmImpl) module.getConfiguration()); + + final Optional tryFind = Iterables.tryFind(afiSafis, new Predicate() { + @Override + public boolean apply(final AfiSafi input) { + final Optional bgpTableType = OpenConfigUtil.toBgpTableType(input.getAfiSafiName()); + if (bgpTableType.isPresent() && AddPathFunction.tableTypeExists(configModuleWriter, rTx, + (String) config.getPathAddressFamily().getName(), bgpTableType.get())) { + final Ibgp ibgp = input.getAugmentation(AfiSafi1.class).getUseMultiplePaths().getIbgp(); + return pathSelectionModeExists(configModuleWriter, rTx, (String) config.getPathSelectionMode().getName(), ibgp); + } + return false; + } + }); + if (tryFind.isPresent()) { + afiSafiToModuleName.put(tryFind.get().getAfiSafiName(), module.getName()); + } + } + return afiSafiToModuleName; + } + + public static boolean pathSelectionModeExists(final BGPConfigModuleProvider configModuleWriter, final ReadTransaction rTx, + final String instanceName, final Ibgp ibgp) { + + try { + final Optional maybeService = configModuleWriter.readConfigService(new ServiceKey(PathSelectionModeFactory.class), rTx); + if (maybeService.isPresent()) { + for (final Instance instance : maybeService.get().getInstance()) { + final String provider = instance.getProvider(); + final String moduleName = OpenConfigUtil.getModuleName(provider); + final String moduleType = OpenConfigUtil.getModuleType(provider); + if (moduleName.equals(instanceName)) { + final ModuleKey moduleKey = new ModuleKey(moduleName, getModuleTypeClass(moduleType)); + final Optional moduleConfig = configModuleWriter.readModuleConfiguration(moduleKey, rTx); + if (moduleConfig.isPresent()) { + if (ibgp != null && ibgp.getConfig() != null && ibgp.getConfig().getMaximumPaths() != null) { + final long maxPaths = ibgp.getConfig().getMaximumPaths(); + if (moduleConfig.get().getType().equals(AdvertiseNPaths.class)) { + final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.path.selection.mode.rev160301.modules.module.configuration.AdvertiseNPaths config = + (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.path.selection.mode.rev160301.modules.module.configuration.AdvertiseNPaths)moduleConfig.get().getConfiguration(); + if (maxPaths == config.getNBestPaths().longValue()) { + return true; + } + } + } else { + if (moduleConfig.get().getType().equals(AdvertiseAllPaths.class)) { + return true; + } + } + } + } + } + } + return false; + } catch (final ReadFailedException e) { + throw new IllegalStateException(OpenConfigUtil.FAILED_TO_READ_SERVICE, e); + } + } + +} diff --git a/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/TableTypesFunction.java b/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/TableTypesFunction.java index d201287810..9f509abe08 100644 --- a/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/TableTypesFunction.java +++ b/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/moduleconfig/TableTypesFunction.java @@ -66,14 +66,26 @@ final class TableTypesFunction { } }).toList(); - return toTableTypes(function, afiSafis, afiSafiToModuleName(afiSafis, modules), moduleNameToService); + return toServices(function, afiSafis, afiSafiToModuleName(afiSafis, modules), moduleNameToService); } throw new IllegalStateException("No BgpTableType service present in configuration."); - } catch (ReadFailedException e) { + } catch (final ReadFailedException e) { throw new IllegalStateException("Failed to read service.", e); } } + public static > List toServices(final Function function, final List afiSafis, + final Map, String> afiSafiToModuleName, final Map moduleNameToService) { + final List serives = new ArrayList<>(afiSafis.size()); + for (final AfiSafi afiSafi : afiSafis) { + final String moduleName = afiSafiToModuleName.get(afiSafi.getAfiSafiName()); + if (moduleName != null) { + serives.add(function.apply(moduleNameToService.get(moduleName))); + } + } + return serives; + } + private static Map, String> afiSafiToModuleName(final List afiSafis, final List modules) { final Map, String> afiSafiToModuleName = new HashMap<>(afiSafis.size()); for (final Module module : modules) { @@ -86,16 +98,4 @@ final class TableTypesFunction { } return afiSafiToModuleName; } - - private static > List toTableTypes(final Function function, final List afiSafis, - final Map, String> afiSafiToModuleName, final Map moduleNameToService) { - final List tableTypes = new ArrayList<>(afiSafis.size()); - for (final AfiSafi afiSafi : afiSafis) { - final String moduleName = afiSafiToModuleName.get(afiSafi.getAfiSafiName()); - if (moduleName != null) { - tableTypes.add(function.apply(moduleNameToService.get(moduleName))); - } - } - return tableTypes; - } } diff --git a/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/util/OpenConfigUtil.java b/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/util/OpenConfigUtil.java index 210324126b..be3ee909a3 100644 --- a/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/util/OpenConfigUtil.java +++ b/bgp/openconfig-impl/src/main/java/org/opendaylight/protocol/bgp/openconfig/impl/util/OpenConfigUtil.java @@ -9,8 +9,8 @@ package org.opendaylight.protocol.bgp.openconfig.impl.util; import com.google.common.base.Optional; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableMap.Builder; +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMap; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -30,6 +30,7 @@ import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.AfiSa import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.AfiSafi2; import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.AfiSafi2Builder; 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.types.rev151009.AfiSafiType; import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.IPV4LABELLEDUNICAST; 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.IPV6LABELLEDUNICAST; @@ -56,32 +57,27 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; public final class OpenConfigUtil { + private static final char EQUALS = '='; + public static final InstanceIdentifier BGP_IID = InstanceIdentifier.create(Bgp.class); public static final String APPLICATION_PEER_GROUP_NAME = "application-peers"; - private static final Map TABLETYPE_TO_AFISAFI; + public static final String FAILED_TO_READ_SERVICE = "Failed to read service."; + + private static final BiMap> TABLETYPE_TO_AFISAFI; static { - final Builder b = ImmutableMap.builder(); - b.put(new BgpTableTypeImpl(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class), - new AfiSafiBuilder().setAfiSafiName(IPV4UNICAST.class).build()); - b.put(new BgpTableTypeImpl(Ipv6AddressFamily.class, UnicastSubsequentAddressFamily.class), - new AfiSafiBuilder().setAfiSafiName(IPV6UNICAST.class).build()); - b.put(new BgpTableTypeImpl(Ipv4AddressFamily.class, LabeledUnicastSubsequentAddressFamily.class), - new AfiSafiBuilder().setAfiSafiName(IPV4LABELLEDUNICAST.class).build()); - b.put(new BgpTableTypeImpl(Ipv6AddressFamily.class, LabeledUnicastSubsequentAddressFamily.class), - new AfiSafiBuilder().setAfiSafiName(IPV6LABELLEDUNICAST.class).build()); - b.put(new BgpTableTypeImpl(Ipv4AddressFamily.class, MplsLabeledVpnSubsequentAddressFamily.class), - new AfiSafiBuilder().setAfiSafiName(L3VPNIPV4UNICAST.class).build()); - b.put(new BgpTableTypeImpl(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class), - new AfiSafiBuilder().setAfiSafiName(Linkstate.class).build()); - b.put(new BgpTableTypeImpl(Ipv4AddressFamily.class, FlowspecSubsequentAddressFamily.class), - new AfiSafiBuilder().setAfiSafiName(Ipv4Flow.class).build()); - b.put(new BgpTableTypeImpl(Ipv6AddressFamily.class, FlowspecSubsequentAddressFamily.class), - new AfiSafiBuilder().setAfiSafiName(Ipv6Flow.class).build()); - b.put(new BgpTableTypeImpl(L2vpnAddressFamily.class, EvpnSubsequentAddressFamily.class), - new AfiSafiBuilder().setAfiSafiName(L2VPNEVPN.class).build()); + final ImmutableBiMap.Builder> b = ImmutableBiMap.builder(); + b.put(new BgpTableTypeImpl(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class), IPV4UNICAST.class); + b.put(new BgpTableTypeImpl(Ipv6AddressFamily.class, UnicastSubsequentAddressFamily.class), IPV6UNICAST.class); + b.put(new BgpTableTypeImpl(Ipv4AddressFamily.class, LabeledUnicastSubsequentAddressFamily.class), IPV4LABELLEDUNICAST.class); + b.put(new BgpTableTypeImpl(Ipv6AddressFamily.class, LabeledUnicastSubsequentAddressFamily.class), IPV6LABELLEDUNICAST.class); + b.put(new BgpTableTypeImpl(Ipv4AddressFamily.class, MplsLabeledVpnSubsequentAddressFamily.class), L3VPNIPV4UNICAST.class); + b.put(new BgpTableTypeImpl(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class), Linkstate.class); + b.put(new BgpTableTypeImpl(Ipv4AddressFamily.class, FlowspecSubsequentAddressFamily.class), Ipv4Flow.class); + b.put(new BgpTableTypeImpl(Ipv6AddressFamily.class, FlowspecSubsequentAddressFamily.class), Ipv6Flow.class); + b.put(new BgpTableTypeImpl(L2vpnAddressFamily.class, EvpnSubsequentAddressFamily.class), L2VPNEVPN.class); TABLETYPE_TO_AFISAFI = b.build(); } @@ -90,7 +86,15 @@ public final class OpenConfigUtil { } public static Optional toAfiSafi(final BgpTableType tableType) { - return Optional.fromNullable(TABLETYPE_TO_AFISAFI.get(tableType)); + final Class afiSafi = TABLETYPE_TO_AFISAFI.get(tableType); + if (afiSafi != null) { + return Optional.of(new AfiSafiBuilder().setAfiSafiName(afiSafi).build()); + } + return Optional.absent(); + } + + public static Optional toBgpTableType(final Class afiSafi) { + return Optional.fromNullable(TABLETYPE_TO_AFISAFI.inverse().get(afiSafi)); } public static List toAfiSafis(final List advertizedTables, final BiFunction function) { @@ -106,7 +110,11 @@ public final class OpenConfigUtil { } public static String getModuleName(final String provider) { - return provider.substring(provider.lastIndexOf('=') + 2, provider.length() - 2); + return provider.substring(provider.lastIndexOf(EQUALS) + 2, provider.length() - 2); + } + + public static String getModuleType(final String provider) { + return provider.substring(provider.indexOf(EQUALS) + 2, provider.indexOf("']")); } public static AfiSafi toNeigborAfiSafiMultiPath(final AfiSafi afiSafi, final BgpTableType tableType, final Collection addPathCapabilities) { diff --git a/bgp/openconfig-impl/src/test/java/org/opendaylight/protocol/bgp/openconfig/impl/util/OpenConfigUtilTest.java b/bgp/openconfig-impl/src/test/java/org/opendaylight/protocol/bgp/openconfig/impl/util/OpenConfigUtilTest.java index d477f59cd4..2f1f9dab40 100644 --- a/bgp/openconfig-impl/src/test/java/org/opendaylight/protocol/bgp/openconfig/impl/util/OpenConfigUtilTest.java +++ b/bgp/openconfig-impl/src/test/java/org/opendaylight/protocol/bgp/openconfig/impl/util/OpenConfigUtilTest.java @@ -12,6 +12,7 @@ import static org.junit.Assert.assertEquals; import static org.opendaylight.protocol.bgp.openconfig.impl.util.OpenConfigUtil.getModuleName; import static org.opendaylight.protocol.bgp.openconfig.impl.util.OpenConfigUtil.toAfiSafi; +import com.google.common.base.Optional; import com.google.common.collect.Lists; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -47,12 +48,24 @@ public class OpenConfigUtilTest { assertEquals("concurrent-data-broker", moduleName); } + @Test + public void testGetModuleType() { + final String moduleType = OpenConfigUtil.getModuleType(TEST); + assertEquals("dom-concurrent-data-broker", moduleType); + } + @Test public void testToAfiSafi() { assertEquals(toAfiSafi(BGP_TABLE_TYPE_IPV4).get(), AFISAFI_IPV4); } + @Test + public void testToBgpTableType() { + final Optional bgpTableType = OpenConfigUtil.toBgpTableType(IPV4UNICAST.class); + assertEquals(BGP_TABLE_TYPE_IPV4, bgpTableType.get()); + } + @Test public void testToAfiSafis() { final List afiSafis = OpenConfigUtil.toAfiSafis(Lists.newArrayList(BGP_TABLE_TYPE_IPV4), -- 2.36.6