Bug-4827: BGP Add-Path OpenConfig Support II
[bgpcep.git] / bgp / openconfig-impl / src / main / java / org / opendaylight / protocol / bgp / openconfig / impl / moduleconfig / BGPPeerProvider.java
1 /*
2  * Copyright (c) 2015 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.openconfig.impl.moduleconfig;
10
11 import com.google.common.base.Function;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import java.util.List;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
17 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
18 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
19 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
20 import org.opendaylight.protocol.bgp.openconfig.impl.spi.BGPConfigHolder;
21 import org.opendaylight.protocol.bgp.openconfig.impl.spi.BGPConfigStateStore;
22 import org.opendaylight.protocol.bgp.openconfig.impl.util.GlobalIdentifier;
23 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.RouteReflector;
24 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Timers;
25 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Transport;
26 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
27 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
28 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.PeerType;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.BgpPeer;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.BgpTableType;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.RibInstance;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPeerBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.AddPath;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.AddPathBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.AdvertizedTable;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.AdvertizedTableBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.Rib;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.RibBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.RpcRegistry;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.RpcRegistryBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.Module;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.ModuleBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.ModuleKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.binding.rev131028.BindingRpcRegistry;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.tcpmd5.cfg.rev140427.Rfc2385Key;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 final class BGPPeerProvider {
52
53     private static final String PEER = "peer_";
54
55     private static final Logger LOG = LoggerFactory.getLogger(BGPPeerProvider.class);
56
57     private static final Function<String, AdvertizedTable> ADVERTIZED_TABLE_FUNCTION = new Function<String, AdvertizedTable>() {
58         @Override
59         public AdvertizedTable apply(final String instance) {
60             return new AdvertizedTableBuilder().setName(instance).setType(BgpTableType.class).build();
61         }
62     };
63
64     private static final Function<String, Rib> TO_RIB_FUNCTION = new Function<String, Rib>() {
65         @Override
66         public Rib apply(final String name) {
67             return new RibBuilder().setName(name).setType(RibInstance.class).build();
68         }
69     };
70
71     private static final Function<String, RpcRegistry> RPC_REG_FUNCTION = new Function<String, RpcRegistry>() {
72         @Override
73         public RpcRegistry apply(final String name) {
74             return new RpcRegistryBuilder().setName(name).setType(BindingRpcRegistry.class).build();
75         }
76     };
77
78     private static final Function<String, AddPath> ADD_PATH_FUNCTION = new Function<String, AddPath>() {
79         @Override
80         public AddPath apply(final String name) {
81             return new AddPathBuilder()
82                 .setName(name)
83                 .setType(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.AddPath.class)
84                 .build();
85         }
86     };
87
88     private final BGPConfigHolder<Neighbor> neighborState;
89     private final BGPConfigHolder<Bgp> globalState;
90     private final BGPConfigModuleProvider configModuleOp;
91     private final DataBroker dataBroker;
92
93     public BGPPeerProvider(final BGPConfigStateStore configHolders, final BGPConfigModuleProvider configModuleWriter, final DataBroker dataBroker) {
94         this.dataBroker = dataBroker;
95         this.configModuleOp = Preconditions.checkNotNull(configModuleWriter);
96         this.globalState = Preconditions.checkNotNull(configHolders.getBGPConfigHolder(Bgp.class));
97         this.neighborState = Preconditions.checkNotNull(configHolders.getBGPConfigHolder(Neighbor.class));
98     }
99
100     public void onNeighborRemoved(final Neighbor removedNeighbor) {
101         final ModuleKey moduleKey = this.neighborState.getModuleKey(removedNeighbor.getKey());
102         if (moduleKey != null) {
103             try {
104                 final ReadWriteTransaction rwTx = this.dataBroker.newReadWriteTransaction();
105                 final Optional<Module> maybeModule = this.configModuleOp.readModuleConfiguration(moduleKey, rwTx);
106                 if (maybeModule.isPresent() && this.neighborState.remove(moduleKey, removedNeighbor)) {
107                     this.configModuleOp.removeModuleConfiguration(moduleKey, rwTx);
108                 }
109             } catch (ReadFailedException | TransactionCommitFailedException e) {
110                 LOG.error("Failed to remove a configuration module: {}", moduleKey, e);
111                 throw new IllegalStateException(e);
112             }
113         }
114     }
115
116     public void onNeighborModified(final Neighbor modifiedNeighbor) {
117         final ModuleKey moduleKey = this.neighborState.getModuleKey(modifiedNeighbor.getKey());
118         final ReadOnlyTransaction rTx = this.dataBroker.newReadOnlyTransaction();
119         final List<AdvertizedTable> advertizedTables = getAdvertizedTables(modifiedNeighbor, rTx);
120         final List<AddPath> addPathCapabilities = getAddPathCapabilities(modifiedNeighbor, rTx);
121         if (moduleKey != null) {
122             updateExistingPeerConfiguration(moduleKey, modifiedNeighbor, advertizedTables, rTx, addPathCapabilities);
123         } else {
124             createNewPeerConfiguration(moduleKey, modifiedNeighbor, advertizedTables, rTx, addPathCapabilities);
125         }
126     }
127
128     private List<AdvertizedTable> getAdvertizedTables(final Neighbor modifiedNeighbor, final ReadOnlyTransaction rTx) {
129         return TableTypesFunction.getLocalTables(rTx, this.configModuleOp, ADVERTIZED_TABLE_FUNCTION, modifiedNeighbor.getAfiSafis().getAfiSafi());
130     }
131
132     private List<AddPath> getAddPathCapabilities(final Neighbor modifiedNeighbor, final ReadOnlyTransaction rTx) {
133         return AddPathFunction.getAddPath(rTx, this.configModuleOp, ADD_PATH_FUNCTION, modifiedNeighbor.getAfiSafis().getAfiSafi());
134     }
135
136     private void updateExistingPeerConfiguration(final ModuleKey moduleKey, final Neighbor modifiedNeighbor, final List<AdvertizedTable>
137         advertizedTables, final ReadOnlyTransaction rTx, final List<AddPath> addPathCapabilities) {
138         if (neighborState.addOrUpdate(moduleKey, modifiedNeighbor.getKey(), modifiedNeighbor)) {
139             final Optional<Module> maybeModule = getOldModuleConfiguration(moduleKey, rTx);
140             if (maybeModule.isPresent()) {
141                 final Module peerConfigModule = toPeerConfigModule(modifiedNeighbor, maybeModule.get(), advertizedTables, addPathCapabilities);
142                 putOldModuleConfigurationIntoNewModule(peerConfigModule);
143             }
144         }
145     }
146
147     private Optional<Module> getOldModuleConfiguration(final ModuleKey moduleKey, final ReadOnlyTransaction rTx) {
148         try {
149             return this.configModuleOp.readModuleConfiguration(moduleKey, rTx);
150         } catch (final Exception e) {
151             LOG.error("Failed to read module configuration: {}", moduleKey, e);
152             throw new IllegalStateException(e);
153         }
154     }
155
156     private void putOldModuleConfigurationIntoNewModule(final Module peerConfigModule) {
157         try {
158             this.configModuleOp.putModuleConfiguration(peerConfigModule, this.dataBroker.newWriteOnlyTransaction());
159         } catch (final TransactionCommitFailedException e) {
160             LOG.error("Failed to update a configuration module: {}", peerConfigModule, e);
161             throw new IllegalStateException(e);
162         }
163     }
164
165     private void createNewPeerConfiguration(final ModuleKey moduleKey, final Neighbor modifiedNeighbor, final List<AdvertizedTable> advertizedTables,
166             final ReadOnlyTransaction rTx, final List<AddPath> addPathCapabilities) {
167         final ModuleKey ribImplKey = this.globalState.getModuleKey(GlobalIdentifier.GLOBAL_IDENTIFIER);
168         if (ribImplKey != null) {
169             try {
170                 final Rib rib = RibInstanceFunction.getRibInstance(this.configModuleOp, TO_RIB_FUNCTION, ribImplKey.getName(), rTx);
171                 final RpcRegistry rpcReg = RpcRegistryFunction.getRpcRegistryInstance(rTx, this.configModuleOp, RPC_REG_FUNCTION);
172                 final Module peerConfigModule = toPeerConfigModule(modifiedNeighbor, advertizedTables, rib, rpcReg, addPathCapabilities);
173                 this.configModuleOp.putModuleConfiguration(peerConfigModule, this.dataBroker.newWriteOnlyTransaction());
174                 this.neighborState.addOrUpdate(peerConfigModule.getKey(), modifiedNeighbor.getKey(), modifiedNeighbor);
175             } catch (final Exception e) {
176                 LOG.error("Failed to create a configuration module: {}", moduleKey, e);
177                 throw new IllegalStateException(e);
178             }
179         }
180     }
181
182     private static Module toPeerConfigModule(final Neighbor neighbor, final Module oldBgpPeer, final List<AdvertizedTable> tableTypes,
183             final List<AddPath> addPathCapabilities) {
184         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPeer bgpPeer =
185             (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPeer) oldBgpPeer.getConfiguration();
186         final BgpPeerBuilder bgpPeerBuilder = toBgpPeerConfig(neighbor, tableTypes, bgpPeer.getRib(), bgpPeer.getRpcRegistry(), addPathCapabilities);
187         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());
188         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());
189
190         final ModuleBuilder mBuilder = new ModuleBuilder(oldBgpPeer);
191         mBuilder.setConfiguration(bgpPeerBuilder.build());
192         return mBuilder.build();
193     }
194
195     private static Module toPeerConfigModule(final Neighbor neighbor, final List<AdvertizedTable> tableTypes, final Rib rib, final RpcRegistry rpcReg,
196             final List<AddPath> addPathCapabilities) {
197         final ModuleBuilder mBuilder = new ModuleBuilder();
198         mBuilder.setName(createPeerName(neighbor.getNeighborAddress()));
199         mBuilder.setType(BgpPeer.class);
200         mBuilder.setConfiguration(toBgpPeerConfig(neighbor, tableTypes, rib, rpcReg, addPathCapabilities).build());
201         mBuilder.setKey(new ModuleKey(mBuilder.getName(), mBuilder.getType()));
202         return mBuilder.build();
203     }
204
205     private static BgpPeerBuilder toBgpPeerConfig(final Neighbor neighbor, final List<AdvertizedTable> tableTypes, final Rib rib, final RpcRegistry rpcReg,
206             final List<AddPath> addPathCapabilities) {
207         final BgpPeerBuilder bgpPeerBuilder = new BgpPeerBuilder();
208         if (rpcReg != null) {
209             bgpPeerBuilder.setRpcRegistry(rpcReg);
210         }
211         bgpPeerBuilder.setAdvertizedTable(tableTypes);
212         bgpPeerBuilder.setAddPath(addPathCapabilities);
213         bgpPeerBuilder.setRib(rib);
214         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress ipAdress = null;
215         if (neighbor.getNeighborAddress().getIpv4Address() != null) {
216             ipAdress = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress(new org.opendaylight.yang
217                 .gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address(neighbor.getNeighborAddress().getIpv4Address().getValue()));
218         } else {
219             ipAdress = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress(new org.opendaylight.yang
220                 .gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address(neighbor.getNeighborAddress().getIpv6Address().getValue()));
221         }
222         bgpPeerBuilder.setHost(ipAdress);
223         final Timers timers = neighbor.getTimers();
224         if (timers != null && timers.getConfig() != null && timers.getConfig().getHoldTime() != null) {
225             bgpPeerBuilder.setHoldtimer(neighbor.getTimers().getConfig().getHoldTime().shortValue());
226         }
227         final Transport transport = neighbor.getTransport();
228         if (transport != null && transport.getConfig() != null && transport.getConfig().isPassiveMode() != null) {
229             bgpPeerBuilder.setInitiateConnection(!neighbor.getTransport().getConfig().isPassiveMode());
230         }
231         if (neighbor.getConfig() != null) {
232             if (neighbor.getConfig().getAuthPassword() != null) {
233                 bgpPeerBuilder.setPassword(new Rfc2385Key(neighbor.getConfig().getAuthPassword()));
234             }
235             if (neighbor.getConfig().getPeerAs() != null) {
236                 bgpPeerBuilder.setRemoteAs(neighbor.getConfig().getPeerAs().getValue());
237             }
238             if (neighbor.getConfig().getPeerType() != null) {
239                 bgpPeerBuilder.setPeerRole(toPeerRole(neighbor));
240             }
241         }
242         return bgpPeerBuilder;
243     }
244
245     private static String createPeerName(final IpAddress ipAddress) {
246         final String address = ipAddress.getIpv4Address() != null ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue();
247         return PEER + address;
248     }
249
250     private static PeerRole toPeerRole(final Neighbor neighbor) {
251         if (isRrClient(neighbor)) {
252             return PeerRole.RrClient;
253         }
254
255         if (neighbor.getConfig() != null) {
256             final PeerType peerType = neighbor.getConfig().getPeerType();
257             if (peerType == PeerType.INTERNAL) {
258                 return PeerRole.Ibgp;
259             }
260             if (peerType == PeerType.EXTERNAL) {
261                 return PeerRole.Ebgp;
262             }
263         }
264         LOG.info("Unknown peer role, setting peer {} role to iBGP", neighbor.getKey());
265         return PeerRole.Ibgp;
266     }
267
268     private static boolean isRrClient(final Neighbor neighbor) {
269         final RouteReflector routeReflector = neighbor.getRouteReflector();
270         if (routeReflector != null && routeReflector.getConfig() != null) {
271             return routeReflector.getConfig().isRouteReflectorClient();
272         }
273         return false;
274     }
275
276 }