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
8 package org.opendaylight.netvirt.cloudservicechain.utils;
10 import java.util.Optional;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.stream.Collectors;
16 import org.opendaylight.mdsal.binding.api.DataBroker;
17 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
18 import org.opendaylight.mdsal.common.api.ReadFailedException;
19 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
20 import org.opendaylight.genius.mdsalutil.ActionInfo;
21 import org.opendaylight.genius.mdsalutil.FlowEntity;
22 import org.opendaylight.genius.mdsalutil.InstructionInfo;
23 import org.opendaylight.genius.mdsalutil.MDSALUtil;
24 import org.opendaylight.genius.mdsalutil.MatchInfo;
25 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
26 import org.opendaylight.genius.mdsalutil.NWUtil;
27 import org.opendaylight.genius.mdsalutil.NwConstants;
28 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
29 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
30 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
31 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
32 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
33 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
34 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
35 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
36 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
37 import org.opendaylight.genius.utils.ServiceIndex;
38 import org.opendaylight.netvirt.cloudservicechain.CloudServiceChainConstants;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.cloud.servicechain.state.rev160711.VpnToPseudoPortList;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.cloud.servicechain.state.rev160711.vpn.to.pseudo.port.list.VpnToPseudoPortData;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.cloud.servicechain.state.rev160711.vpn.to.pseudo.port.list.VpnToPseudoPortDataKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
66 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
70 public final class VpnServiceChainUtils {
72 private static final Logger LOG = LoggerFactory.getLogger(VpnServiceChainUtils.class);
74 private VpnServiceChainUtils() { }
76 public static BigInteger getMetadataSCF(long scfTag) { // TODO: Move to a common place
77 return new BigInteger("FF", 16).and(BigInteger.valueOf(scfTag)).shiftLeft(32);
80 public static BigInteger getCookieL3(int vpnId) {
81 return CloudServiceChainConstants.COOKIE_L3_BASE.add(new BigInteger("0610000", 16))
82 .add(BigInteger.valueOf(vpnId));
86 public static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
87 return InstanceIdentifier.builder(VpnInstanceOpData.class)
88 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
91 public static InstanceIdentifier<BoundServices> buildBoundServicesIid(short servicePrio, String ifaceName) {
92 return InstanceIdentifier.builder(ServiceBindings.class)
93 .child(ServicesInfo.class, new ServicesInfoKey(ifaceName, ServiceModeIngress.class))
94 .child(BoundServices.class, new BoundServicesKey(servicePrio))
99 * Retrieves from MDSAL the Operational Data of the VPN specified by its
100 * Route-Distinguisher.
102 * @param rd Route-Distinguisher of the VPN
104 * @return the Operational Data of the VPN or absent if no VPN could be
105 * found for the given RD or if the VPN does not have operational
108 public static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(DataBroker broker, String rd) {
109 InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnServiceChainUtils.getVpnInstanceOpDataIdentifier(rd);
110 return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
113 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
114 return InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).build();
117 public static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
118 return InstanceIdentifier.builder(VpnInstanceOpData.class)
119 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd))
120 .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
123 public static InstanceIdentifier<VpnInstance> getVpnInstanceToVpnIdIdentifier(String vpnName) {
124 return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
125 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
128 public static InstanceIdentifier<VpnToPseudoPortData> getVpnToPseudoPortTagIid(String rd) {
129 VpnToPseudoPortDataKey key = new VpnToPseudoPortDataKey(rd);
130 return InstanceIdentifier.builder(VpnToPseudoPortList.class).child(VpnToPseudoPortData.class, key).build();
133 public static Optional<VpnToPseudoPortData> getVpnPseudoPortData(DataBroker broker, String rd)
134 throws ReadFailedException {
135 InstanceIdentifier<VpnToPseudoPortData> id = getVpnToPseudoPortTagIid(rd);
136 return SingleTransactionDataBroker.syncReadOptional(broker, LogicalDatastoreType.CONFIGURATION, id);
139 public static List<VpnToPseudoPortData> getAllVpnToPseudoPortData(DataBroker broker) throws ReadFailedException {
140 InstanceIdentifier<VpnToPseudoPortList> path = InstanceIdentifier.builder(VpnToPseudoPortList.class).build();
141 return SingleTransactionDataBroker.syncReadOptional(broker, LogicalDatastoreType.CONFIGURATION, path)
142 .toJavaUtil().map(VpnToPseudoPortList::getVpnToPseudoPortData).orElse(new ArrayList<>());
146 * Get fake VPNPseudoPort interface name.
149 * @param scfTag Service Function tag
150 * @param scsTag Service Chain tag
151 * @param lportTag Lport tag
152 * @return the fake VpnPseudoPort interface name
154 public static String buildVpnPseudoPortIfName(Long dpId, long scfTag, int scsTag, int lportTag) {
155 return new StringBuilder("VpnPseudo.").append(dpId).append(NwConstants.FLOWID_SEPARATOR)
156 .append(lportTag).append(NwConstants.FLOWID_SEPARATOR)
157 .append(scfTag).append(NwConstants.FLOWID_SEPARATOR)
158 .append(scsTag).toString();
162 * Retrieves the VpnId (datapath id) searching by VpnInstanceName.
164 * @param broker Reference to the MDSAL Databroker service
165 * @param vpnName The Vpn instance name
166 * @return the datapath identifier for the specified VPN
168 public static long getVpnId(DataBroker broker, String vpnName) {
170 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt
171 .l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id =
172 getVpnInstanceToVpnIdIdentifier(vpnName);
173 Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt
174 .l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance =
175 MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
177 return vpnInstance.isPresent() ? vpnInstance.get().getVpnId() : CloudServiceChainConstants.INVALID_VPN_TAG;
181 * Retrieves the VPN's Route Distinguisher out from the VpnName.
183 * @param broker Reference to the MDSAL Databroker service
184 * @param vpnName The Vpn Instance Name. Typically the UUID.
185 * @return the RouteDistinguiser for the specified VPN
187 public static String getVpnRd(DataBroker broker, String vpnName) {
188 InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
189 return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(
190 VpnInstance::getVrfId).orElse(null);
194 * Returns all the VrfEntries that belong to a given VPN.
196 * @param broker Reference to the MDSAL Databroker service
197 * @param rd Route-distinguisher of the VPN
198 * @return the list of the matching VrfEntries
200 public static List<VrfEntry> getAllVrfEntries(DataBroker broker, String rd) {
201 InstanceIdentifier<VrfTables> vpnVrfTables =
202 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).build();
203 return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnVrfTables).toJavaUtil().map(
204 VrfTables::getVrfEntry).orElse(new ArrayList<>());
208 * Installs/removes a flow in LPortDispatcher table that is in charge of
209 * handling packets that falls back from SCF Pipeline to L3Vpn.
211 * @param mdsalManager MDSAL Util API accessor
212 * @param vpnId Dataplane identifier of the VPN, the Vrf Tag.
213 * @param dpId The DPN where the flow must be installed/removed
214 * @param vpnPseudoLportTag Dataplane identifier for the VpnPseudoPort
215 * @param addOrRemove States if the flow must be created or removed
217 public static void programLPortDispatcherFlowForScfToVpn(IMdsalApiManager mdsalManager, long vpnId, BigInteger dpId,
218 Integer vpnPseudoLportTag, int addOrRemove) {
219 LOG.trace("programLPortDispatcherFlowForScfToVpn: vpnId={} dpId={}, vpnPseudoLportTag={} addOrRemove={}",
220 vpnId, dpId, vpnPseudoLportTag, addOrRemove);
221 Flow flow = buildLPortDispFromScfToL3VpnFlow(vpnId, dpId, vpnPseudoLportTag, addOrRemove);
222 if (addOrRemove == NwConstants.ADD_FLOW) {
223 mdsalManager.installFlow(dpId, flow);
225 mdsalManager.removeFlow(dpId, flow);
230 * Build the flow that must be inserted when there is a ScHop whose
231 * egressPort is a VPN Pseudo Port. In that case, packets must be moved
232 * from the SCF to VPN Pipeline.
234 * Flow matches: VpnPseudo port lPortTag + SI=L3VPN
235 * Actions: Write vrfTag in Metadata + goto FIB Table
237 * @param vpnId Dataplane identifier of the VPN, the Vrf Tag.
238 * @param dpId The DPN where the flow must be installed/removed
239 * @param lportTag Dataplane identifier for the VpnPseudoPort
240 * @param addOrRemove States if it must build a Flow to be created or
243 * @return the Flow object
245 public static Flow buildLPortDispFromScfToL3VpnFlow(Long vpnId, BigInteger dpId, Integer lportTag,
247 LOG.info("buildLPortDispFlowForScf vpnId={} dpId={} lportTag={} addOrRemove={} ",
248 vpnId, dpId, lportTag, addOrRemove);
249 List<MatchInfo> matches = buildMatchOnLportTagAndSI(lportTag,
250 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
251 NwConstants.L3VPN_SERVICE_INDEX));
252 List<Instruction> instructions = buildSetVrfTagAndGotoFibInstructions(vpnId.intValue());
254 String flowRef = getScfToL3VpnLportDispatcherFlowRef(lportTag);
257 if (addOrRemove == NwConstants.ADD_FLOW) {
258 result = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
259 CloudServiceChainConstants.DEFAULT_SCF_FLOW_PRIORITY, flowRef,
260 0, 0, VpnServiceChainUtils.getCookieL3(vpnId.intValue()),
261 matches, instructions);
264 result = new FlowBuilder().setTableId(NwConstants.LPORT_DISPATCHER_TABLE)
265 .setId(new FlowId(flowRef))
273 * Builds the Match for flows that must match on a given lportTag and
276 * @return the Match as a list.
278 public static List<MatchInfo> buildMatchOnLportTagAndSI(Integer lportTag, short serviceIndex) {
279 return Collections.singletonList(
280 new MatchMetadata(MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, serviceIndex),
281 MetaDataUtil.getMetaDataMaskForLPortDispatcher()));
285 * Builds a The Instructions that sets the VpnTag in metadata and sends to
288 * @param vpnTag Dataplane identifier of the VPN.
289 * @return the list of Instructions
291 public static List<Instruction> buildSetVrfTagAndGotoFibInstructions(Integer vpnTag) {
292 List<Instruction> result = new ArrayList<>();
293 int instructionKey = 0;
294 result.add(MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getVpnIdMetadata(vpnTag),
295 MetaDataUtil.METADATA_MASK_VRFID,
297 result.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_FIB_TABLE, ++instructionKey));
303 * Builds a Flow for the LFIB table that sets the LPortTag of the
304 * VpnPseudoPort and sends to LPortDispatcher table.
306 * <li>Matching: eth_type = MPLS, mpls_label = VPN MPLS label
307 * <li>Actions: setMetadata LportTag and SI=2, pop MPLS, Go to
308 * LPortDispacherTable
312 * @param label MPLS label
313 * @param nextHop Next Hop IP
314 * @param lportTag Pseudo Logical Port tag
315 * @return the FlowEntity
317 public static FlowEntity buildLFibVpnPseudoPortFlow(BigInteger dpId, Long label, int etherType, String nextHop,
320 List<MatchInfo> matches = new ArrayList<>();
321 matches.add(MatchEthernetType.MPLS_UNICAST);
322 matches.add(new MatchMplsLabel(label));
324 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionPopMpls(etherType));
325 List<InstructionInfo> instructions = new ArrayList<>();
326 instructions.add(new InstructionWriteMetadata(
327 MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
328 ServiceIndex.getIndex(NwConstants.SCF_SERVICE_NAME,
329 NwConstants.SCF_SERVICE_INDEX)),
330 MetaDataUtil.getMetaDataMaskForLPortDispatcher()
333 instructions.add(new InstructionApplyActions(actionsInfos));
334 instructions.add(new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE));
335 String flowRef = getLFibVpnPseudoPortFlowRef(lportTag, label, nextHop);
336 return MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
337 CloudServiceChainConstants.DEFAULT_SCF_FLOW_PRIORITY, flowRef, 0, 0,
338 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
343 * Modifies the LFIB table by adding/removing flows that redirects traffic
344 * from a VPN into the SCF via the VpnPseudoLport.
345 * Flows that match on the label and sets the VpnPseudoPort lportTag and
346 * sends to LPortDispatcher (via table 80)
349 public static void programLFibEntriesForSCF(IMdsalApiManager mdsalMgr, BigInteger dpId, List<VrfEntry> vrfEntries,
350 int lportTag, int addOrRemove) {
351 LOG.trace("programLFibEntriesForSCF: dpId={} lportTag={} addOrRemove={}", dpId, lportTag, addOrRemove);
352 if (vrfEntries != null) {
353 vrfEntries.forEach(vrfEntry -> vrfEntry.getRoutePaths()
354 .forEach(routePath -> {
355 Long label = routePath.getLabel();
356 String nextHop = routePath.getNexthopAddress();
358 int etherType = NWUtil.getEtherTypeFromIpPrefix(vrfEntry.getDestPrefix());
359 FlowEntity flowEntity = buildLFibVpnPseudoPortFlow(dpId, label, etherType, nextHop,
361 if (addOrRemove == NwConstants.ADD_FLOW) {
362 mdsalMgr.installFlow(flowEntity);
364 mdsalMgr.removeFlow(flowEntity);
367 "LFIBEntry for label={}, destination={}, nexthop={} {} successfully in dpn={}",
368 label, vrfEntry.getDestPrefix(), nextHop,
369 addOrRemove == NwConstants.DEL_FLOW ? "removed" : "installed", dpId);
370 } catch (IllegalArgumentException ex) {
371 LOG.warn("Unable to get etherType for IP Prefix {}", vrfEntry.getDestPrefix());
378 * Installs/removes a flow in LPortDispatcher table that is in charge
379 * of sending the traffic to the SCF Pipeline.
382 public static void programLPortDispatcherFlowForVpnToScf(IMdsalApiManager mdsalManager, BigInteger dpId,
383 int lportTag, long scfTag, short gotoTableId,
385 LOG.trace("programLPortDispatcherFlowForVpnToScf: dpId={} lportTag={} scfTag={} gotoTableId={} addOrRemove={}",
386 dpId, lportTag, scfTag, gotoTableId, addOrRemove);
387 FlowEntity flowEntity = VpnServiceChainUtils.buildLportFlowDispForVpnToScf(dpId, lportTag, scfTag, gotoTableId);
388 if (addOrRemove == NwConstants.ADD_FLOW) {
389 mdsalManager.installFlow(flowEntity);
391 mdsalManager.removeFlow(flowEntity);
396 * Creates the flow that sends the packet from the VPN to the SCF pipeline.
397 * This usually happens when there is an ScHop whose ingressPort is a
400 * <li>Matches: lportTag = vpnPseudoLPortTag, SI = 1
401 * <li>Actions: setMetadata(scfTag), Go to: UpSubFilter table
404 public static FlowEntity buildLportFlowDispForVpnToScf(BigInteger dpId, int lportTag, long scfTag,
406 List<InstructionInfo> instructions = new ArrayList<>();
407 List<ActionInfo> actionsInfos = new ArrayList<>();
408 actionsInfos.add(new ActionRegLoad(NxmNxReg2.class, 0, 31, scfTag));
409 instructions.add(new InstructionApplyActions(actionsInfos));
410 instructions.add(new InstructionGotoTable(gotoTableId));
411 String flowRef = getL3VpnToScfLportDispatcherFlowRef(lportTag);
413 List<MatchInfo> matches =
414 buildMatchOnLportTagAndSI(lportTag, ServiceIndex.getIndex(NwConstants.SCF_SERVICE_NAME,
415 NwConstants.SCF_SERVICE_INDEX));
416 return MDSALUtil.buildFlowEntity(dpId, NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
417 CloudServiceChainConstants.DEFAULT_SCF_FLOW_PRIORITY, flowRef, 0, 0,
418 getCookieSCHop(scfTag), matches, instructions);
422 public static Optional<Long> getVpnPseudoLportTag(DataBroker broker, String rd) {
423 InstanceIdentifier<VpnToPseudoPortData> path = getVpnToPseudoPortTagIid(rd);
424 return Optional.fromJavaUtil(MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path).toJavaUtil().map(
425 VpnToPseudoPortData::getVpnLportTag));
429 * Creates a Flow that does the trick of moving the packets from one VPN to
433 public static Flow buildLPortDispFlowForVpntoVpn(Integer dstLportTag, Integer vpnTag) {
434 List<MatchInfo> matches =
435 buildMatchOnLportTagAndSI(dstLportTag, ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
436 NwConstants.L3VPN_SERVICE_INDEX));
437 List<Instruction> instructions = buildSetVrfTagAndGotoFibInstructions(vpnTag);
438 String flowRef = getL3VpnToL3VpnLportDispFlowRef(dstLportTag, vpnTag);
440 return MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
441 CloudServiceChainConstants.DEFAULT_LPORT_DISPATCHER_FLOW_PRIORITY, flowRef,
442 0, 0, VpnServiceChainUtils.getCookieL3(vpnTag),
443 matches, instructions);
447 private static BigInteger getCookieSCHop(long scfInstanceTag) {
448 return CloudServiceChainConstants.COOKIE_SCF_BASE.add(new BigInteger("0610000", 16))
449 .add(BigInteger.valueOf(scfInstanceTag));
453 * Id for the Flow that is inserted in LFIB that is in charge of receiving packets coming from
454 * DC-GW and setting the VpnPseudoLport tag in metadata and send to LPortDispatcher. There is
455 * one of this entries per VrfEntry.
457 private static String getLFibVpnPseudoPortFlowRef(int vpnLportTag, long label, String nextHop) {
458 return new StringBuilder(64).append(CloudServiceChainConstants.VPN_PSEUDO_PORT_FLOWID_PREFIX)
459 .append(NwConstants.FLOWID_SEPARATOR).append(vpnLportTag)
460 .append(NwConstants.FLOWID_SEPARATOR).append(label)
461 .append(NwConstants.FLOWID_SEPARATOR).append(nextHop).toString();
464 private static String getL3VpnToL3VpnLportDispFlowRef(Integer lportTag, Integer vpnTag) {
465 return new StringBuilder().append(CloudServiceChainConstants.FLOWID_PREFIX_L3).append(lportTag)
466 .append(NwConstants.FLOWID_SEPARATOR).append(vpnTag)
467 .append(NwConstants.FLOWID_SEPARATOR)
468 .append(CloudServiceChainConstants.DEFAULT_LPORT_DISPATCHER_FLOW_PRIORITY).toString();
472 * Id for the Flow that is inserted in LPortDispatcher table that is in
473 * charge of delivering packets from the L3VPN to the SCF Pipeline.
474 * The VpnPseudoLPort tag and the SCF_SERVICE_INDEX is enough to identify
475 * this kind of flows.
477 public static String getL3VpnToScfLportDispatcherFlowRef(Integer lportTag) {
478 return new StringBuilder(64).append(CloudServiceChainConstants.VPN_PSEUDO_VPN2SCF_FLOWID_PREFIX)
480 .append(NwConstants.FLOWID_SEPARATOR)
481 .append(ServiceIndex.getIndex(NwConstants.SCF_SERVICE_NAME,
482 NwConstants.SCF_SERVICE_INDEX))
483 .append(NwConstants.FLOWID_SEPARATOR)
484 .append(CloudServiceChainConstants.DEFAULT_SCF_FLOW_PRIORITY).toString();
488 * Builds an identifier for the flow that is inserted in LPortDispatcher
489 * table and that is in charge of handling packets that are delivered from
490 * the SCF to the L3VPN Pipeline.
493 public static String getScfToL3VpnLportDispatcherFlowRef(Integer lportTag) {
494 return new StringBuilder().append(CloudServiceChainConstants.VPN_PSEUDO_SCF2VPN_FLOWID_PREFIX).append(lportTag)
495 .append(NwConstants.FLOWID_SEPARATOR)
496 .append(ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
497 NwConstants.L3VPN_SERVICE_INDEX))
498 .append(NwConstants.FLOWID_SEPARATOR)
499 .append(CloudServiceChainConstants.DEFAULT_SCF_FLOW_PRIORITY).toString();
502 public static List<String> getAllVpnIfaceNames(DataBroker dataBroker, String vpnName) {
504 String vpnRd = getVpnRd(dataBroker, vpnName);
505 InstanceIdentifier<VpnInstanceOpDataEntry> vpnOpDataIid =
506 InstanceIdentifier.builder(VpnInstanceOpData.class)
507 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(vpnRd)).build();
510 VpnInstanceOpDataEntry vpnOpData =
511 SingleTransactionDataBroker.syncRead(dataBroker, LogicalDatastoreType.OPERATIONAL, vpnOpDataIid);
513 if (vpnOpData == null) {
514 return Collections.emptyList();
516 List<VpnToDpnList> dpnToVpns = vpnOpData.getVpnToDpnList();
517 if (dpnToVpns == null) {
518 return Collections.emptyList();
521 return dpnToVpns.stream()
522 .filter(dpn -> dpn.getVpnInterfaces() != null)
523 .flatMap(dpn -> dpn.getVpnInterfaces().stream())
524 .map(VpnInterfaces::getInterfaceName)
525 .collect(Collectors.toList());
526 } catch (InterruptedException | ExecutionException e) {
527 LOG.warn("getAllVpnInterfaces for vpn {}: Failure on read operation", vpnName, e);
528 return Collections.emptyList();