2 * Copyright (C) 2014 SDN Hub, LLC.
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
8 * Authors : Srini Seetharaman, Madhu Venugopal
10 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services;
12 import java.math.BigInteger;
13 import java.util.Iterator;
14 import java.util.List;
17 import org.opendaylight.controller.sal.utils.Status;
18 import org.opendaylight.controller.sal.utils.StatusCode;
19 import org.opendaylight.controller.sal.core.Node;
20 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
21 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration.LoadBalancerPoolMember;
22 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerProvider;
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.Ipv4Prefix;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv4Builder;
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.flow.inventory.rev130819.FlowId;
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.inventory.rev130819.tables.table.FlowKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
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.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovs.nx.action.rev140421.OfjNxHashFields;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.ovs.nx.action.rev140421.OfjNxMpAlgorithm;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
53 import com.google.common.collect.Lists;
55 public class LoadBalancerService extends AbstractServiceInstance implements LoadBalancerProvider {
57 private static final int DEFAULT_FLOW_PRIORITY = 32768;
58 private static final Long SECOND_PASS_REG0_MATCH_VALUE = 1L;
60 public LoadBalancerService() {
61 super(Service.LOAD_BALANCER);
64 public LoadBalancerService(Service service) {
69 public boolean isBridgeInPipeline (String nodeId) {
74 * When this method is called, we do the following for minimizing flow updates:
75 * 1. Overwrite the solo multipath rule that applies to all members
76 * 2. Append second pass rule for the header rewriting specific to this member
77 * 3. Append reverse rules specific to this member
80 public Status programLoadBalancerPoolMemberRules(Node node,
81 LoadBalancerConfiguration lbConfig, LoadBalancerPoolMember member, org.opendaylight.ovsdb.openstack.netvirt.api.Action action) {
82 NodeBuilder nodeBuilder = new NodeBuilder();
83 nodeBuilder.setId((NodeId) node.getID());
84 nodeBuilder.setKey(new NodeKey(nodeBuilder.getId()));
86 //Update the multipath rule
87 insertLoadBalancerVIPRulesFirstPass(nodeBuilder, lbConfig);
89 if (action.equals(org.opendaylight.ovsdb.openstack.netvirt.api.Action.ADD)) {
90 insertLoadBalancerMemberVIPRulesSecondPass(nodeBuilder, lbConfig.getVip(), member);
91 insertLoadBalancerMemberReverseRules(nodeBuilder, lbConfig.getVip(), member);
92 return new Status(StatusCode.SUCCESS);
94 /* TODO: Delete single member.
95 * For now, removing a member requires deleting the full LB instance and re-adding
97 return new Status(StatusCode.NOTIMPLEMENTED);
101 * When this method is called, we perform the following:
102 * 1. Write the solo multipath rule that applies to all members
103 * 2. Append second pass rules for the header rewriting for all members
104 * 3. Append reverse rules for all the members, specific to the protocol/port
107 public Status programLoadBalancerRules(Node node, LoadBalancerConfiguration lbConfig, org.opendaylight.ovsdb.openstack.netvirt.api.Action action) {
108 //for (org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node:InventoryDataServiceUtil.readAllNodes()) {
109 NodeBuilder nodeBuilder = new NodeBuilder();
110 nodeBuilder.setId((NodeId) node.getID());
111 nodeBuilder.setKey(new NodeKey(nodeBuilder.getId()));
113 if (action.equals(org.opendaylight.ovsdb.openstack.netvirt.api.Action.ADD)) {
114 insertLoadBalancerVIPRulesFirstPass(nodeBuilder, lbConfig);
115 insertLoadBalancerVIPRulesSecondPass(nodeBuilder, lbConfig);
116 insertLoadBalancerReverseRules(nodeBuilder, lbConfig);
117 return new Status(StatusCode.SUCCESS);
119 else if (action.equals(org.opendaylight.ovsdb.openstack.netvirt.api.Action.DELETE)) {
120 removeLoadBalancerVIPRules(nodeBuilder, lbConfig);
121 removeLoadBalancerReverseRules(nodeBuilder, lbConfig);
122 return new Status(StatusCode.SUCCESS);
125 return new Status(StatusCode.NOTIMPLEMENTED);
128 private void insertLoadBalancerVIPRulesFirstPass(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig) {
129 MatchBuilder matchBuilder = new MatchBuilder();
130 FlowBuilder flowBuilder = new FlowBuilder();
133 MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(lbConfig.getVip()));
135 // Create the OF Actions and Instructions
136 InstructionsBuilder isb = new InstructionsBuilder();
138 // Instructions List Stores Individual Instructions
139 List<Instruction> instructions = Lists.newArrayList();
141 List<Action> actionList = Lists.newArrayList();
143 ActionBuilder ab = new ActionBuilder();
144 ab.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(NxmNxReg0.class).build(),
145 BigInteger.valueOf(SECOND_PASS_REG0_MATCH_VALUE)));
147 ab.setKey(new ActionKey(0));
148 actionList.add(ab.build());
150 ab = new ActionBuilder();
151 ab.setAction(ActionUtils.nxMultipathAction(OfjNxHashFields.NXHASHFIELDSSYMMETRICL4,
152 (Integer)0, OfjNxMpAlgorithm.NXMPALGMODULON, (Integer)lbConfig.getMembers().size(),
153 (Long)0L, (Integer)0, new DstNxRegCaseBuilder().setNxReg(NxmNxReg1.class).build()));
155 ab.setKey(new ActionKey(1));
156 actionList.add(ab.build());
158 ab = new ActionBuilder();
159 ab.setAction(ActionUtils.nxResubmitAction(null, this.getTable()));
161 ab.setKey(new ActionKey(2));
162 actionList.add(ab.build());
164 // Create an Apply Action
165 ApplyActionsBuilder aab = new ApplyActionsBuilder();
166 aab.setAction(actionList);
167 InstructionBuilder ib = new InstructionBuilder();
168 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
170 // Call the InstructionBuilder Methods Containing Actions
172 ib.setKey(new InstructionKey(0));
173 instructions.add(ib.build());
175 // Add InstructionBuilder to the Instruction(s)Builder List
176 isb.setInstruction(instructions);
178 // Add InstructionsBuilder to FlowBuilder
179 flowBuilder.setInstructions(isb.build());
181 String flowId = "LOADBALANCER_PIPELINE_FLOW_FORWARD1_" + lbConfig.getVip();
182 flowBuilder.setId(new FlowId(flowId));
183 FlowKey key = new FlowKey(new FlowId(flowId));
184 flowBuilder.setMatch(matchBuilder.build());
185 flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY);
186 flowBuilder.setBarrier(true);
187 flowBuilder.setTableId((short) this.getTable());
188 flowBuilder.setKey(key);
189 flowBuilder.setFlowName(flowId);
190 flowBuilder.setHardTimeout(0);
191 flowBuilder.setIdleTimeout(0);
192 writeFlow(flowBuilder, nodeBuilder);
196 * Method to program each rule that matches on Reg0 and Reg1 to insert appropriate header rewriting
197 * rules for all members. This function calls insertLoadBalancerMemberVIPRulesSecondPass in turn.
198 * @param nodeBuilder Node to insert rule to
199 * @param lbConfig Configuration for this LoadBalancer instance
201 private void insertLoadBalancerVIPRulesSecondPass(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig) {
202 Iterator<Map.Entry<String, LoadBalancerPoolMember>> it = lbConfig.getMembers().entrySet().iterator();
203 Map.Entry<String, LoadBalancerPoolMember> entry;
204 while (it.hasNext()) {
205 entry = (Map.Entry<String, LoadBalancerPoolMember>)it.next();
206 insertLoadBalancerMemberVIPRulesSecondPass(nodeBuilder, lbConfig.getVip(), (LoadBalancerPoolMember)entry.getValue());
211 private void insertLoadBalancerMemberVIPRulesSecondPass(NodeBuilder nodeBuilder, String vip, LoadBalancerPoolMember member) {
212 MatchBuilder matchBuilder = new MatchBuilder();
213 FlowBuilder flowBuilder = new FlowBuilder();
215 // Match VIP, Reg0==1 and Reg1==Index of member
216 MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(NxmNxReg0.class, SECOND_PASS_REG0_MATCH_VALUE));
217 MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(NxmNxReg1.class, (long)member.getIndex()));
218 MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(vip));
220 // Create the OF Actions and Instructions
221 InstructionsBuilder isb = new InstructionsBuilder();
223 // Instructions List Stores Individual Instructions
224 List<Instruction> instructions = Lists.newArrayList();
226 List<Action> actionList = Lists.newArrayList();
227 ActionBuilder ab = new ActionBuilder();
228 ab.setAction(ActionUtils.setDlDstAction(new MacAddress(member.getMAC())));
230 ab.setKey(new ActionKey(0));
231 actionList.add(ab.build());
233 ab = new ActionBuilder();
234 Ipv4Builder ipb = new Ipv4Builder().setIpv4Address(new Ipv4Prefix(member.getIP()));
235 ab.setAction(ActionUtils.setNwDstAction(ipb.build()));
237 ab.setKey(new ActionKey(1));
238 actionList.add(ab.build());
240 // Create an Apply Action
241 ApplyActionsBuilder aab = new ApplyActionsBuilder();
242 aab.setAction(actionList);
244 // Call the InstructionBuilder Methods Containing Actions
245 InstructionBuilder ib = new InstructionBuilder();
246 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
248 ib.setKey(new InstructionKey(0));
249 instructions.add(ib.build());
251 // Call the InstructionBuilder Methods Containing Actions
252 ib = this.getMutablePipelineInstructionBuilder();
254 ib.setKey(new InstructionKey(1));
255 instructions.add(ib.build());
257 // Add InstructionBuilder to the Instruction(s)Builder List
258 isb.setInstruction(instructions);
260 // Add InstructionsBuilder to FlowBuilder
261 flowBuilder.setInstructions(isb.build());
263 String flowId = "LOADBALANCER_PIPELINE_FORWARD2_" + vip + "_" + member.getIP();
264 flowBuilder.setId(new FlowId(flowId));
265 FlowKey key = new FlowKey(new FlowId(flowId));
266 flowBuilder.setMatch(matchBuilder.build());
267 flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY + 1);
268 flowBuilder.setBarrier(true);
269 flowBuilder.setTableId((short) this.getTable());
270 flowBuilder.setKey(key);
271 flowBuilder.setFlowName(flowId);
272 flowBuilder.setHardTimeout(0);
273 flowBuilder.setIdleTimeout(0);
274 writeFlow(flowBuilder, nodeBuilder);
278 * Method to program all reverse rules that matches member {IP, Protocol, Port} for all members.
279 * This function calls insertLoadBalancerMemberReverseRules in turn.
280 * @param nodeBuilder Node to insert rule to
281 * @param lbConfig Configuration for this LoadBalancer instance
283 private void insertLoadBalancerReverseRules(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig) {
284 Iterator<Map.Entry<String, LoadBalancerPoolMember>> it = lbConfig.getMembers().entrySet().iterator();
285 Map.Entry<String, LoadBalancerPoolMember> entry;
286 while (it.hasNext()) {
287 entry = (Map.Entry<String, LoadBalancerPoolMember>)it.next();
288 insertLoadBalancerMemberReverseRules(nodeBuilder, lbConfig.getVip(), (LoadBalancerPoolMember)entry.getValue());
293 private void insertLoadBalancerMemberReverseRules(NodeBuilder nodeBuilder, String vip, LoadBalancerPoolMember member) {
294 MatchBuilder matchBuilder = new MatchBuilder();
295 FlowBuilder flowBuilder = new FlowBuilder();
297 // Match MemberIP, and Protocol/Port
298 MatchUtils.createSrcL3IPv4Match(matchBuilder, new Ipv4Prefix(member.getIP()));
299 if (member.getProtocol().equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP))
300 MatchUtils.createSetSrcTcpMatch(matchBuilder, new PortNumber(LoadBalancerConfiguration.PROTOCOL_HTTP_PORT));
301 else if (member.getProtocol().equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS))
302 MatchUtils.createSetSrcTcpMatch(matchBuilder, new PortNumber(LoadBalancerConfiguration.PROTOCOL_HTTPS_PORT));
306 // Create the OF Actions and Instructions
307 InstructionsBuilder isb = new InstructionsBuilder();
309 // Instructions List Stores Individual Instructions
310 List<Instruction> instructions = Lists.newArrayList();
312 List<Action> actionList = Lists.newArrayList();
313 ActionBuilder ab = new ActionBuilder();
314 Ipv4Builder ipb = new Ipv4Builder().setIpv4Address(new Ipv4Prefix(vip));
315 ab.setAction(ActionUtils.setNwSrcAction(ipb.build()));
317 ab.setKey(new ActionKey(0));
318 actionList.add(ab.build());
320 // Create an Apply Action
321 ApplyActionsBuilder aab = new ApplyActionsBuilder();
322 aab.setAction(actionList);
324 // Call the InstructionBuilder Methods Containing Actions
325 InstructionBuilder ib = new InstructionBuilder();
326 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
328 ib.setKey(new InstructionKey(0));
329 instructions.add(ib.build());
331 // Call the InstructionBuilder Methods Containing Actions
332 ib = this.getMutablePipelineInstructionBuilder();
334 ib.setKey(new InstructionKey(1));
335 instructions.add(ib.build());
337 // Add InstructionBuilder to the Instruction(s)Builder List
338 isb.setInstruction(instructions);
340 // Add InstructionsBuilder to FlowBuilder
341 flowBuilder.setInstructions(isb.build());
343 String flowId = "LOADBALANCER_PIPELINE_REVERSE_" + vip + "_" + member.getIP();
344 flowBuilder.setId(new FlowId(flowId));
345 FlowKey key = new FlowKey(new FlowId(flowId));
346 flowBuilder.setMatch(matchBuilder.build());
347 flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY);
348 flowBuilder.setBarrier(true);
349 flowBuilder.setTableId((short) this.getTable());
350 flowBuilder.setKey(key);
351 flowBuilder.setFlowName(flowId);
352 flowBuilder.setHardTimeout(0);
353 flowBuilder.setIdleTimeout(0);
354 writeFlow(flowBuilder, nodeBuilder);
358 * Method to remove all rules that are regarding traffic destined to the VIP
359 * (both first and second pass rules)
360 * @param nodeBuilder NodeBuilder
361 * @param lbConfig LoadBalancerConfiguration
363 private void removeLoadBalancerVIPRules(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig) {
364 MatchBuilder matchBuilder = new MatchBuilder();
365 FlowBuilder flowBuilder = new FlowBuilder();
367 // Match all traffic with nw_dst==VIP
368 MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(lbConfig.getVip()));
370 flowBuilder.setMatch(matchBuilder.build());
371 flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY);
372 flowBuilder.setBarrier(true);
373 flowBuilder.setTableId((short) this.getTable());
374 removeFlow(flowBuilder, nodeBuilder);
378 * Method to remove all reverse traffic from LB member VMs
379 * @param nodeBuilder NodeBuilder
380 * @param lbConfig LoadBalancerConfiguration
382 private void removeLoadBalancerReverseRules(NodeBuilder nodeBuilder, LoadBalancerConfiguration lbConfig) {
383 Iterator<Map.Entry<String, LoadBalancerPoolMember>> it = lbConfig.getMembers().entrySet().iterator();
384 Map.Entry<String, LoadBalancerPoolMember> entry;
385 while (it.hasNext()) {
386 entry = (Map.Entry<String, LoadBalancerPoolMember>)it.next();
387 LoadBalancerPoolMember member = (LoadBalancerPoolMember) entry.getValue();
389 MatchBuilder matchBuilder = new MatchBuilder();
390 FlowBuilder flowBuilder = new FlowBuilder();
392 // Match MemberIP, and Protocol/Port
393 MatchUtils.createSrcL3IPv4Match(matchBuilder, new Ipv4Prefix(member.getIP()));
394 if (member.getProtocol().equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTP))
395 MatchUtils.createSetSrcTcpMatch(matchBuilder, new PortNumber(LoadBalancerConfiguration.PROTOCOL_HTTP_PORT));
396 else if (member.getProtocol().equalsIgnoreCase(LoadBalancerConfiguration.PROTOCOL_HTTPS))
397 MatchUtils.createSetSrcTcpMatch(matchBuilder, new PortNumber(LoadBalancerConfiguration.PROTOCOL_HTTPS_PORT));
401 flowBuilder.setMatch(matchBuilder.build());
402 flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY);
403 flowBuilder.setBarrier(true);
404 flowBuilder.setTableId((short) this.getTable());
405 removeFlow(flowBuilder, nodeBuilder);