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 static java.util.stream.Collectors.joining;
12 import static java.util.stream.Collectors.toList;
13 import static org.opendaylight.netvirt.fibmanager.VrfEntryListener.isOpenStackVniSemanticsEnforced;
15 import com.google.common.base.Optional;
16 import com.google.common.base.Preconditions;
17 import com.google.common.net.InetAddresses;
19 import java.math.BigInteger;
20 import java.net.InetAddress;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.concurrent.ExecutionException;
25 import java.util.concurrent.Future;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.genius.mdsalutil.BucketInfo;
31 import org.opendaylight.genius.mdsalutil.MDSALUtil;
32 import org.opendaylight.genius.mdsalutil.NwConstants;
33 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
34 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
35 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
36 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
37 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfoKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.DpidL3vpnLbNexthops;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.L3vpnLbNexthops;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpid.l3vpn.lb.nexthops.DpnLbNexthops;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpid.l3vpn.lb.nexthops.DpnLbNexthopsBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpid.l3vpn.lb.nexthops.DpnLbNexthopsKey;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.Nexthops;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.NexthopsBuilder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.NexthopsKey;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIdsKey;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
97 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
98 import org.opendaylight.yangtools.yang.common.RpcResult;
99 import org.slf4j.Logger;
100 import org.slf4j.LoggerFactory;
102 public final class FibUtil {
103 private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class);
104 private static final String FLOWID_PREFIX = "L3.";
109 static InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
110 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang
111 .l3vpn.rev140815.VpnInterfaces.class)
112 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
114 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
115 .VpnInterfaceKey(vpnInterfaceName))
116 .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
117 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.class,
118 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list
119 .AdjacencyKey(ipAddress)).build();
122 static InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
123 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
124 .rev140815.VpnInterfaces.class)
125 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
127 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
128 .VpnInterfaceKey(vpnInterfaceName))
129 .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
133 static InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(long vpnId, String ipPrefix) {
134 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
135 .rev130911.PrefixToInterface.class)
136 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
138 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
140 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
141 .vpn.ids.Prefixes.class,
142 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to
143 ._interface.vpn.ids.PrefixesKey(ipPrefix)).build();
146 static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
147 return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
148 .rev140815.VpnInterfaces.class)
149 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
151 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
152 .VpnInterfaceKey(vpnInterfaceName)).build();
155 static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
156 return InstanceIdentifier.builder(VpnInstanceOpData.class)
157 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
160 static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(DataBroker broker, String rd) {
161 InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
162 return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
165 static VpnInstanceOpDataEntry getVpnInstance(DataBroker dataBroker, String rd) {
166 InstanceIdentifier<VpnInstanceOpDataEntry> id =
167 InstanceIdentifier.create(VpnInstanceOpData.class)
168 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
169 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
170 MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
171 return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
174 static String getNextHopLabelKey(String rd, String prefix) {
175 return rd + FibConstants.SEPARATOR + prefix;
178 static Prefixes getPrefixToInterface(DataBroker broker, Long vpnId, String ipPrefix) {
179 Optional<Prefixes> localNextHopInfoData = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
180 getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
181 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
184 static String getMacAddressFromPrefix(DataBroker broker, String ifName, String ipPrefix) {
185 Optional<Adjacency> adjacencyData = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
186 getAdjacencyIdentifier(ifName, ipPrefix));
187 return adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
190 static void releaseId(IdManagerService idManager, String poolName, String idKey) {
191 ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
193 Future<RpcResult<Void>> result = idManager.releaseId(idInput);
194 RpcResult<Void> rpcResult = result.get();
195 if (!rpcResult.isSuccessful()) {
196 LOG.error("RPC Call to Get Unique Id for key {} returned with Errors {}", idKey, rpcResult.getErrors());
198 } catch (InterruptedException | ExecutionException e) {
199 LOG.warn("Exception when getting Unique Id for key {}", idKey, e);
203 static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
204 .instance.to.vpn.id.VpnInstance> getVpnInstanceToVpnIdIdentifier(String vpnName) {
205 return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
206 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
208 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
209 .VpnInstanceKey(vpnName)).build();
212 public static long getVpnId(DataBroker broker, String vpnName) {
214 InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
215 return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(
216 VpnInstance::getVpnId).orElse(-1L);
220 * Retrieves the VpnInstance name (typically the VPN Uuid) out from the route-distinguisher.
222 * @param broker The DataBroker
223 * @param rd The route-distinguisher
224 * @return The vpn instance
226 public static Optional<String> getVpnNameFromRd(DataBroker broker, String rd) {
227 return Optional.fromJavaUtil(
228 getVpnInstanceOpData(broker, rd).toJavaUtil().map(VpnInstanceOpDataEntry::getVpnInstanceName));
231 public static String getVpnNameFromId(DataBroker broker, long vpnId) {
232 InstanceIdentifier<VpnIds> id = getVpnIdToVpnInstanceIdentifier(vpnId);
233 return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(
234 VpnIds::getVpnInstanceName).orElse(null);
237 static InstanceIdentifier<VpnIds> getVpnIdToVpnInstanceIdentifier(long vpnId) {
238 return InstanceIdentifier.builder(VpnIdToVpnInstance.class)
239 .child(VpnIds.class, new VpnIdsKey(vpnId)).build();
242 // TODO Clean up the exception handling
243 @SuppressWarnings("checkstyle:IllegalCatch")
244 public static void addOrUpdateFibEntry(DataBroker broker, String rd, String macAddress, String prefix,
245 List<String> nextHopList, VrfEntry.EncapType encapType, long label,
246 long l3vni, String gwMacAddress, String parentVpnRd, RouteOrigin origin,
247 WriteTransaction writeConfigTxn) {
248 if (rd == null || rd.isEmpty()) {
249 LOG.error("Prefix {} not associated with vpn", prefix);
253 Preconditions.checkNotNull(nextHopList, "NextHopList can't be null");
256 InstanceIdentifier<VrfEntry> vrfEntryId =
257 InstanceIdentifier.builder(FibEntries.class)
258 .child(VrfTables.class, new VrfTablesKey(rd))
259 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
261 writeFibEntryToDs(vrfEntryId, prefix, nextHopList, label, l3vni, encapType, origin, macAddress,
262 gwMacAddress, parentVpnRd, writeConfigTxn, broker);
263 LOG.debug("Created/Updated vrfEntry for {} nexthop {} label {}", prefix, nextHopList, label);
264 } catch (Exception e) {
265 LOG.error("addOrUpdateFibEntry: Prefix {} rd {} label {} error ", prefix, rd, label, e);
269 // TODO Clean up the exception handling
270 @SuppressWarnings("checkstyle:IllegalCatch")
271 public static void writeFibEntryToDs(InstanceIdentifier<VrfEntry> vrfEntryId, String prefix,
272 List<String> nextHopList, long label, Long l3vni,
273 VrfEntry.EncapType encapType, RouteOrigin origin, String macAddress,
274 String gatewayMacAddress, String parentVpnRd,
275 WriteTransaction writeConfigTxn, DataBroker broker) {
276 VrfEntryBuilder vrfEntryBuilder = new VrfEntryBuilder().setDestPrefix(prefix).setOrigin(origin.getValue());
277 if (parentVpnRd != null) {
278 vrfEntryBuilder.setParentVpnRd(parentVpnRd);
280 buildVpnEncapSpecificInfo(vrfEntryBuilder, encapType, label, l3vni, macAddress, gatewayMacAddress, nextHopList);
281 if (writeConfigTxn != null) {
282 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build(), true);
284 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build());
288 @SuppressWarnings("checkstyle:IllegalCatch")
289 public static void addFibEntryForRouterInterface(DataBroker broker,
292 RouterInterface routerInterface,
294 WriteTransaction writeConfigTxn) {
295 if (rd == null || rd.isEmpty()) {
296 LOG.error("Prefix {} not associated with vpn", prefix);
301 InstanceIdentifier<VrfEntry> vrfEntryId =
302 InstanceIdentifier.builder(FibEntries.class)
303 .child(VrfTables.class, new VrfTablesKey(rd))
304 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
306 // Filling the nextHop with dummy nextHopAddress
307 VrfEntry vrfEntry = FibHelper.getVrfEntryBuilder(prefix, label,
308 FibConstants.DEFAULT_NEXTHOP_IP, RouteOrigin.LOCAL, null /* parentVpnRd */)
309 .addAugmentation(RouterInterface.class, routerInterface).build();
311 if (writeConfigTxn != null) {
312 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
314 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
316 LOG.debug("Created vrfEntry for router-interface-prefix {} rd {} label {}", prefix, rd, label);
317 } catch (Exception e) {
318 LOG.error("addFibEntryForRouterInterface: prefix {} rd {} label {} error ", prefix, rd, label, e);
322 private static void buildVpnEncapSpecificInfo(VrfEntryBuilder builder, VrfEntry.EncapType encapType, long label,
323 long l3vni, String macAddress, String gatewayMac, List<String> nextHopList) {
324 if (encapType == null) {
325 builder.setMac(macAddress);
329 // TODO - validate this check
331 builder.setL3vni(l3vni);
333 builder.setEncapType(encapType);
334 builder.setGatewayMacAddress(gatewayMac);
335 builder.setMac(macAddress);
336 Long lbl = encapType.equals(VrfEntry.EncapType.Mplsgre) ? label : null;
337 List<RoutePaths> routePaths = nextHopList.stream()
338 .filter(nextHop -> nextHop != null && !nextHop.isEmpty())
339 .map(nextHop -> FibHelper.buildRoutePath(nextHop, lbl)).collect(toList());
340 builder.setRoutePaths(routePaths);
343 public static void removeFibEntry(DataBroker broker, String rd, String prefix, WriteTransaction writeConfigTxn) {
345 if (rd == null || rd.isEmpty()) {
346 LOG.error("Prefix {} not associated with vpn", prefix);
349 LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
351 InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
352 InstanceIdentifier.builder(FibEntries.class)
353 .child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix));
354 InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
355 if (writeConfigTxn != null) {
356 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
358 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
363 * Removes a specific Nexthop from a VrfEntry. If Nexthop to remove is the
364 * last one in the VrfEntry, then the VrfEntry is removed too.
366 * @param broker dataBroker service reference
367 * @param rd Route-Distinguisher to which the VrfEntry belongs to
368 * @param prefix Destination of the route
369 * @param nextHopToRemove Specific nexthop within the Route to be removed.
370 * If null or empty, then the whole VrfEntry is removed
372 public static void removeOrUpdateFibEntry(DataBroker broker, String rd, String prefix, String nextHopToRemove,
373 WriteTransaction writeConfigTxn) {
375 LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
377 // Looking for existing prefix in MDSAL database
378 InstanceIdentifier<VrfEntry> vrfEntryId =
379 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
380 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
381 Optional<VrfEntry> entry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
382 if (entry.isPresent()) {
383 final List<RoutePaths> routePaths = entry.get().getRoutePaths();
384 if (routePaths == null || routePaths.isEmpty()) {
385 LOG.warn("routePaths is null/empty for given rd {}, prefix {}", rd, prefix);
388 java.util.Optional<RoutePaths> optRoutePath =
390 .filter(routePath -> routePath.getNexthopAddress().equals(
391 nextHopToRemove)).findFirst();
392 if (!optRoutePath.isPresent()) {
393 LOG.error("Unable to find a routePath that contains the given nextHop to remove {}", nextHopToRemove);
396 RoutePaths routePath = optRoutePath.get();
397 if (routePaths.size() == 1) {
398 // Remove the whole entry
399 if (writeConfigTxn != null) {
400 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
402 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
404 LOG.info("Removed Fib Entry rd {} prefix {}", rd, prefix);
406 InstanceIdentifier<RoutePaths> routePathsId =
407 FibHelper.buildRoutePathId(rd, prefix, routePath.getNexthopAddress());
409 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routePathsId);
411 LOG.info("Removed Route Path rd {} prefix {}, nextHop {}, label {}", rd, prefix,
412 routePath.getNexthopAddress(), routePath.getLabel());
415 LOG.warn("Could not find VrfEntry for Route-Distinguisher={} and prefix={}", rd, prefix);
420 * Adds or removes nextHop from routePath based on the flag nextHopAdd.
422 public static void updateRoutePathForFibEntry(DataBroker broker, String rd, String prefix, String nextHop,
423 long label, boolean nextHopAdd, WriteTransaction writeConfigTxn) {
425 LOG.debug("Updating fib entry for prefix {} with nextHop {} for rd {}.", prefix, nextHop, rd);
427 InstanceIdentifier<RoutePaths> routePathId = FibHelper.buildRoutePathId(rd, prefix, nextHop);
428 String routePathKey = rd + prefix + nextHop;
429 synchronized (routePathKey.intern()) {
431 RoutePaths routePaths = FibHelper.buildRoutePath(nextHop, label);
432 if (writeConfigTxn != null) {
433 writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, routePathId, routePaths,
434 WriteTransaction.CREATE_MISSING_PARENTS);
436 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routePathId, routePaths);
438 LOG.debug("Added routepath with nextHop {} for prefix {} and label {}.", nextHop, prefix, label);
440 Optional<RoutePaths> routePath = MDSALUtil.read(broker,
441 LogicalDatastoreType.CONFIGURATION, routePathId);
442 if (!routePath.isPresent()) {
443 LOG.warn("Couldn't find RoutePath with rd {}, prefix {} and nh {} for deleting",
444 rd, prefix, nextHop);
447 if (writeConfigTxn != null) {
448 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, routePathId);
450 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routePathId);
452 LOG.info("Removed routepath with nextHop {} for prefix {} and rd {}.", nextHop, prefix, rd);
457 public static void removeVrfTable(DataBroker broker, String rd, WriteTransaction writeConfigTxn) {
458 LOG.debug("Removing vrf table for rd {}", rd);
459 InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
460 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
461 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
463 if (writeConfigTxn != null) {
464 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfTableId);
466 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId);
470 public static java.util.Optional<Long> getLabelFromRoutePaths(final VrfEntry vrfEntry) {
471 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
472 if (routePaths == null || routePaths.isEmpty() || vrfEntry.getRoutePaths().get(0).getLabel() == null) {
473 return java.util.Optional.empty();
475 return java.util.Optional.of(vrfEntry.getRoutePaths().get(0).getLabel());
478 public static java.util.Optional<String> getFirstNextHopAddress(final VrfEntry vrfEntry) {
479 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
480 if (routePaths == null || routePaths.isEmpty()) {
481 return java.util.Optional.empty();
483 return java.util.Optional.of(vrfEntry.getRoutePaths().get(0).getNexthopAddress());
486 public static java.util.Optional<Long> getLabelForNextHop(final VrfEntry vrfEntry, String nextHopIp) {
487 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
488 if (routePaths == null || routePaths.isEmpty()) {
489 return java.util.Optional.empty();
491 return routePaths.stream()
492 .filter(routePath -> routePath.getNexthopAddress().equals(nextHopIp))
494 .map(RoutePaths::getLabel);
497 public static InstanceIdentifier<Interface> buildStateInterfaceId(String interfaceName) {
498 InstanceIdentifier.InstanceIdentifierBuilder<Interface> idBuilder =
499 InstanceIdentifier.builder(InterfacesState.class)
500 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
501 .interfaces.state.Interface.class, new org.opendaylight.yang.gen.v1.urn.ietf
502 .params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
503 .InterfaceKey(interfaceName));
504 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
505 .interfaces.state.Interface> id = idBuilder.build();
509 public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
510 .state.Interface getInterfaceStateFromOperDS(DataBroker dataBroker, String interfaceName) {
511 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
512 .interfaces.state.Interface> ifStateId = buildStateInterfaceId(interfaceName);
513 Optional<Interface> ifStateOptional = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
514 if (ifStateOptional.isPresent()) {
515 return ifStateOptional.get();
521 public static String getCreateLocalNextHopJobKey(Long vpnId, BigInteger dpnId, String prefix) {
522 return "FIB-" + vpnId.toString() + "-" + dpnId.toString() + "-" + prefix;
525 public static String getJobKeyForRdPrefix(String rd, String prefix) {
526 return "FIB-" + rd + "-" + prefix;
529 public static String getJobKeyForVpnIdDpnId(Long vpnId, BigInteger dpnId) {
530 return "FIB-" + vpnId.toString() + "-" + dpnId.toString() ;
533 public static void updateUsedRdAndVpnToExtraRoute(WriteTransaction writeOperTxn, DataBroker broker,
534 String tunnelIpRemoved, String primaryRd, String prefix) {
535 Optional<VpnInstanceOpDataEntry> optVpnInstance = getVpnInstanceOpData(broker, primaryRd);
536 if (!optVpnInstance.isPresent()) {
539 VpnInstanceOpDataEntry vpnInstance = optVpnInstance.get();
540 String vpnName = vpnInstance.getVpnInstanceName();
541 long vpnId = vpnInstance.getVpnId();
542 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(broker, vpnId, prefix);
543 // To identify the rd to be removed, iterate through the allocated rds for the prefix and check
544 // which rd is allocated for the particular OVS.
545 for (String usedRd : usedRds) {
546 Optional<Routes> vpnExtraRoutes = VpnExtraRouteHelper
547 .getVpnExtraroutes(broker, vpnName, usedRd, prefix);
548 if (vpnExtraRoutes.isPresent()) {
549 // Since all the nexthops under one OVS will be present under one rd, only 1 nexthop is read
550 // to identify the OVS
551 String nextHopRemoved = vpnExtraRoutes.get().getNexthopIpList().get(0);
552 Prefixes prefixToInterface = getPrefixToInterface(broker, vpnId, getIpPrefix(nextHopRemoved));
553 if (prefixToInterface != null && tunnelIpRemoved
554 .equals(getEndpointIpAddressForDPN(broker, prefixToInterface.getDpnId()))) {
555 InstanceIdentifier<Adjacency> adjId = getAdjacencyIdentifier(
556 prefixToInterface.getVpnInterfaceName(), prefix);
557 Interface ifState = FibUtil.getInterfaceStateFromOperDS(
558 broker, prefixToInterface.getVpnInterfaceName());
559 //Delete datastore only if extra route is deleted or VM interface is deleted/down
560 if (!MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, adjId).isPresent()
561 || ifState == null || ifState.getOperStatus() == OperStatus.Down) {
562 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
563 getAdjacencyIdentifier(prefixToInterface.getVpnInterfaceName(), prefix));
564 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
565 VpnExtraRouteHelper.getVpnToExtrarouteVrfIdIdentifier(vpnName, usedRd, prefix));
566 writeOperTxn.delete(LogicalDatastoreType.CONFIGURATION,
567 VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, prefix, nextHopRemoved));
575 private static String getEndpointIpAddressForDPN(DataBroker broker, BigInteger dpnId) {
576 //TODO: Move it to a common place for vpn and fib
577 String nextHopIp = null;
578 InstanceIdentifier<DPNTEPsInfo> tunnelInfoId =
579 InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, new DPNTEPsInfoKey(dpnId)).build();
580 Optional<DPNTEPsInfo> tunnelInfo = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, tunnelInfoId);
581 if (tunnelInfo.isPresent()) {
582 List<TunnelEndPoints> nexthopIpList = tunnelInfo.get().getTunnelEndPoints();
583 if (nexthopIpList != null && !nexthopIpList.isEmpty()) {
584 nextHopIp = String.valueOf(nexthopIpList.get(0).getIpAddress().getValue());
590 public static String getIpPrefix(String prefix) {
591 String[] prefixValues = prefix.split(FibConstants.PREFIX_SEPARATOR);
592 if (prefixValues.length == 1) {
593 prefix = prefix + NwConstants.IPV4PREFIX;
598 public static boolean isTunnelInterface(AdjacencyResult adjacencyResult) {
599 return Tunnel.class.equals(adjacencyResult.getInterfaceType());
602 public static InstanceIdentifier<VrfEntry> getNextHopIdentifier(String rd, String prefix) {
603 return InstanceIdentifier.builder(FibEntries.class)
604 .child(VrfTables.class,new VrfTablesKey(rd)).child(VrfEntry.class,new VrfEntryKey(prefix)).build();
607 public static List<String> getNextHopAddresses(DataBroker broker, String rd, String prefix) {
608 InstanceIdentifier<VrfEntry> vrfEntryId = getNextHopIdentifier(rd, prefix);
609 Optional<VrfEntry> vrfEntry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
610 if (vrfEntry.isPresent()) {
611 return FibHelper.getNextHopListFromRoutePaths(vrfEntry.get());
613 return Collections.emptyList();
617 public static Subnetmap getSubnetMap(DataBroker broker, Uuid subnetId) {
618 InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier.builder(Subnetmaps.class)
619 .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
620 return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subnetmapId).orNull();
623 public static String getGreLbGroupKey(List<String> availableDcGws) {
624 Preconditions.checkNotNull(availableDcGws, "AvailableDcGws is null");
625 return "gre-" + availableDcGws.stream().sorted().collect(joining(":"));
628 public static void updateLbGroupInfo(BigInteger dpnId, String destinationIp, String groupIdKey,
629 String groupId, WriteTransaction tx) {
630 InstanceIdentifier<DpnLbNexthops> id = getDpnLbNexthopsIdentifier(dpnId, destinationIp);
631 DpnLbNexthops dpnToLbNextHop = buildDpnLbNextHops(dpnId, destinationIp, groupIdKey);
632 tx.merge(LogicalDatastoreType.OPERATIONAL, id, dpnToLbNextHop);
633 InstanceIdentifier<Nexthops> nextHopsId = getNextHopsIdentifier(groupIdKey);
634 Nexthops nextHopsToGroupId = buildNextHops(dpnId, groupIdKey, groupId);
635 tx.merge(LogicalDatastoreType.OPERATIONAL, nextHopsId, nextHopsToGroupId);
638 public static void removeDpnIdToNextHopInfo(String destinationIp, BigInteger dpnId, WriteTransaction tx) {
639 InstanceIdentifier<DpnLbNexthops> id = getDpnLbNexthopsIdentifier(dpnId, destinationIp);
640 tx.delete(LogicalDatastoreType.OPERATIONAL, id);
643 public static void removeOrUpdateNextHopInfo(BigInteger dpnId, String nextHopKey, String groupId,
644 Nexthops nexthops, WriteTransaction tx) {
645 InstanceIdentifier<Nexthops> nextHopsId = getNextHopsIdentifier(nextHopKey);
646 List<String> targetDeviceIds = nexthops.getTargetDeviceId();
647 targetDeviceIds.remove(dpnId.toString());
648 if (targetDeviceIds.isEmpty()) {
649 tx.delete(LogicalDatastoreType.OPERATIONAL, nextHopsId);
651 Nexthops nextHopsToGroupId = new NexthopsBuilder().setKey(new NexthopsKey(nextHopKey))
652 .setNexthopKey(nextHopKey)
654 .setTargetDeviceId(targetDeviceIds).build();
655 tx.put(LogicalDatastoreType.OPERATIONAL, nextHopsId, nextHopsToGroupId);
659 private static InstanceIdentifier<DpnLbNexthops> getDpnLbNexthopsIdentifier(BigInteger dpnId,
660 String destinationIp) {
661 return InstanceIdentifier.builder(DpidL3vpnLbNexthops.class)
662 .child(DpnLbNexthops.class, new DpnLbNexthopsKey(destinationIp, dpnId))
666 private static InstanceIdentifier<Nexthops> getNextHopsIdentifier(String groupIdKey) {
667 return InstanceIdentifier.builder(L3vpnLbNexthops.class)
668 .child(Nexthops.class, new NexthopsKey(groupIdKey)).build();
671 private static Nexthops buildNextHops(BigInteger dpnId, String groupIdKey, String groupId) {
672 return new NexthopsBuilder().setKey(new NexthopsKey(groupIdKey))
673 .setNexthopKey(groupIdKey)
675 .setTargetDeviceId(Collections.singletonList(dpnId.toString())).build();
678 private static DpnLbNexthops buildDpnLbNextHops(BigInteger dpnId, String destinationIp,
680 return new DpnLbNexthopsBuilder().setKey(new DpnLbNexthopsKey(destinationIp, dpnId))
681 .setDstDeviceId(destinationIp).setSrcDpId(dpnId)
682 .setNexthopKey(Collections.singletonList(groupIdKey)).build();
685 public static Optional<Nexthops> getNexthops(DataBroker dataBroker, String nextHopKey) {
686 InstanceIdentifier<Nexthops> nextHopsId = InstanceIdentifier.builder(L3vpnLbNexthops.class)
687 .child(Nexthops.class, new NexthopsKey(nextHopKey)).build();
688 return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, nextHopsId);
691 public static Optional<DpnLbNexthops> getDpnLbNexthops(DataBroker dataBroker, BigInteger dpnId,
692 String destinationIp) {
693 InstanceIdentifier<DpnLbNexthops> id = InstanceIdentifier.builder(DpidL3vpnLbNexthops.class)
694 .child(DpnLbNexthops.class, new DpnLbNexthopsKey(destinationIp, dpnId))
696 return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
699 protected static boolean isVxlanNetworkAndInternalRouterVpn(DataBroker dataBroker, Uuid subnetId, String
700 vpnInstanceName, String rd) {
701 if (rd.equals(vpnInstanceName)) {
702 Subnetmap subnetmap = getSubnetMap(dataBroker, subnetId);
703 if (subnetmap != null) {
704 return subnetmap.getNetworkType() == NetworkAttributes.NetworkType.VXLAN;
710 protected static java.util.Optional<Long> getVniForVxlanNetwork(DataBroker dataBroker, Uuid subnetId) {
711 Subnetmap subnetmap = getSubnetMap(dataBroker, subnetId);
712 if (subnetmap != null && subnetmap.getNetworkType() == NetworkAttributes.NetworkType.VXLAN) {
713 return java.util.Optional.of(subnetmap.getSegmentationId());
715 return java.util.Optional.empty();
718 protected static boolean enforceVxlanDatapathSemanticsforInternalRouterVpn(DataBroker dataBroker, Uuid subnetId,
719 long vpnId, String rd) {
720 return isOpenStackVniSemanticsEnforced
721 && isVxlanNetworkAndInternalRouterVpn(dataBroker, subnetId, getVpnNameFromId(dataBroker, vpnId), rd);
724 protected static boolean enforceVxlanDatapathSemanticsforInternalRouterVpn(DataBroker dataBroker, Uuid subnetId,
725 String vpnName, String rd) {
726 return isOpenStackVniSemanticsEnforced
727 && isVxlanNetworkAndInternalRouterVpn(dataBroker, subnetId, vpnName, rd);
730 static NodeRef buildNodeRef(BigInteger dpId) {
731 return new NodeRef(InstanceIdentifier.builder(Nodes.class)
732 .child(Node.class, new NodeKey(new NodeId("openflow:" + dpId))).build());
735 static InstanceIdentifier<Group> buildGroupInstanceIdentifier(long groupId, BigInteger dpId) {
736 return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(new NodeId("openflow:" + dpId)))
737 .augmentation(FlowCapableNode.class).child(Group.class, new GroupKey(new GroupId(groupId))).build();
740 static Buckets buildBuckets(List<BucketInfo> listBucketInfo) {
742 BucketsBuilder bucketsBuilder = new BucketsBuilder();
743 if (listBucketInfo != null) {
744 List<Bucket> bucketList = new ArrayList<>();
746 for (BucketInfo bucketInfo : listBucketInfo) {
747 BucketBuilder bucketBuilder = new BucketBuilder();
748 bucketBuilder.setAction(bucketInfo.buildActions());
749 bucketBuilder.setWeight(bucketInfo.getWeight());
750 bucketBuilder.setBucketId(new BucketId(index++));
751 bucketBuilder.setWeight(bucketInfo.getWeight()).setWatchPort(bucketInfo.getWatchPort())
752 .setWatchGroup(bucketInfo.getWatchGroup());
753 bucketList.add(bucketBuilder.build());
756 bucketsBuilder.setBucket(bucketList);
758 return bucketsBuilder.build();
761 static String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
762 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + label
763 + NwConstants.FLOWID_SEPARATOR + priority;
766 static String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
767 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + rd
768 + NwConstants.FLOWID_SEPARATOR + priority + NwConstants.FLOWID_SEPARATOR + destPrefix.getHostAddress();
771 static String getL3VpnGatewayFlowRef(short l3GwMacTable, BigInteger dpId, long vpnId, String gwMacAddress) {
772 return gwMacAddress + NwConstants.FLOWID_SEPARATOR + vpnId + NwConstants.FLOWID_SEPARATOR + dpId
773 + NwConstants.FLOWID_SEPARATOR + l3GwMacTable;
776 static Node buildDpnNode(BigInteger dpnId) {
777 return new NodeBuilder().setId(new NodeId("openflow:" + dpnId))
778 .setKey(new NodeKey(new NodeId("openflow:" + dpnId))).build();
781 public static String getBroadcastAddressFromCidr(String cidr) {
782 String[] ipaddressValues = cidr.split("/");
783 int address = InetAddresses.coerceToInteger(InetAddresses.forString(ipaddressValues[0]));
784 int cidrPart = Integer.parseInt(ipaddressValues[1]);
786 for (int j = 0; j < cidrPart; ++j) {
787 netmask |= 1 << 31 - j;
789 int network = address & netmask;
790 int broadcast = network | ~netmask;
791 return InetAddresses.toAddrString(InetAddresses.fromInteger(broadcast));