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