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