MRI version bumpup for Aluminium
[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.ActionableResourceImpl;
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         ActionableResourceImpl actResource = new ActionableResourceImpl(path.toString());
148         actResource.setAction(ActionableResource.UPDATE);
149         actResource.setInstanceIdentifier(path);
150         actResource.setInstance(data);
151         bgpResourcesBufferQ.add(actResource);
152     }
153
154     public <T extends DataObject> void write(final InstanceIdentifier<T> path, final T data) {
155         ActionableResourceImpl actResource = new ActionableResourceImpl(path.toString());
156         actResource.setAction(ActionableResource.CREATE);
157         actResource.setInstanceIdentifier(path);
158         actResource.setInstance(data);
159         bgpResourcesBufferQ.add(actResource);
160     }
161
162     public <T extends DataObject> void delete(final InstanceIdentifier<T> path) {
163         ActionableResourceImpl actResource = new ActionableResourceImpl(path.toString());
164         actResource.setAction(ActionableResource.DELETE);
165         actResource.setInstanceIdentifier(path);
166         actResource.setInstance(null);
167         bgpResourcesBufferQ.add(actResource);
168     }
169
170     // Convert ProtocolType to thrift protocol_type
171     public static protocol_type convertToThriftProtocolType(BgpControlPlaneType protocolType) {
172         switch (protocolType) {
173             case PROTOCOLLU:
174                 return protocol_type.PROTOCOL_LU;
175             case PROTOCOLL3VPN:
176                 return protocol_type.PROTOCOL_L3VPN;
177             case PROTOCOLEVPN:
178                 return protocol_type.PROTOCOL_EVPN;
179             default:
180                 return protocol_type.PROTOCOL_ANY;
181         }
182     }
183
184     // Convert EncapType to thrift encap_type
185     public static encap_type convertToThriftEncapType(EncapType encapType) {
186         switch (encapType) {
187             case L2TPV3OVERIP:
188                 return encap_type.L2TPV3_OVER_IP;
189             case GRE:
190                 return encap_type.GRE;
191             case IPINIP:
192                 return encap_type.IP_IN_IP;
193             case VXLAN:
194                 return encap_type.VXLAN;
195             case MPLS:
196             default:
197                 return encap_type.MPLS;
198         }
199     }
200
201     public VpnInstanceOpDataEntry getVpnInstanceOpData(String rd)  {
202         InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
203         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = Optional.empty();
204         try {
205             vpnInstanceOpData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
206                     LogicalDatastoreType.OPERATIONAL, id);
207         } catch (ExecutionException | InterruptedException e) {
208             LOG.error("Exception while reading VpnInstanceOpDataEntry DS for the Vpn Rd {}", rd, e);
209         }
210         if (vpnInstanceOpData.isPresent()) {
211             return vpnInstanceOpData.get();
212         }
213         return null;
214     }
215
216     public static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
217         return InstanceIdentifier.builder(VpnInstanceOpData.class)
218                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
219     }
220
221     private String getElanNamefromRd(String rd)  {
222         InstanceIdentifier<EvpnRdToNetwork> id = getEvpnRdToNetworkIdentifier(rd);
223         Optional<EvpnRdToNetwork> evpnRdToNetworkOpData = Optional.empty();
224         try {
225             evpnRdToNetworkOpData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
226                     LogicalDatastoreType.CONFIGURATION, id);
227         } catch (ExecutionException | InterruptedException e) {
228             LOG.error("Exception while reading EvpnRdToNetwork DS for the Vpn Rd {}", rd, e);
229         }
230         if (evpnRdToNetworkOpData.isPresent()) {
231             return evpnRdToNetworkOpData.get().getNetworkId();
232         }
233         return null;
234     }
235
236     private static InstanceIdentifier<EvpnRdToNetwork> getEvpnRdToNetworkIdentifier(String rd) {
237         return InstanceIdentifier.builder(EvpnRdToNetworks.class)
238                 .child(EvpnRdToNetwork.class, new EvpnRdToNetworkKey(rd)).build();
239     }
240
241     public void addTepToElanInstance(String rd, String tepIp) {
242         if (rd == null || tepIp == null) {
243             LOG.error("addTepToElanInstance : Null parameters returning");
244             return;
245         }
246         String elanName = getElanNamefromRd(rd);
247         if (elanName == null) {
248             LOG.error("Elan null while processing RT2 for RD {}", rd);
249             return;
250         }
251         LOG.debug("Adding tepIp {} to elan {}", tepIp, elanName);
252         InstanceIdentifier<ExternalTeps> externalTepsId = getExternalTepsIdentifier(elanName, tepIp);
253         ExternalTepsBuilder externalTepsBuilder = new ExternalTepsBuilder();
254         ExternalTepsKey externalTepsKey = externalTepsId.firstKeyOf(ExternalTeps.class);
255         externalTepsBuilder.setTepIp(externalTepsKey.getTepIp());
256         update(externalTepsId, externalTepsBuilder.build());
257     }
258
259     public void deleteTepFromElanInstance(String rd, String tepIp) {
260         if (rd == null || tepIp == null) {
261             LOG.error("deleteTepFromElanInstance : Null parameters returning");
262             return;
263         }
264         String elanName = getElanNamefromRd(rd);
265         if (elanName == null) {
266             LOG.error("Elan null while processing RT2 withdraw for RD {}", rd);
267             return;
268         }
269         LOG.debug("Deleting tepIp {} from elan {}", tepIp, elanName);
270         InstanceIdentifier<ExternalTeps> externalTepsId = getExternalTepsIdentifier(elanName, tepIp);
271         delete(externalTepsId);
272     }
273
274     private static InstanceIdentifier<ExternalTeps> getExternalTepsIdentifier(String elanInstanceName, String tepIp) {
275         IpAddress tepAdress = tepIp == null ? null : new IpAddress(new Ipv4Address(tepIp));
276         return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class,
277                 new ElanInstanceKey(elanInstanceName)).child(ExternalTeps.class,
278                 new ExternalTepsKey(tepAdress)).build();
279     }
280
281     public String getVpnNameFromRd(String rd) {
282         final Map<String, String> rdtoVpnMap = new HashMap<>();
283         if (rdtoVpnMap.get(rd) != null) {
284             return rdtoVpnMap.get(rd);
285         } else {
286             VpnInstanceOpDataEntry vpnInstanceOpData = getVpnInstanceOpData(rd);
287             String vpnName = vpnInstanceOpData != null ? vpnInstanceOpData.getVpnInstanceName() : null;
288             rdtoVpnMap.put(rd, vpnName);
289             return vpnName;
290         }
291     }
292
293     /** get the vrf with the RouterDistinguisher pass in param.
294      * @param rd is the RouteDistinguisher of vrf
295      * @return the vrf of rd or null if no exist
296      */
297     public Vrfs getVrfFromRd(String rd) {
298         Vrfs vrfs = null;
299         KeyedInstanceIdentifier<Vrfs, VrfsKey> id = InstanceIdentifier.create(Bgp.class)
300                 .child(VrfsContainer.class)
301                 .child(Vrfs.class, new VrfsKey(rd));
302         Optional<Vrfs> vrfsFromDs = Optional.empty();
303         try {
304             vrfsFromDs = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
305                     id);
306         } catch (ExecutionException | InterruptedException e) {
307             LOG.error("Exception while reading BGP VRF table for the Vpn Rd {}", rd, e);
308         }
309         if (vrfsFromDs.isPresent()) {
310             vrfs = vrfsFromDs.get();
311         }
312         return vrfs;
313     }
314
315     /** get layerType used from an AddressFamiliesVrf.
316      * @param adf is the AddressFamiliesVrf from which the layer is asked.
317      * @return the layerType to reach from the argument addressFamilyVrf or null if not found
318      */
319     public static LayerType getLayerType(AddressFamiliesVrf adf) {
320         LayerType layerTypeValue = null;
321         if (adf.getSafi().intValue() == af_safi.SAFI_EVPN.getValue()) {
322             layerTypeValue = LayerType.LAYER2;
323         } else if (adf.getSafi().intValue() == af_safi.SAFI_MPLS_VPN.getValue()) {
324             layerTypeValue = LayerType.LAYER3;
325         }
326         return layerTypeValue;
327     }
328
329     public void removeVrfEntry(String rd, VrfEntry vrfEntry) {
330         LOG.debug("removeVrfEntry : vrf {} prefix {}", rd, vrfEntry.getDestPrefix());
331         InstanceIdentifier<VrfEntry> vrfEntryId =
332                    InstanceIdentifier.builder(FibEntries.class)
333                    .child(VrfTables.class, new VrfTablesKey(rd))
334                    .child(VrfEntry.class, new VrfEntryKey(vrfEntry.getDestPrefix())).build();
335         delete(vrfEntryId);
336     }
337
338     public void enableBfdFlag() {
339         enableBfdFlag = 1;
340     }
341
342     public void disableBfdFlag() {
343         enableBfdFlag = 0;
344     }
345
346     public boolean isBfdEnabled() {
347         if (enableBfdFlag == 1) {
348             return true;
349         } else if (enableBfdFlag == 0) {
350             return false;
351         }
352         BfdConfig bfdConfig = getBfdConfig();
353         if (bfdConfig != null) {
354             return bfdConfig.isBfdEnabled();
355         }
356         return false;
357     }
358
359     public BfdConfig getBfdConfig() {
360         InstanceIdentifier<BfdConfig> id =
361                 InstanceIdentifier.builder(BfdConfig.class).build();
362         Optional<BfdConfig> bfdConfigOptional = Optional.empty();
363         try {
364             bfdConfigOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
365                     LogicalDatastoreType.CONFIGURATION, id);
366         } catch (ExecutionException | InterruptedException e) {
367             LOG.error("Exception while reading BfdConfig", e);
368         }
369         if (bfdConfigOptional.isPresent()) {
370             return bfdConfigOptional.get();
371         }
372         return null;
373     }
374
375     public DcgwTepList getDcgwTepConfig() {
376         InstanceIdentifier<DcgwTepList> id =
377                 InstanceIdentifier.builder(Bgp.class).child(DcgwTepList.class).build();
378         Optional<DcgwTepList> dcgwTepListOptional = Optional.empty();
379         try {
380             dcgwTepListOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
381                     LogicalDatastoreType.CONFIGURATION, id);
382         } catch (ExecutionException | InterruptedException e) {
383             LOG.error("getDcgwTepConfig: Exception while reading DcgwTepList", e);
384         }
385         if (dcgwTepListOptional.isPresent()) {
386             return dcgwTepListOptional.get();
387         }
388         return null;
389     }
390
391     public List<String> getDcgwTepConfig(String dcgwIp) {
392         InstanceIdentifier<DcgwTep> id =
393                 InstanceIdentifier.builder(Bgp.class)
394                         .child(DcgwTepList.class)
395                         .child(DcgwTep.class, new DcgwTepKey(dcgwIp)).build();
396         Optional<DcgwTep> tepListOptional = Optional.empty();
397         try {
398             tepListOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
399                     LogicalDatastoreType.CONFIGURATION, id);
400         } catch (ExecutionException | InterruptedException e) {
401             LOG.error("Exception while reading DcgwTep for the IP {}", dcgwIp, e);
402         }
403         if (tepListOptional.isPresent()) {
404             return tepListOptional.get().getTepIps();
405         }
406         LOG.debug("No tep configured for DCGW {}", dcgwIp);
407         return null;
408     }
409
410     public static List<DPNTEPsInfo> getDpnTEPsInfos(DataBroker dataBroker) {
411         InstanceIdentifier<DpnEndpoints> iid = InstanceIdentifier.builder(DpnEndpoints.class).build();
412         Optional<DpnEndpoints> dpnEndpoints = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, iid, dataBroker);
413         if (dpnEndpoints.isPresent()) {
414             return new ArrayList<DPNTEPsInfo>(dpnEndpoints.get().getDPNTEPsInfo().values());
415         } else {
416             return new ArrayList<>();
417         }
418     }
419
420     public void removeOrUpdateLBGroups(String tepIp, int addRemoveOrUpdate) {
421         getDpnTEPsInfos(dataBroker).forEach(dpnInfo -> {
422             if (NwConstants.MOD_FLOW == addRemoveOrUpdate) {
423                 LOG.debug("Updating bucket in DPN {}", dpnInfo.getDPNID());
424             } else if (NwConstants.DEL_FLOW == addRemoveOrUpdate) {
425                 LOG.debug("Deleting groups in DPN {}", dpnInfo.getDPNID());
426             }
427             Class<? extends TunnelTypeBase> tunType = TunnelTypeMplsOverGre.class;
428             fibManager.programDcGwLoadBalancingGroup(dpnInfo.getDPNID(),
429                     tepIp, addRemoveOrUpdate, false, tunType);
430         });
431     }
432 }