BUG-1491: handle SET_TP_SRC/SET_TP_DST actions
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / sal / convertor / FlowConvertor.java
index 562a67451b9431b5a96c5b31ffdbfba53f4abe3b..b6e37717e6f2279d54161ba77b830634dce954d5 100644 (file)
@@ -8,30 +8,50 @@
 
 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor;
 
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.List;
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.collect.Ordering;
 
-import org.opendaylight.openflowplugin.openflow.md.OFConstants;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.OrderComparator;
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flowflag.FlowFlagReactor;
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.MatchReactor;
 import org.opendaylight.openflowplugin.openflow.md.util.ByteUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.VlanCfi;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.push.vlan.action._case.PushVlanActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ClearActionsCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.GoToTableCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.MeterCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteActionsCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteMetadataCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.clear.actions._case.ClearActions;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTable;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.meter._case.Meter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.write.actions._case.WriteActions;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.write.metadata._case.WriteMetadata;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ActionsInstruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ActionsInstructionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MetadataInstruction;
@@ -53,7 +73,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Objects;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Utility class for converting a MD-SAL Flow into the OF flow mod
@@ -64,9 +86,9 @@ public class FlowConvertor {
     // Default values for when things are null
     private static final BigInteger DEFAULT_COOKIE = BigInteger.ZERO;
     private static final BigInteger DEFAULT_COOKIE_MASK = BigInteger.ZERO;
-    private static final TableId DEFAULT_TABLE_ID = new TableId(new Long(0));
-    private static final Integer DEFAULT_IDLE_TIMEOUT = new Integer(5 * 60);
-    private static final Integer DEFAULT_HARD_TIMEOUT = new Integer(10 * 60);
+    private static final TableId DEFAULT_TABLE_ID = new TableId(0L);
+    private static final Integer DEFAULT_IDLE_TIMEOUT = 5 * 60;
+    private static final Integer DEFAULT_HARD_TIMEOUT = 10 * 60;
     private static final Integer DEFAULT_PRIORITY = Integer.parseInt("8000", 16);
     private static final Long DEFAULT_BUFFER_ID = Long.parseLong("ffffffff", 16);
     private static final Long OFPP_ANY = Long.parseLong("ffffffff", 16);
@@ -90,16 +112,34 @@ public class FlowConvertor {
     /** default match entries - empty */
     public static final List<MatchEntries> DEFAULT_MATCH_ENTRIES = new ArrayList<MatchEntries>();
 
-    public static FlowModInputBuilder toFlowModInput(Flow flow, short version,BigInteger datapathid) {
+
+    /**
+     * This method converts the SAL Flow to OF Flow.
+     * It checks if there is a set-vlan-id (1.0) action made on OF1.3.
+     * If yes its handled separately
+     */
+    public static List<FlowModInputBuilder> toFlowModInputs(Flow srcFlow, short version, BigInteger datapathId) {
+        List<FlowModInputBuilder> list = new ArrayList<>();
+
+        if (version >= OFConstants.OFP_VERSION_1_3 && isSetVlanIdActionCasePresent(srcFlow)) {
+            list.addAll(handleSetVlanIdForOF13(srcFlow, version, datapathId));
+        } else {
+            list.add(toFlowModInput(srcFlow, version, datapathId));
+        }
+        return list;
+    }
+
+    public static FlowModInputBuilder toFlowModInput(Flow flow, short version, BigInteger datapathid) {
+
         FlowModInputBuilder flowMod = new FlowModInputBuilder();
         if (flow.getCookie() != null) {
-            flowMod.setCookie(flow.getCookie());
+            flowMod.setCookie(flow.getCookie().getValue());
         } else {
             flowMod.setCookie(DEFAULT_COOKIE);
         }
 
         if (flow.getCookieMask() != null) {
-            flowMod.setCookieMask(new BigInteger(flow.getCookieMask().toString()));
+            flowMod.setCookieMask(flow.getCookieMask().getValue());
         } else {
             flowMod.setCookieMask(DEFAULT_COOKIE_MASK);
         }
@@ -125,6 +165,7 @@ public class FlowConvertor {
                 flowMod.setCommand(FlowModCommand.OFPFCMODIFY);
             }
         }
+
         if (flow.getIdleTimeout() != null) {
             flowMod.setIdleTimeout(flow.getIdleTimeout());
         } else {
@@ -165,8 +206,8 @@ public class FlowConvertor {
         MatchReactor.getInstance().convert(flow.getMatch(), version, flowMod,datapathid);
 
         if (flow.getInstructions() != null) {
-            flowMod.setInstruction(toInstructions(flow.getInstructions(), version,datapathid));
-            flowMod.setAction(getActions(flow.getInstructions(), version,datapathid));
+            flowMod.setInstruction(toInstructions(flow, version,datapathid));
+            flowMod.setAction(getActions(version,datapathid, flow));
         }
         flowMod.setVersion(version);
         
@@ -174,10 +215,11 @@ public class FlowConvertor {
     }
 
     private static List<Instruction> toInstructions(
-            org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions instructions,
+            Flow flow,
             short version,BigInteger datapathid) {
         List<Instruction> instructionsList = new ArrayList<>();
 
+        org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions instructions = flow.getInstructions();
         for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction instruction : instructions
                 .getInstruction()) {
             InstructionBuilder instructionBuilder = new InstructionBuilder();
@@ -216,7 +258,7 @@ public class FlowConvertor {
                         .setType(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.WriteActions.class);
                 ActionsInstructionBuilder actionsInstructionBuilder = new ActionsInstructionBuilder();
                 actionsInstructionBuilder.setAction(ActionConvertor.getActions(writeActions.getAction(),
-                        version,datapathid));
+                        version,datapathid, flow));
                 instructionBuilder.addAugmentation(ActionsInstruction.class, actionsInstructionBuilder.build());
                 instructionsList.add(instructionBuilder.build());
             }
@@ -228,7 +270,7 @@ public class FlowConvertor {
                         .setType(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.ApplyActions.class);
                 ActionsInstructionBuilder actionsInstructionBuilder = new ActionsInstructionBuilder();
                 actionsInstructionBuilder.setAction(ActionConvertor.getActions(applyActions.getAction(),
-                        version,datapathid));
+                        version,datapathid, flow));
                 instructionBuilder.addAugmentation(ActionsInstruction.class, actionsInstructionBuilder.build());
                 instructionsList.add(instructionBuilder.build());
             }
@@ -256,22 +298,231 @@ public class FlowConvertor {
         return instructionsList;
     }
     
-    private static List<Action> getActions(
+    /*private static List<Action> getActions(
             org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions instructions,
-            short version,BigInteger datapathid) {
+            short version,BigInteger datapathid) {*/
+    private static List<Action> getActions(short version,BigInteger datapathid, Flow flow) {
+        
+        org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions instructions = flow.getInstructions();
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> sortedInstructions =
+            Ordering.from(OrderComparator.<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction>toInstance())
+                .sortedCopy(instructions.getInstruction());
 
-        for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction instruction : instructions
-                .getInstruction()) {
+        for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction instruction : sortedInstructions) {
             org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction curInstruction = instruction
                     .getInstruction();
 
             if (curInstruction instanceof ApplyActionsCase) {
                 ApplyActionsCase applyActionscase = (ApplyActionsCase) curInstruction;
                 ApplyActions applyActions = applyActionscase.getApplyActions();
-                return ActionConvertor.getActions(applyActions.getAction(), version,datapathid);
+                return ActionConvertor.getActions(applyActions.getAction(), version,datapathid, flow);
             }
-
         }
         return null;
     }
-}
\ No newline at end of file
+
+    // check if set vlanid action is present in the flow
+    private static boolean isSetVlanIdActionCasePresent(Flow flow) {
+        boolean isPresent = false;
+        // we are trying to find if there is a set-vlan-id action (OF1.0) action present in the flow.
+        // If yes,then we would need to two flows
+        if (flow.getInstructions() != null) {
+            for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction instruction :
+                flow.getInstructions().getInstruction()) {
+                org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction curInstruction =
+                    instruction.getInstruction();
+
+                if (curInstruction instanceof ApplyActionsCase) {
+                    ApplyActionsCase applyActionscase = (ApplyActionsCase) curInstruction;
+                    ApplyActions applyActions = applyActionscase.getApplyActions();
+                    for (org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action action :
+                            applyActions.getAction()) {
+                        if (action.getAction() instanceof SetVlanIdActionCase) {
+                            isPresent = true;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        return isPresent;
+    }
+
+
+    /**
+     * A) If user provided flow's match includes vlan match  and action has set_vlan_field
+     * Install following rules
+     *   1) match on (OFPVID_PRESENT |value) without mask + action [set_field]
+     *
+     * B) if user provided flow's match doesn't include vlan match but action has set_vlan field
+     *    1) Match on (OFPVID_NONE ) without mask + action [push vlan tag + set_field]
+     *    2) Match on (OFPVID_PRESENT) with mask (OFPVID_PRESENT ) + action [ set_field]
+     */
+    private static List<FlowModInputBuilder> handleSetVlanIdForOF13(Flow srcFlow, short version, BigInteger datapathId) {
+        List<FlowModInputBuilder> list = new ArrayList<>();
+
+        VlanMatch srcVlanMatch = srcFlow.getMatch().getVlanMatch();
+        boolean hasVlanMatch = (srcFlow.getMatch() != null && srcVlanMatch != null);
+        if (hasVlanMatch) {
+            //create flow with setfield and match
+            // match on vlan tag or vlanid with no mask
+            VlanMatchBuilder vlanMatchBuilder = new VlanMatchBuilder(srcVlanMatch);
+            VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
+            vlanIdBuilder.setVlanIdPresent(srcVlanMatch.getVlanId().isVlanIdPresent());
+            vlanIdBuilder.setVlanId(srcVlanMatch.getVlanId().getVlanId());
+            vlanMatchBuilder.setVlanId(vlanIdBuilder.build());
+            Match match = new MatchBuilder(srcFlow.getMatch()).setVlanMatch(vlanMatchBuilder.build()).build();
+
+            Optional<? extends Flow> optional = injectMatchToFlow(srcFlow, match);
+            if (optional.isPresent()) {
+                list.add(toFlowModInput(optional.get(), version, datapathId));
+            }
+        } else {
+            // create 2 flows
+            //flow 1
+            // match on no vlan tag with no mask
+            VlanMatchBuilder vlanMatchBuilder = new VlanMatchBuilder();
+            VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
+            vlanIdBuilder.setVlanIdPresent(false);
+            vlanIdBuilder.setVlanId(new VlanId(0));
+            vlanMatchBuilder.setVlanId(vlanIdBuilder.build());
+            Match match1 = new MatchBuilder(srcFlow.getMatch()).setVlanMatch(vlanMatchBuilder.build()).build();
+
+            Optional<? extends Flow> optional1 = injectMatchAndAction(srcFlow, match1);
+            if (optional1.isPresent()) {
+                list.add(toFlowModInput(optional1.get(), version, datapathId));
+            }
+
+            //flow2
+            // match on vlan tag with mask
+            VlanMatchBuilder vlanMatchBuilder2 = new VlanMatchBuilder();
+            VlanIdBuilder vlanIdBuilder2 = new VlanIdBuilder();
+            vlanIdBuilder2.setVlanIdPresent(true);
+            vlanIdBuilder2.setVlanId(new VlanId(0));
+            vlanMatchBuilder2.setVlanId(vlanIdBuilder2.build());
+            Match match2 = new MatchBuilder(srcFlow.getMatch()).setVlanMatch(vlanMatchBuilder2.build()).build();
+            Optional<? extends Flow> optional2 = injectMatchToFlow(srcFlow, match2);
+            if (optional2.isPresent()) {
+                list.add(toFlowModInput(optional2.get(), version, datapathId));
+            }
+        }
+        return list;
+    }
+
+
+    private static Optional<? extends Flow> injectMatchToFlow(Flow sourceFlow, Match match) {
+        if (sourceFlow instanceof AddFlowInput) {
+            return Optional.<AddFlowInput>of(new AddFlowInputBuilder(sourceFlow).setMatch(match).build());
+        } else if (sourceFlow instanceof RemoveFlowInput) {
+            return Optional.<RemoveFlowInput>of(new RemoveFlowInputBuilder(sourceFlow).setMatch(match).build());
+        } else if (sourceFlow instanceof UpdatedFlow) {
+            return Optional.<UpdatedFlow>of(new UpdatedFlowBuilder(sourceFlow).setMatch(match).build());
+        } else {
+            return Optional.<Flow>absent();
+        }
+    }
+
+    private static Optional<? extends Flow> injectMatchAndAction(Flow sourceFlow, Match match) {
+
+        Instructions instructions = (new InstructionsBuilder())
+            .setInstruction(injectPushActionToInstruction(sourceFlow))
+            .build();
+
+        if (sourceFlow instanceof AddFlowInput) {
+            return Optional.<AddFlowInput>of(new AddFlowInputBuilder(sourceFlow)
+                .setMatch(match).setInstructions(instructions).build());
+        } else if (sourceFlow instanceof RemoveFlowInput) {
+            return Optional.<RemoveFlowInput>of(new RemoveFlowInputBuilder(sourceFlow)
+                .setMatch(match).setInstructions(instructions).build());
+        } else if (sourceFlow instanceof UpdatedFlow) {
+            return Optional.<UpdatedFlow>of(new UpdatedFlowBuilder(sourceFlow)
+                .setMatch(match).setInstructions(instructions).build());
+        } else {
+            return Optional.<Flow>absent();
+        }
+    }
+
+    private static List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction>
+        injectPushActionToInstruction(final Flow sourceFlow) {
+
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> srcInstructionList =
+            sourceFlow.getInstructions().getInstruction();
+
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> targetInstructionList = new ArrayList<>(srcInstructionList.size());
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> targetActionList = new ArrayList<>();
+
+        org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder instructionBuilder =
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder();
+        
+        for (int i=0; i < srcInstructionList.size(); i++) {
+            org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction srcInstruction = 
+                    srcInstructionList.get(i);
+            org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction curSrcInstruction = 
+                    srcInstruction.getInstruction();
+            
+            if (curSrcInstruction instanceof ApplyActionsCase) {
+                ApplyActionsCase applyActionscase = (ApplyActionsCase) curSrcInstruction;
+                ApplyActions applyActions = applyActionscase.getApplyActions();
+                List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> srcActionList = applyActions.getAction();
+
+                int offset = 0;
+                for (int j=0; j < srcActionList.size(); j++) {
+                    // check if its a set-vlan-action. If yes, then add the injected-action
+
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action actionItem = srcActionList.get(j);
+                    if(actionItem.getAction() instanceof SetVlanIdActionCase) {
+                        SetVlanIdActionCase setVlanIdActionCase = (SetVlanIdActionCase) actionItem.getAction();
+
+                        PushVlanActionCaseBuilder pushVlanActionCaseBuilder = new PushVlanActionCaseBuilder();
+                        PushVlanActionBuilder pushVlanActionBuilder = new PushVlanActionBuilder();
+
+                        pushVlanActionBuilder.setCfi(new VlanCfi(1))
+                            .setVlanId(setVlanIdActionCase.getSetVlanIdAction().getVlanId())
+                            .setEthernetType(sourceFlow.getMatch().getEthernetMatch()
+                                .getEthernetType().getType().getValue().intValue())
+                            .setTag(sourceFlow.getMatch().getEthernetMatch()
+                                .getEthernetType().getType().getValue().intValue());
+                        pushVlanActionCaseBuilder.setPushVlanAction(pushVlanActionBuilder.build());
+                        PushVlanActionCase injectedAction = pushVlanActionCaseBuilder.build();
+
+                        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder actionBuilder = new ActionBuilder();
+                        actionBuilder.setAction(injectedAction)
+                            .setKey(actionItem.getKey())
+                            .setOrder(actionItem.getOrder() + offset);
+
+                        targetActionList.add(actionBuilder.build());
+                        offset ++;
+                    }
+
+                    if (offset > 0) {
+                        // we need to increment the order for all the actions added after injection
+                        org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder actionBuilder =
+                            new org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder(actionItem);
+                        actionBuilder.setOrder(actionItem.getOrder() + offset);
+                        actionItem = actionBuilder.build();
+                    }
+                    
+                    targetActionList.add(actionItem);
+                }
+
+                ApplyActionsCaseBuilder applyActionsCaseBuilder = new ApplyActionsCaseBuilder();
+                ApplyActionsBuilder applyActionsBuilder = new ApplyActionsBuilder();
+                applyActionsBuilder.setAction(targetActionList);
+                applyActionsCaseBuilder.setApplyActions(applyActionsBuilder.build());
+                    
+                instructionBuilder.setInstruction(applyActionsCaseBuilder.build());
+            } else {
+                instructionBuilder.setInstruction(curSrcInstruction);
+            }
+            
+            instructionBuilder
+                .setKey(srcInstruction.getKey())
+                .setOrder(srcInstruction.getOrder());
+            targetInstructionList.add(instructionBuilder.build());
+            
+        }
+
+        return targetInstructionList;
+    }
+
+}