Freeze upstream versions
[netvirt.git] / cloud-servicechain / impl / src / main / java / org / opendaylight / netvirt / cloudservicechain / utils / VpnServiceChainUtils.java
1 /*
2  * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.cloudservicechain.utils;
9
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;
69
70 public final class VpnServiceChainUtils {
71
72     private static final Logger LOG = LoggerFactory.getLogger(VpnServiceChainUtils.class);
73
74     private VpnServiceChainUtils() {
75
76     }
77
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);
80     }
81
82     public static BigInteger getCookieL3(int vpnId) {
83         return CloudServiceChainConstants.COOKIE_L3_BASE.add(new BigInteger("0610000", 16))
84                                                       .add(BigInteger.valueOf(vpnId));
85     }
86
87
88     public static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
89         return InstanceIdentifier.builder(VpnInstanceOpData.class)
90                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
91     }
92
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))
97                                  .build();
98     }
99
100     /**
101      * Retrieves from MDSAL the Operational Data of the VPN specified by its
102      * Route-Distinguisher.
103      *
104      * @param rd Route-Distinguisher of the VPN
105      *
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
108      *         data.
109      */
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);
113     }
114
115     public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
116         return InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).build();
117     }
118
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();
123     }
124
125     public static InstanceIdentifier<VpnInstance> getVpnInstanceToVpnIdIdentifier(String vpnName) {
126         return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
127                                  .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
128     }
129
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();
133     }
134
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);
139     }
140
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<>());
145     }
146
147     /**
148      * Get fake VPNPseudoPort interface name.
149      *
150      * @param dpId Dpn Id
151      * @param scfTag Service Function tag
152      * @param scsTag Service Chain tag
153      * @param lportTag Lport tag
154      * @return the fake VpnPseudoPort interface name
155      */
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();
161     }
162
163     /**
164      * Retrieves the VpnId (datapath id) searching by VpnInstanceName.
165      *
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
169      */
170     public static long getVpnId(DataBroker broker, String vpnName) {
171
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);
178
179         return vpnInstance.isPresent() ? vpnInstance.get().getVpnId() : CloudServiceChainConstants.INVALID_VPN_TAG;
180     }
181
182     /**
183      * Retrieves the VPN's Route Distinguisher out from the VpnName.
184      *
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
188      */
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);
193     }
194
195     /**
196      * Returns all the VrfEntries that belong to a given VPN.
197      *
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
201      */
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<>());
207     }
208
209     /**
210      * Installs/removes a flow in LPortDispatcher table that is in charge of
211      * handling packets that falls back from SCF Pipeline to L3Vpn.
212      *
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
218      */
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);
226         } else {
227             mdsalManager.removeFlow(dpId, flow);
228         }
229     }
230
231     /**
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.
235      * <p>
236      * Flow matches:  VpnPseudo port lPortTag + SI=L3VPN
237      * Actions: Write vrfTag in Metadata + goto FIB Table
238      * </p>
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
243      *     removed
244      *
245      * @return the Flow object
246      */
247     public static Flow buildLPortDispFromScfToL3VpnFlow(Long vpnId, BigInteger dpId, Integer lportTag,
248                                                         int addOrRemove) {
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());
255
256         String flowRef = getScfToL3VpnLportDispatcherFlowRef(lportTag);
257
258         Flow result;
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);
264
265         } else {
266             result = new FlowBuilder().setTableId(NwConstants.LPORT_DISPATCHER_TABLE)
267                                       .setId(new FlowId(flowRef))
268                                       .build();
269         }
270         return result;
271     }
272
273
274     /**
275      * Builds the Match for flows that must match on a given lportTag and
276      * serviceIndex.
277      *
278      * @return the Match as a list.
279      */
280     public static List<MatchInfo> buildMatchOnLportTagAndSI(Integer lportTag, short serviceIndex) {
281         return Collections.singletonList(
282                 new MatchMetadata(MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, serviceIndex),
283                         MetaDataUtil.getMetaDataMaskForLPortDispatcher()));
284     }
285
286     /**
287      * Builds a The Instructions that sets the VpnTag in metadata and sends to
288      * FIB table.
289      *
290      * @param vpnTag Dataplane identifier of the VPN.
291      * @return the list of Instructions
292      */
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,
298                                                                ++instructionKey));
299         result.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_FIB_TABLE, ++instructionKey));
300         return result;
301     }
302
303
304     /**
305      * Builds a Flow for the LFIB table that sets the LPortTag of the
306      * VpnPseudoPort and sends to LPortDispatcher table.
307      * <ul>
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
311      * </ul>
312      *
313      * @param dpId  DpnId
314      * @param label MPLS label
315      * @param nextHop Next Hop IP
316      * @param lportTag Pseudo Logical Port tag
317      * @return the FlowEntity
318      */
319     public static FlowEntity buildLFibVpnPseudoPortFlow(BigInteger dpId, Long label, int etherType, String nextHop,
320                                                         int lportTag) {
321
322         List<MatchInfo> matches = new ArrayList<>();
323         matches.add(MatchEthernetType.MPLS_UNICAST);
324         matches.add(new MatchMplsLabel(label));
325
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()
333         ));
334
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);
341     }
342
343
344     /**
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)
349      *
350      */
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();
359                         try {
360                             int etherType = NWUtil.getEtherTypeFromIpPrefix(vrfEntry.getDestPrefix());
361                             FlowEntity flowEntity = buildLFibVpnPseudoPortFlow(dpId, label, etherType, nextHop,
362                                     lportTag);
363                             if (addOrRemove == NwConstants.ADD_FLOW) {
364                                 mdsalMgr.installFlow(flowEntity);
365                             } else {
366                                 mdsalMgr.removeFlow(flowEntity);
367                             }
368                             LOG.debug(
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());
374                         }
375                     }));
376         }
377     }
378
379     /**
380      * Installs/removes a flow in LPortDispatcher table that is in charge
381      * of sending the traffic to the SCF Pipeline.
382      *
383      */
384     public static void programLPortDispatcherFlowForVpnToScf(IMdsalApiManager mdsalManager, BigInteger dpId,
385                                                              int lportTag, long scfTag, short gotoTableId,
386                                                              int addOrRemove) {
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);
392         } else {
393             mdsalManager.removeFlow(flowEntity);
394         }
395     }
396
397     /**
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
400      * VpnPseudoPort.
401      * <ul>
402      * <li>Matches: lportTag = vpnPseudoLPortTag, SI = 1
403      * <li>Actions: setMetadata(scfTag), Go to: UpSubFilter table
404      * </ul>
405      */
406     public static FlowEntity buildLportFlowDispForVpnToScf(BigInteger dpId, int lportTag, long scfTag,
407                                                            short gotoTableId) {
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);
414
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);
421
422     }
423
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));
428     }
429
430     /**
431      * Creates a Flow that does the trick of moving the packets from one VPN to
432      * another VPN.
433      *
434      */
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);
441
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);
446     }
447
448
449     private static BigInteger getCookieSCHop(long scfInstanceTag) {
450         return CloudServiceChainConstants.COOKIE_SCF_BASE.add(new BigInteger("0610000", 16))
451                 .add(BigInteger.valueOf(scfInstanceTag));
452     }
453
454     /*
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.
458      */
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();
464     }
465
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();
471     }
472
473     /**
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.
478      */
479     public static String getL3VpnToScfLportDispatcherFlowRef(Integer lportTag) {
480         return new StringBuilder(64).append(CloudServiceChainConstants.VPN_PSEUDO_VPN2SCF_FLOWID_PREFIX)
481                                    .append(lportTag)
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();
487     }
488
489     /**
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.
493      *
494      */
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();
502     }
503
504     public static List<String> getAllVpnIfaceNames(DataBroker dataBroker, String vpnName) {
505
506         String vpnRd = getVpnRd(dataBroker, vpnName);
507         InstanceIdentifier<VpnInstanceOpDataEntry> vpnOpDataIid =
508             InstanceIdentifier.builder(VpnInstanceOpData.class)
509                               .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(vpnRd)).build();
510
511         try {
512             VpnInstanceOpDataEntry vpnOpData =
513                 SingleTransactionDataBroker.syncRead(dataBroker, LogicalDatastoreType.OPERATIONAL, vpnOpDataIid);
514
515             if (vpnOpData == null) {
516                 return Collections.emptyList();
517             }
518             List<VpnToDpnList> dpnToVpns = vpnOpData.getVpnToDpnList();
519             if (dpnToVpns == null) {
520                 return Collections.emptyList();
521             }
522
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();
531         }
532     }
533 }