Add support for official OVS NSH implementation
[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.genius.infra.Datastore.Configuration;
18 import org.opendaylight.genius.infra.TypedWriteTransaction;
19 import org.opendaylight.genius.mdsalutil.NwConstants;
20 import org.opendaylight.netvirt.sfc.classifier.utils.AclMatches;
21 import org.opendaylight.netvirt.sfc.classifier.utils.OpenFlow13Utils;
22 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;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36
37 @Singleton
38 public class OpenFlow13Provider {
39     // Unique cookie values for each type of flow
40     public static final BigInteger INGRESS_CLASSIFIER_FILTER_COOKIE = new BigInteger("F005BA1100000001", 16);
41     public static final BigInteger INGRESS_CLASSIFIER_ACL_COOKIE = new BigInteger("F005BA1100000002", 16);
42     public static final BigInteger EGRESS_CLASSIFIER_FILTER_COOKIE = new BigInteger("F005BA1100000003", 16);
43     public static final BigInteger EGRESS_CLASSIFIER_NEXTHOP_COOKIE = new BigInteger("F005BA1100000004", 16);
44     public static final BigInteger EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE = new BigInteger("F005BA1100000005", 16);
45     public static final BigInteger INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_COOKIE =
46             new BigInteger("F005BA1100000006", 16);
47
48     // Priorities for each flow
49     public static final int INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_PRIORITY = 10;
50     public static final int INGRESS_CLASSIFIER_FILTER_CHAIN_EGRESS_PRIORITY = 520;
51     public static final int INGRESS_CLASSIFIER_FILTER_NSH_TUN_PRIORITY = 510;
52     public static final int INGRESS_CLASSIFIER_FILTER_NSH_PRIORITY = 511;
53     public static final int INGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY = 500;
54     public static final int INGRESS_CLASSIFIER_ACL_MATCH_PRIORITY = 500;
55     public static final int INGRESS_CLASSIFIER_ACL_NOMATCH_PRIORITY = 10;
56     public static final int EGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY = 260;
57     public static final int EGRESS_CLASSIFIER_FILTER_NSH_PRIORITY = 250;
58     public static final int EGRESS_CLASSIFIER_NEXTHOP_PRIORITY = 250;
59     public static final int EGRESS_CLASSIFIER_EGRESS_PRIORITY = 250;
60
61     // Flow names for each table
62     public static final String INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_ETH_NSH_TRAFFIC_FLOW_NAME =
63             "nvsfc_ingr_class_capture_sfc_tunnel_eth_nsh";
64     public static final String INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_NSH_TRAFFIC_FLOW_NAME =
65             "nvsfc_ingr_class_capture_sfc_tunnel_nsh";
66     public static final String INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME =
67             "nvsfc_ingr_class_filter_chain_egress";
68     public static final String INGRESS_CLASSIFIER_FILTER_NSH_TUN_FLOW_NAME = "nvsfc_ingr_class_filter_nsh_tun";
69     public static final String INGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME = "nvsfc_ingr_class_filter_nsh";
70     public static final String INGRESS_CLASSIFIER_FILTER_ETH_NSH_FLOW_NAME = "nvsfc_ingr_class_filter_eth_nsh";
71     public static final String INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME = "nvsfc_ingr_class_filter_nonsh";
72     public static final String INGRESS_CLASSIFIER_ACL_FLOW_NAME = "nvsfc_ingr_class_acl";
73     public static final String EGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME = "nvsfc_egr_class_filter_nsh";
74     public static final String EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME = "nvsfc_egr_class_filter_nonsh";
75     public static final String EGRESS_CLASSIFIER_NEXTHOP_FLOW_NAME = "nvsfc_egr_class_nexthop_noc1c2";
76     public static final String EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME = "nvsfc_egr_class_ tport egress";
77
78     public static final long SFC_TUNNEL_ID = 0L;
79     public static final String OF_URI_SEPARATOR = ":";
80     public static final Ipv4Address NULL_IP = new Ipv4Address("0.0.0.0");
81
82     public MatchBuilder getMatchBuilderFromAceMatches(Matches matches) {
83         if (matches == null) {
84             return null;
85         }
86
87         return new AclMatches(matches).buildMatch();
88     }
89
90     public void appendFlowForCreate(NodeId node, Flow flow, TypedWriteTransaction<Configuration> tx) {
91         NodeKey nodeKey = new NodeKey(node);
92         InstanceIdentifier<Flow> iidFlow = InstanceIdentifier.builder(Nodes.class)
93             .child(Node.class, nodeKey)
94             .augmentation(FlowCapableNode.class)
95             .child(Table.class, new TableKey(flow.getTableId()))
96             .child(Flow.class, flow.key())
97             .build();
98
99         tx.put(iidFlow, flow, WriteTransaction.CREATE_MISSING_PARENTS);
100     }
101
102     public void appendFlowForDelete(NodeId node, Flow flow, TypedWriteTransaction<Configuration> tx) {
103         NodeKey nodeKey = new NodeKey(node);
104         InstanceIdentifier<Flow> iidFlow = InstanceIdentifier.builder(Nodes.class)
105             .child(Node.class, nodeKey)
106             .augmentation(FlowCapableNode.class)
107             .child(Table.class, new TableKey(flow.getTableId()))
108             .child(Flow.class, flow.key())
109             .build();
110
111         tx.delete(iidFlow);
112     }
113
114     /*
115      * Ingress Classifier SFC Tunnel Traffic Capture Flow
116      *     Captures eth+nsh traffic coming from tunnel port, normalizes
117      *     the packet type to nsh by removing the outer ethernet header
118      *     and redirects it to the ingress classifier pipeline.
119      */
120     public Flow createIngressClassifierTunnelEthNshTrafficCaptureFlow(NodeId nodeId) {
121         MatchBuilder match = new MatchBuilder();
122         OpenFlow13Utils.addMatchTunId(match, SFC_TUNNEL_ID);
123         OpenFlow13Utils.addMatchEthNsh(match);
124
125         List<Action> actionList = new ArrayList<>();
126         actionList.add(OpenFlow13Utils.createActionNxDecap(actionList.size()));
127
128         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
129         OpenFlow13Utils.appendGotoTableInstruction(isb, NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE);
130         String flowIdStr = INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_ETH_NSH_TRAFFIC_FLOW_NAME + nodeId.getValue();
131
132
133         return OpenFlow13Utils.createFlowBuilder(NwConstants.INTERNAL_TUNNEL_TABLE,
134                 INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_PRIORITY,
135                 INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_COOKIE,
136                 INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_ETH_NSH_TRAFFIC_FLOW_NAME, flowIdStr, match, isb).build();
137     }
138
139     /*
140      * Ingress Classifier SFC Tunnel Traffic Capture Flow
141      *     Captures nsh traffic coming from tunnel port,
142      *     and redirects it to the ingress classifier pipeline.
143      */
144     public Flow createIngressClassifierTunnelNshTrafficCaptureFlow(NodeId nodeId) {
145         MatchBuilder match = new MatchBuilder();
146         OpenFlow13Utils.addMatchTunId(match, SFC_TUNNEL_ID);
147         OpenFlow13Utils.addMatchPacketTypeNsh(match);
148
149         InstructionsBuilder isb = new InstructionsBuilder();
150         OpenFlow13Utils.appendGotoTableInstruction(isb, NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE);
151         String flowIdStr = INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_NSH_TRAFFIC_FLOW_NAME + nodeId.getValue();
152
153
154         return OpenFlow13Utils.createFlowBuilder(NwConstants.INTERNAL_TUNNEL_TABLE,
155                 INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_PRIORITY,
156                 INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_TRAFFIC_COOKIE,
157                 INGRESS_CLASSIFIER_CAPTURE_SFC_TUNNEL_NSH_TRAFFIC_FLOW_NAME, flowIdStr, match, isb).build();
158     }
159
160     /*
161      * Ingress Classifier Filter tunnel packet type NSH flow:
162      *     Prevents nsh packets coming from a tunnel port to proceed.
163      *     This is the least priority filter flow so it wont match
164      *     packets coming from other than tunnel ports.
165      *     Since no service port binding and thus no dispatching is
166      *     available on tunnel port, resubmit direct to SFC pipeline.
167      */
168     public Flow createIngressClassifierFilterTunnelNshFlow(NodeId nodeId) {
169         MatchBuilder match = new MatchBuilder();
170         OpenFlow13Utils.addMatchPacketTypeNsh(match);
171
172         List<Action> actionList = new ArrayList<>();
173         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.SFC_TRANSPORT_INGRESS_TABLE,
174             actionList.size()));
175
176         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
177         String flowIdStr = INGRESS_CLASSIFIER_FILTER_NSH_TUN_FLOW_NAME + nodeId.getValue();
178
179         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
180                 INGRESS_CLASSIFIER_FILTER_NSH_TUN_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
181                 INGRESS_CLASSIFIER_FILTER_NSH_TUN_FLOW_NAME, flowIdStr, match, isb).build();
182     }
183
184     /*
185      * Ingress Classifier Filter Eth NSH flow:
186      *     Prevents eth+nsh packets coming from other than a tunnel port
187      *     to proceed. Verify that packet are not coming from tunnel
188      *     by verifying there is no tunnel ip set with high priority
189      *     flow. Resubmit to ingress dispatcher so that other nsh
190      *     service handles the packet.
191      */
192     public Flow createIngressClassifierFilterEthNshFlow(NodeId nodeId) {
193         MatchBuilder match = new MatchBuilder();
194         OpenFlow13Utils.addMatchEthNsh(match);
195         OpenFlow13Utils.addMatchTunDstIp(match, NULL_IP);
196
197         List<Action> actionList = new ArrayList<>();
198         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE,
199             actionList.size()));
200
201         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
202         String flowIdStr = INGRESS_CLASSIFIER_FILTER_ETH_NSH_FLOW_NAME + nodeId.getValue();
203
204         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
205                 INGRESS_CLASSIFIER_FILTER_NSH_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
206                 INGRESS_CLASSIFIER_FILTER_ETH_NSH_FLOW_NAME, flowIdStr, match, isb).build();
207     }
208
209     /*
210      * Ingress Classifier Filter packet type NSH floww:
211      *     Prevents nsh packets coming from other than a tunnel port
212      *     to proceed. Verify that packet are not coming from tunnel
213      *     by checking there is no tunnel ip set with high priority
214      *     flow. Resubmit to ingress dispatcher so that other nsh
215      *     service handles the packet.
216      */
217     public Flow createIngressClassifierFilterNshFlow(NodeId nodeId) {
218         MatchBuilder match = new MatchBuilder();
219         OpenFlow13Utils.addMatchPacketTypeNsh(match);
220         OpenFlow13Utils.addMatchTunDstIp(match, NULL_IP);
221
222         List<Action> actionList = new ArrayList<>();
223         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE,
224                 actionList.size()));
225
226         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
227         String flowIdStr = INGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME + nodeId.getValue();
228
229         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
230                 INGRESS_CLASSIFIER_FILTER_NSH_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
231                 INGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME, flowIdStr, match, isb).build();
232     }
233
234     /*
235      * Classifier chain termination flow:
236      *     Handle packets at the end of the chain for which the final
237      *     destination might be the classifier node.
238      *     Match nsh packets on classified paths at their final index.
239      *     Restores the lport tag on reg6, removes the nsh header and
240      *     resubmits to egress dispatcher.
241      */
242     public Flow createIngressClassifierFilterChainEgressFlow(NodeId nodeId, long nsp, short egressNsi) {
243
244         MatchBuilder match = new MatchBuilder();
245         OpenFlow13Utils.addMatchPacketTypeNsh(match);
246         OpenFlow13Utils.addMatchNsp(match, nsp);
247         OpenFlow13Utils.addMatchNsi(match, egressNsi);
248
249         List<Action> actionList = new ArrayList<>();
250         actionList.add(OpenFlow13Utils.createActionNxMoveNsc4ToReg6Register(actionList.size()));
251         actionList.add(OpenFlow13Utils.createActionNxDecap(actionList.size()));
252         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE,
253                 actionList.size()));
254
255         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
256         String flowIdStr = INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp;
257
258         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
259                 INGRESS_CLASSIFIER_FILTER_CHAIN_EGRESS_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
260                 INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME, flowIdStr, match, isb).build();
261     }
262
263     /*
264      * Ingress Classifier Filter No NSH flow:
265      *     Non nsh packets, those that have not been matched by other
266      *     higher priority nsh matching flows, proceed to the ACL
267      *     table.
268      */
269     public Flow createIngressClassifierFilterNoNshFlow(NodeId nodeId) {
270         // MatchAny
271         MatchBuilder match = new MatchBuilder();
272
273         InstructionsBuilder isb = OpenFlow13Utils.appendGotoTableInstruction(new InstructionsBuilder(),
274             NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE);
275         String flowIdStr = INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME + nodeId.getValue();
276
277         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
278                 INGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
279                 INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME, flowIdStr, match, isb).build();
280     }
281
282     /*
283      * Ingress Classifier ACL flow:
284      *     Performs the ACL classification, and sends packets to back
285      *     to ingress dispatcher.
286      *     Add the in_port (corresponds to Neutron NW/tenant) to the ACL match,
287      *     and sets the nsp and nsi on the registry for later usage.
288      */
289     public Flow createIngressClassifierAclFlow(NodeId nodeId, MatchBuilder match, Long port, long nsp, short nsi) {
290         OpenFlow13Utils.addMatchInPort(match, nodeId, port);
291
292         List<Action> actionList = new ArrayList<>();
293         actionList.add(OpenFlow13Utils.createActionNxLoadNspToReg2High(nsp, actionList.size()));
294         actionList.add(OpenFlow13Utils.createActionNxLoadNsiToReg2Low(nsi, actionList.size()));
295
296         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE,
297             actionList.size()));
298
299         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
300
301         // The flowIdStr needs to be unique, so the best way to make it unique is to use the match
302         String flowIdStr = INGRESS_CLASSIFIER_ACL_FLOW_NAME + "_" + nodeId.getValue() + match.build().toString();
303
304         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE,
305                 INGRESS_CLASSIFIER_ACL_MATCH_PRIORITY, INGRESS_CLASSIFIER_ACL_COOKIE, INGRESS_CLASSIFIER_ACL_FLOW_NAME,
306             flowIdStr, match, isb).build();
307     }
308
309     /*
310      * Ingress Classifier ACL NoMatch flow:
311      *     If there are no ACL classification matches, then resubmit back to
312      *     the Ingress Dispatcher to let other services handle the packet.
313      */
314     public Flow createIngressClassifierAclNoMatchFlow(NodeId nodeId) {
315         // This is a MatchAny flow
316         MatchBuilder match = new MatchBuilder();
317
318         List<Action> actionList = new ArrayList<>();
319         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE,
320                 actionList.size()));
321
322         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
323
324         String flowIdStr = INGRESS_CLASSIFIER_ACL_FLOW_NAME + "_" + nodeId.getValue();
325
326         return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE,
327                 INGRESS_CLASSIFIER_ACL_NOMATCH_PRIORITY, INGRESS_CLASSIFIER_ACL_COOKIE,
328                 INGRESS_CLASSIFIER_ACL_FLOW_NAME, flowIdStr, match, isb).build();
329     }
330
331     //
332     // Internal EgressFlow util methods
333     //
334
335     /*
336      * Egress Classifier Filter NoNsh flow:
337      *     Filters out packets that have not been classified in the
338       *    ingress classifier, those for which registry has not
339      *     been set with nsp and nsi. Resubmit to egress dispatcher.
340      */
341     public Flow createEgressClassifierFilterNoNshFlow(NodeId nodeId) {
342         MatchBuilder match = new MatchBuilder();
343
344         OpenFlow13Utils.addMatchReg2(match, 0);
345
346         List<Action> actionList = new ArrayList<>();
347         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE,
348                 actionList.size()));
349
350         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
351         String flowIdStr = EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME + nodeId.getValue();
352
353         return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE,
354                 EGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY, EGRESS_CLASSIFIER_FILTER_COOKIE,
355                 EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME, flowIdStr, match, isb).build();
356     }
357
358     /*
359      * Egress Classifier Filter Nsh flow.
360      *     Packets proceed to NextHop table.
361      */
362     public Flow createEgressClassifierFilterNshFlow(NodeId nodeId) {
363         MatchBuilder match = new MatchBuilder();
364
365         InstructionsBuilder isb = new InstructionsBuilder();
366         isb = OpenFlow13Utils.appendGotoTableInstruction(isb, NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE);
367         String flowIdStr = EGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME + nodeId.getValue();
368
369         return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE,
370                 EGRESS_CLASSIFIER_FILTER_NSH_PRIORITY, EGRESS_CLASSIFIER_FILTER_COOKIE,
371                 EGRESS_CLASSIFIER_FILTER_NSH_FLOW_NAME, flowIdStr, match, isb).build();
372     }
373
374     /*
375      * Egress Classifier NextHop flow:
376      *     Encapsulates the packet and sets the NSH header values.
377      *     Packets proceed to TransportEgress table.
378      */
379     public Flow createEgressClassifierNextHopFlow(NodeId nodeId) {
380         final MatchBuilder match = new MatchBuilder();
381
382         List<Action> actionList = new ArrayList<>();
383         actionList.add(OpenFlow13Utils.createActionNxEncapNsh(actionList.size()));
384         actionList.add(OpenFlow13Utils.createActionNxMoveReg2HighToNsp(actionList.size()));
385         actionList.add(OpenFlow13Utils.createActionNxMoveReg2LowToNsi(actionList.size()));
386         actionList.add(OpenFlow13Utils.createActionNxLoadReg2(0, actionList.size()));
387         actionList.add(OpenFlow13Utils.createActionNxMoveReg0ToNsc1Register(actionList.size()));
388         actionList.add(OpenFlow13Utils.createActionNxMoveTunIdToNsc2Register(actionList.size()));
389         actionList.add(OpenFlow13Utils.createActionNxMoveReg6ToNsc4Register(actionList.size()));
390         actionList.add(OpenFlow13Utils.createActionNxLoadTunId(SFC_TUNNEL_ID, actionList.size()));
391
392         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
393         OpenFlow13Utils.appendGotoTableInstruction(isb, NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE);
394         String flowIdStr = EGRESS_CLASSIFIER_NEXTHOP_FLOW_NAME + nodeId.getValue();
395
396         return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE,
397                 EGRESS_CLASSIFIER_NEXTHOP_PRIORITY, EGRESS_CLASSIFIER_NEXTHOP_COOKIE,
398                 EGRESS_CLASSIFIER_NEXTHOP_FLOW_NAME, flowIdStr, match, isb).build();
399     }
400
401     /*
402      * Egress Classifier TransportEgress Local Flow
403      *     First SFF is located on same node. NSH packets are
404      *     sent to the SFC pipeline.
405      */
406     public Flow createEgressClassifierTransportEgressLocalFlow(NodeId nodeId, long nsp) {
407         MatchBuilder match = new MatchBuilder();
408
409         OpenFlow13Utils.addMatchPacketTypeNsh(match);
410         OpenFlow13Utils.addMatchNsp(match, nsp);
411
412         List<Action> actionList = new ArrayList<>();
413         actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.SFC_TRANSPORT_INGRESS_TABLE,
414             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_PRIORITY, EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE,
421                 EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME, flowIdStr, match, isb).build();
422     }
423
424     /*
425      * Egress Classifier TransportEgress Remote Flow
426      *     Sends packet to a remote SFF ip though a tunnel port.
427      *     Packets are not encapsulated with an extra ethernet header.
428      */
429     public Flow createEgressClassifierTransportEgressRemoteNshFlow(NodeId nodeId, long nsp, long outport,
430                                                                    String firstHopIp) {
431         MatchBuilder match = new MatchBuilder();
432
433         OpenFlow13Utils.addMatchPacketTypeNsh(match);
434         OpenFlow13Utils.addMatchNsp(match, nsp);
435
436         Long ipl = InetAddresses.coerceToInteger(InetAddresses.forString(firstHopIp)) & 0xffffffffL;
437         List<Action> actionList = new ArrayList<>();
438         actionList.add(OpenFlow13Utils.createActionNxLoadTunIpv4Dst(ipl, actionList.size()));
439         actionList.add(OpenFlow13Utils.createActionOutPort("output:" + outport, actionList.size()));
440
441         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
442         String flowIdStr = EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp;
443
444         return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE,
445                 EGRESS_CLASSIFIER_EGRESS_PRIORITY, EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE,
446                 EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME, flowIdStr, match, isb).build();
447     }
448
449     /*
450      * Egress Classifier TransportEgress Remote Flow
451      *     Sends packet to a remote SFF ip though a tunnel port.
452      *     Packets are encapsulated with an extra ethernet header.
453      */
454     public Flow createEgressClassifierTransportEgressRemoteEthNshFlow(NodeId nodeId, long nsp, long outport,
455                                                                       String firstHopIp) {
456         MatchBuilder match = new MatchBuilder();
457
458         OpenFlow13Utils.addMatchPacketTypeNsh(match);
459         OpenFlow13Utils.addMatchNsp(match, nsp);
460
461         Long ipl = InetAddresses.coerceToInteger(InetAddresses.forString(firstHopIp)) & 0xffffffffL;
462         List<Action> actionList = new ArrayList<>();
463         actionList.add(OpenFlow13Utils.createActionNxEncapEthernet(actionList.size()));
464         actionList.add(OpenFlow13Utils.createActionNxLoadTunIpv4Dst(ipl, actionList.size()));
465         actionList.add(OpenFlow13Utils.createActionOutPort("output:" + outport, actionList.size()));
466
467         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
468         String flowIdStr = EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp;
469
470         return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE,
471                 EGRESS_CLASSIFIER_EGRESS_PRIORITY, EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE,
472                 EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME, flowIdStr, match, isb).build();
473     }
474
475
476
477     public static Long getPortNoFromNodeConnector(String connector) {
478         /*
479          * NodeConnectorId is of the form 'openflow:dpnid:portnum'
480          */
481         return Long.valueOf(connector.split(OF_URI_SEPARATOR)[2]);
482     }
483
484     public static BigInteger getDpnIdFromNodeId(NodeId nodeId) {
485         /*
486          * NodeId is of the form 'openflow:dpnid'
487          */
488         return BigInteger.valueOf(Long.parseLong(nodeId.getValue().split(OF_URI_SEPARATOR)[1]));
489     }
490
491 }