Freeze upstream versions
[netvirt.git] / bgpmanager / impl / src / main / java / org / opendaylight / netvirt / bgpmanager / BgpUtil.java
1 /*
2  * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.netvirt.bgpmanager;
9
10 import java.net.Inet4Address;
11 import java.net.Inet6Address;
12 import java.net.InetAddress;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Optional;
18 import java.util.concurrent.BlockingQueue;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.LinkedBlockingQueue;
21 import javax.annotation.PostConstruct;
22 import javax.annotation.PreDestroy;
23 import javax.inject.Inject;
24 import javax.inject.Singleton;
25 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
26 import org.opendaylight.genius.mdsalutil.MDSALUtil;
27 import org.opendaylight.genius.mdsalutil.NwConstants;
28 import org.opendaylight.genius.utils.batching.ActionableResource;
29 import org.opendaylight.genius.utils.batching.ActionableResources;
30 import org.opendaylight.genius.utils.batching.DefaultBatchHandler;
31 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
32 import org.opendaylight.mdsal.binding.api.DataBroker;
33 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
34 import org.opendaylight.netvirt.bgpmanager.thrift.gen.af_afi;
35 import org.opendaylight.netvirt.bgpmanager.thrift.gen.af_safi;
36 import org.opendaylight.netvirt.bgpmanager.thrift.gen.encap_type;
37 import org.opendaylight.netvirt.bgpmanager.thrift.gen.protocol_type;
38 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
39 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebfd.rev190219.BfdConfig;
40 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.Bgp;
41 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.BgpControlPlaneType;
42 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.EncapType;
43 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.LayerType;
44 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.DcgwTepList;
45 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.VrfsContainer;
46 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.dcgw.tep.list.DcgwTep;
47 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.dcgw.tep.list.DcgwTepKey;
48 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.vrfscontainer.Vrfs;
49 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.vrfscontainer.VrfsKey;
50 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.vrfscontainer.vrfs.AddressFamiliesVrf;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTeps;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.EvpnRdToNetworks;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.evpn.rd.to.networks.EvpnRdToNetwork;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.evpn.rd.to.networks.EvpnRdToNetworkKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
74 import org.opendaylight.yangtools.yang.binding.DataObject;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
79
80 @Singleton
81 public class BgpUtil implements AutoCloseable {
82     private static final Logger LOG = LoggerFactory.getLogger(BgpUtil.class);
83     private static final String RESOURCE_TYPE = "BGP-RESOURCES";
84     private static final int DEFAULT_BATCH_SIZE = 1000;
85     private static final int DEFAULT_BATCH_INTERVAL = 500;
86     private int enableBfdFlag = -1;
87
88     private final DataBroker dataBroker;
89     private final IFibManager fibManager;
90
91
92     private final BlockingQueue<ActionableResource<?>> bgpResourcesBufferQ = new LinkedBlockingQueue<>();
93
94     @Inject
95     public BgpUtil(DataBroker dataBroker, final IFibManager fibManager) {
96         this.dataBroker = dataBroker;
97         this.fibManager = fibManager;
98     }
99
100     @PostConstruct
101     public void init() {
102         ResourceBatchingManager resBatchingManager = ResourceBatchingManager.getInstance();
103
104         Integer batchSize = Integer.getInteger("batch.size", DEFAULT_BATCH_SIZE);
105         Integer batchInterval = Integer.getInteger("batch.wait.time", DEFAULT_BATCH_INTERVAL);
106
107         resBatchingManager.registerBatchableResource(RESOURCE_TYPE, bgpResourcesBufferQ,
108                 new DefaultBatchHandler(dataBroker, LogicalDatastoreType.CONFIGURATION, batchSize, batchInterval));
109     }
110
111     @Override
112     @PreDestroy
113     public void close() {
114         ResourceBatchingManager.getInstance().deregisterBatchableResource(RESOURCE_TYPE);
115     }
116
117     /**
118      * get a translation from prefix ipv6 to afi<br>.
119      * "ffff::1/128" sets afi as 2 because is an IPv6 value
120      * @param argPrefix ip address as ipv4 or ipv6
121      * @return afi 1 for AFI_IP 2 for AFI_IPV6
122      */
123     public static int getAFItranslatedfromPrefix(String argPrefix) {
124         int retValue = af_afi.AFI_IP.getValue();//default afiValue is 1 (= ipv4)
125         String prefixOnly;
126         if (argPrefix.indexOf("/") == -1) {
127             prefixOnly = argPrefix;
128         } else {
129             prefixOnly = argPrefix.substring(0, argPrefix.indexOf("/"));
130         }
131         try {
132             InetAddress address = InetAddress.getByName(prefixOnly);
133             if (address instanceof Inet6Address) {
134                 retValue = af_afi.AFI_IPV6.getValue();
135             } else if (address instanceof Inet4Address) {
136                 retValue = af_afi.AFI_IP.getValue();
137             }
138         } catch (java.net.UnknownHostException e) {
139             /*if exception is catched then the prefix is not an IPv6 and IPv4*/
140             LOG.error("Unrecognized ip address ipAddress: {}", argPrefix);
141             retValue = af_afi.AFI_IP.getValue();//default afiValue is 1 (= ipv4)
142         }
143         return retValue;
144     }
145
146     public <T extends DataObject> void update(final InstanceIdentifier<T> path, final T data) {
147         bgpResourcesBufferQ.add(ActionableResources.update(path, data));
148     }
149
150     public <T extends DataObject> void write(final InstanceIdentifier<T> path, final T data) {
151         bgpResourcesBufferQ.add(ActionableResources.create(path, data));
152     }
153
154     public <T extends DataObject> void delete(final InstanceIdentifier<T> path) {
155         bgpResourcesBufferQ.add(ActionableResources.delete(path));
156     }
157
158     // Convert ProtocolType to thrift protocol_type
159     public static protocol_type convertToThriftProtocolType(BgpControlPlaneType protocolType) {
160         switch (protocolType) {
161             case PROTOCOLLU:
162                 return protocol_type.PROTOCOL_LU;
163             case PROTOCOLL3VPN:
164                 return protocol_type.PROTOCOL_L3VPN;
165             case PROTOCOLEVPN:
166                 return protocol_type.PROTOCOL_EVPN;
167             default:
168                 return protocol_type.PROTOCOL_ANY;
169         }
170     }
171
172     // Convert EncapType to thrift encap_type
173     public static encap_type convertToThriftEncapType(EncapType encapType) {
174         switch (encapType) {
175             case L2TPV3OVERIP:
176                 return encap_type.L2TPV3_OVER_IP;
177             case GRE:
178                 return encap_type.GRE;
179             case IPINIP:
180                 return encap_type.IP_IN_IP;
181             case VXLAN:
182                 return encap_type.VXLAN;
183             case MPLS:
184             default:
185                 return encap_type.MPLS;
186         }
187     }
188
189     public VpnInstanceOpDataEntry getVpnInstanceOpData(String rd)  {
190         InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
191         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = Optional.empty();
192         try {
193             vpnInstanceOpData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
194                     LogicalDatastoreType.OPERATIONAL, id);
195         } catch (ExecutionException | InterruptedException e) {
196             LOG.error("Exception while reading VpnInstanceOpDataEntry DS for the Vpn Rd {}", rd, e);
197         }
198         if (vpnInstanceOpData.isPresent()) {
199             return vpnInstanceOpData.get();
200         }
201         return null;
202     }
203
204     public static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
205         return InstanceIdentifier.builder(VpnInstanceOpData.class)
206                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
207     }
208
209     private String getElanNamefromRd(String rd)  {
210         InstanceIdentifier<EvpnRdToNetwork> id = getEvpnRdToNetworkIdentifier(rd);
211         Optional<EvpnRdToNetwork> evpnRdToNetworkOpData = Optional.empty();
212         try {
213             evpnRdToNetworkOpData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
214                     LogicalDatastoreType.CONFIGURATION, id);
215         } catch (ExecutionException | InterruptedException e) {
216             LOG.error("Exception while reading EvpnRdToNetwork DS for the Vpn Rd {}", rd, e);
217         }
218         if (evpnRdToNetworkOpData.isPresent()) {
219             return evpnRdToNetworkOpData.get().getNetworkId();
220         }
221         return null;
222     }
223
224     private static InstanceIdentifier<EvpnRdToNetwork> getEvpnRdToNetworkIdentifier(String rd) {
225         return InstanceIdentifier.builder(EvpnRdToNetworks.class)
226                 .child(EvpnRdToNetwork.class, new EvpnRdToNetworkKey(rd)).build();
227     }
228
229     public void addTepToElanInstance(String rd, String tepIp) {
230         if (rd == null || tepIp == null) {
231             LOG.error("addTepToElanInstance : Null parameters returning");
232             return;
233         }
234         String elanName = getElanNamefromRd(rd);
235         if (elanName == null) {
236             LOG.error("Elan null while processing RT2 for RD {}", rd);
237             return;
238         }
239         LOG.debug("Adding tepIp {} to elan {}", tepIp, elanName);
240         InstanceIdentifier<ExternalTeps> externalTepsId = getExternalTepsIdentifier(elanName, tepIp);
241         ExternalTepsBuilder externalTepsBuilder = new ExternalTepsBuilder();
242         ExternalTepsKey externalTepsKey = externalTepsId.firstKeyOf(ExternalTeps.class);
243         externalTepsBuilder.setTepIp(externalTepsKey.getTepIp());
244         update(externalTepsId, externalTepsBuilder.build());
245     }
246
247     public void deleteTepFromElanInstance(String rd, String tepIp) {
248         if (rd == null || tepIp == null) {
249             LOG.error("deleteTepFromElanInstance : Null parameters returning");
250             return;
251         }
252         String elanName = getElanNamefromRd(rd);
253         if (elanName == null) {
254             LOG.error("Elan null while processing RT2 withdraw for RD {}", rd);
255             return;
256         }
257         LOG.debug("Deleting tepIp {} from elan {}", tepIp, elanName);
258         InstanceIdentifier<ExternalTeps> externalTepsId = getExternalTepsIdentifier(elanName, tepIp);
259         delete(externalTepsId);
260     }
261
262     private static InstanceIdentifier<ExternalTeps> getExternalTepsIdentifier(String elanInstanceName, String tepIp) {
263         IpAddress tepAdress = tepIp == null ? null : new IpAddress(new Ipv4Address(tepIp));
264         return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class,
265             new ElanInstanceKey(elanInstanceName)).child(ExternalTeps.class,
266                 new ExternalTepsKey(tepAdress)).build();
267     }
268
269     public String getVpnNameFromRd(String rd) {
270         final Map<String, String> rdtoVpnMap = new HashMap<>();
271         if (rdtoVpnMap.get(rd) != null) {
272             return rdtoVpnMap.get(rd);
273         } else {
274             VpnInstanceOpDataEntry vpnInstanceOpData = getVpnInstanceOpData(rd);
275             String vpnName = vpnInstanceOpData != null ? vpnInstanceOpData.getVpnInstanceName() : null;
276             rdtoVpnMap.put(rd, vpnName);
277             return vpnName;
278         }
279     }
280
281     /** get the vrf with the RouterDistinguisher pass in param.
282      * @param rd is the RouteDistinguisher of vrf
283      * @return the vrf of rd or null if no exist
284      */
285     public Vrfs getVrfFromRd(String rd) {
286         Vrfs vrfs = null;
287         KeyedInstanceIdentifier<Vrfs, VrfsKey> id = InstanceIdentifier.create(Bgp.class)
288                 .child(VrfsContainer.class)
289                 .child(Vrfs.class, new VrfsKey(rd));
290         Optional<Vrfs> vrfsFromDs = Optional.empty();
291         try {
292             vrfsFromDs = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
293                     id);
294         } catch (ExecutionException | InterruptedException e) {
295             LOG.error("Exception while reading BGP VRF table for the Vpn Rd {}", rd, e);
296         }
297         if (vrfsFromDs.isPresent()) {
298             vrfs = vrfsFromDs.get();
299         }
300         return vrfs;
301     }
302
303     /** get layerType used from an AddressFamiliesVrf.
304      * @param adf is the AddressFamiliesVrf from which the layer is asked.
305      * @return the layerType to reach from the argument addressFamilyVrf or null if not found
306      */
307     public static LayerType getLayerType(AddressFamiliesVrf adf) {
308         LayerType layerTypeValue = null;
309         if (adf.getSafi().intValue() == af_safi.SAFI_EVPN.getValue()) {
310             layerTypeValue = LayerType.LAYER2;
311         } else if (adf.getSafi().intValue() == af_safi.SAFI_MPLS_VPN.getValue()) {
312             layerTypeValue = LayerType.LAYER3;
313         }
314         return layerTypeValue;
315     }
316
317     public void removeVrfEntry(String rd, VrfEntry vrfEntry) {
318         LOG.debug("removeVrfEntry : vrf {} prefix {}", rd, vrfEntry.getDestPrefix());
319         InstanceIdentifier<VrfEntry> vrfEntryId =
320                    InstanceIdentifier.builder(FibEntries.class)
321                    .child(VrfTables.class, new VrfTablesKey(rd))
322                    .child(VrfEntry.class, new VrfEntryKey(vrfEntry.getDestPrefix())).build();
323         delete(vrfEntryId);
324     }
325
326     public void enableBfdFlag() {
327         enableBfdFlag = 1;
328     }
329
330     public void disableBfdFlag() {
331         enableBfdFlag = 0;
332     }
333
334     public boolean isBfdEnabled() {
335         if (enableBfdFlag == 1) {
336             return true;
337         } else if (enableBfdFlag == 0) {
338             return false;
339         }
340         BfdConfig bfdConfig = getBfdConfig();
341         if (bfdConfig != null) {
342             return bfdConfig.isBfdEnabled();
343         }
344         return false;
345     }
346
347     public BfdConfig getBfdConfig() {
348         InstanceIdentifier<BfdConfig> id =
349                 InstanceIdentifier.builder(BfdConfig.class).build();
350         Optional<BfdConfig> bfdConfigOptional = Optional.empty();
351         try {
352             bfdConfigOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
353                     LogicalDatastoreType.CONFIGURATION, id);
354         } catch (ExecutionException | InterruptedException e) {
355             LOG.error("Exception while reading BfdConfig", e);
356         }
357         if (bfdConfigOptional.isPresent()) {
358             return bfdConfigOptional.get();
359         }
360         return null;
361     }
362
363     public DcgwTepList getDcgwTepConfig() {
364         InstanceIdentifier<DcgwTepList> id =
365                 InstanceIdentifier.builder(Bgp.class).child(DcgwTepList.class).build();
366         Optional<DcgwTepList> dcgwTepListOptional = Optional.empty();
367         try {
368             dcgwTepListOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
369                     LogicalDatastoreType.CONFIGURATION, id);
370         } catch (ExecutionException | InterruptedException e) {
371             LOG.error("getDcgwTepConfig: Exception while reading DcgwTepList", e);
372         }
373         if (dcgwTepListOptional.isPresent()) {
374             return dcgwTepListOptional.get();
375         }
376         return null;
377     }
378
379     public List<String> getDcgwTepConfig(String dcgwIp) {
380         InstanceIdentifier<DcgwTep> id =
381                 InstanceIdentifier.builder(Bgp.class)
382                         .child(DcgwTepList.class)
383                         .child(DcgwTep.class, new DcgwTepKey(dcgwIp)).build();
384         Optional<DcgwTep> tepListOptional = Optional.empty();
385         try {
386             tepListOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
387                     LogicalDatastoreType.CONFIGURATION, id);
388         } catch (ExecutionException | InterruptedException e) {
389             LOG.error("Exception while reading DcgwTep for the IP {}", dcgwIp, e);
390         }
391         if (tepListOptional.isPresent()) {
392             return tepListOptional.get().getTepIps();
393         }
394         LOG.debug("No tep configured for DCGW {}", dcgwIp);
395         return null;
396     }
397
398     public static List<DPNTEPsInfo> getDpnTEPsInfos(DataBroker dataBroker) {
399         InstanceIdentifier<DpnEndpoints> iid = InstanceIdentifier.builder(DpnEndpoints.class).build();
400         Optional<DpnEndpoints> dpnEndpoints = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, iid, dataBroker);
401         if (dpnEndpoints.isPresent()) {
402             return new ArrayList<DPNTEPsInfo>(dpnEndpoints.get().getDPNTEPsInfo().values());
403         } else {
404             return new ArrayList<>();
405         }
406     }
407
408     public void removeOrUpdateLBGroups(String tepIp, int addRemoveOrUpdate) {
409         getDpnTEPsInfos(dataBroker).forEach(dpnInfo -> {
410             if (NwConstants.MOD_FLOW == addRemoveOrUpdate) {
411                 LOG.debug("Updating bucket in DPN {}", dpnInfo.getDPNID());
412             } else if (NwConstants.DEL_FLOW == addRemoveOrUpdate) {
413                 LOG.debug("Deleting groups in DPN {}", dpnInfo.getDPNID());
414             }
415             Class<? extends TunnelTypeBase> tunType = TunnelTypeMplsOverGre.class;
416             fibManager.programDcGwLoadBalancingGroup(dpnInfo.getDPNID(),
417                     tepIp, addRemoveOrUpdate, false, tunType);
418         });
419     }
420 }