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