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