Update .gitreview for new repo
[netvirt.git] / openstack / net-virt-sfc / impl / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / sfc / workaround / services / SfcClassifierService.java
1 /*
2  * Copyright © 2015 Red Hat, 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.ovsdb.openstack.netvirt.sfc.workaround.services;
10
11 import com.google.common.collect.Lists;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Map;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
21 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
22 import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
23 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
24 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
25 import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcClassifierService;
26 import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
27 import org.opendaylight.ovsdb.utils.mdsal.openflow.ActionUtils;
28 import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
29 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
30 import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
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.FlowCookie;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.osgi.framework.BundleContext;
56 import org.osgi.framework.ServiceReference;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface, ISfcClassifierService {
61     private static final Logger LOG = LoggerFactory.getLogger(SfcClassifierService.class);
62     private static final short UDP_SHORT = 17;
63     static int cookieIndex = 0;
64     private FlowCache flowCache = new FlowCache();
65
66     private enum FlowID {
67         FLOW_INGRESSCLASS(1), FLOW_SFINGRESS(2), FLOW_SFEGRESS(3), FLOW_SFARP(4),
68         FLOW_EGRESSCLASSUNUSED(5), FLOW_EGRESSCLASS(6), FLOW_EGRESSCLASSBYPASS(7), FLOW_SFCTABLE(8);
69
70         private int value;
71         FlowID(int value) {
72             this.value = value;
73         }
74     }
75
76     private BigInteger getCookie(FlowID flowID) {
77         String cookieString = String.format("1110%02d%010d", flowID.value, cookieIndex++);
78         return new BigInteger(cookieString, 16);
79     }
80
81     private BigInteger getCookie(FlowID flowID, short nsp, short nsi) {
82         String cookieString = String.format("1110%02d%03d%03d0%03d", flowID.value, 0, nsp, nsi);
83         return new BigInteger(cookieString, 16);
84     }
85
86     public SfcClassifierService(Service service) {
87         super(service);
88     }
89
90     public SfcClassifierService() {
91         super(Service.SFC_CLASSIFIER);
92     }
93
94     @Override
95     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
96         super.setDependencies(bundleContext.getServiceReference(ISfcClassifierService.class.getName()), this);
97     }
98
99     @Override
100     public void setDependencies(Object impl) {}
101
102     private FlowBuilder initFlowBuilder(FlowBuilder flowBuilder, String flowName, short table, FlowID flowID) {
103         FlowUtils.initFlowBuilder(flowBuilder, flowName, table)
104                 .setCookie(new FlowCookie(getCookie(flowID)))
105                 .setCookieMask(new FlowCookie(getCookie(flowID)));
106         return flowBuilder;
107     }
108
109     private FlowBuilder initFlowBuilder(FlowBuilder flowBuilder, String flowName, short table, FlowID flowID,
110                                         short nsp, short nsi) {
111         FlowUtils.initFlowBuilder(flowBuilder, flowName, table)
112                 .setCookie(new FlowCookie(getCookie(flowID, nsp, nsi)))
113                 .setCookieMask(new FlowCookie(getCookie(flowID, nsp, nsi)));
114         return flowBuilder;
115     }
116
117     private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder, String rspName, FlowID flowID) {
118         flowCache.addFlow(flowBuilder, nodeBuilder, rspName, flowID.value);
119         writeFlow(flowBuilder, nodeBuilder);
120     }
121
122     private void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder, String rspName, FlowID flowID) {
123         flowCache.removeFlow(rspName, flowID.value);
124         removeFlow(flowBuilder, nodeBuilder);
125     }
126
127     @Override
128     public void programIngressClassifier(long dataPathId, String ruleName, Matches matches, long nsp, short nsi,
129                                          NshUtils nshHeader, long vxGpeOfPort, String rspName, boolean write) {
130         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
131         FlowBuilder flowBuilder = new FlowBuilder();
132         String flowName = FlowNames.getSfcIngressClass(ruleName, nsp, nsi);
133         initFlowBuilder(flowBuilder, flowName, getTable(), FlowID.FLOW_INGRESSCLASS,
134                 (short)nshHeader.getNshNsp(), nshHeader.getNshNsi());
135
136         MatchBuilder matchBuilder = new AclMatches(matches).buildMatch();
137         MatchUtils.addNxRegMatch(matchBuilder,
138                 MatchUtils.RegMatch.of(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL));
139         flowBuilder.setMatch(matchBuilder.build());
140
141         if (write) {
142             ActionBuilder ab = new ActionBuilder();
143             List<Action> actionList = new ArrayList<>();
144
145             ab.setAction(ActionUtils.nxMoveTunIdtoNshc2());
146             ab.setOrder(actionList.size());
147             ab.setKey(new ActionKey(actionList.size()));
148             actionList.add(ab.build());
149
150             getNshAction(nshHeader, actionList);
151
152             if (vxGpeOfPort != 0) {
153                 ab.setAction(ActionUtils.outputAction(FlowUtils.getNodeConnectorId(dataPathId, vxGpeOfPort)));
154                 ab.setOrder(actionList.size());
155                 ab.setKey(new ActionKey(actionList.size()));
156                 actionList.add(ab.build());
157             } else {
158                 ab.setAction(ActionUtils.nxResubmitAction(null, Service.CLASSIFIER.getTable()));
159                 ab.setOrder(actionList.size());
160                 ab.setKey(new ActionKey(actionList.size()));
161                 actionList.add(ab.build());
162             }
163
164             ApplyActionsBuilder aab = new ApplyActionsBuilder();
165             aab.setAction(actionList);
166
167             InstructionBuilder ib = new InstructionBuilder();
168             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
169             ib.setOrder(0);
170             ib.setKey(new InstructionKey(0));
171             List<Instruction> instructions = Lists.newArrayList();
172             instructions.add(ib.build());
173
174             InstructionsBuilder isb = new InstructionsBuilder();
175             isb.setInstruction(instructions);
176             flowBuilder.setInstructions(isb.build());
177             writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_INGRESSCLASS);
178         } else {
179             removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_INGRESSCLASS);
180         }
181     }
182
183     @Override
184     public void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write) {
185         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
186         FlowBuilder flowBuilder = new FlowBuilder();
187         String flowName = FlowNames.getSfcTable(vxGpeOfPort);
188         initFlowBuilder(flowBuilder, flowName, getTable(Service.CLASSIFIER), FlowID.FLOW_SFCTABLE)
189                 .setPriority(1000);
190
191         MatchBuilder matchBuilder = new MatchBuilder();
192         MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort);
193         flowBuilder.setMatch(matchBuilder.build());
194
195         if (write) {
196             InstructionsBuilder isb = new InstructionsBuilder();
197             List<Instruction> instructions = Lists.newArrayList();
198             InstructionBuilder ib =
199                     InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), goToTableId);
200             ib.setOrder(0);
201             ib.setKey(new InstructionKey(0));
202             instructions.add(ib.build());
203
204             isb.setInstruction(instructions);
205             flowBuilder.setInstructions(isb.build());
206             writeFlow(flowBuilder, nodeBuilder);
207         } else {
208             removeFlow(flowBuilder, nodeBuilder);
209         }
210     }
211
212     @Override
213     public void programEgressClassifier1(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
214                                          int tunnelOfPort, int tunnelId, short gotoTableId, boolean write) {
215         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
216         FlowBuilder flowBuilder = new FlowBuilder();
217         String flowName = FlowNames.getSfcEgressClass1(vxGpeOfPort);
218         initFlowBuilder(flowBuilder, flowName, getTable(Service.CLASSIFIER), FlowID.FLOW_EGRESSCLASSUNUSED,
219                 (short)nsp, nsi);
220
221         MatchBuilder matchBuilder = new MatchBuilder();
222         MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort);
223         MatchUtils.addNxNspMatch(matchBuilder, nsp);
224         MatchUtils.addNxNsiMatch(matchBuilder, nsi);
225         flowBuilder.setMatch(matchBuilder.build());
226
227         if (write) {
228             InstructionsBuilder isb = new InstructionsBuilder();
229             List<Instruction> instructions = Lists.newArrayList();
230
231             InstructionBuilder ib = InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), getTable());
232             ib.setOrder(instructions.size());
233             ib.setKey(new InstructionKey(instructions.size()));
234             instructions.add(ib.build());
235
236             isb.setInstruction(instructions);
237             flowBuilder.setInstructions(isb.build());
238             writeFlow(flowBuilder, nodeBuilder);
239         } else {
240             removeFlow(flowBuilder, nodeBuilder);
241         }
242     }
243
244     @Override
245     public void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
246                                         long sfOfPort, int tunnelId, String rspName, boolean write) {
247         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
248         FlowBuilder flowBuilder = new FlowBuilder();
249         String flowName = FlowNames.getSfcEgressClass(vxGpeOfPort, nsp, nsi);
250         initFlowBuilder(flowBuilder, flowName, getTable(Service.SFC_CLASSIFIER), FlowID.FLOW_EGRESSCLASS,
251                 (short)nsp, nsi);
252
253         MatchBuilder matchBuilder = new MatchBuilder();
254         MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort);
255         MatchUtils.addNxNspMatch(matchBuilder, nsp);
256         MatchUtils.addNxNsiMatch(matchBuilder, nsi);
257         flowBuilder.setMatch(matchBuilder.build());
258
259         if (write) {
260             InstructionsBuilder isb = new InstructionsBuilder();
261             List<Instruction> instructions = Lists.newArrayList();
262             List<Action> actionList = Lists.newArrayList();
263
264             ActionBuilder ab = new ActionBuilder();
265
266             ab.setAction(
267                     ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(FlowUtils.REG_FIELD).build(),
268                     BigInteger.valueOf(FlowUtils.REG_VALUE_FROM_LOCAL)));
269             ab.setOrder(actionList.size());
270             ab.setKey(new ActionKey(actionList.size()));
271             actionList.add(ab.build());
272
273             ab.setAction(ActionUtils.nxMoveNshc2ToTunId());
274             ab.setOrder(actionList.size());
275             ab.setKey(new ActionKey(actionList.size()));
276             actionList.add(ab.build());
277
278             ab.setAction(ActionUtils.nxResubmitAction((int)sfOfPort, getTable(Service.CLASSIFIER)));
279             ab.setOrder(actionList.size());
280             ab.setKey(new ActionKey(actionList.size()));
281             actionList.add(ab.build());
282
283             ApplyActionsBuilder aab = new ApplyActionsBuilder();
284             aab.setAction(actionList);
285             InstructionBuilder ib = new InstructionBuilder();
286             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
287
288             ib.setOrder(0);
289             ib.setKey(new InstructionKey(0));
290             instructions.add(ib.build());
291
292             isb.setInstruction(instructions);
293             flowBuilder.setInstructions(isb.build());
294             writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASS);
295         } else {
296             removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASS);
297         }
298     }
299
300     @Override
301     public void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
302                                               long sfOfPort, int tunnelId, String rspName, boolean write) {
303         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
304         FlowBuilder flowBuilder = new FlowBuilder();
305         String flowName = FlowNames.getSfcEgressClassBypass(nsp, nsi, sfOfPort);
306         initFlowBuilder(flowBuilder, flowName, getTable(Service.CLASSIFIER),
307                 FlowID.FLOW_EGRESSCLASSBYPASS, (short)nsp, nsi)
308                 .setPriority(40000);
309
310         MatchBuilder matchBuilder = new MatchBuilder();
311         MatchUtils.createInPortMatch(matchBuilder, dataPathId, sfOfPort);
312         MatchUtils.addNxRegMatch(matchBuilder,
313                 MatchUtils.RegMatch.of(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL));
314         MatchUtils.addNxNspMatch(matchBuilder, nsp);
315         MatchUtils.addNxNsiMatch(matchBuilder, nsi);
316         flowBuilder.setMatch(matchBuilder.build());
317
318         if (write) {
319             InstructionsBuilder isb = new InstructionsBuilder();
320             List<Instruction> instructions = Lists.newArrayList();
321
322             InstructionBuilder ib;
323             ib = this.getMutablePipelineInstructionBuilder();
324             ib.setOrder(0);
325             ib.setKey(new InstructionKey(0));
326             instructions.add(ib.build());
327
328             isb.setInstruction(instructions);
329             flowBuilder.setInstructions(isb.build());
330             writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASSBYPASS);
331         } else {
332             removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASSBYPASS);
333         }
334     }
335
336     // packet from sf to sff that need to go out local
337     @Override
338     public void program_sfEgress(long dataPathId, int dstPort, String rspName, boolean write) {
339         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
340         FlowBuilder flowBuilder = new FlowBuilder();
341         String flowName = FlowNames.getSfEgress(dstPort);
342         initFlowBuilder(flowBuilder, flowName, getTable(), FlowID.FLOW_SFEGRESS);
343
344         MatchBuilder matchBuilder = new MatchBuilder();
345         MatchUtils.createIpProtocolMatch(matchBuilder, UDP_SHORT);
346         MatchUtils.addLayer4Match(matchBuilder, UDP_SHORT, 0, dstPort);
347         MatchUtils.addNxRegMatch(matchBuilder,
348                 MatchUtils.RegMatch.of(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL));
349         flowBuilder.setMatch(matchBuilder.build());
350
351         if (write) {
352             InstructionBuilder ib = new InstructionBuilder();
353             InstructionsBuilder isb = new InstructionsBuilder();
354             List<Instruction> instructions = Lists.newArrayList();
355             InstructionUtils.createLocalInstructions(ib, dataPathId);
356             ib.setOrder(0);
357             ib.setKey(new InstructionKey(0));
358             instructions.add(ib.build());
359
360             isb.setInstruction(instructions);
361             flowBuilder.setInstructions(isb.build());
362             writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFEGRESS);
363         } else {
364             removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFEGRESS);
365         }
366     }
367
368     // looped back sff to sf packets
369     @Override
370     public void program_sfIngress(long dataPathId, int dstPort, long sfOfPort,
371                                   String ipAddress, String sfDplName, String rspName, boolean write) {
372         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
373         FlowBuilder flowBuilder = new FlowBuilder();
374         String flowName = FlowNames.getSfIngress(dstPort, ipAddress);
375         initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable(), FlowID.FLOW_SFINGRESS);
376
377         MatchBuilder matchBuilder = new MatchBuilder();
378         MatchUtils.createIpProtocolMatch(matchBuilder, UDP_SHORT);
379         Ipv4Prefix ipCidr = MatchUtils.iPv4PrefixFromIPv4Address(ipAddress);
380         MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(ipCidr));
381         MatchUtils.addLayer4Match(matchBuilder, UDP_SHORT, 0, dstPort);
382         flowBuilder.setMatch(matchBuilder.build());
383
384         if (write) {
385             InstructionBuilder ib = new InstructionBuilder();
386             InstructionsBuilder isb = new InstructionsBuilder();
387             List<Instruction> instructions = Lists.newArrayList();
388             InstructionUtils.createOutputPortInstructions(ib, dataPathId, sfOfPort);
389
390             ib.setOrder(0);
391             ib.setKey(new InstructionKey(0));
392             instructions.add(ib.build());
393
394             isb.setInstruction(instructions);
395             flowBuilder.setInstructions(isb.build());
396             writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFINGRESS);
397         } else {
398             removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFINGRESS);
399         }
400     }
401
402     @Override
403     public void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
404                                       String ipAddress, String rspName, boolean write) {
405         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
406         FlowBuilder flowBuilder = new FlowBuilder();
407         String flowName = FlowNames.getArpResponder(ipAddress);
408         initFlowBuilder(flowBuilder, flowName, getTable(Service.ARP_RESPONDER), FlowID.FLOW_SFARP)
409                 .setPriority(1024);
410
411         MacAddress macAddress = new MacAddress(macAddressStr);
412
413         MatchBuilder matchBuilder = new MatchBuilder();
414         MatchUtils.createInPortReservedMatch(matchBuilder, dataPathId, OutputPortValues.LOCAL.toString());
415         MatchUtils.createEtherTypeMatch(matchBuilder, new EtherType(Constants.ARP_ETHERTYPE));
416         MatchUtils.createArpDstIpv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(ipAddress));
417         flowBuilder.setMatch(matchBuilder.build());
418
419         if (write) {
420             InstructionBuilder ib = new InstructionBuilder();
421             InstructionsBuilder isb = new InstructionsBuilder();
422             List<Instruction> instructions = Lists.newArrayList();
423             ApplyActionsBuilder aab = new ApplyActionsBuilder();
424             ActionBuilder ab = new ActionBuilder();
425             List<Action> actionList = Lists.newArrayList();
426
427             // Move Eth Src to Eth Dst
428             ab.setAction(ActionUtils.nxMoveEthSrcToEthDstAction());
429             ab.setOrder(0);
430             ab.setKey(new ActionKey(0));
431             actionList.add(ab.build());
432
433             // Set Eth Src
434             ab.setAction(ActionUtils.setDlSrcAction(new MacAddress(macAddress)));
435             ab.setOrder(1);
436             ab.setKey(new ActionKey(1));
437             actionList.add(ab.build());
438
439             // Set ARP OP
440             ab.setAction(ActionUtils.nxLoadArpOpAction(BigInteger.valueOf(FlowUtils.ARP_OP_REPLY)));
441             ab.setOrder(2);
442             ab.setKey(new ActionKey(2));
443             actionList.add(ab.build());
444
445             // Move ARP SHA to ARP THA
446             ab.setAction(ActionUtils.nxMoveArpShaToArpThaAction());
447             ab.setOrder(3);
448             ab.setKey(new ActionKey(3));
449             actionList.add(ab.build());
450
451             // Move ARP SPA to ARP TPA
452             ab.setAction(ActionUtils.nxMoveArpSpaToArpTpaAction());
453             ab.setOrder(4);
454             ab.setKey(new ActionKey(4));
455             actionList.add(ab.build());
456
457             // Load Mac to ARP SHA
458             ab.setAction(ActionUtils.nxLoadArpShaAction(macAddress));
459             ab.setOrder(5);
460             ab.setKey(new ActionKey(5));
461             actionList.add(ab.build());
462
463             // Load IP to ARP SPA
464             ab.setAction(ActionUtils.nxLoadArpSpaAction(ipAddress));
465             ab.setOrder(6);
466             ab.setKey(new ActionKey(6));
467             actionList.add(ab.build());
468
469             // Output of InPort
470             ab.setAction(ActionUtils.outputAction(
471                     FlowUtils.getSpecialNodeConnectorId(dataPathId, OutputPortValues.INPORT.toString())));
472             ab.setOrder(7);
473             ab.setKey(new ActionKey(7));
474             actionList.add(ab.build());
475
476             // Create Apply Actions Instruction
477             aab.setAction(actionList);
478             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
479             ib.setOrder(0);
480             ib.setKey(new InstructionKey(0));
481             instructions.add(ib.build());
482
483             isb.setInstruction(instructions);
484             flowBuilder.setInstructions(isb.build());
485             writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFARP);
486         } else {
487             removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFARP);
488         }
489     }
490
491     private List<Action> getNshAction(NshUtils header, List<Action> actionList) {
492         // Build the Actions to Add the NSH Header
493         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC1Load =
494                 ActionUtils.nxLoadNshc1RegAction(header.getNshMetaC1());
495         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nspLoad =
496                 ActionUtils.nxSetNspAction(header.getNshNsp());
497         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nsiLoad =
498                 ActionUtils.nxSetNsiAction(header.getNshNsi());
499         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunVnid =
500                 ActionUtils.nxLoadTunIdAction(BigInteger.valueOf(header.getNshNsp()), false);
501         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunDest =
502                 ActionUtils.nxLoadTunIPv4Action(header.getNshTunIpDst().getValue(), false);
503
504         int count = actionList.size();
505         actionList.add(new ActionBuilder()
506                 .setKey(new ActionKey(count)).setOrder(count++).setAction(nshC1Load).build());
507         actionList.add(new ActionBuilder()
508                 .setKey(new ActionKey(count)).setOrder(count++).setAction(nspLoad).build());
509         actionList.add(new ActionBuilder()
510                 .setKey(new ActionKey(count)).setOrder(count++).setAction(nsiLoad).build());
511         actionList.add(new ActionBuilder()
512                 .setKey(new ActionKey(count)).setOrder(count++).setAction(loadChainTunDest).build());
513         actionList.add(new ActionBuilder()
514                 .setKey(new ActionKey(count)).setOrder(count).setAction(loadChainTunVnid).build());
515         return actionList;
516     }
517
518     private static FlowID flowSet[] = {FlowID.FLOW_INGRESSCLASS, FlowID.FLOW_EGRESSCLASS,
519             FlowID.FLOW_EGRESSCLASSBYPASS, FlowID.FLOW_SFARP, FlowID.FLOW_SFINGRESS, FlowID.FLOW_SFEGRESS};
520
521     @Override
522     public void clearFlows(DataBroker dataBroker, String rspName) {
523         Map<Integer, InstanceIdentifier<Flow>> flowMap = flowCache.getFlows(rspName);
524         if (flowMap != null) {
525             for (FlowID flowID : flowSet) {
526                 InstanceIdentifier<Flow> path = flowMap.get(flowID.value);
527                 if (path != null) {
528                     flowCache.removeFlow(rspName, flowID.value);
529                     removeFlow(dataBroker, path);
530                 }
531             }
532         }
533     }
534
535     private void removeFlow(DataBroker dataBroker, InstanceIdentifier<Flow> path) {
536         WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
537         modification.delete(LogicalDatastoreType.CONFIGURATION, path);
538
539         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
540         try {
541             commitFuture.get();  // TODO: Make it async (See bug 1362)
542             LOG.debug("Transaction success for deletion of Flow {}", path);
543         } catch (Exception e) {
544             LOG.error("Failed to remove flow {}", path, e);
545             modification.cancel();
546         }
547     }
548 }