2 * Copyright © 2016, 2017 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
9 package org.opendaylight.netvirt.fibmanager;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.CheckedFuture;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import java.math.BigInteger;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.List;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
24 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
27 import org.opendaylight.genius.mdsalutil.MDSALUtil;
28 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
29 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIdsKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkStates;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinks;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
61 import org.opendaylight.yangtools.yang.binding.DataObject;
62 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
63 import org.opendaylight.yangtools.yang.common.RpcResult;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
67 public class FibUtil {
68 private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class);
70 // TODO Clean up the exception handling
71 @SuppressWarnings("checkstyle:IllegalCatch")
72 public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
73 InstanceIdentifier<T> path) {
75 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
77 Optional<T> result = Optional.absent();
79 result = tx.read(datastoreType, path).get();
80 } catch (Exception e) {
81 throw new RuntimeException(e);
87 static <T extends DataObject> void asyncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
88 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
89 WriteTransaction tx = broker.newWriteOnlyTransaction();
90 tx.merge(datastoreType, path, data, true);
91 Futures.addCallback(tx.submit(), callback);
94 static <T extends DataObject> void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
95 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
96 WriteTransaction tx = broker.newWriteOnlyTransaction();
97 tx.put(datastoreType, path, data, true);
98 CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
101 } catch (InterruptedException | ExecutionException e) {
102 LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data, e);
103 throw new RuntimeException(e.getMessage());
107 static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
108 InstanceIdentifier<T> path) {
109 WriteTransaction tx = broker.newWriteOnlyTransaction();
110 tx.delete(datastoreType, path);
111 Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
114 static InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
115 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang
116 .l3vpn.rev140815.VpnInterfaces.class)
117 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
119 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
120 .VpnInterfaceKey(vpnInterfaceName))
121 .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
122 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.class,
123 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list
124 .AdjacencyKey(ipAddress)).build();
127 static InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
128 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
129 .rev140815.VpnInterfaces.class)
130 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
132 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
133 .VpnInterfaceKey(vpnInterfaceName))
134 .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
138 static InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(long vpnId, String ipPrefix) {
139 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
140 .rev130911.PrefixToInterface.class)
141 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
143 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
145 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
146 .vpn.ids.Prefixes.class,
147 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to
148 ._interface.vpn.ids.PrefixesKey(ipPrefix)).build();
151 static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
152 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
153 .rev140815.VpnInterfaces.class)
154 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
156 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
157 .VpnInterfaceKey(vpnInterfaceName)).build();
160 public static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
161 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
162 .rev130911.VpnInstanceOpData.class)
163 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
164 .VpnInstanceOpDataEntry.class,
165 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
166 .VpnInstanceOpDataEntryKey(rd))
167 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
168 .vpn.instance.op.data.entry.VpnToDpnList.class,
169 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
170 .vpn.instance.op.data.entry.VpnToDpnListKey(dpnId)).build();
173 static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to
174 .extraroute.vpn.Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
175 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
176 .rev130911.VpnToExtraroute.class)
177 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn
178 .class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to
179 .extraroute.VpnKey(vrfId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
180 .rev130911.vpn.to.extraroute.vpn.Extraroute.class,
181 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn
182 .ExtrarouteKey(ipPrefix)).build();
185 static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
186 return InstanceIdentifier.builder(VpnInstanceOpData.class)
187 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
190 static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(DataBroker broker, String rd) {
191 InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
192 return read(broker, LogicalDatastoreType.OPERATIONAL, id);
195 static String getNextHopLabelKey(String rd, String prefix) {
196 String key = rd + FibConstants.SEPARATOR + prefix;
200 static Prefixes getPrefixToInterface(DataBroker broker, Long vpnId, String ipPrefix) {
201 Optional<Prefixes> localNextHopInfoData = read(broker, LogicalDatastoreType.OPERATIONAL,
202 getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
203 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
206 static String getMacAddressFromPrefix(DataBroker broker, String ifName, String ipPrefix) {
207 Optional<Adjacency> adjacencyData = read(broker, LogicalDatastoreType.OPERATIONAL,
208 getAdjacencyIdentifier(ifName, ipPrefix));
209 return adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
212 static void releaseId(IdManagerService idManager, String poolName, String idKey) {
213 ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
215 Future<RpcResult<Void>> result = idManager.releaseId(idInput);
216 RpcResult<Void> rpcResult = result.get();
217 if (!rpcResult.isSuccessful()) {
218 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
220 } catch (InterruptedException | ExecutionException e) {
221 LOG.warn("Exception when getting Unique Id for key {}", idKey, e);
225 static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
226 .instance.to.vpn.id.VpnInstance> getVpnInstanceToVpnIdIdentifier(String vpnName) {
227 return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
228 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
230 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
231 .VpnInstanceKey(vpnName)).build();
234 public static long getVpnId(DataBroker broker, String vpnName) {
236 InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
237 return read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnInstance::getVpnId).or(-1L);
241 * Retrieves the VpnInstance name (typically the VPN Uuid) out from the route-distinguisher.
243 * @param broker The DataBroker
244 * @param rd The route-distinguisher
245 * @return The vpn instance
247 public static Optional<String> getVpnNameFromRd(DataBroker broker, String rd) {
248 return getVpnInstanceOpData(broker, rd).transform(VpnInstanceOpDataEntry::getVpnInstanceName);
251 static List<InterVpnLink> getAllInterVpnLinks(DataBroker broker) {
252 InstanceIdentifier<InterVpnLinks> interVpnLinksIid = InstanceIdentifier.builder(InterVpnLinks.class).build();
254 return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinksIid).transform(
255 InterVpnLinks::getInterVpnLink).or(new ArrayList<>());
259 * Returns the instance identifier for a given vpnLinkName.
261 * @param vpnLinkName The vpn link name
262 * @return InstanceIdentifier
264 public static InstanceIdentifier<InterVpnLinkState> getInterVpnLinkStateIid(String vpnLinkName) {
265 return InstanceIdentifier.builder(InterVpnLinkStates.class)
266 .child(InterVpnLinkState.class, new InterVpnLinkStateKey(vpnLinkName)).build();
270 * Checks if the InterVpnLink is in Active state.
272 * @param broker The DataBroker
273 * @param vpnLinkName The vpn linkname
274 * @return The link state
276 public static boolean isInterVpnLinkActive(DataBroker broker, String vpnLinkName) {
277 Optional<InterVpnLinkState> interVpnLinkState = getInterVpnLinkState(broker, vpnLinkName);
278 if (!interVpnLinkState.isPresent()) {
279 LOG.warn("Could not find Operative State for InterVpnLink {}", vpnLinkName);
283 return interVpnLinkState.get().getState().equals(InterVpnLinkState.State.Active);
287 * Checks if the state of the interVpnLink.
289 * @param broker The DataBroker
290 * @param vpnLinkName The vpn linkname
291 * @return The link state
293 public static Optional<InterVpnLinkState> getInterVpnLinkState(DataBroker broker, String vpnLinkName) {
294 InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid = getInterVpnLinkStateIid(vpnLinkName);
295 return read(broker, LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid);
299 * Retrieves the InterVpnLink in which the VPN, represented by its Uuid,
302 * @param dataBroker The DataBroker
303 * @param vpnUuid The vpn uuid
304 * @return The InterVpnLink or Optional.absent() if the VPN does not participate in an InterVpnLink
306 public static Optional<InterVpnLink> getInterVpnLinkByVpnUuid(DataBroker dataBroker, String vpnUuid) {
307 List<InterVpnLink> interVpnLinkList = getAllInterVpnLinks(dataBroker);
308 for (InterVpnLink interVpnLink : interVpnLinkList) {
309 if (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid)
310 || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnUuid)) {
311 LOG.debug("InterVpnLink found for VPN {}. Details: vpn1=( uuid={} endpoint={}) "
312 + "vpn2=( uuid={} endpoint={} ))",
313 vpnUuid, interVpnLink.getFirstEndpoint().getVpnUuid(),
314 interVpnLink.getFirstEndpoint().getIpAddress(), interVpnLink.getSecondEndpoint().getVpnUuid(),
315 interVpnLink.getSecondEndpoint().getIpAddress());
316 return Optional.fromNullable(interVpnLink);
319 LOG.debug("Could not find a suitable InterVpnLink for VpnUuid={}", vpnUuid);
320 return Optional.absent();
324 * Retrieves the InterVpnLink in which the VPN, represented by its
325 * Route-Distinguisher, participates.
327 * @param dataBroker The DataBroker
328 * @param rd route-distinguisher
329 * @return The InterVpnLink or Optional.absent() if the VPN does not participate in an InterVpnLink
331 public static Optional<InterVpnLink> getInterVpnLinkByRd(DataBroker dataBroker, String rd) {
332 Optional<String> vpnId = getVpnNameFromRd(dataBroker, rd);
333 if (!vpnId.isPresent()) {
334 LOG.debug("Could not find vpnId for RouteDistinguisher {}", rd);
335 return Optional.absent();
338 return getInterVpnLinkByVpnUuid(dataBroker, vpnId.get());
342 * Checks if the route-distinguisher is involved in any inter-vpn-link, which is returned if its found.
344 * @param dataBroker The DataBroker
345 * @param rd route-distinguisher
346 * @return The inter vpn link
348 public static Optional<InterVpnLink> getActiveInterVpnLinkFromRd(DataBroker dataBroker, String rd) {
349 Optional<InterVpnLink> interVpnLink = getInterVpnLinkByRd(dataBroker, rd);
350 if (interVpnLink.isPresent()) {
351 if (isInterVpnLinkActive(dataBroker, interVpnLink.get().getName())) {
354 LOG.warn("InterVpnLink for RouteDistinguisher {} exists, but it's in error state. InterVpnLink={}",
355 rd, interVpnLink.get().getName());
356 return Optional.absent();
359 return Optional.absent();
363 * Checks if the route-distinguisher is involved in any inter-vpn-link. In that case, this method will return
364 * the endpoint of the other vpn involved in the inter-vpn-link.
366 * @param dataBroker The DataBroker
367 * @param rd route-distinguisher
368 * @return Opposite endpoint
370 public static Optional<String> getInterVpnLinkOppositeEndPointIpAddress(DataBroker dataBroker, String rd) {
371 Optional<String> vpnId = getVpnNameFromRd(dataBroker, rd);
372 if (!vpnId.isPresent()) {
373 LOG.debug("Could not find the VpnName for RouteDistinguisher {}", rd);
374 return Optional.absent();
376 List<InterVpnLink> interVpnLinkList = getAllInterVpnLinks(dataBroker);
377 if (!interVpnLinkList.isEmpty()) {
378 for (InterVpnLink interVpnLink : interVpnLinkList) {
379 if (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnId)) {
380 return Optional.fromNullable(interVpnLink.getSecondEndpoint().getVpnUuid().getValue());
381 } else if (interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(vpnId)) {
382 return Optional.fromNullable(interVpnLink.getFirstEndpoint().getIpAddress().getValue());
386 return Optional.absent();
390 * Obtains the route-distinguisher for a given vpn-name.
392 * @param broker The DataBroker
393 * @param vpnName vpn name
394 * @return route-distinguisher
396 public static String getVpnRd(DataBroker broker, String vpnName) {
397 InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
398 return read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnInstance::getVrfId).orNull();
402 * Returns a boolean value which indicates if the endpoint's IP received as parameter belongs to any InterVpnLink.
404 * @param broker DataBroker
405 * @param endpointIp IP to search for.
406 * @return inter vpn link
408 public static boolean getInterVpnLinkByEndpointIp(DataBroker broker, String endpointIp) {
409 List<InterVpnLink> allInterVpnLinks = getAllInterVpnLinks(broker);
410 for (InterVpnLink interVpnLink : allInterVpnLinks) {
411 if (interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(endpointIp)
412 || interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(endpointIp)) {
419 public static int getUniqueId(IdManagerService idManager, String poolName, String idKey) {
420 AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
423 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
424 RpcResult<AllocateIdOutput> rpcResult = result.get();
425 if (rpcResult.isSuccessful()) {
426 return rpcResult.getResult().getIdValue().intValue();
428 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
430 } catch (InterruptedException | ExecutionException e) {
431 LOG.warn("Exception when getting Unique Id", e);
436 static final FutureCallback<Void> DEFAULT_CALLBACK =
437 new FutureCallback<Void>() {
439 public void onSuccess(Void result) {
440 LOG.debug("Success in Datastore operation");
444 public void onFailure(Throwable error) {
445 LOG.error("Error in Datastore operation", error);
451 public static String getVpnNameFromId(DataBroker broker, long vpnId) {
452 InstanceIdentifier<VpnIds> id = getVpnIdToVpnInstanceIdentifier(vpnId);
453 return read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnIds::getVpnInstanceName).orNull();
456 static InstanceIdentifier<VpnIds> getVpnIdToVpnInstanceIdentifier(long vpnId) {
457 return InstanceIdentifier.builder(VpnIdToVpnInstance.class)
458 .child(VpnIds.class, new VpnIdsKey(vpnId)).build();
461 public static <T extends DataObject> void syncUpdate(DataBroker broker, LogicalDatastoreType datastoreType,
462 InstanceIdentifier<T> path, T data) {
463 WriteTransaction tx = broker.newWriteOnlyTransaction();
464 tx.put(datastoreType, path, data, true);
465 CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
468 } catch (InterruptedException | ExecutionException e) {
469 LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data, e);
470 throw new RuntimeException(e.getMessage());
474 // TODO Clean up the exception handling
475 @SuppressWarnings("checkstyle:IllegalCatch")
476 public static void addOrUpdateFibEntry(DataBroker broker, String rd, String macAddress, String prefix,
477 List<String> nextHopList, VrfEntry.EncapType encapType, int label,
478 long l3vni, String gwMacAddress, RouteOrigin origin,
479 WriteTransaction writeConfigTxn) {
480 if (rd == null || rd.isEmpty()) {
481 LOG.error("Prefix {} not associated with vpn", prefix);
485 Preconditions.checkNotNull(nextHopList, "NextHopList can't be null");
488 InstanceIdentifier<VrfEntry> vrfEntryId =
489 InstanceIdentifier.builder(FibEntries.class)
490 .child(VrfTables.class, new VrfTablesKey(rd))
491 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
492 Optional<VrfEntry> entry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
494 if (! entry.isPresent()) {
495 writeFibEntryToDs(vrfEntryId, prefix, nextHopList, label, l3vni, encapType, origin, macAddress,
496 gwMacAddress, writeConfigTxn, broker);
497 LOG.debug("Created vrfEntry for {} nexthop {} label {}", prefix, nextHopList, label);
498 } else { // Found in MDSAL database
499 List<String> nh = entry.get().getNextHopAddressList();
500 for (String nextHop : nextHopList) {
501 if (!nh.contains(nextHop)) {
505 writeFibEntryToDs(vrfEntryId, prefix, nh, label, l3vni, encapType, origin, macAddress,
506 gwMacAddress, writeConfigTxn, broker);
507 LOG.debug("Updated vrfEntry for {} nexthop {} label {}", prefix, nh, label);
509 } catch (Exception e) {
510 LOG.error("addFibEntryToDS: error ", e);
514 // TODO Clean up the exception handling
515 @SuppressWarnings("checkstyle:IllegalCatch")
516 public static void writeFibEntryToDs(InstanceIdentifier<VrfEntry> vrfEntryId, String prefix,
517 List<String> nextHopList, long label, Long l3vni,
518 VrfEntry.EncapType encapType, RouteOrigin origin, String macAddress,
519 String gatewayMacAddress, WriteTransaction writeConfigTxn,
521 VrfEntryBuilder vrfEntryBuilder = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(nextHopList)
522 .setOrigin(origin.getValue());
523 buildVpnEncapSpecificInfo(vrfEntryBuilder, encapType, label, l3vni, macAddress, gatewayMacAddress);
524 if (writeConfigTxn != null) {
525 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build(), true);
527 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build());
531 @SuppressWarnings("checkstyle:IllegalCatch")
532 public static void addFibEntryForRouterInterface(DataBroker broker,
535 RouterInterface routerInterface,
537 WriteTransaction writeConfigTxn) {
538 if (rd == null || rd.isEmpty()) {
539 LOG.error("Prefix {} not associated with vpn", prefix);
544 InstanceIdentifier<VrfEntry> vrfEntryId =
545 InstanceIdentifier.builder(FibEntries.class)
546 .child(VrfTables.class, new VrfTablesKey(rd))
547 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
549 VrfEntry vrfEntry = new VrfEntryBuilder().setKey(new VrfEntryKey(prefix)).setDestPrefix(prefix)
550 .setNextHopAddressList(Collections.singletonList(""))
552 .setOrigin(RouteOrigin.LOCAL.getValue())
553 .addAugmentation(RouterInterface.class, routerInterface).build();
555 if (writeConfigTxn != null) {
556 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
558 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
560 LOG.debug("Created vrfEntry for router-interface-prefix {} rd {} label {}", prefix, rd, label);
561 } catch (Exception e) {
562 LOG.error("addFibEntryToDS: error ", e);
566 private static void buildVpnEncapSpecificInfo(VrfEntryBuilder builder, VrfEntry.EncapType encapType, long label,
567 long l3vni, String macAddress, String gatewayMac) {
568 if (encapType.equals(VrfEntry.EncapType.Mplsgre)) {
569 builder.setLabel(label);
571 builder.setL3vni(l3vni).setGatewayMacAddress(gatewayMac);
573 builder.setEncapType(encapType);
576 public static void removeFibEntry(DataBroker broker, String rd, String prefix, WriteTransaction writeConfigTxn) {
578 if (rd == null || rd.isEmpty()) {
579 LOG.error("Prefix {} not associated with vpn", prefix);
582 LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
584 InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
585 InstanceIdentifier.builder(FibEntries.class)
586 .child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix));
587 InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
588 if (writeConfigTxn != null) {
589 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
591 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
596 * Removes a specific Nexthop from a VrfEntry. If Nexthop to remove is the
597 * last one in the VrfEntry, then the VrfEntry is removed too.
599 * @param broker dataBroker service reference
600 * @param rd Route-Distinguisher to which the VrfEntry belongs to
601 * @param prefix Destination of the route
602 * @param nextHopToRemove Specific nexthop within the Route to be removed.
603 * If null or empty, then the whole VrfEntry is removed
605 public static void removeOrUpdateFibEntry(DataBroker broker, String rd, String prefix, String nextHopToRemove,
606 WriteTransaction writeConfigTxn) {
608 LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
610 // Looking for existing prefix in MDSAL database
611 InstanceIdentifier<VrfEntry> vrfEntryId =
612 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
613 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
614 Optional<VrfEntry> entry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
616 if (entry.isPresent()) {
617 List<String> nhListRead = new ArrayList<>();
618 if (nextHopToRemove != null && !nextHopToRemove.isEmpty()) {
619 nhListRead = entry.get().getNextHopAddressList();
620 if (nhListRead.contains(nextHopToRemove)) {
621 nhListRead.remove(nextHopToRemove);
625 if (nhListRead.isEmpty()) {
626 // Remove the whole entry
627 if (writeConfigTxn != null) {
628 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
630 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
632 LOG.info("Removed Fib Entry rd {} prefix {}", rd, prefix);
634 // An update must be done, not including the current next hop
636 new VrfEntryBuilder(entry.get()).setDestPrefix(prefix).setNextHopAddressList(nhListRead)
637 .setKey(new VrfEntryKey(prefix)).build();
638 if (writeConfigTxn != null) {
639 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
641 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
643 LOG.info("Removed Nexthop {} from Fib Entry rd {} prefix {}", nextHopToRemove, rd, prefix);
646 LOG.warn("Could not find VrfEntry for Route-Distinguisher={} and prefix={}", rd, prefix);
650 public static void updateFibEntry(DataBroker broker, String rd, String prefix, List<String> nextHopList,
651 String gwMacAddress, WriteTransaction writeConfigTxn) {
653 LOG.debug("Updating fib entry for prefix {} with nextHopList {} for rd {}", prefix, nextHopList, rd);
655 // Looking for existing prefix in MDSAL database
656 InstanceIdentifier<VrfEntry> vrfEntryId =
657 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
658 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
659 Optional<VrfEntry> entry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
661 if (entry.isPresent()) {
662 // Update the VRF entry with nextHopList
664 new VrfEntryBuilder(entry.get()).setDestPrefix(prefix).setNextHopAddressList(nextHopList)
665 .setGatewayMacAddress(gwMacAddress).setKey(new VrfEntryKey(prefix)).build();
666 if (nextHopList.isEmpty()) {
667 if (writeConfigTxn != null) {
668 writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
670 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
673 if (writeConfigTxn != null) {
674 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
676 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
679 LOG.debug("Updated fib entry for prefix {} with nextHopList {} for rd {}", prefix, nextHopList, rd);
681 LOG.warn("Could not find VrfEntry for Route-Distinguisher={} and prefix={}", rd, prefix);
685 public static void addVrfTable(DataBroker broker, String rd, WriteTransaction writeConfigTxn) {
686 LOG.debug("Adding vrf table for rd {}", rd);
687 InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
688 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
689 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
690 VrfTablesBuilder vrfTablesBuilder = new VrfTablesBuilder().setKey(new VrfTablesKey(rd))
691 .setRouteDistinguisher(rd).setVrfEntry(new ArrayList<>());
692 if (writeConfigTxn != null) {
693 writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTablesBuilder.build());
695 syncWrite(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTablesBuilder.build(),
696 FibUtil.DEFAULT_CALLBACK);
701 public static void removeVrfTable(DataBroker broker, String rd, WriteTransaction writeConfigTxn) {
702 LOG.debug("Removing vrf table for rd {}", rd);
703 InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
704 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
705 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
707 if (writeConfigTxn != null) {
708 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfTableId);
710 delete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId);
714 public static boolean isControllerManagedRoute(RouteOrigin routeOrigin) {
715 return routeOrigin == RouteOrigin.STATIC
716 || routeOrigin == RouteOrigin.CONNECTED
717 || routeOrigin == RouteOrigin.LOCAL
718 || routeOrigin == RouteOrigin.INTERVPN;
721 public static boolean isControllerManagedNonInterVpnLinkRoute(RouteOrigin routeOrigin) {
722 return routeOrigin == RouteOrigin.STATIC
723 || routeOrigin == RouteOrigin.CONNECTED
724 || routeOrigin == RouteOrigin.LOCAL;