OpenConfig BGP more defensive
[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.protocol.bgp.openconfig.impl.util.OpenConfigUtil;
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.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.BgpPeer;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.BgpTableType;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.RibInstance;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPeerBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.AddPath;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.AddPathBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.AdvertizedTable;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.AdvertizedTableBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.Rib;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.RibBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.RpcRegistry;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.bgp.peer.RpcRegistryBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.Module;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.ModuleBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.ModuleKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.binding.rev131028.BindingRpcRegistry;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.rfc2385.cfg.rev160324.Rfc2385Key;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 final class BGPPeerProvider {
50
51     private static final String PEER = "peer_";
52
53     private static final Logger LOG = LoggerFactory.getLogger(BGPPeerProvider.class);
54
55     private static final Function<String, AdvertizedTable> ADVERTIZED_TABLE_FUNCTION = new Function<String, AdvertizedTable>() {
56         @Override
57         public AdvertizedTable apply(final String instance) {
58             return new AdvertizedTableBuilder().setName(instance).setType(BgpTableType.class).build();
59         }
60     };
61
62     private static final Function<String, Rib> TO_RIB_FUNCTION = new Function<String, Rib>() {
63         @Override
64         public Rib apply(final String name) {
65             return new RibBuilder().setName(name).setType(RibInstance.class).build();
66         }
67     };
68
69     private static final Function<String, RpcRegistry> RPC_REG_FUNCTION = new Function<String, RpcRegistry>() {
70         @Override
71         public RpcRegistry apply(final String name) {
72             return new RpcRegistryBuilder().setName(name).setType(BindingRpcRegistry.class).build();
73         }
74     };
75
76     private static final Function<String, AddPath> ADD_PATH_FUNCTION = new Function<String, AddPath>() {
77         @Override
78         public AddPath apply(final String name) {
79             return new AddPathBuilder()
80                 .setName(name)
81                 .setType(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.AddPath.class)
82                 .build();
83         }
84     };
85
86     private final BGPConfigHolder<Neighbor> neighborState;
87     private final BGPConfigHolder<Bgp> globalState;
88     private final BGPConfigModuleProvider configModuleOp;
89     private final DataBroker dataBroker;
90
91     public BGPPeerProvider(final BGPConfigStateStore configHolders, final BGPConfigModuleProvider configModuleWriter, final DataBroker dataBroker) {
92         this.dataBroker = dataBroker;
93         this.configModuleOp = Preconditions.checkNotNull(configModuleWriter);
94         this.globalState = Preconditions.checkNotNull(configHolders.getBGPConfigHolder(Bgp.class));
95         this.neighborState = Preconditions.checkNotNull(configHolders.getBGPConfigHolder(Neighbor.class));
96     }
97
98     public void onNeighborRemoved(final Neighbor removedNeighbor) {
99         final ModuleKey moduleKey = this.neighborState.getModuleKey(removedNeighbor.getKey());
100         if (moduleKey != null) {
101             try {
102                 final ReadWriteTransaction rwTx = this.dataBroker.newReadWriteTransaction();
103                 final Optional<Module> maybeModule = this.configModuleOp.readModuleConfiguration(moduleKey, rwTx);
104                 if (maybeModule.isPresent() && this.neighborState.remove(moduleKey, removedNeighbor)) {
105                     this.configModuleOp.removeModuleConfiguration(moduleKey, rwTx);
106                 }
107             } catch (ReadFailedException | TransactionCommitFailedException e) {
108                 LOG.error("Failed to remove a configuration module: {}", moduleKey, e);
109                 throw new IllegalStateException(e);
110             }
111         }
112     }
113
114     public void onNeighborModified(final Neighbor modifiedNeighbor) {
115         final ModuleKey moduleKey = this.neighborState.getModuleKey(modifiedNeighbor.getKey());
116         final ReadOnlyTransaction rTx = this.dataBroker.newReadOnlyTransaction();
117         final List<AdvertizedTable> advertizedTables = getAdvertizedTables(modifiedNeighbor, rTx);
118         final List<AddPath> addPathCapabilities = getAddPathCapabilities(modifiedNeighbor, rTx);
119         if (moduleKey != null) {
120             updateExistingPeerConfiguration(moduleKey, modifiedNeighbor, advertizedTables, rTx, addPathCapabilities);
121         } else {
122             createNewPeerConfiguration(moduleKey, modifiedNeighbor, advertizedTables, rTx, addPathCapabilities);
123         }
124     }
125
126     private List<AdvertizedTable> getAdvertizedTables(final Neighbor modifiedNeighbor, final ReadOnlyTransaction rTx) {
127         return TableTypesFunction.getLocalTables(rTx, this.configModuleOp, ADVERTIZED_TABLE_FUNCTION, modifiedNeighbor.getAfiSafis().getAfiSafi());
128     }
129
130     private List<AddPath> getAddPathCapabilities(final Neighbor modifiedNeighbor, final ReadOnlyTransaction rTx) {
131         return AddPathFunction.getAddPath(rTx, this.configModuleOp, ADD_PATH_FUNCTION, modifiedNeighbor.getAfiSafis().getAfiSafi());
132     }
133
134     private void updateExistingPeerConfiguration(final ModuleKey moduleKey, final Neighbor modifiedNeighbor, final List<AdvertizedTable>
135         advertizedTables, final ReadOnlyTransaction rTx, final List<AddPath> addPathCapabilities) {
136         if (neighborState.addOrUpdate(moduleKey, modifiedNeighbor.getKey(), modifiedNeighbor)) {
137             final Optional<Module> maybeModule = getOldModuleConfiguration(moduleKey, rTx);
138             if (maybeModule.isPresent()) {
139                 final Module peerConfigModule = toPeerConfigModule(modifiedNeighbor, maybeModule.get(), advertizedTables, addPathCapabilities);
140                 putOldModuleConfigurationIntoNewModule(peerConfigModule);
141             }
142         }
143     }
144
145     private Optional<Module> getOldModuleConfiguration(final ModuleKey moduleKey, final ReadOnlyTransaction rTx) {
146         try {
147             return this.configModuleOp.readModuleConfiguration(moduleKey, rTx);
148         } catch (final Exception e) {
149             LOG.error("Failed to read module configuration: {}", moduleKey, e);
150             throw new IllegalStateException(e);
151         }
152     }
153
154     private void putOldModuleConfigurationIntoNewModule(final Module peerConfigModule) {
155         try {
156             this.configModuleOp.putModuleConfiguration(peerConfigModule, this.dataBroker.newWriteOnlyTransaction());
157         } catch (final TransactionCommitFailedException e) {
158             LOG.error("Failed to update a configuration module: {}", peerConfigModule, e);
159             throw new IllegalStateException(e);
160         }
161     }
162
163     private void createNewPeerConfiguration(final ModuleKey moduleKey, final Neighbor modifiedNeighbor, final List<AdvertizedTable> advertizedTables,
164             final ReadOnlyTransaction rTx, final List<AddPath> addPathCapabilities) {
165         final ModuleKey ribImplKey = this.globalState.getModuleKey(GlobalIdentifier.GLOBAL_IDENTIFIER);
166         if (ribImplKey != null) {
167             try {
168                 final Rib rib = RibInstanceFunction.getRibInstance(this.configModuleOp, TO_RIB_FUNCTION, ribImplKey.getName(), rTx);
169                 final RpcRegistry rpcReg = RpcRegistryFunction.getRpcRegistryInstance(rTx, this.configModuleOp, RPC_REG_FUNCTION);
170                 final Module peerConfigModule = toPeerConfigModule(modifiedNeighbor, advertizedTables, rib, rpcReg, addPathCapabilities);
171                 this.configModuleOp.putModuleConfiguration(peerConfigModule, this.dataBroker.newWriteOnlyTransaction());
172                 this.neighborState.addOrUpdate(peerConfigModule.getKey(), modifiedNeighbor.getKey(), modifiedNeighbor);
173             } catch (final Exception e) {
174                 LOG.error("Failed to create a configuration module: {}", moduleKey, e);
175                 throw new IllegalStateException(e);
176             }
177         }
178     }
179
180     private static Module toPeerConfigModule(final Neighbor neighbor, final Module oldBgpPeer, final List<AdvertizedTable> tableTypes,
181             final List<AddPath> addPathCapabilities) {
182         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPeer bgpPeer =
183             (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.bgp.rib.impl.rev160330.modules.module.configuration.BgpPeer) oldBgpPeer.getConfiguration();
184         final BgpPeerBuilder bgpPeerBuilder = toBgpPeerConfig(neighbor, tableTypes, bgpPeer.getRib(), bgpPeer.getRpcRegistry(), addPathCapabilities);
185         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());
186         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());
187
188         final ModuleBuilder mBuilder = new ModuleBuilder(oldBgpPeer);
189         mBuilder.setConfiguration(bgpPeerBuilder.build());
190         return mBuilder.build();
191     }
192
193     private static Module toPeerConfigModule(final Neighbor neighbor, final List<AdvertizedTable> tableTypes, final Rib rib, final RpcRegistry rpcReg,
194             final List<AddPath> addPathCapabilities) {
195         final ModuleBuilder mBuilder = new ModuleBuilder();
196         mBuilder.setName(createPeerName(neighbor.getNeighborAddress()));
197         mBuilder.setType(BgpPeer.class);
198         mBuilder.setConfiguration(toBgpPeerConfig(neighbor, tableTypes, rib, rpcReg, addPathCapabilities).build());
199         mBuilder.setKey(new ModuleKey(mBuilder.getName(), mBuilder.getType()));
200         return mBuilder.build();
201     }
202
203     private static BgpPeerBuilder toBgpPeerConfig(final Neighbor neighbor, final List<AdvertizedTable> tableTypes, final Rib rib, final RpcRegistry rpcReg,
204             final List<AddPath> addPathCapabilities) {
205         final BgpPeerBuilder bgpPeerBuilder = new BgpPeerBuilder();
206         if (rpcReg != null) {
207             bgpPeerBuilder.setRpcRegistry(rpcReg);
208         }
209         bgpPeerBuilder.setAdvertizedTable(tableTypes);
210         bgpPeerBuilder.setAddPath(addPathCapabilities);
211         bgpPeerBuilder.setRib(rib);
212         bgpPeerBuilder.setHost(neighbor.getNeighborAddress());
213         final Timers timers = neighbor.getTimers();
214         if (timers != null && timers.getConfig() != null && timers.getConfig().getHoldTime() != null) {
215             bgpPeerBuilder.setHoldtimer(neighbor.getTimers().getConfig().getHoldTime().intValue());
216         }
217         final Transport transport = neighbor.getTransport();
218         if (transport != null && transport.getConfig() != null && transport.getConfig().isPassiveMode() != null) {
219             bgpPeerBuilder.setInitiateConnection(!neighbor.getTransport().getConfig().isPassiveMode());
220         }
221         if (neighbor.getConfig() != null) {
222             if (neighbor.getConfig().getAuthPassword() != null) {
223                 bgpPeerBuilder.setPassword(new Rfc2385Key(neighbor.getConfig().getAuthPassword()));
224             }
225             if (neighbor.getConfig().getPeerAs() != null) {
226                 bgpPeerBuilder.setRemoteAs(neighbor.getConfig().getPeerAs());
227             }
228             if (neighbor.getConfig().getPeerType() != null) {
229                 bgpPeerBuilder.setPeerRole(OpenConfigUtil.toPeerRole(neighbor));
230             }
231         }
232         return bgpPeerBuilder;
233     }
234
235     private static String createPeerName(final IpAddress ipAddress) {
236         final String address = ipAddress.getIpv4Address() != null ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue();
237         return PEER + address;
238     }
239
240 }