Fixup Augmentable and Identifiable methods changing
[netvirt.git] / sfc / classifier / impl / src / main / java / org / opendaylight / netvirt / sfc / classifier / providers / OpenFlow13Provider.java
1 /*
2  * Copyright © 2017 Ericsson, Inc. 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
9 package org.opendaylight.netvirt.sfc.classifier.providers;
10
11 import com.google.common.net.InetAddresses;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.List;
15 import javax.inject.Singleton;
16 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.genius.mdsalutil.NwConstants;
19 import org.opendaylight.netvirt.sfc.classifier.utils.AclMatches;
20 import org.opendaylight.netvirt.sfc.classifier.utils.OpenFlow13Utils;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35
36 @Singleton
37 public class OpenFlow13Provider {
38     // Unique cookie values for each type of flow
39     public static final BigInteger INGRESS_CLASSIFIER_FILTER_COOKIE = new BigInteger("F005BA1100000001", 16);
40     public static final BigInteger INGRESS_CLASSIFIER_ACL_COOKIE = new BigInteger("F005BA1100000002", 16);
41     public static final BigInteger EGRESS_CLASSIFIER_FILTER_COOKIE = new BigInteger("F005BA1100000003", 16);
42     public static final BigInteger EGRESS_CLASSIFIER_NEXTHOP_COOKIE = new BigInteger("F005BA1100000004", 16);
43     public static final BigInteger EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE = new BigInteger("F005BA1100000005", 16);
44     public static final BigInteger INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_COOKIE =
45             new BigInteger("F005BA1100000006", 16);
46
47     // Priorities for each flow
48     public static final int INGRESS_CLASSIFIER_FILTER_CHAIN_EGRESS_PRIORITY = 520;
49     public static final int INGRESS_CLASSIFIER_FILTER_TUN_NSH_PRIORITY = 510;
50     public static final int INGRESS_CLASSIFIER_FILTER_ETH_NSH_PRIORITY = 511;
51     public static final int INGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY = 500;
52     public static final int INGRESS_CLASSIFIER_ACL_PRIORITY = 500;
53     public static final int INGRESS_CLASSIFIER_ACL_NOMATCH_PRIORITY = 10;
54     public static final int INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_PRIORITY = 10;
55     public static final int EGRESS_CLASSIFIER_FILTER_NSH_PRIORITY = 260;
56     public static final int EGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY = 250;
57     public static final int EGRESS_CLASSIFIER_NEXTHOP_C1C2_PRIORITY = 250;
58     public static final int EGRESS_CLASSIFIER_NEXTHOP_NOC1C2_PRIORITY = 260;
59     public static final int EGRESS_CLASSIFIER_EGRESS_LOCAL_PRIORITY = 260;
60     public static final int EGRESS_CLASSIFIER_EGRESS_REMOTE_PRIORITY = 250;
61
62     // Flow names for each table
63     public static final String INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME =
64             "nvsfc_ingr_class_filter_chain_egress";
65     public static final String INGRESS_CLASSIFIER_FILTER_VXGPENSH_FLOW_NAME = "nvsfc_ingr_class_filter_vxgpe";
66     public static final String INGRESS_CLASSIFIER_FILTER_ETHNSH_FLOW_NAME = "nvsfc_ingr_class_filter_eth";
67     public static final String INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME = "nvsfc_ingr_class_filter_nonsh";
68     public static final String INGRESS_CLASSIFIER_ACL_FLOW_NAME = "nvsfc_ingr_class_acl";
69     public static final String INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_FLOW_NAME =
70             "nvsfc_ingr_class_capture_sfc_tunnel";
71     public static final String EGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME = "nvsfc_egr_class_filter_nsh";
72     public static final String EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME = "nvsfc_egr_class_filter_nonsh";
73     public static final String EGRESS_CLASSIFIER_NEXTHOP_C1C2_FLOW_NAME = "nvsfc_egr_class_nexthop_c1c2";
74     public static final String EGRESS_CLASSIFIER_NEXTHOP_NOC1C2_FLOW_NAME = "nvsfc_egr_class_nexthop_noc1c2";
75     public static final String EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME = "nvsfc_egr_class_ tport egress";
76
77     public static final short NSH_MDTYPE_ONE = 0x01;
78     public static final short NSH_NP_ETH = 0x3;
79     public static final long DEFAULT_NSH_CONTEXT_VALUE = 0L;
80     public static final long ACL_FLAG_CONTEXT_VALUE = 0xFFFFFFL;
81     public static final long SFC_TUNNEL_ID = 0L;
82     public static final String OF_URI_SEPARATOR = ":";
83     public static final Ipv4Address NULL_IP = new Ipv4Address("0.0.0.0");
84
85     public MatchBuilder getMatchBuilderFromAceMatches(Matches matches) {
86         if (matches == null) {
87             return null;
88         }
89
90         return new AclMatches(matches).buildMatch();
91     }
92
93     public void appendFlowForCreate(NodeId node, Flow flow, WriteTransaction tx) {
94         NodeKey nodeKey = new NodeKey(node);
95         InstanceIdentifier<Flow> iidFlow = InstanceIdentifier.builder(Nodes.class)
96             .child(Node.class, nodeKey)
97             .augmentation(FlowCapableNode.class)
98             .child(Table.class, new TableKey(flow.getTableId()))
99             .child(Flow.class, flow.key())
100             .build();
101
102         tx.put(LogicalDatastoreType.CONFIGURATION, iidFlow, flow, WriteTransaction.CREATE_MISSING_PARENTS);
103     }
104
105     public void appendFlowForDelete(NodeId node, Flow flow, WriteTransaction tx) {
106         NodeKey nodeKey = new NodeKey(node);
107         InstanceIdentifier<Flow> iidFlow = InstanceIdentifier.builder(Nodes.class)
108             .child(Node.class, nodeKey)
109             .augmentation(FlowCapableNode.class)
110             .child(Table.class, new TableKey(flow.getTableId()))
111             .child(Flow.class, flow.key())
112             .build();
113
114         tx.delete(LogicalDatastoreType.CONFIGURATION, iidFlow);
115     }
116
117     /*
118      * Ingress Classifier SFC Tunnel Traffic Capture Flow
119      *     Captures SFC traffic coming from tunnel port and redirects it
120      *     to the ingress classifier pipeline. From there, if no chain
121      *     egress actions apply, it will be sent back to SFC pipeline.
122      *     Match on SFC VNI = 0 and ethertype = nsh, and resubmit to
123      *     ingress classifier.
124      */
125     public Flow createIngressClassifierSfcTunnelTrafficCaptureFlow(NodeId nodeId) {
126         MatchBuilder match = new MatchBuilder();
127         OpenFlow13Utils.addMatchTunId(match, SFC_TUNNEL_ID);
128         OpenFlow13Utils.addMatchEthNsh(match);
129
130         List<Action> actionList = new ArrayList<>();
131         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
132                 actionList.size()));
133
134         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
135         String flowIdStr = INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_FLOW_NAME + nodeId.getValue();
136
137
138         return OpenFlow13Utils.createFlowBuilder(NwConstants.INTERNAL_TUNNEL_TABLE,
139                 INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_PRIORITY,
140                 INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_COOKIE,
141                 INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_FLOW_NAME, flowIdStr, match, isb).build();
142     }
143
144     /*
145      * Ingress Classifier Filter Vxgpe NSH flow:
146      *     Only allows Non-NSH packets to proceed in the classifier
147      *     Match on ethertype and resubmit to SFC (we don't resubmit to
148      *     dispatcher since it is still not used for tunnel ports)
149      */
150     public Flow createIngressClassifierFilterVxgpeNshFlow(NodeId nodeId) {
151         MatchBuilder match = new MatchBuilder();
152         OpenFlow13Utils.addMatchEthNsh(match);
153
154         List<Action> actionList = new ArrayList<>();
155         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.SFC_TRANSPORT_INGRESS_TABLE,
156             actionList.size()));
157
158         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
159         String flowIdStr = INGRESS_CLASSIFIER_FILTER_VXGPENSH_FLOW_NAME + nodeId.getValue();
160
161         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
162                 INGRESS_CLASSIFIER_FILTER_TUN_NSH_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
163             INGRESS_CLASSIFIER_FILTER_VXGPENSH_FLOW_NAME, flowIdStr, match, isb).build();
164     }
165
166     /*
167      * Ingress Classifier Filter Eth NSH flow:
168      *     Only allows Non-NSH packets to proceed in the classifier
169      *     Match on ethertype and null tunnel IP and resubmit to
170      *     Ingress Dispatcher on match
171      */
172     public Flow createIngressClassifierFilterEthNshFlow(NodeId nodeId) {
173         MatchBuilder match = new MatchBuilder();
174         OpenFlow13Utils.addMatchEthNsh(match);
175         OpenFlow13Utils.addMatchTunDstIp(match, NULL_IP);
176
177         List<Action> actionList = new ArrayList<>();
178         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE,
179             actionList.size()));
180
181         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
182         String flowIdStr = INGRESS_CLASSIFIER_FILTER_ETHNSH_FLOW_NAME + nodeId.getValue();
183
184         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
185                 INGRESS_CLASSIFIER_FILTER_ETH_NSH_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
186             INGRESS_CLASSIFIER_FILTER_ETHNSH_FLOW_NAME, flowIdStr, match, isb).build();
187     }
188
189     /*
190      * Classifier chain termination flow:
191      *     Handle packets at the end of the chain
192      *     Match C1 on local IP, NSP and ending NSI, restore metadata and
193      *     resubmit to egress dispatcher
194      */
195     public Flow createIngressClassifierFilterChainEgressFlow(NodeId nodeId, long nsp, short egressNsi) {
196
197         MatchBuilder match = new MatchBuilder();
198         OpenFlow13Utils.addMatchNsp(match, nsp);
199         OpenFlow13Utils.addMatchNsi(match, egressNsi);
200
201         List<Action> actionList = new ArrayList<>();
202         actionList.add(OpenFlow13Utils.createActionNxMoveNsc4ToReg6Register(actionList.size()));
203         actionList.add(OpenFlow13Utils.createActionNxPopNsh(actionList.size()));
204         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE,
205                 actionList.size()));
206
207         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
208         String flowIdStr = INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp;
209
210         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
211                 INGRESS_CLASSIFIER_FILTER_CHAIN_EGRESS_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
212                 INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME, flowIdStr, match, isb).build();
213     }
214
215     /*
216      * Ingress Classifier Filter No NSH flow:
217      *     Only allows Non-NSH packets to proceed in the classifier
218      *     Match Any (NSH not present), Goto Classifier ACL table
219      */
220     public Flow createIngressClassifierFilterNoNshFlow(NodeId nodeId) {
221         // MatchAny
222         MatchBuilder match = new MatchBuilder();
223
224         InstructionsBuilder isb = OpenFlow13Utils.appendGotoTableInstruction(new InstructionsBuilder(),
225             NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE);
226         String flowIdStr = INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME + nodeId.getValue();
227
228         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
229             INGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
230             INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME, flowIdStr, match, isb).build();
231     }
232
233     /*
234      * Ingress Classifier ACL flow:
235      *     Performs the ACL classification, and sends packets to Ingress Dispatcher
236      *     Match on inport (corresponds to Neutron NW/tenant), Push NSH, init(nsp, nsi, C1, C2),
237      *     and resubmit to Ingress Dispatcher to be sent down the rest of
238      *     the pipeline
239      */
240     public Flow createIngressClassifierAclFlow(NodeId nodeId, MatchBuilder match, Long port, long nsp, short nsi) {
241         OpenFlow13Utils.addMatchInPort(match, nodeId, port);
242
243         List<Action> actionList = new ArrayList<>();
244         actionList.add(OpenFlow13Utils.createActionNxPushNsh(actionList.size()));
245         actionList.add(OpenFlow13Utils.createActionNxLoadNshMdtype(NSH_MDTYPE_ONE, actionList.size()));
246         actionList.add(OpenFlow13Utils.createActionNxLoadNp(NSH_NP_ETH, actionList.size()));
247         actionList.add(OpenFlow13Utils.createActionNxLoadNsp((int) nsp, actionList.size()));
248         actionList.add(OpenFlow13Utils.createActionNxLoadNsi(nsi, actionList.size()));
249         actionList.add(OpenFlow13Utils.createActionNxLoadNshc1(ACL_FLAG_CONTEXT_VALUE, actionList.size()));
250         actionList.add(OpenFlow13Utils.createActionNxLoadNshc2(DEFAULT_NSH_CONTEXT_VALUE, actionList.size()));
251         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE,
252             actionList.size()));
253
254         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
255
256         // The flowIdStr needs to be unique, so the best way to make it unique is to use the match
257         String flowIdStr = INGRESS_CLASSIFIER_ACL_FLOW_NAME + "_" + nodeId.getValue() + match.build().toString();
258
259         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE,
260             INGRESS_CLASSIFIER_ACL_PRIORITY, INGRESS_CLASSIFIER_ACL_COOKIE, INGRESS_CLASSIFIER_ACL_FLOW_NAME,
261             flowIdStr, match, isb).build();
262     }
263
264     /*
265      * Ingress Classifier ACL NoMatch flow:
266      *     If there are no ACL classification matches, then resubmit back to
267      *     the Ingress Dispatcher to let other services handle the packet.
268      */
269     public Flow createIngressClassifierAclNoMatchFlow(NodeId nodeId) {
270         // This is a MatchAny flow
271         MatchBuilder match = new MatchBuilder();
272
273         List<Action> actionList = new ArrayList<>();
274         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE,
275                 actionList.size()));
276
277         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
278
279         String flowIdStr = INGRESS_CLASSIFIER_ACL_FLOW_NAME + "_" + nodeId.getValue();
280
281         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE,
282                 INGRESS_CLASSIFIER_ACL_NOMATCH_PRIORITY, INGRESS_CLASSIFIER_ACL_COOKIE,
283                 INGRESS_CLASSIFIER_ACL_FLOW_NAME, flowIdStr, match, isb).build();
284     }
285
286     //
287     // Internal EgressFlow util methods
288     //
289
290     /*
291      * Egress Classifier Filter NSH flow:
292      *     Only allows NSH packets to proceed in the egress classifier
293      *     Match on NSH MdType=1, Goto table Egress Classifier NextHop on match
294      * Since we need to check if the packet has passed through the classifier and has been
295      * encapsulated with NSH. We cant check for Vxgpe+NSH or Eth+NSH yet, since the outer
296      * encapsulation wont be added until the packet egresses, so instead check for NSH MD-type,
297      * which was set in the classification flow.
298      */
299     public Flow createEgressClassifierFilterNshFlow(NodeId nodeId) {
300         MatchBuilder match = new MatchBuilder();
301         OpenFlow13Utils.addMatchNshNsc1(match, ACL_FLAG_CONTEXT_VALUE);
302
303         List<Action> actionList = new ArrayList<>();
304         actionList.add(OpenFlow13Utils.createActionNxLoadNshc1(DEFAULT_NSH_CONTEXT_VALUE, actionList.size()));
305
306         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
307         isb = OpenFlow13Utils.appendGotoTableInstruction(isb, NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE);
308         String flowIdStr = EGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME + nodeId.getValue();
309
310         return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE,
311             EGRESS_CLASSIFIER_FILTER_NSH_PRIORITY, EGRESS_CLASSIFIER_FILTER_COOKIE,
312             EGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME, flowIdStr, match, isb).build();
313     }
314
315     /*
316      * Egress Classifier Filter No NSH flow:
317      *     Only allows NSH packets to proceed in the egress classifier
318      *     MatchAny (NSH not present), Resubmit to Egress Dispatcher
319      *     since the packet is not for SFC
320      */
321     public Flow createEgressClassifierFilterNoNshFlow(NodeId nodeId) {
322         MatchBuilder match = new MatchBuilder();
323
324         List<Action> actionList = new ArrayList<>();
325         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE,
326             actionList.size()));
327
328         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
329         String flowIdStr = EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME + nodeId.getValue();
330
331         return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE,
332             EGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY, EGRESS_CLASSIFIER_FILTER_COOKIE,
333             EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME, flowIdStr, match, isb).build();
334     }
335
336     /*
337      * Egress Classifier NextHop No C1/C2 flow:
338      *     Set C1/C2 accordingly
339      *     Match [C1, C2] == [0, 0], Move [TunIpv4Dst, TunVnid] to [C1, C2],
340      *     Move Reg0 (SFF IP) to TunIpv4Dst, and goto Egress Classifier
341      *     Transport Egress table on match
342      */
343     public Flow createEgressClassifierNextHopNoC1C2Flow(NodeId nodeId) {
344         MatchBuilder match = new MatchBuilder();
345         OpenFlow13Utils.addMatchNshNsc1(match, DEFAULT_NSH_CONTEXT_VALUE);
346         OpenFlow13Utils.addMatchNshNsc2(match, DEFAULT_NSH_CONTEXT_VALUE);
347
348         List<Action> actionList = new ArrayList<>();
349         actionList.add(OpenFlow13Utils.createActionNxMoveReg0ToNsc1Register(actionList.size()));
350         actionList.add(OpenFlow13Utils.createActionNxMoveTunIdToNsc2Register(actionList.size()));
351         actionList.add(OpenFlow13Utils.createActionNxMoveReg6ToNsc4Register(actionList.size()));
352         actionList.add(OpenFlow13Utils.createActionNxLoadTunId(SFC_TUNNEL_ID, actionList.size()));
353
354         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
355         OpenFlow13Utils.appendGotoTableInstruction(isb, NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE);
356         String flowIdStr = EGRESS_CLASSIFIER_NEXTHOP_NOC1C2_FLOW_NAME + nodeId.getValue();
357
358         return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE,
359             EGRESS_CLASSIFIER_NEXTHOP_NOC1C2_PRIORITY, EGRESS_CLASSIFIER_NEXTHOP_COOKIE,
360             EGRESS_CLASSIFIER_NEXTHOP_NOC1C2_FLOW_NAME, flowIdStr, match, isb).build();
361     }
362
363     /*
364      * Egress Classifier NextHop with C1/C2 flow:
365      *     Set C1/C2 accordingly
366      *     MatchAny (C1, C2 already set) goto Egress Classifier
367      *     Transport Egress table
368      */
369     public Flow createEgressClassifierNextHopC1C2Flow(NodeId nodeId) {
370         MatchBuilder match = new MatchBuilder();
371
372         InstructionsBuilder isb = OpenFlow13Utils.appendGotoTableInstruction(new InstructionsBuilder(),
373                 NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE);
374         String flowIdStr = EGRESS_CLASSIFIER_NEXTHOP_C1C2_FLOW_NAME + nodeId.getValue();
375
376         return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE,
377             EGRESS_CLASSIFIER_NEXTHOP_C1C2_PRIORITY, EGRESS_CLASSIFIER_NEXTHOP_COOKIE,
378             EGRESS_CLASSIFIER_NEXTHOP_C1C2_FLOW_NAME, flowIdStr, match, isb).build();
379     }
380
381     /*
382      * Egress Classifier TransportEgress Local Flow
383      *     Final egress processing and egress packets. Resubmit to Ingress
384      *     Dispatcher to be processed by SFC SFF on match
385      */
386     public Flow createEgressClassifierTransportEgressLocalFlow(NodeId nodeId, long nsp) {
387         MatchBuilder match = OpenFlow13Utils.getNspMatch(nsp);
388
389         List<Action> actionList = new ArrayList<>();
390         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.SFC_TRANSPORT_INGRESS_TABLE,
391             actionList.size()));
392
393         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
394         String flowIdStr = EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp;
395
396         return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE,
397             EGRESS_CLASSIFIER_EGRESS_LOCAL_PRIORITY, EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE,
398             EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME, flowIdStr, match, isb).build();
399     }
400
401     /*
402      * Egress Classifier TransportEgress Remote Flow
403      *     Final egress processing and egress packets. Determines if the
404      *     packet should go to a local or remote SFF.
405      *     Match on Nsp, Output to port to send to remote SFF on match.
406      */
407     public Flow createEgressClassifierTransportEgressRemoteFlow(NodeId nodeId, long nsp, long outport,
408                                                                 String firstHopIp) {
409         MatchBuilder match = OpenFlow13Utils.getNspMatch(nsp);
410
411         Long ipl = InetAddresses.coerceToInteger(InetAddresses.forString(firstHopIp)) & 0xffffffffL;
412         List<Action> actionList = new ArrayList<>();
413         actionList.add(OpenFlow13Utils.createActionNxLoadTunIpv4Dst(ipl, actionList.size()));
414         actionList.add(OpenFlow13Utils.createActionOutPort("output:" + outport, actionList.size()));
415
416         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
417         String flowIdStr = EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp;
418
419         return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE,
420             EGRESS_CLASSIFIER_EGRESS_REMOTE_PRIORITY, EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE,
421             EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME, flowIdStr, match, isb).build();
422     }
423
424     public static Long getPortNoFromNodeConnector(String connector) {
425         /*
426          * NodeConnectorId is of the form 'openflow:dpnid:portnum'
427          */
428         return Long.valueOf(connector.split(OF_URI_SEPARATOR)[2]);
429     }
430
431     public static BigInteger getDpnIdFromNodeId(NodeId nodeId) {
432         /*
433          * NodeId is of the form 'openflow:dpnid'
434          */
435         return BigInteger.valueOf(Long.parseLong(nodeId.getValue().split(OF_URI_SEPARATOR)[1]));
436     }
437
438 }