2 * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.bgpmanager;
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;
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;
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;
88 private final DataBroker dataBroker;
89 private final IFibManager fibManager;
92 private final BlockingQueue<ActionableResource> bgpResourcesBufferQ = new LinkedBlockingQueue<>();
95 public BgpUtil(DataBroker dataBroker, final IFibManager fibManager) {
96 this.dataBroker = dataBroker;
97 this.fibManager = fibManager;
102 ResourceBatchingManager resBatchingManager = ResourceBatchingManager.getInstance();
104 Integer batchSize = Integer.getInteger("batch.size", DEFAULT_BATCH_SIZE);
105 Integer batchInterval = Integer.getInteger("batch.wait.time", DEFAULT_BATCH_INTERVAL);
107 resBatchingManager.registerBatchableResource(RESOURCE_TYPE, bgpResourcesBufferQ,
108 new DefaultBatchHandler(dataBroker, LogicalDatastoreType.CONFIGURATION, batchSize, batchInterval));
113 public void close() {
114 ResourceBatchingManager.getInstance().deregisterBatchableResource(RESOURCE_TYPE);
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
123 public static int getAFItranslatedfromPrefix(String argPrefix) {
124 int retValue = af_afi.AFI_IP.getValue();//default afiValue is 1 (= ipv4)
126 if (argPrefix.indexOf("/") == -1) {
127 prefixOnly = argPrefix;
129 prefixOnly = argPrefix.substring(0, argPrefix.indexOf("/"));
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();
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)
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);
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);
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);
170 // Convert ProtocolType to thrift protocol_type
171 public static protocol_type convertToThriftProtocolType(BgpControlPlaneType protocolType) {
172 switch (protocolType) {
174 return protocol_type.PROTOCOL_LU;
176 return protocol_type.PROTOCOL_L3VPN;
178 return protocol_type.PROTOCOL_EVPN;
180 return protocol_type.PROTOCOL_ANY;
184 // Convert EncapType to thrift encap_type
185 public static encap_type convertToThriftEncapType(EncapType encapType) {
188 return encap_type.L2TPV3_OVER_IP;
190 return encap_type.GRE;
192 return encap_type.IP_IN_IP;
194 return encap_type.VXLAN;
197 return encap_type.MPLS;
201 public VpnInstanceOpDataEntry getVpnInstanceOpData(String rd) {
202 InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
203 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = Optional.empty();
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);
210 if (vpnInstanceOpData.isPresent()) {
211 return vpnInstanceOpData.get();
216 public static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
217 return InstanceIdentifier.builder(VpnInstanceOpData.class)
218 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
221 private String getElanNamefromRd(String rd) {
222 InstanceIdentifier<EvpnRdToNetwork> id = getEvpnRdToNetworkIdentifier(rd);
223 Optional<EvpnRdToNetwork> evpnRdToNetworkOpData = Optional.empty();
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);
230 if (evpnRdToNetworkOpData.isPresent()) {
231 return evpnRdToNetworkOpData.get().getNetworkId();
236 private static InstanceIdentifier<EvpnRdToNetwork> getEvpnRdToNetworkIdentifier(String rd) {
237 return InstanceIdentifier.builder(EvpnRdToNetworks.class)
238 .child(EvpnRdToNetwork.class, new EvpnRdToNetworkKey(rd)).build();
241 public void addTepToElanInstance(String rd, String tepIp) {
242 if (rd == null || tepIp == null) {
243 LOG.error("addTepToElanInstance : Null parameters returning");
246 String elanName = getElanNamefromRd(rd);
247 if (elanName == null) {
248 LOG.error("Elan null while processing RT2 for RD {}", rd);
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());
259 public void deleteTepFromElanInstance(String rd, String tepIp) {
260 if (rd == null || tepIp == null) {
261 LOG.error("deleteTepFromElanInstance : Null parameters returning");
264 String elanName = getElanNamefromRd(rd);
265 if (elanName == null) {
266 LOG.error("Elan null while processing RT2 withdraw for RD {}", rd);
269 LOG.debug("Deleting tepIp {} from elan {}", tepIp, elanName);
270 InstanceIdentifier<ExternalTeps> externalTepsId = getExternalTepsIdentifier(elanName, tepIp);
271 delete(externalTepsId);
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();
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);
286 VpnInstanceOpDataEntry vpnInstanceOpData = getVpnInstanceOpData(rd);
287 String vpnName = vpnInstanceOpData != null ? vpnInstanceOpData.getVpnInstanceName() : null;
288 rdtoVpnMap.put(rd, vpnName);
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
297 public Vrfs getVrfFromRd(String rd) {
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();
304 vrfsFromDs = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
306 } catch (ExecutionException | InterruptedException e) {
307 LOG.error("Exception while reading BGP VRF table for the Vpn Rd {}", rd, e);
309 if (vrfsFromDs.isPresent()) {
310 vrfs = vrfsFromDs.get();
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
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;
326 return layerTypeValue;
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();
338 public void enableBfdFlag() {
342 public void disableBfdFlag() {
346 public boolean isBfdEnabled() {
347 if (enableBfdFlag == 1) {
349 } else if (enableBfdFlag == 0) {
352 BfdConfig bfdConfig = getBfdConfig();
353 if (bfdConfig != null) {
354 return bfdConfig.isBfdEnabled();
359 public BfdConfig getBfdConfig() {
360 InstanceIdentifier<BfdConfig> id =
361 InstanceIdentifier.builder(BfdConfig.class).build();
362 Optional<BfdConfig> bfdConfigOptional = Optional.empty();
364 bfdConfigOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
365 LogicalDatastoreType.CONFIGURATION, id);
366 } catch (ExecutionException | InterruptedException e) {
367 LOG.error("Exception while reading BfdConfig", e);
369 if (bfdConfigOptional.isPresent()) {
370 return bfdConfigOptional.get();
375 public DcgwTepList getDcgwTepConfig() {
376 InstanceIdentifier<DcgwTepList> id =
377 InstanceIdentifier.builder(Bgp.class).child(DcgwTepList.class).build();
378 Optional<DcgwTepList> dcgwTepListOptional = Optional.empty();
380 dcgwTepListOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
381 LogicalDatastoreType.CONFIGURATION, id);
382 } catch (ExecutionException | InterruptedException e) {
383 LOG.error("getDcgwTepConfig: Exception while reading DcgwTepList", e);
385 if (dcgwTepListOptional.isPresent()) {
386 return dcgwTepListOptional.get();
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();
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);
403 if (tepListOptional.isPresent()) {
404 return tepListOptional.get().getTepIps();
406 LOG.debug("No tep configured for DCGW {}", dcgwIp);
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());
416 return new ArrayList<>();
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());
427 Class<? extends TunnelTypeBase> tunType = TunnelTypeMplsOverGre.class;
428 fibManager.programDcGwLoadBalancingGroup(dpnInfo.getDPNID(),
429 tepIp, addRemoveOrUpdate, false, tunType);