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;
17 import java.math.BigInteger;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.Future;
23 import java.util.stream.Collectors;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
27 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
30 import org.opendaylight.genius.mdsalutil.MDSALUtil;
31 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
32 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
33 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.vrfentry.RoutePaths;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIdsKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkStates;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinks;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
66 import org.opendaylight.yangtools.yang.binding.DataObject;
67 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
68 import org.opendaylight.yangtools.yang.common.RpcResult;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
72 public class FibUtil {
73 private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class);
75 // TODO Clean up the exception handling
76 @SuppressWarnings("checkstyle:IllegalCatch")
77 public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
78 InstanceIdentifier<T> path) {
80 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
82 Optional<T> result = Optional.absent();
84 result = tx.read(datastoreType, path).get();
85 } catch (Exception e) {
86 throw new RuntimeException(e);
92 static <T extends DataObject> void asyncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
93 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
94 WriteTransaction tx = broker.newWriteOnlyTransaction();
95 tx.merge(datastoreType, path, data, true);
96 Futures.addCallback(tx.submit(), callback);
99 static <T extends DataObject> void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
100 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
101 WriteTransaction tx = broker.newWriteOnlyTransaction();
102 tx.put(datastoreType, path, data, true);
103 CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
106 } catch (InterruptedException | ExecutionException e) {
107 LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data, e);
108 throw new RuntimeException(e.getMessage());
112 static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
113 InstanceIdentifier<T> path) {
114 WriteTransaction tx = broker.newWriteOnlyTransaction();
115 tx.delete(datastoreType, path);
116 Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
119 static InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
120 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang
121 .l3vpn.rev140815.VpnInterfaces.class)
122 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
124 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
125 .VpnInterfaceKey(vpnInterfaceName))
126 .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
127 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.class,
128 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list
129 .AdjacencyKey(ipAddress)).build();
132 static InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
133 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
134 .rev140815.VpnInterfaces.class)
135 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
137 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
138 .VpnInterfaceKey(vpnInterfaceName))
139 .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
143 static InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(long vpnId, String ipPrefix) {
144 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
145 .rev130911.PrefixToInterface.class)
146 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
148 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
150 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
151 .vpn.ids.Prefixes.class,
152 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to
153 ._interface.vpn.ids.PrefixesKey(ipPrefix)).build();
156 static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
157 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
158 .rev140815.VpnInterfaces.class)
159 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
161 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
162 .VpnInterfaceKey(vpnInterfaceName)).build();
165 public static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
166 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
167 .rev130911.VpnInstanceOpData.class)
168 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
169 .VpnInstanceOpDataEntry.class,
170 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
171 .VpnInstanceOpDataEntryKey(rd))
172 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
173 .vpn.instance.op.data.entry.VpnToDpnList.class,
174 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
175 .vpn.instance.op.data.entry.VpnToDpnListKey(dpnId)).build();
178 static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
179 return InstanceIdentifier.builder(VpnInstanceOpData.class)
180 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
183 static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(DataBroker broker, String rd) {
184 InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
185 return read(broker, LogicalDatastoreType.OPERATIONAL, id);
188 static String getNextHopLabelKey(String rd, String prefix) {
189 String key = rd + FibConstants.SEPARATOR + prefix;
193 static Prefixes getPrefixToInterface(DataBroker broker, Long vpnId, String ipPrefix) {
194 Optional<Prefixes> localNextHopInfoData = read(broker, LogicalDatastoreType.OPERATIONAL,
195 getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
196 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
199 static String getMacAddressFromPrefix(DataBroker broker, String ifName, String ipPrefix) {
200 Optional<Adjacency> adjacencyData = read(broker, LogicalDatastoreType.OPERATIONAL,
201 getAdjacencyIdentifier(ifName, ipPrefix));
202 return adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
205 static void releaseId(IdManagerService idManager, String poolName, String idKey) {
206 ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
208 Future<RpcResult<Void>> result = idManager.releaseId(idInput);
209 RpcResult<Void> rpcResult = result.get();
210 if (!rpcResult.isSuccessful()) {
211 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
213 } catch (InterruptedException | ExecutionException e) {
214 LOG.warn("Exception when getting Unique Id for key {}", idKey, e);
218 static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
219 .instance.to.vpn.id.VpnInstance> getVpnInstanceToVpnIdIdentifier(String vpnName) {
220 return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
221 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
223 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
224 .VpnInstanceKey(vpnName)).build();
227 public static long getVpnId(DataBroker broker, String vpnName) {
229 InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
230 return read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnInstance::getVpnId).or(-1L);
234 * Retrieves the VpnInstance name (typically the VPN Uuid) out from the route-distinguisher.
236 * @param broker The DataBroker
237 * @param rd The route-distinguisher
238 * @return The vpn instance
240 public static Optional<String> getVpnNameFromRd(DataBroker broker, String rd) {
241 return getVpnInstanceOpData(broker, rd).transform(VpnInstanceOpDataEntry::getVpnInstanceName);
244 static List<InterVpnLink> getAllInterVpnLinks(DataBroker broker) {
245 InstanceIdentifier<InterVpnLinks> interVpnLinksIid = InstanceIdentifier.builder(InterVpnLinks.class).build();
247 return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinksIid).transform(
248 InterVpnLinks::getInterVpnLink).or(new ArrayList<>());
252 * Returns the instance identifier for a given vpnLinkName.
254 * @param vpnLinkName The vpn link name
255 * @return InstanceIdentifier
257 public static InstanceIdentifier<InterVpnLinkState> getInterVpnLinkStateIid(String vpnLinkName) {
258 return InstanceIdentifier.builder(InterVpnLinkStates.class)
259 .child(InterVpnLinkState.class, new InterVpnLinkStateKey(vpnLinkName)).build();
263 * Checks if the InterVpnLink is in Active state.
265 * @param broker The DataBroker
266 * @param vpnLinkName The vpn linkname
267 * @return The link state
269 public static boolean isInterVpnLinkActive(DataBroker broker, String vpnLinkName) {
270 Optional<InterVpnLinkState> interVpnLinkState = getInterVpnLinkState(broker, vpnLinkName);
271 if (!interVpnLinkState.isPresent()) {
272 LOG.warn("Could not find Operative State for InterVpnLink {}", vpnLinkName);
276 return interVpnLinkState.get().getState().equals(InterVpnLinkState.State.Active);
280 * Checks if the state of the interVpnLink.
282 * @param broker The DataBroker
283 * @param vpnLinkName The vpn linkname
284 * @return The link state
286 public static Optional<InterVpnLinkState> getInterVpnLinkState(DataBroker broker, String vpnLinkName) {
287 InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid = getInterVpnLinkStateIid(vpnLinkName);
288 return read(broker, LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid);
292 * Obtains the route-distinguisher for a given vpn-name.
294 * @param broker The DataBroker
295 * @param vpnName vpn name
296 * @return route-distinguisher
298 public static String getVpnRd(DataBroker broker, String vpnName) {
299 InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
300 return read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnInstance::getVrfId).orNull();
303 public static int getUniqueId(IdManagerService idManager, String poolName, String idKey) {
304 AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
307 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
308 RpcResult<AllocateIdOutput> rpcResult = result.get();
309 if (rpcResult.isSuccessful()) {
310 return rpcResult.getResult().getIdValue().intValue();
312 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
314 } catch (InterruptedException | ExecutionException e) {
315 LOG.warn("Exception when getting Unique Id", e);
320 static final FutureCallback<Void> DEFAULT_CALLBACK =
321 new FutureCallback<Void>() {
323 public void onSuccess(Void result) {
324 LOG.debug("Success in Datastore operation");
328 public void onFailure(Throwable error) {
329 LOG.error("Error in Datastore operation", error);
335 public static String getVpnNameFromId(DataBroker broker, long vpnId) {
336 InstanceIdentifier<VpnIds> id = getVpnIdToVpnInstanceIdentifier(vpnId);
337 return read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnIds::getVpnInstanceName).orNull();
340 static InstanceIdentifier<VpnIds> getVpnIdToVpnInstanceIdentifier(long vpnId) {
341 return InstanceIdentifier.builder(VpnIdToVpnInstance.class)
342 .child(VpnIds.class, new VpnIdsKey(vpnId)).build();
345 public static <T extends DataObject> void syncUpdate(DataBroker broker, LogicalDatastoreType datastoreType,
346 InstanceIdentifier<T> path, T data) {
347 WriteTransaction tx = broker.newWriteOnlyTransaction();
348 tx.put(datastoreType, path, data, true);
349 CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
352 } catch (InterruptedException | ExecutionException e) {
353 LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data, e);
354 throw new RuntimeException(e.getMessage());
358 // TODO Clean up the exception handling
359 @SuppressWarnings("checkstyle:IllegalCatch")
360 public static void addOrUpdateFibEntry(DataBroker broker, String rd, String macAddress, String prefix,
361 List<String> nextHopList, VrfEntry.EncapType encapType, long label,
362 long l3vni, String gwMacAddress, RouteOrigin origin,
363 WriteTransaction writeConfigTxn) {
364 if (rd == null || rd.isEmpty()) {
365 LOG.error("Prefix {} not associated with vpn", prefix);
369 Preconditions.checkNotNull(nextHopList, "NextHopList can't be null");
372 InstanceIdentifier<VrfEntry> vrfEntryId =
373 InstanceIdentifier.builder(FibEntries.class)
374 .child(VrfTables.class, new VrfTablesKey(rd))
375 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
377 writeFibEntryToDs(vrfEntryId, prefix, nextHopList, label, l3vni, encapType, origin, macAddress,
378 gwMacAddress, writeConfigTxn, broker);
379 LOG.debug("Created/Updated vrfEntry for {} nexthop {} label {}", prefix, nextHopList, label);
380 } catch (Exception e) {
381 LOG.error("addFibEntryToDS: error ", e);
385 // TODO Clean up the exception handling
386 @SuppressWarnings("checkstyle:IllegalCatch")
387 public static void writeFibEntryToDs(InstanceIdentifier<VrfEntry> vrfEntryId, String prefix,
388 List<String> nextHopList, long label, Long l3vni,
389 VrfEntry.EncapType encapType, RouteOrigin origin, String macAddress,
390 String gatewayMacAddress, WriteTransaction writeConfigTxn,
392 VrfEntryBuilder vrfEntryBuilder = new VrfEntryBuilder().setDestPrefix(prefix).setOrigin(origin.getValue());
393 buildVpnEncapSpecificInfo(vrfEntryBuilder, encapType, label, l3vni, macAddress, gatewayMacAddress, nextHopList);
394 if (writeConfigTxn != null) {
395 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build(), true);
397 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build());
401 @SuppressWarnings("checkstyle:IllegalCatch")
402 public static void addFibEntryForRouterInterface(DataBroker broker,
405 RouterInterface routerInterface,
407 WriteTransaction writeConfigTxn) {
408 if (rd == null || rd.isEmpty()) {
409 LOG.error("Prefix {} not associated with vpn", prefix);
414 InstanceIdentifier<VrfEntry> vrfEntryId =
415 InstanceIdentifier.builder(FibEntries.class)
416 .child(VrfTables.class, new VrfTablesKey(rd))
417 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
419 // Filling the nextHop with dummy nextHopAddress
420 VrfEntry vrfEntry = FibHelper.getVrfEntryBuilder(prefix, label,
421 FibConstants.DEFAULT_NEXTHOP_IP, RouteOrigin.LOCAL)
422 .addAugmentation(RouterInterface.class, routerInterface).build();
424 if (writeConfigTxn != null) {
425 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
427 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
429 LOG.debug("Created vrfEntry for router-interface-prefix {} rd {} label {}", prefix, rd, label);
430 } catch (Exception e) {
431 LOG.error("addFibEntryToDS: error ", e);
435 private static void buildVpnEncapSpecificInfo(VrfEntryBuilder builder, VrfEntry.EncapType encapType, long label,
436 long l3vni, String macAddress, String gatewayMac, List<String> nextHopList) {
437 if (!encapType.equals(VrfEntry.EncapType.Mplsgre)) {
438 builder.setL3vni(l3vni);
440 builder.setEncapType(encapType);
441 builder.setGatewayMacAddress(gatewayMac);
442 Long lbl = encapType.equals(VrfEntry.EncapType.Mplsgre) ? label : null;
443 List<RoutePaths> routePaths = nextHopList.stream()
444 .filter(nextHop -> nextHop != null && !nextHop.isEmpty())
446 return FibHelper.buildRoutePath(nextHop, lbl);
447 }).collect(Collectors.toList());
448 builder.setRoutePaths(routePaths);
451 public static void removeFibEntry(DataBroker broker, String rd, String prefix, WriteTransaction writeConfigTxn) {
453 if (rd == null || rd.isEmpty()) {
454 LOG.error("Prefix {} not associated with vpn", prefix);
457 LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
459 InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
460 InstanceIdentifier.builder(FibEntries.class)
461 .child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix));
462 InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
463 if (writeConfigTxn != null) {
464 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
466 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
471 * Removes a specific Nexthop from a VrfEntry. If Nexthop to remove is the
472 * last one in the VrfEntry, then the VrfEntry is removed too.
474 * @param broker dataBroker service reference
475 * @param rd Route-Distinguisher to which the VrfEntry belongs to
476 * @param prefix Destination of the route
477 * @param nextHopToRemove Specific nexthop within the Route to be removed.
478 * If null or empty, then the whole VrfEntry is removed
480 public static void removeOrUpdateFibEntry(DataBroker broker, String rd, String prefix, String nextHopToRemove,
481 WriteTransaction writeConfigTxn) {
483 LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
485 // Looking for existing prefix in MDSAL database
486 InstanceIdentifier<VrfEntry> vrfEntryId =
487 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
488 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
489 Optional<VrfEntry> entry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
491 if (entry.isPresent()) {
492 final List<RoutePaths> routePaths = entry.get().getRoutePaths();
493 if (routePaths == null || routePaths.isEmpty()) {
494 LOG.warn("routePaths is null/empty for given rd {}, prefix {}", rd, prefix);
497 java.util.Optional<RoutePaths> optRoutePath =
499 .filter(routePath -> routePath.getNexthopAddress().equals(
500 nextHopToRemove)).findFirst();
501 if (!optRoutePath.isPresent()) {
502 LOG.error("Unable to find a routePath that contains the given nextHop to remove {}", nextHopToRemove);
505 RoutePaths routePath = optRoutePath.get();
506 if (routePaths.size() == 1) {
507 // Remove the whole entry
508 if (writeConfigTxn != null) {
509 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
511 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
513 LOG.info("Removed Fib Entry rd {} prefix {}", rd, prefix);
515 InstanceIdentifier<RoutePaths> routePathsId =
516 FibHelper.buildRoutePathId(rd, prefix, routePath.getNexthopAddress());
518 if (writeConfigTxn != null) {
519 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, routePathsId);
521 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routePathsId);
523 LOG.info("Removed Route Path rd {} prefix {}, nextHop {}, label {}", rd, prefix,
524 routePath.getNexthopAddress(), routePath.getLabel());
527 LOG.warn("Could not find VrfEntry for Route-Distinguisher={} and prefix={}", rd, prefix);
531 public static void updateFibEntry(DataBroker broker, String rd, String prefix, List<String> nextHopList,
532 String gwMacAddress, long label, WriteTransaction writeConfigTxn) {
534 LOG.debug("Updating fib entry for prefix {} with nextHopList {} for rd {}", prefix, nextHopList, rd);
536 // Looking for existing prefix in MDSAL database
537 InstanceIdentifier<VrfEntry> vrfEntryId =
538 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
539 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
540 Optional<VrfEntry> entry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
542 if (entry.isPresent()) {
543 RouteOrigin routeOrigin = RouteOrigin.value(entry.get().getOrigin());
544 // Update the VRF entry with nextHopList
545 VrfEntry vrfEntry = FibHelper.getVrfEntryBuilder(entry.get(), label, nextHopList, routeOrigin)
546 .setGatewayMacAddress(gwMacAddress).build();
548 if (nextHopList.isEmpty()) {
549 if (writeConfigTxn != null) {
550 writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
552 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
555 if (writeConfigTxn != null) {
556 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
558 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
561 LOG.debug("Updated fib entry for prefix {} with nextHopList {} for rd {}", prefix, nextHopList, rd);
563 LOG.warn("Could not find VrfEntry for Route-Distinguisher={} and prefix={}", rd, prefix);
567 public static void addVrfTable(DataBroker broker, String rd, WriteTransaction writeConfigTxn) {
568 LOG.debug("Adding vrf table for rd {}", rd);
569 InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
570 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
571 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
572 VrfTablesBuilder vrfTablesBuilder = new VrfTablesBuilder().setKey(new VrfTablesKey(rd))
573 .setRouteDistinguisher(rd).setVrfEntry(new ArrayList<>());
574 if (writeConfigTxn != null) {
575 writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTablesBuilder.build());
577 syncWrite(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTablesBuilder.build(),
578 FibUtil.DEFAULT_CALLBACK);
583 public static void removeVrfTable(DataBroker broker, String rd, WriteTransaction writeConfigTxn) {
584 LOG.debug("Removing vrf table for rd {}", rd);
585 InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
586 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
587 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
589 if (writeConfigTxn != null) {
590 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfTableId);
592 delete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId);
596 public static boolean isControllerManagedRoute(RouteOrigin routeOrigin) {
597 return routeOrigin == RouteOrigin.STATIC
598 || routeOrigin == RouteOrigin.CONNECTED
599 || routeOrigin == RouteOrigin.LOCAL
600 || routeOrigin == RouteOrigin.INTERVPN;
603 public static boolean isControllerManagedNonInterVpnLinkRoute(RouteOrigin routeOrigin) {
604 return routeOrigin == RouteOrigin.STATIC
605 || routeOrigin == RouteOrigin.CONNECTED
606 || routeOrigin == RouteOrigin.LOCAL;
609 public static List<String> getNextHopListFromRoutePaths(final VrfEntry vrfEntry) {
610 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
611 if (routePaths == null || routePaths.isEmpty()) {
612 return Collections.EMPTY_LIST;
614 return routePaths.stream()
615 .map(routePath -> routePath.getNexthopAddress())
616 .collect(Collectors.toList());
619 public static java.util.Optional<Long> getLabelFromRoutePaths(final VrfEntry vrfEntry) {
620 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
621 if (routePaths == null || routePaths.isEmpty()) {
622 return java.util.Optional.empty();
624 return java.util.Optional.of(vrfEntry.getRoutePaths().get(0).getLabel());
627 public static java.util.Optional<String> getFirstNextHopAddress(final VrfEntry vrfEntry) {
628 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
629 if (routePaths == null || routePaths.isEmpty()) {
630 return java.util.Optional.empty();
632 return java.util.Optional.of(vrfEntry.getRoutePaths().get(0).getNexthopAddress());