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.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.List;
14 import java.util.Optional;
15 import java.util.stream.Collectors;
16 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
17 import org.opendaylight.genius.mdsalutil.ActionInfo;
18 import org.opendaylight.genius.mdsalutil.FlowEntity;
19 import org.opendaylight.genius.mdsalutil.InstructionInfo;
20 import org.opendaylight.genius.mdsalutil.MDSALUtil;
21 import org.opendaylight.genius.mdsalutil.MatchInfo;
22 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
23 import org.opendaylight.genius.mdsalutil.NWUtil;
24 import org.opendaylight.genius.mdsalutil.NwConstants;
25 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
26 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
27 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
28 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
29 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
30 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
31 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
32 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
33 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
34 import org.opendaylight.genius.utils.ServiceIndex;
35 import org.opendaylight.mdsal.binding.api.DataBroker;
36 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
37 import org.opendaylight.mdsal.common.api.ReadFailedException;
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() {
78 public static BigInteger getMetadataSCF(long scfTag) { // TODO: Move to a common place
79 return new BigInteger("FF", 16).and(BigInteger.valueOf(scfTag)).shiftLeft(32);
82 public static BigInteger getCookieL3(int vpnId) {
83 return CloudServiceChainConstants.COOKIE_L3_BASE.add(new BigInteger("0610000", 16))
84 .add(BigInteger.valueOf(vpnId));
88 public static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
89 return InstanceIdentifier.builder(VpnInstanceOpData.class)
90 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
93 public static InstanceIdentifier<BoundServices> buildBoundServicesIid(short servicePrio, String ifaceName) {
94 return InstanceIdentifier.builder(ServiceBindings.class)
95 .child(ServicesInfo.class, new ServicesInfoKey(ifaceName, ServiceModeIngress.class))
96 .child(BoundServices.class, new BoundServicesKey(servicePrio))
101 * Retrieves from MDSAL the Operational Data of the VPN specified by its
102 * Route-Distinguisher.
104 * @param rd Route-Distinguisher of the VPN
106 * @return the Operational Data of the VPN or absent if no VPN could be
107 * found for the given RD or if the VPN does not have operational
110 public static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(DataBroker broker, String rd) {
111 InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnServiceChainUtils.getVpnInstanceOpDataIdentifier(rd);
112 return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
115 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
116 return InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).build();
119 public static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
120 return InstanceIdentifier.builder(VpnInstanceOpData.class)
121 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd))
122 .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
125 public static InstanceIdentifier<VpnInstance> getVpnInstanceToVpnIdIdentifier(String vpnName) {
126 return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
127 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
130 public static InstanceIdentifier<VpnToPseudoPortData> getVpnToPseudoPortTagIid(String rd) {
131 VpnToPseudoPortDataKey key = new VpnToPseudoPortDataKey(rd);
132 return InstanceIdentifier.builder(VpnToPseudoPortList.class).child(VpnToPseudoPortData.class, key).build();
135 public static Optional<VpnToPseudoPortData> getVpnPseudoPortData(DataBroker broker, String rd)
136 throws ReadFailedException {
137 InstanceIdentifier<VpnToPseudoPortData> id = getVpnToPseudoPortTagIid(rd);
138 return SingleTransactionDataBroker.syncReadOptional(broker, LogicalDatastoreType.CONFIGURATION, id);
141 public static List<VpnToPseudoPortData> getAllVpnToPseudoPortData(DataBroker broker) throws ReadFailedException {
142 InstanceIdentifier<VpnToPseudoPortList> path = InstanceIdentifier.builder(VpnToPseudoPortList.class).build();
143 return SingleTransactionDataBroker.syncReadOptional(broker, LogicalDatastoreType.CONFIGURATION, path)
144 .toJavaUtil().map(VpnToPseudoPortList::getVpnToPseudoPortData).orElse(new ArrayList<>());
148 * Get fake VPNPseudoPort interface name.
151 * @param scfTag Service Function tag
152 * @param scsTag Service Chain tag
153 * @param lportTag Lport tag
154 * @return the fake VpnPseudoPort interface name
156 public static String buildVpnPseudoPortIfName(Long dpId, long scfTag, int scsTag, int lportTag) {
157 return new StringBuilder("VpnPseudo.").append(dpId).append(NwConstants.FLOWID_SEPARATOR)
158 .append(lportTag).append(NwConstants.FLOWID_SEPARATOR)
159 .append(scfTag).append(NwConstants.FLOWID_SEPARATOR)
160 .append(scsTag).toString();
164 * Retrieves the VpnId (datapath id) searching by VpnInstanceName.
166 * @param broker Reference to the MDSAL Databroker service
167 * @param vpnName The Vpn instance name
168 * @return the datapath identifier for the specified VPN
170 public static long getVpnId(DataBroker broker, String vpnName) {
172 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt
173 .l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id =
174 getVpnInstanceToVpnIdIdentifier(vpnName);
175 Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt
176 .l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance =
177 MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
179 return vpnInstance.isPresent() ? vpnInstance.get().getVpnId() : CloudServiceChainConstants.INVALID_VPN_TAG;
183 * Retrieves the VPN's Route Distinguisher out from the VpnName.
185 * @param broker Reference to the MDSAL Databroker service
186 * @param vpnName The Vpn Instance Name. Typically the UUID.
187 * @return the RouteDistinguiser for the specified VPN
189 public static String getVpnRd(DataBroker broker, String vpnName) {
190 InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
191 return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(
192 VpnInstance::getVrfId).orElse(null);
196 * Returns all the VrfEntries that belong to a given VPN.
198 * @param broker Reference to the MDSAL Databroker service
199 * @param rd Route-distinguisher of the VPN
200 * @return the list of the matching VrfEntries
202 public static List<VrfEntry> getAllVrfEntries(DataBroker broker, String rd) {
203 InstanceIdentifier<VrfTables> vpnVrfTables =
204 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).build();
205 return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnVrfTables).toJavaUtil().map(
206 VrfTables::getVrfEntry).orElse(new ArrayList<>());
210 * Installs/removes a flow in LPortDispatcher table that is in charge of
211 * handling packets that falls back from SCF Pipeline to L3Vpn.
213 * @param mdsalManager MDSAL Util API accessor
214 * @param vpnId Dataplane identifier of the VPN, the Vrf Tag.
215 * @param dpId The DPN where the flow must be installed/removed
216 * @param vpnPseudoLportTag Dataplane identifier for the VpnPseudoPort
217 * @param addOrRemove States if the flow must be created or removed
219 public static void programLPortDispatcherFlowForScfToVpn(IMdsalApiManager mdsalManager, long vpnId, BigInteger dpId,
220 Integer vpnPseudoLportTag, int addOrRemove) {
221 LOG.trace("programLPortDispatcherFlowForScfToVpn: vpnId={} dpId={}, vpnPseudoLportTag={} addOrRemove={}",
222 vpnId, dpId, vpnPseudoLportTag, addOrRemove);
223 Flow flow = buildLPortDispFromScfToL3VpnFlow(vpnId, dpId, vpnPseudoLportTag, addOrRemove);
224 if (addOrRemove == NwConstants.ADD_FLOW) {
225 mdsalManager.installFlow(dpId, flow);
227 mdsalManager.removeFlow(dpId, flow);
232 * Build the flow that must be inserted when there is a ScHop whose
233 * egressPort is a VPN Pseudo Port. In that case, packets must be moved
234 * from the SCF to VPN Pipeline.
236 * Flow matches: VpnPseudo port lPortTag + SI=L3VPN
237 * Actions: Write vrfTag in Metadata + goto FIB Table
239 * @param vpnId Dataplane identifier of the VPN, the Vrf Tag.
240 * @param dpId The DPN where the flow must be installed/removed
241 * @param lportTag Dataplane identifier for the VpnPseudoPort
242 * @param addOrRemove States if it must build a Flow to be created or
245 * @return the Flow object
247 public static Flow buildLPortDispFromScfToL3VpnFlow(Long vpnId, BigInteger dpId, Integer lportTag,
249 LOG.info("buildLPortDispFlowForScf vpnId={} dpId={} lportTag={} addOrRemove={} ",
250 vpnId, dpId, lportTag, addOrRemove);
251 List<MatchInfo> matches = buildMatchOnLportTagAndSI(lportTag,
252 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
253 NwConstants.L3VPN_SERVICE_INDEX));
254 List<Instruction> instructions = buildSetVrfTagAndGotoFibInstructions(vpnId.intValue());
256 String flowRef = getScfToL3VpnLportDispatcherFlowRef(lportTag);
259 if (addOrRemove == NwConstants.ADD_FLOW) {
260 result = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
261 CloudServiceChainConstants.DEFAULT_SCF_FLOW_PRIORITY, flowRef,
262 0, 0, VpnServiceChainUtils.getCookieL3(vpnId.intValue()),
263 matches, instructions);
266 result = new FlowBuilder().setTableId(NwConstants.LPORT_DISPATCHER_TABLE)
267 .setId(new FlowId(flowRef))
275 * Builds the Match for flows that must match on a given lportTag and
278 * @return the Match as a list.
280 public static List<MatchInfo> buildMatchOnLportTagAndSI(Integer lportTag, short serviceIndex) {
281 return Collections.singletonList(
282 new MatchMetadata(MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, serviceIndex),
283 MetaDataUtil.getMetaDataMaskForLPortDispatcher()));
287 * Builds a The Instructions that sets the VpnTag in metadata and sends to
290 * @param vpnTag Dataplane identifier of the VPN.
291 * @return the list of Instructions
293 public static List<Instruction> buildSetVrfTagAndGotoFibInstructions(Integer vpnTag) {
294 List<Instruction> result = new ArrayList<>();
295 int instructionKey = 0;
296 result.add(MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getVpnIdMetadata(vpnTag),
297 MetaDataUtil.METADATA_MASK_VRFID,
299 result.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_FIB_TABLE, ++instructionKey));
305 * Builds a Flow for the LFIB table that sets the LPortTag of the
306 * VpnPseudoPort and sends to LPortDispatcher table.
308 * <li>Matching: eth_type = MPLS, mpls_label = VPN MPLS label
309 * <li>Actions: setMetadata LportTag and SI=2, pop MPLS, Go to
310 * LPortDispacherTable
314 * @param label MPLS label
315 * @param nextHop Next Hop IP
316 * @param lportTag Pseudo Logical Port tag
317 * @return the FlowEntity
319 public static FlowEntity buildLFibVpnPseudoPortFlow(BigInteger dpId, Long label, int etherType, String nextHop,
322 List<MatchInfo> matches = new ArrayList<>();
323 matches.add(MatchEthernetType.MPLS_UNICAST);
324 matches.add(new MatchMplsLabel(label));
326 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionPopMpls(etherType));
327 List<InstructionInfo> instructions = new ArrayList<>();
328 instructions.add(new InstructionWriteMetadata(
329 MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
330 ServiceIndex.getIndex(NwConstants.SCF_SERVICE_NAME,
331 NwConstants.SCF_SERVICE_INDEX)),
332 MetaDataUtil.getMetaDataMaskForLPortDispatcher()
335 instructions.add(new InstructionApplyActions(actionsInfos));
336 instructions.add(new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE));
337 String flowRef = getLFibVpnPseudoPortFlowRef(lportTag, label, nextHop);
338 return MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
339 CloudServiceChainConstants.DEFAULT_SCF_FLOW_PRIORITY, flowRef, 0, 0,
340 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
345 * Modifies the LFIB table by adding/removing flows that redirects traffic
346 * from a VPN into the SCF via the VpnPseudoLport.
347 * Flows that match on the label and sets the VpnPseudoPort lportTag and
348 * sends to LPortDispatcher (via table 80)
351 public static void programLFibEntriesForSCF(IMdsalApiManager mdsalMgr, BigInteger dpId, List<VrfEntry> vrfEntries,
352 int lportTag, int addOrRemove) {
353 LOG.trace("programLFibEntriesForSCF: dpId={} lportTag={} addOrRemove={}", dpId, lportTag, addOrRemove);
354 if (vrfEntries != null) {
355 vrfEntries.forEach(vrfEntry -> vrfEntry.getRoutePaths()
356 .forEach(routePath -> {
357 Long label = routePath.getLabel();
358 String nextHop = routePath.getNexthopAddress();
360 int etherType = NWUtil.getEtherTypeFromIpPrefix(vrfEntry.getDestPrefix());
361 FlowEntity flowEntity = buildLFibVpnPseudoPortFlow(dpId, label, etherType, nextHop,
363 if (addOrRemove == NwConstants.ADD_FLOW) {
364 mdsalMgr.installFlow(flowEntity);
366 mdsalMgr.removeFlow(flowEntity);
369 "LFIBEntry for label={}, destination={}, nexthop={} {} successfully in dpn={}",
370 label, vrfEntry.getDestPrefix(), nextHop,
371 addOrRemove == NwConstants.DEL_FLOW ? "removed" : "installed", dpId);
372 } catch (IllegalArgumentException ex) {
373 LOG.warn("Unable to get etherType for IP Prefix {}", vrfEntry.getDestPrefix());
380 * Installs/removes a flow in LPortDispatcher table that is in charge
381 * of sending the traffic to the SCF Pipeline.
384 public static void programLPortDispatcherFlowForVpnToScf(IMdsalApiManager mdsalManager, BigInteger dpId,
385 int lportTag, long scfTag, short gotoTableId,
387 LOG.trace("programLPortDispatcherFlowForVpnToScf: dpId={} lportTag={} scfTag={} gotoTableId={} addOrRemove={}",
388 dpId, lportTag, scfTag, gotoTableId, addOrRemove);
389 FlowEntity flowEntity = VpnServiceChainUtils.buildLportFlowDispForVpnToScf(dpId, lportTag, scfTag, gotoTableId);
390 if (addOrRemove == NwConstants.ADD_FLOW) {
391 mdsalManager.installFlow(flowEntity);
393 mdsalManager.removeFlow(flowEntity);
398 * Creates the flow that sends the packet from the VPN to the SCF pipeline.
399 * This usually happens when there is an ScHop whose ingressPort is a
402 * <li>Matches: lportTag = vpnPseudoLPortTag, SI = 1
403 * <li>Actions: setMetadata(scfTag), Go to: UpSubFilter table
406 public static FlowEntity buildLportFlowDispForVpnToScf(BigInteger dpId, int lportTag, long scfTag,
408 List<InstructionInfo> instructions = new ArrayList<>();
409 List<ActionInfo> actionsInfos = new ArrayList<>();
410 actionsInfos.add(new ActionRegLoad(NxmNxReg2.class, 0, 31, scfTag));
411 instructions.add(new InstructionApplyActions(actionsInfos));
412 instructions.add(new InstructionGotoTable(gotoTableId));
413 String flowRef = getL3VpnToScfLportDispatcherFlowRef(lportTag);
415 List<MatchInfo> matches =
416 buildMatchOnLportTagAndSI(lportTag, ServiceIndex.getIndex(NwConstants.SCF_SERVICE_NAME,
417 NwConstants.SCF_SERVICE_INDEX));
418 return MDSALUtil.buildFlowEntity(dpId, NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
419 CloudServiceChainConstants.DEFAULT_SCF_FLOW_PRIORITY, flowRef, 0, 0,
420 getCookieSCHop(scfTag), matches, instructions);
424 public static Optional<Long> getVpnPseudoLportTag(DataBroker broker, String rd) {
425 InstanceIdentifier<VpnToPseudoPortData> path = getVpnToPseudoPortTagIid(rd);
426 return Optional.fromJavaUtil(MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path).toJavaUtil().map(
427 VpnToPseudoPortData::getVpnLportTag));
431 * Creates a Flow that does the trick of moving the packets from one VPN to
435 public static Flow buildLPortDispFlowForVpntoVpn(Integer dstLportTag, Integer vpnTag) {
436 List<MatchInfo> matches =
437 buildMatchOnLportTagAndSI(dstLportTag, ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
438 NwConstants.L3VPN_SERVICE_INDEX));
439 List<Instruction> instructions = buildSetVrfTagAndGotoFibInstructions(vpnTag);
440 String flowRef = getL3VpnToL3VpnLportDispFlowRef(dstLportTag, vpnTag);
442 return MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
443 CloudServiceChainConstants.DEFAULT_LPORT_DISPATCHER_FLOW_PRIORITY, flowRef,
444 0, 0, VpnServiceChainUtils.getCookieL3(vpnTag),
445 matches, instructions);
449 private static BigInteger getCookieSCHop(long scfInstanceTag) {
450 return CloudServiceChainConstants.COOKIE_SCF_BASE.add(new BigInteger("0610000", 16))
451 .add(BigInteger.valueOf(scfInstanceTag));
455 * Id for the Flow that is inserted in LFIB that is in charge of receiving packets coming from
456 * DC-GW and setting the VpnPseudoLport tag in metadata and send to LPortDispatcher. There is
457 * one of this entries per VrfEntry.
459 private static String getLFibVpnPseudoPortFlowRef(int vpnLportTag, long label, String nextHop) {
460 return new StringBuilder(64).append(CloudServiceChainConstants.VPN_PSEUDO_PORT_FLOWID_PREFIX)
461 .append(NwConstants.FLOWID_SEPARATOR).append(vpnLportTag)
462 .append(NwConstants.FLOWID_SEPARATOR).append(label)
463 .append(NwConstants.FLOWID_SEPARATOR).append(nextHop).toString();
466 private static String getL3VpnToL3VpnLportDispFlowRef(Integer lportTag, Integer vpnTag) {
467 return new StringBuilder().append(CloudServiceChainConstants.FLOWID_PREFIX_L3).append(lportTag)
468 .append(NwConstants.FLOWID_SEPARATOR).append(vpnTag)
469 .append(NwConstants.FLOWID_SEPARATOR)
470 .append(CloudServiceChainConstants.DEFAULT_LPORT_DISPATCHER_FLOW_PRIORITY).toString();
474 * Id for the Flow that is inserted in LPortDispatcher table that is in
475 * charge of delivering packets from the L3VPN to the SCF Pipeline.
476 * The VpnPseudoLPort tag and the SCF_SERVICE_INDEX is enough to identify
477 * this kind of flows.
479 public static String getL3VpnToScfLportDispatcherFlowRef(Integer lportTag) {
480 return new StringBuilder(64).append(CloudServiceChainConstants.VPN_PSEUDO_VPN2SCF_FLOWID_PREFIX)
482 .append(NwConstants.FLOWID_SEPARATOR)
483 .append(ServiceIndex.getIndex(NwConstants.SCF_SERVICE_NAME,
484 NwConstants.SCF_SERVICE_INDEX))
485 .append(NwConstants.FLOWID_SEPARATOR)
486 .append(CloudServiceChainConstants.DEFAULT_SCF_FLOW_PRIORITY).toString();
490 * Builds an identifier for the flow that is inserted in LPortDispatcher
491 * table and that is in charge of handling packets that are delivered from
492 * the SCF to the L3VPN Pipeline.
495 public static String getScfToL3VpnLportDispatcherFlowRef(Integer lportTag) {
496 return new StringBuilder().append(CloudServiceChainConstants.VPN_PSEUDO_SCF2VPN_FLOWID_PREFIX).append(lportTag)
497 .append(NwConstants.FLOWID_SEPARATOR)
498 .append(ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
499 NwConstants.L3VPN_SERVICE_INDEX))
500 .append(NwConstants.FLOWID_SEPARATOR)
501 .append(CloudServiceChainConstants.DEFAULT_SCF_FLOW_PRIORITY).toString();
504 public static List<String> getAllVpnIfaceNames(DataBroker dataBroker, String vpnName) {
506 String vpnRd = getVpnRd(dataBroker, vpnName);
507 InstanceIdentifier<VpnInstanceOpDataEntry> vpnOpDataIid =
508 InstanceIdentifier.builder(VpnInstanceOpData.class)
509 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(vpnRd)).build();
512 VpnInstanceOpDataEntry vpnOpData =
513 SingleTransactionDataBroker.syncRead(dataBroker, LogicalDatastoreType.OPERATIONAL, vpnOpDataIid);
515 if (vpnOpData == null) {
516 return Collections.emptyList();
518 List<VpnToDpnList> dpnToVpns = vpnOpData.getVpnToDpnList();
519 if (dpnToVpns == null) {
520 return Collections.emptyList();
523 return dpnToVpns.stream()
524 .filter(dpn -> dpn.getVpnInterfaces() != null)
525 .flatMap(dpn -> dpn.getVpnInterfaces().stream())
526 .map(VpnInterfaces::getInterfaceName)
527 .collect(Collectors.toList());
528 } catch (InterruptedException | ExecutionException e) {
529 LOG.warn("getAllVpnInterfaces for vpn {}: Failure on read operation", vpnName, e);
530 return Collections.emptyList();