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