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