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