Bug 5540 - ConvertorManager DataContainer source, one Convertor interface
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / sal / convertor / flow / FlowConvertor.java
1 /*
2  * Copyright (c) 2013, 2015 Ericsson. 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.openflowplugin.openflow.md.core.sal.convertor.flow;
10
11 import com.google.common.base.MoreObjects;
12 import com.google.common.base.Preconditions;
13 import com.google.common.collect.Ordering;
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.Optional;
19 import org.opendaylight.openflowplugin.api.OFConstants;
20 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorManager;
21 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.action.data.ActionConvertorData;
22 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.Convertor;
23 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.ConvertorProcessor;
24 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.OrderComparator;
25 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.VersionDatapathIdConvertorData;
26 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.ApplyActionsCase;
27 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.ClearActionsCase;
28 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.GoToTableCase;
29 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.MeterCase;
30 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.WriteActionsCase;
31 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.WriteMetadataCase;
32 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.flowflag.FlowFlagReactor;
33 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.MatchReactor;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.VlanCfi;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCaseBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCase;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.push.vlan.action._case.PushVlanActionBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.Action;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.instructions.grouping.Instruction;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.FlowModCommand;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MatchTypeBase;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortNumber;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.TableId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.OxmMatchType;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowModInputBuilder;
67 import org.opendaylight.yangtools.yang.binding.DataContainer;
68
69 /**
70  * Converts the SAL Flow to OF Flow. It checks if there is a set-vlan-id (1.0) action made on OF1.3.
71  * If yes its handled separately.
72  *
73  * Example usage:
74  * <pre>
75  * {@code
76  * VersionDatapathIdConvertorData data = new VersionDatapathIdConvertorData(version);
77  * data.setDatapathId(datapathId);
78  * Optional<List<FlowModInputBuilder>> ofFlow = ConvertorManager.getInstance().convert(salFlow, data);
79  * }
80  * </pre>
81  */
82 public class FlowConvertor implements Convertor<Flow, List<FlowModInputBuilder>, VersionDatapathIdConvertorData> {
83     /**
84      * Default idle timeout
85      */
86     public static final Integer DEFAULT_IDLE_TIMEOUT = 0;
87     /**
88      * Default hard timeout
89      */
90     public static final Integer DEFAULT_HARD_TIMEOUT = 0;
91     /**
92      * Default priority
93      */
94     public static final Integer DEFAULT_PRIORITY = Integer.parseInt("8000", 16);
95     /**
96      * flow flag: remove
97      */
98     public static final boolean DEFAULT_OFPFF_FLOW_REM = false;
99     /**
100      * flow flag: check overlap
101      */
102     public static final boolean DEFAULT_OFPFF_CHECK_OVERLAP = false;
103     /**
104      * flow flag: reset counts
105      */
106     public static final boolean DEFAULT_OFPFF_RESET_COUNTS = false;
107     /**
108      * flow flag: don't keep track of packet counts
109      */
110     public static final boolean DEFAULT_OFPFF_NO_PKT_COUNTS = false;
111     /**
112      * flow flag: don't keep track of byte counts
113      */
114     public static final boolean DEFAULT_OFPFF_NO_BYT_COUNTS = false;
115     /**
116      * flow flag: emergency [OFP-1.0]
117      */
118     public static final boolean DEFAULT_OFPFF_EMERGENCY = false;
119     /**
120      * OxmMatch type
121      */
122     public static final Class<? extends MatchTypeBase> DEFAULT_MATCH_TYPE = OxmMatchType.class;
123     /**
124      * default match entries - empty
125      */
126     public static final List<MatchEntry> DEFAULT_MATCH_ENTRIES = new ArrayList<>();
127
128     // Default values for when things are null
129     private static final TableId DEFAULT_TABLE_ID = new TableId(0L);
130     private static final Long DEFAULT_BUFFER_ID = OFConstants.OFP_NO_BUFFER;
131     private static final Long OFPP_ANY = Long.parseLong("ffffffff", 16);
132     private static final Long DEFAULT_OUT_PORT = OFPP_ANY;
133     private static final Long OFPG_ANY = Long.parseLong("ffffffff", 16);
134     private static final Long DEFAULT_OUT_GROUP = OFPG_ANY;
135     private static final Integer PUSH_VLAN = 0x8100;
136     private static final Ordering<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> INSTRUCTION_ORDERING = Ordering.from(OrderComparator.build());
137     private static final VlanMatch VLAN_MATCH_FALSE;
138     private static final VlanMatch VLAN_MATCH_TRUE;
139     private static final ConvertorProcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction, Instruction, ActionConvertorData> PROCESSOR = new ConvertorProcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction, Instruction, ActionConvertorData>()
140             .addCase(new ApplyActionsCase())
141             .addCase(new ClearActionsCase())
142             .addCase(new GoToTableCase())
143             .addCase(new MeterCase())
144             .addCase(new WriteActionsCase())
145             .addCase(new WriteMetadataCase());
146
147     static {
148         final VlanId zeroVlan = new VlanId(0);
149         VlanMatchBuilder vlanMatchBuilder = new VlanMatchBuilder();
150         VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
151         vlanIdBuilder.setVlanIdPresent(false);
152         vlanIdBuilder.setVlanId(zeroVlan);
153         vlanMatchBuilder.setVlanId(vlanIdBuilder.build());
154
155         VLAN_MATCH_FALSE = vlanMatchBuilder.build();
156
157         VlanMatchBuilder vlanMatchBuilder2 = new VlanMatchBuilder();
158         VlanIdBuilder vlanIdBuilder2 = new VlanIdBuilder();
159         vlanIdBuilder2.setVlanIdPresent(true);
160         vlanIdBuilder2.setVlanId(zeroVlan);
161         vlanMatchBuilder2.setVlanId(vlanIdBuilder2.build());
162
163         VLAN_MATCH_TRUE = vlanMatchBuilder2.build();
164     }
165
166     private static FlowModInputBuilder toFlowModInput(Flow flow, short version, BigInteger datapathid) {
167
168         FlowModInputBuilder flowMod = new FlowModInputBuilder();
169         salToOFFlowCookie(flow, flowMod);
170         salToOFFlowCookieMask(flow, flowMod);
171         salToOFFlowTableId(flow, flowMod);
172         salToOFFlowCommand(flow, flowMod);
173         salToOFFlowIdleTimeout(flow, flowMod);
174         salToOFFlowHardTimeout(flow, flowMod);
175         salToOFFlowPriority(flow, flowMod);
176         salToOFFlowBufferId(flow, flowMod);
177         salToOFFlowOutPort(flow, flowMod);
178         salToOFFlowOutGroup(flow, flowMod);
179
180         // convert and inject flowFlags
181         FlowFlagReactor.getInstance().convert(flow.getFlags(), version, flowMod);
182
183         // convert and inject match
184         MatchReactor.getInstance().convert(flow.getMatch(), version, flowMod);
185
186         if (flow.getInstructions() != null) {
187             flowMod.setInstruction(toInstructions(flow, version, datapathid));
188             flowMod.setAction(getActions(version, datapathid, flow));
189         }
190
191         flowMod.setVersion(version);
192
193         return flowMod;
194     }
195
196     private static void salToOFFlowOutGroup(Flow flow, FlowModInputBuilder flowMod) {
197         if (flow.getOutGroup() != null) {
198             flowMod.setOutGroup(flow.getOutGroup());
199         } else {
200             flowMod.setOutGroup(DEFAULT_OUT_GROUP);
201         }
202     }
203
204     private static void salToOFFlowOutPort(Flow flow, FlowModInputBuilder flowMod) {
205         if (flow.getOutPort() != null) {
206             flowMod.setOutPort(new PortNumber(flow.getOutPort().longValue()));
207         } else {
208             flowMod.setOutPort(new PortNumber(DEFAULT_OUT_PORT));
209         }
210     }
211
212     private static void salToOFFlowBufferId(Flow flow, FlowModInputBuilder flowMod) {
213         if (flow.getBufferId() != null) {
214             flowMod.setBufferId(flow.getBufferId());
215         } else {
216             flowMod.setBufferId(DEFAULT_BUFFER_ID);
217         }
218     }
219
220     private static void salToOFFlowPriority(Flow flow, FlowModInputBuilder flowMod) {
221         if (flow.getPriority() != null) {
222             flowMod.setPriority(flow.getPriority());
223         } else {
224             flowMod.setPriority(DEFAULT_PRIORITY);
225         }
226     }
227
228     private static void salToOFFlowHardTimeout(Flow flow, FlowModInputBuilder flowMod) {
229         if (flow.getHardTimeout() != null) {
230             flowMod.setHardTimeout(flow.getHardTimeout());
231         } else {
232             flowMod.setHardTimeout(DEFAULT_HARD_TIMEOUT);
233         }
234     }
235
236     private static void salToOFFlowIdleTimeout(Flow flow, FlowModInputBuilder flowMod) {
237         if (flow.getIdleTimeout() != null) {
238             flowMod.setIdleTimeout(flow.getIdleTimeout());
239         } else {
240             flowMod.setIdleTimeout(DEFAULT_IDLE_TIMEOUT);
241         }
242     }
243
244     private static void salToOFFlowCommand(Flow flow, FlowModInputBuilder flowMod) {
245         if (flow instanceof AddFlowInput || flow instanceof UpdatedFlow) {
246             flowMod.setCommand(FlowModCommand.OFPFCADD);
247         } else if (flow instanceof RemoveFlowInput) {
248             if (MoreObjects.firstNonNull(flow.isStrict(), Boolean.FALSE)) {
249                 flowMod.setCommand(FlowModCommand.OFPFCDELETESTRICT);
250             } else {
251                 flowMod.setCommand(FlowModCommand.OFPFCDELETE);
252             }
253         }
254     }
255
256     private static void salToOFFlowTableId(Flow flow, FlowModInputBuilder flowMod) {
257         if (flow.getTableId() != null) {
258             flowMod.setTableId(new TableId(flow.getTableId().longValue()));
259         } else {
260             flowMod.setTableId(DEFAULT_TABLE_ID);
261         }
262     }
263
264     private static void salToOFFlowCookieMask(Flow flow, FlowModInputBuilder flowMod) {
265         if (flow.getCookieMask() != null) {
266             flowMod.setCookieMask(flow.getCookieMask().getValue());
267         } else {
268             flowMod.setCookieMask(OFConstants.DEFAULT_COOKIE_MASK);
269         }
270     }
271
272     private static void salToOFFlowCookie(Flow flow, FlowModInputBuilder flowMod) {
273         if (flow.getCookie() != null) {
274             flowMod.setCookie(flow.getCookie().getValue());
275         } else {
276             flowMod.setCookie(OFConstants.DEFAULT_COOKIE);
277         }
278     }
279
280     private static List<Instruction> toInstructions(Flow flow, short version, BigInteger datapathid) {
281         final List<Instruction> instructionsList = new ArrayList<>();
282         final ActionConvertorData data = new ActionConvertorData(version);
283         data.setDatapathId(datapathid);
284         data.setIpProtocol(FlowConvertorUtil.getIpProtocolFromFlow(flow));
285
286         Instructions instructions = flow.getInstructions();
287
288         for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction instruction : instructions
289                 .getInstruction()) {
290             org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction curInstruction = instruction
291                     .getInstruction();
292
293             Optional<Instruction> result = PROCESSOR.process(curInstruction, data);
294
295             if (result.isPresent()) {
296                 instructionsList.add(result.get());
297             }
298         }
299
300         return instructionsList;
301     }
302
303     private static List<Action> getActions(short version, BigInteger datapathid, Flow flow) {
304         Instructions instructions = flow.getInstructions();
305         List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> sortedInstructions =
306                 INSTRUCTION_ORDERING.sortedCopy(instructions.getInstruction());
307
308         for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction instruction : sortedInstructions) {
309             org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction curInstruction = instruction
310                     .getInstruction();
311
312             if (curInstruction instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase) {
313                 org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase applyActionscase = (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase) curInstruction;
314                 ApplyActions applyActions = applyActionscase.getApplyActions();
315
316                 final ActionConvertorData data = new ActionConvertorData(version);
317                 data.setDatapathId(datapathid);
318                 data.setIpProtocol(FlowConvertorUtil.getIpProtocolFromFlow(flow));
319                 Optional<List<Action>> result = ConvertorManager.getInstance().convert(applyActions.getAction(), data);
320                 return result.orElse(Collections.emptyList());
321             }
322         }
323
324         return null;
325     }
326
327     // check if set vlanid action is present in the flow
328     private static boolean isSetVlanIdActionCasePresent(Flow flow) {
329         // we are trying to find if there is a set-vlan-id action (OF1.0) action present in the flow.
330         // If yes,then we would need to two flows
331         if (flow.getInstructions() != null && flow.getInstructions().getInstruction() != null) {
332             for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction instruction :
333                     flow.getInstructions().getInstruction()) {
334                 org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction curInstruction =
335                         instruction.getInstruction();
336
337                 if (curInstruction instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase) {
338                     org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase applyActionscase = (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase) curInstruction;
339                     ApplyActions applyActions = applyActionscase.getApplyActions();
340                     for (org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action action :
341                             applyActions.getAction()) {
342                         if (action.getAction() instanceof SetVlanIdActionCase) {
343                             return true;
344                         }
345                     }
346                 }
347             }
348         }
349         return false;
350     }
351
352
353     /**
354      * A) If user provided flow's match includes vlan match Â and action has set_vlan_field
355      * Install following rules
356      * Â  Â 1) match on (OFPVID_PRESENT |value) without mask + action [set_field]
357      * <p/>
358      * B) if user provided flow's match doesn't include vlan match but action has set_vlan field
359      * Â  Â  1) Match on (OFPVID_NONE ) without mask + action [push vlan tag + set_field]
360      * Â  Â  2) Match on (OFPVID_PRESENT) with mask (OFPVID_PRESENT ) + action [ set_field]
361      */
362     private static List<FlowModInputBuilder> handleSetVlanIdForOF13(Flow srcFlow, short version, BigInteger datapathId) {
363         List<FlowModInputBuilder> list = new ArrayList<>(2);
364
365         final Match srcMatch = Preconditions.checkNotNull(srcFlow.getMatch());
366         final VlanMatch srcVlanMatch = srcMatch.getVlanMatch();
367         if (srcVlanMatch != null) {
368             //create flow with setfield and match
369             // match on vlan tag or vlanid with no mask
370             VlanMatchBuilder vlanMatchBuilder = new VlanMatchBuilder(srcVlanMatch);
371             VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
372             vlanIdBuilder.setVlanIdPresent(srcVlanMatch.getVlanId().isVlanIdPresent());
373             vlanIdBuilder.setVlanId(srcVlanMatch.getVlanId().getVlanId());
374             vlanMatchBuilder.setVlanId(vlanIdBuilder.build());
375             Match match = new MatchBuilder(srcMatch).setVlanMatch(vlanMatchBuilder.build()).build();
376
377             Optional<? extends Flow> optional = injectMatchToFlow(srcFlow, match);
378             if (optional.isPresent()) {
379                 list.add(toFlowModInput(optional.get(), version, datapathId));
380             }
381         } else {
382             // create 2 flows
383             //flow 1
384             // match on no vlan tag with no mask
385             Match match1 = new MatchBuilder(srcMatch).setVlanMatch(VLAN_MATCH_FALSE).build();
386
387             Optional<? extends Flow> optional1 = injectMatchAndAction(srcFlow, match1);
388             if (optional1.isPresent()) {
389                 list.add(toFlowModInput(optional1.get(), version, datapathId));
390             }
391
392             //flow2
393             // match on vlan tag with mask
394             Match match2 = new MatchBuilder(srcMatch).setVlanMatch(VLAN_MATCH_TRUE).build();
395             Optional<? extends Flow> optional2 = injectMatchToFlow(srcFlow, match2);
396             if (optional2.isPresent()) {
397                 list.add(toFlowModInput(optional2.get(), version, datapathId));
398             }
399         }
400         return list;
401     }
402
403
404     private static Optional<? extends Flow> injectMatchToFlow(Flow sourceFlow, Match match) {
405         if (sourceFlow instanceof AddFlowInput) {
406             return Optional.of(new AddFlowInputBuilder(sourceFlow).setMatch(match).build());
407         } else if (sourceFlow instanceof RemoveFlowInput) {
408             return Optional.of(new RemoveFlowInputBuilder(sourceFlow).setMatch(match).build());
409         } else if (sourceFlow instanceof UpdatedFlow) {
410             return Optional.of(new UpdatedFlowBuilder(sourceFlow).setMatch(match).build());
411         } else {
412             return Optional.empty();
413         }
414     }
415
416     private static Optional<? extends Flow> injectMatchAndAction(Flow sourceFlow, Match match) {
417
418         Instructions instructions = (new InstructionsBuilder())
419                 .setInstruction(injectPushActionToInstruction(sourceFlow))
420                 .build();
421
422         if (sourceFlow instanceof AddFlowInput) {
423             return Optional.of(new AddFlowInputBuilder(sourceFlow)
424                     .setMatch(match).setInstructions(instructions).build());
425         } else if (sourceFlow instanceof RemoveFlowInput) {
426             return Optional.of(new RemoveFlowInputBuilder(sourceFlow)
427                     .setMatch(match).setInstructions(instructions).build());
428         } else if (sourceFlow instanceof UpdatedFlow) {
429             return Optional.of(new UpdatedFlowBuilder(sourceFlow)
430                     .setMatch(match).setInstructions(instructions).build());
431         } else {
432             return Optional.empty();
433         }
434     }
435
436     private static List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction>
437     injectPushActionToInstruction(final Flow sourceFlow) {
438
439         List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> srcInstructionList =
440                 sourceFlow.getInstructions().getInstruction();
441
442         List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> targetInstructionList = new ArrayList<>(srcInstructionList.size());
443         List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> targetActionList = new ArrayList<>();
444
445         org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder instructionBuilder =
446                 new org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder();
447
448         for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction srcInstruction : srcInstructionList) {
449             org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction curSrcInstruction =
450                     srcInstruction.getInstruction();
451
452             if (curSrcInstruction instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase) {
453                 org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase applyActionscase = (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase) curSrcInstruction;
454                 ApplyActions applyActions = applyActionscase.getApplyActions();
455                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> srcActionList = applyActions.getAction();
456
457                 int offset = 0;
458                 for (org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action actionItem : srcActionList) {
459                     // check if its a set-vlan-action. If yes, then add the injected-action
460
461                     if (actionItem.getAction() instanceof SetVlanIdActionCase) {
462                         SetVlanIdActionCase setVlanIdActionCase = (SetVlanIdActionCase) actionItem.getAction();
463
464                         PushVlanActionCaseBuilder pushVlanActionCaseBuilder = new PushVlanActionCaseBuilder();
465                         PushVlanActionBuilder pushVlanActionBuilder = new PushVlanActionBuilder();
466
467                         pushVlanActionBuilder.setCfi(new VlanCfi(1))
468                                 .setVlanId(setVlanIdActionCase.getSetVlanIdAction().getVlanId())
469                                 .setEthernetType(PUSH_VLAN)
470                                 .setTag(PUSH_VLAN);
471                         pushVlanActionCaseBuilder.setPushVlanAction(pushVlanActionBuilder.build());
472                         PushVlanActionCase injectedAction = pushVlanActionCaseBuilder.build();
473
474                         ActionBuilder actionBuilder = new ActionBuilder();
475                         actionBuilder.setAction(injectedAction)
476                                 .setKey(actionItem.getKey())
477                                 .setOrder(actionItem.getOrder() + offset);
478
479                         targetActionList.add(actionBuilder.build());
480                         offset++;
481                     }
482
483                     if (offset > 0) {
484                         // we need to increment the order for all the actions added after injection
485                         ActionBuilder actionBuilder =
486                                 new ActionBuilder(actionItem);
487                         actionBuilder.setOrder(actionItem.getOrder() + offset);
488                         actionItem = actionBuilder.build();
489                     }
490
491                     targetActionList.add(actionItem);
492                 }
493
494                 ApplyActionsCaseBuilder applyActionsCaseBuilder = new ApplyActionsCaseBuilder();
495                 ApplyActionsBuilder applyActionsBuilder = new ApplyActionsBuilder();
496                 applyActionsBuilder.setAction(targetActionList);
497                 applyActionsCaseBuilder.setApplyActions(applyActionsBuilder.build());
498
499                 instructionBuilder.setInstruction(applyActionsCaseBuilder.build());
500             } else {
501                 instructionBuilder.setInstruction(curSrcInstruction);
502             }
503
504             instructionBuilder
505                     .setKey(srcInstruction.getKey())
506                     .setOrder(srcInstruction.getOrder());
507             targetInstructionList.add(instructionBuilder.build());
508
509         }
510
511         return targetInstructionList;
512     }
513
514     @Override
515     public Class<? extends DataContainer> getType() {
516         return Flow.class;
517     }
518
519     @Override
520     public List<FlowModInputBuilder> convert(Flow source, VersionDatapathIdConvertorData data) {
521         if (data.getVersion() >= OFConstants.OFP_VERSION_1_3 && isSetVlanIdActionCasePresent(source)) {
522             return handleSetVlanIdForOF13(source, data.getVersion(), data.getDatapathId());
523         } else {
524             return Collections.singletonList(toFlowModInput(source, data.getVersion(), data.getDatapathId()));
525         }
526     }
527 }