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