Remove plugin dependencies
[ovsdb.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / providers / openflow13 / services / LoadBalancerService.java
1 /*
2  * Copyright (C) 2014 SDN Hub, LLC.
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  * Authors : Srini Seetharaman, Madhu Venugopal
9  */
10 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services;
11
12 import java.math.BigInteger;
13 import java.util.List;
14 import java.util.Map;
15
16 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
17 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
18 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
19 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration.LoadBalancerPoolMember;
20 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerProvider;
21 import org.opendaylight.ovsdb.openstack.netvirt.api.Status;
22 import org.opendaylight.ovsdb.openstack.netvirt.api.StatusCode;
23 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
24 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
25 import org.opendaylight.ovsdb.utils.mdsal.openflow.ActionUtils;
26 import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv4Builder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.OfjNxHashFields;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.OfjNxMpAlgorithm;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 import com.google.common.collect.Lists;
58
59 public class LoadBalancerService extends AbstractServiceInstance implements LoadBalancerProvider {
60
61     private static final Logger logger = LoggerFactory.getLogger(LoadBalancerProvider.class);
62     private static final int DEFAULT_FLOW_PRIORITY = 32768;
63     private static final Long FIRST_PASS_REGA_MATCH_VALUE = 0L;
64     private static final Long SECOND_PASS_REGA_MATCH_VALUE = 1L;
65
66     private static final Class<? extends NxmNxReg> REG_FIELD_A = NxmNxReg1.class;
67     private static final Class<? extends NxmNxReg> REG_FIELD_B = NxmNxReg2.class;
68
69     public LoadBalancerService() {
70         super(Service.LOAD_BALANCER);
71     }
72
73     public LoadBalancerService(Service service) {
74         super(service);
75     }
76
77     /**
78      * When this method is called, we do the following for minimizing flow updates:
79      * 1. Overwrite the solo multipath rule that applies to all members
80      * 2. Append second pass rule for the header rewriting specific to this member
81      * 3. Append reverse rules specific to this member
82      */
83     @Override
84     public Status programLoadBalancerPoolMemberRules(Node node,
85             LoadBalancerConfiguration lbConfig, LoadBalancerPoolMember member, org.opendaylight.ovsdb.openstack.netvirt.api.Action action) {
86         if (lbConfig == null || member == null) {
87             logger.error("Null value for LB config {} or Member {}", lbConfig, member);
88             return new Status(StatusCode.BADREQUEST);
89         }
90         if (!lbConfig.isValid()) {
91             logger.error("LB config is invalid: {}", lbConfig);
92             return new Status(StatusCode.BADREQUEST);
93         }
94         logger.debug("Performing {} rules for member {} with index {} on LB with VIP {} and total members {}",
95                 action, member.getIP(), member.getIndex(), lbConfig.getVip(), lbConfig.getMembers().size());
96
97         NodeBuilder nodeBuilder = new NodeBuilder();
98         nodeBuilder.setId(new NodeId(Constants.OPENFLOW_NODE_PREFIX + node.getId().getValue()));
99         nodeBuilder.setKey(new NodeKey(nodeBuilder.getId()));
100
101         //Update the multipath rule
102         manageLoadBalancerVIPRulesFirstPass(nodeBuilder, lbConfig, true);
103
104         if (action.equals(org.opendaylight.ovsdb.openstack.netvirt.api.Action.ADD)) {
105             manageLoadBalancerMemberVIPRulesSecondPass(nodeBuilder, lbConfig, member, true);
106             manageLoadBalancerMemberReverseRules(nodeBuilder, lbConfig, member, true);
107             return new Status(StatusCode.SUCCESS);
108         }
109         /* TODO: Delete single member.
110          * For now, removing a member requires deleting the full LB instance and re-adding
111          */
112         return new Status(StatusCode.NOTIMPLEMENTED);
113     }
114
115     /**
116      * When this method is called, we perform the following:
117      * 1. Write the solo multipath rule that applies to all members
118      * 2. Append second pass rules for the header rewriting for all members
119      * 3. Append reverse rules for all the members, specific to the protocol/port
120      */
121     @Override
122     public Status programLoadBalancerRules(Node node, LoadBalancerConfiguration lbConfig, org.opendaylight.ovsdb.openstack.netvirt.api.Action action) {
123         if (lbConfig == null) {
124             logger.error("LB config is invalid: {}", lbConfig);
125             return new Status(StatusCode.BADREQUEST);
126         }
127         if (!lbConfig.isValid()) {
128             logger.error("LB config is invalid: {}", lbConfig);
129             return new Status(StatusCode.BADREQUEST);
130         }
131         logger.debug("Performing {} rules for VIP {} and {} members", action, lbConfig.getVip(), lbConfig.getMembers().size());
132
133         NodeBuilder nodeBuilder = new NodeBuilder();
134         nodeBuilder.setId(new NodeId(Constants.OPENFLOW_NODE_PREFIX + node.getId().getValue()));
135         nodeBuilder.setKey(new NodeKey(nodeBuilder.getId()));
136
137         if (action.equals(org.opendaylight.ovsdb.openstack.netvirt.api.Action.ADD)) {
138             manageLoadBalancerVIPRulesFirstPass(nodeBuilder, lbConfig, true);
139             manageLoadBalancerVIPRulesSecondPass(nodeBuilder, lbConfig, true);
140             manageLoadBalancerReverseRules(nodeBuilder, lbConfig, true);
141             return new Status(StatusCode.SUCCESS);
142         }
143         else if (action.equals(org.opendaylight.ovsdb.openstack.netvirt.api.Action.DELETE)) {
144             manageLoadBalancerVIPRulesFirstPass(nodeBuilder, lbConfig, false);
145             manageLoadBalancerVIPRulesSecondPass(nodeBuilder, lbConfig, false);
146             manageLoadBalancerReverseRules(nodeBuilder, lbConfig, false);
147             return new Status(StatusCode.SUCCESS);
148         }
149
150         return new Status(StatusCode.NOTIMPLEMENTED);
151     }
152
153     /**
154      * Method to insert/remove default rule for traffic destined to the VIP and no
155      * server selection performed yet
156      * @param nodeBuilder NodeBuilder
157      * @param lbConfig LoadBalancerConfiguration
158      * @param write Boolean to indicate of the flow is to be inserted or removed
159      */
160     private void manageLoadBalancerVIPRulesFirstPass(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig, boolean write) {
161         MatchBuilder matchBuilder = new MatchBuilder();
162         FlowBuilder flowBuilder = new FlowBuilder();
163
164         // Match Tunnel-ID, VIP, and Reg0==0
165         if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
166             lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE))
167             MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(lbConfig.getProviderSegmentationId()));
168         else if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN))
169             MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(lbConfig.getProviderSegmentationId())), true);
170         else
171             return; //Should not get here. TODO: Other types
172
173         MatchUtils.createDstL3IPv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(lbConfig.getVip()));
174         MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(REG_FIELD_A, FIRST_PASS_REGA_MATCH_VALUE));
175
176         String flowId = "LOADBALANCER_FORWARD_FLOW1_" + lbConfig.getVip();
177         flowBuilder.setId(new FlowId(flowId));
178         FlowKey key = new FlowKey(new FlowId(flowId));
179         flowBuilder.setMatch(matchBuilder.build());
180         flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY);
181         flowBuilder.setBarrier(true);
182         flowBuilder.setTableId(this.getTable());
183         flowBuilder.setKey(key);
184         flowBuilder.setFlowName(flowId);
185         flowBuilder.setHardTimeout(0);
186         flowBuilder.setIdleTimeout(0);
187
188         if (write) {
189             // Create the OF Actions and Instructions
190             InstructionsBuilder isb = new InstructionsBuilder();
191
192             // Instructions List Stores Individual Instructions
193             List<Instruction> instructions = Lists.newArrayList();
194
195             List<Action> actionList = Lists.newArrayList();
196
197             ActionBuilder ab = new ActionBuilder();
198             ab.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(REG_FIELD_A).build(),
199                     BigInteger.valueOf(SECOND_PASS_REGA_MATCH_VALUE)));
200             ab.setOrder(0);
201             ab.setKey(new ActionKey(0));
202             actionList.add(ab.build());
203
204             ab = new ActionBuilder();
205             ab.setAction(ActionUtils.nxMultipathAction(OfjNxHashFields.NXHASHFIELDSSYMMETRICL4,
206                     0, OfjNxMpAlgorithm.NXMPALGMODULON,
207                     lbConfig.getMembers().size()-1, //By Nicira-Ext spec, this field is max_link minus 1
208                     0L, new DstNxRegCaseBuilder().setNxReg(REG_FIELD_B).build(),
209                     0, 31));
210             ab.setOrder(1);
211             ab.setKey(new ActionKey(1));
212             actionList.add(ab.build());
213
214             ab = new ActionBuilder();
215             ab.setAction(ActionUtils.nxResubmitAction(null, this.getTable()));
216             ab.setOrder(2);
217             ab.setKey(new ActionKey(2));
218             actionList.add(ab.build());
219
220             // Create an Apply Action
221             ApplyActionsBuilder aab = new ApplyActionsBuilder();
222             aab.setAction(actionList);
223             InstructionBuilder ib = new InstructionBuilder();
224             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
225
226             // Call the InstructionBuilder Methods Containing Actions
227             ib.setOrder(0);
228             ib.setKey(new InstructionKey(0));
229             instructions.add(ib.build());
230
231             // Add InstructionBuilder to the Instruction(s)Builder List
232             isb.setInstruction(instructions);
233
234             // Add InstructionsBuilder to FlowBuilder
235             flowBuilder.setInstructions(isb.build());
236
237             writeFlow(flowBuilder, nodeBuilder);
238
239         } else {
240             removeFlow(flowBuilder, nodeBuilder);
241         }
242     }
243
244     /*
245      * Method to program each rule that matches on Reg0 and Reg1 to insert appropriate header rewriting
246      * rules for all members. This function calls manageLoadBalancerMemberVIPRulesSecondPass in turn.
247      * @param nodeBuilder Node to insert rule to
248      * @param lbConfig Configuration for this LoadBalancer instance
249      * @param write Boolean to indicate of the flow is to be inserted or removed
250      */
251     private void manageLoadBalancerVIPRulesSecondPass(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig, boolean write) {
252         for(Map.Entry<String, LoadBalancerPoolMember> entry : lbConfig.getMembers().entrySet()){
253             manageLoadBalancerMemberVIPRulesSecondPass(nodeBuilder, lbConfig, entry.getValue(), write);
254         }
255     }
256
257     private void manageLoadBalancerMemberVIPRulesSecondPass(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig, LoadBalancerPoolMember member, boolean write) {
258         String vip = lbConfig.getVip();
259
260         MatchBuilder matchBuilder = new MatchBuilder();
261         FlowBuilder flowBuilder = new FlowBuilder();
262
263         // Match Tunnel-ID, VIP, Reg0==1 and Reg1==Index of member
264         if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
265             lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE))
266             MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(lbConfig.getProviderSegmentationId()));
267         else if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN))
268             MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(lbConfig.getProviderSegmentationId())), true);
269         else
270             return; //Should not get here. TODO: Other types
271
272         MatchUtils.createDstL3IPv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(vip));
273         MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(REG_FIELD_A, SECOND_PASS_REGA_MATCH_VALUE),
274                                                new MatchUtils.RegMatch(REG_FIELD_B, (long)member.getIndex()));
275
276         String flowId = "LOADBALANCER_FORWARD_FLOW2_" + vip + "_" + member.getIP();
277         flowBuilder.setId(new FlowId(flowId));
278         FlowKey key = new FlowKey(new FlowId(flowId));
279         flowBuilder.setMatch(matchBuilder.build());
280         flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY+1);
281         flowBuilder.setBarrier(true);
282         flowBuilder.setTableId(this.getTable());
283         flowBuilder.setKey(key);
284         flowBuilder.setFlowName(flowId);
285         flowBuilder.setHardTimeout(0);
286         flowBuilder.setIdleTimeout(0);
287
288         if (write) {
289             // Create the OF Actions and Instructions
290             InstructionsBuilder isb = new InstructionsBuilder();
291
292             // Instructions List Stores Individual Instructions
293             List<Instruction> instructions = Lists.newArrayList();
294
295             List<Action> actionList = Lists.newArrayList();
296             ActionBuilder ab = new ActionBuilder();
297             ab.setAction(ActionUtils.setDlDstAction(new MacAddress(member.getMAC())));
298             ab.setOrder(0);
299             ab.setKey(new ActionKey(0));
300             actionList.add(ab.build());
301
302             ab = new ActionBuilder();
303             Ipv4Builder ipb = new Ipv4Builder().setIpv4Address(MatchUtils.iPv4PrefixFromIPv4Address(member.getIP()));
304             ab.setAction(ActionUtils.setNwDstAction(ipb.build()));
305             ab.setOrder(1);
306             ab.setKey(new ActionKey(1));
307             actionList.add(ab.build());
308
309             // Create an Apply Action
310             ApplyActionsBuilder aab = new ApplyActionsBuilder();
311             aab.setAction(actionList);
312
313             // Call the InstructionBuilder Methods Containing Actions
314             InstructionBuilder ib = new InstructionBuilder();
315             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
316             ib.setOrder(0);
317             ib.setKey(new InstructionKey(0));
318             instructions.add(ib.build());
319
320             // Call the InstructionBuilder Methods Containing Actions
321             ib = this.getMutablePipelineInstructionBuilder();
322             ib.setOrder(1);
323             ib.setKey(new InstructionKey(1));
324             instructions.add(ib.build());
325
326             // Add InstructionBuilder to the Instruction(s)Builder List
327             isb.setInstruction(instructions);
328
329             // Add InstructionsBuilder to FlowBuilder
330             flowBuilder.setInstructions(isb.build());
331
332             writeFlow(flowBuilder, nodeBuilder);
333
334         } else {
335             removeFlow(flowBuilder, nodeBuilder);
336         }
337     }
338
339     /**
340      * Method to program all reverse rules that matches member {IP, Protocol, Port} for all members.
341      * This function calls manageLoadBalancerMemberReverseRules in turn.
342      * @param nodeBuilder Node to insert rule to
343      * @param lbConfig Configuration for this LoadBalancer instance
344      */
345     private void manageLoadBalancerReverseRules(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig, boolean write) {
346         for(Map.Entry<String, LoadBalancerPoolMember> entry : lbConfig.getMembers().entrySet()){
347             manageLoadBalancerMemberReverseRules(nodeBuilder, lbConfig, entry.getValue(), write);
348         }
349     }
350
351     private void manageLoadBalancerMemberReverseRules(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig,
352             LoadBalancerPoolMember member, boolean write) {
353
354         String vip = lbConfig.getVip();
355         String vmac = lbConfig.getVmac();
356
357         MatchBuilder matchBuilder = new MatchBuilder();
358         FlowBuilder flowBuilder = new FlowBuilder();
359
360         // Match Tunnel-ID, MemberIP, and Protocol/Port
361         if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
362                    lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE))
363             MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(lbConfig.getProviderSegmentationId()));
364         else if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN))
365             MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(lbConfig.getProviderSegmentationId())), true);
366         else
367             return; //Should not get here. TODO: Other types
368
369         MatchUtils.createSrcL3IPv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(member.getIP()));
370         MatchUtils.createSetSrcTcpMatch(matchBuilder, new PortNumber(member.getPort()));
371
372         String flowId = "LOADBALANCER_REVERSE_FLOW_" + vip + "_" + member.getIP();
373         flowBuilder.setId(new FlowId(flowId));
374         FlowKey key = new FlowKey(new FlowId(flowId));
375         flowBuilder.setMatch(matchBuilder.build());
376         flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY);
377         flowBuilder.setBarrier(true);
378         flowBuilder.setTableId(this.getTable());
379         flowBuilder.setKey(key);
380         flowBuilder.setFlowName(flowId);
381         flowBuilder.setHardTimeout(0);
382         flowBuilder.setIdleTimeout(0);
383
384         if (write) {
385             // Create the OF Actions and Instructions
386             InstructionsBuilder isb = new InstructionsBuilder();
387
388             // Instructions List Stores Individual Instructions
389             List<Instruction> instructions = Lists.newArrayList();
390
391             List<Action> actionList = Lists.newArrayList();
392             ActionBuilder ab = new ActionBuilder();
393             Ipv4Builder ipb = new Ipv4Builder().setIpv4Address(MatchUtils.iPv4PrefixFromIPv4Address(vip));
394             ab.setAction(ActionUtils.setNwSrcAction(ipb.build()));
395             ab.setOrder(0);
396             ab.setKey(new ActionKey(0));
397             actionList.add(ab.build());
398
399             /* If a dummy MAC is assigned to the VIP, we use that as the
400              * source MAC for the reverse traffic.
401              */
402             if (vmac != null) {
403                 ab = new ActionBuilder();
404                 ab.setAction(ActionUtils.setDlDstAction(new MacAddress(vmac)));
405                 ab.setOrder(1);
406                 ab.setKey(new ActionKey(1));
407                 actionList.add(ab.build());
408             }
409
410             // Create an Apply Action
411             ApplyActionsBuilder aab = new ApplyActionsBuilder();
412             aab.setAction(actionList);
413
414             // Call the InstructionBuilder Methods Containing Actions
415             InstructionBuilder ib = new InstructionBuilder();
416             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
417             ib.setOrder(0);
418             ib.setKey(new InstructionKey(0));
419             instructions.add(ib.build());
420
421             // Call the InstructionBuilder Methods Containing Actions
422             ib = this.getMutablePipelineInstructionBuilder();
423             ib.setOrder(1);
424             ib.setKey(new InstructionKey(1));
425             instructions.add(ib.build());
426
427             // Add InstructionBuilder to the Instruction(s)Builder List
428             isb.setInstruction(instructions);
429
430             // Add InstructionsBuilder to FlowBuilder
431             flowBuilder.setInstructions(isb.build());
432
433             writeFlow(flowBuilder, nodeBuilder);
434
435         } else {
436             removeFlow(flowBuilder, nodeBuilder);
437         }
438     }
439 }