Merge "Bug 2013 Vlan flows needs merging from traditional rules to a single L2Fwding...
[ovsdb.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / providers / openflow13 / services / L2ForwardingService.java
1 /*
2  * Copyright (C) 2014 Red Hat, Inc.
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 : 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
15 //import java.util.ListIterator;
16 import org.opendaylight.ovsdb.openstack.netvirt.api.L2ForwardingProvider;
17 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
18 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
19 import org.opendaylight.ovsdb.utils.mdsal.openflow.ActionUtils;
20 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
21 import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
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.NodeConnectorId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 import com.google.common.collect.Lists;
51
52 public class L2ForwardingService extends AbstractServiceInstance implements L2ForwardingProvider {
53     private static final Logger logger = LoggerFactory.getLogger(L2ForwardingService.class);
54     public L2ForwardingService() {
55         super(Service.L2_FORWARDING);
56     }
57
58     public L2ForwardingService(Service service) {
59         super(service);
60     }
61
62     /*
63      * (Table:L2Forwarding) Local Unicast
64      * Match: Tunnel ID and dMAC
65      * Action: Output Port
66      * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2 goto:<next-table>
67      */
68     @Override
69     public void programLocalUcastOut(Long dpidLong, String segmentationId,
70             Long localPort, String attachedMac, boolean write) {
71
72         String nodeName = OPENFLOW + dpidLong;
73
74         MatchBuilder matchBuilder = new MatchBuilder();
75         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
76         FlowBuilder flowBuilder = new FlowBuilder();
77
78         // Create the OF Match using MatchBuilder
79         flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
80         flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null).build());
81
82         String flowId = "UcastOut_"+segmentationId+"_"+localPort+"_"+attachedMac;
83         // Add Flow Attributes
84         flowBuilder.setId(new FlowId(flowId));
85         FlowKey key = new FlowKey(new FlowId(flowId));
86         flowBuilder.setStrict(true);
87         flowBuilder.setBarrier(false);
88         flowBuilder.setTableId(getTable());
89         flowBuilder.setKey(key);
90         flowBuilder.setFlowName(flowId);
91         flowBuilder.setHardTimeout(0);
92         flowBuilder.setIdleTimeout(0);
93
94         if (write) {
95             // Instantiate the Builders for the OF Actions and Instructions
96             InstructionBuilder ib = new InstructionBuilder();
97             InstructionsBuilder isb = new InstructionsBuilder();
98
99             // Instructions List Stores Individual Instructions
100             List<Instruction> instructions = Lists.newArrayList();
101
102             // Set the Output Port/Iface
103             InstructionUtils.createOutputPortInstructions(ib, dpidLong, localPort);
104             ib.setOrder(0);
105             ib.setKey(new InstructionKey(0));
106             instructions.add(ib.build());
107
108             // Add InstructionBuilder to the Instruction(s)Builder List
109             isb.setInstruction(instructions);
110
111             // Add InstructionsBuilder to FlowBuilder
112             flowBuilder.setInstructions(isb.build());
113             writeFlow(flowBuilder, nodeBuilder);
114         } else {
115             removeFlow(flowBuilder, nodeBuilder);
116         }
117     }
118     /*
119      * (Table:2) Local VLAN unicast
120      * Match: VLAN ID and dMAC
121      * Action: Output Port
122      * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
123      * table=110,dl_vlan=2001,dl_dst=fa:16:3e:a3:3b:cc actions=pop_vlan,output:1
124      */
125
126     @Override
127     public void programLocalVlanUcastOut (Long dpidLong, String segmentationId, Long localPort, String attachedMac, boolean write) {
128
129         String nodeName = OPENFLOW + dpidLong;
130
131         MatchBuilder matchBuilder = new MatchBuilder();
132         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
133         FlowBuilder flowBuilder = new FlowBuilder();
134
135         // Create the OF Match using MatchBuilder
136         flowBuilder.setMatch(
137                 MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true).build());
138         flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null).build());
139
140         String flowId = "VlanUcastOut_"+segmentationId+"_"+localPort+"_"+attachedMac;
141         // Add Flow Attributes
142         flowBuilder.setId(new FlowId(flowId));
143         FlowKey key = new FlowKey(new FlowId(flowId));
144         flowBuilder.setStrict(true);
145         flowBuilder.setBarrier(false);
146         flowBuilder.setTableId(getTable());
147         flowBuilder.setKey(key);
148         flowBuilder.setFlowName(flowId);
149         flowBuilder.setHardTimeout(0);
150         flowBuilder.setIdleTimeout(0);
151
152         if (write) {
153             // Instantiate the Builders for the OF Actions and Instructions
154             InstructionBuilder ib = new InstructionBuilder();
155             InstructionsBuilder isb = new InstructionsBuilder();
156
157             // Instructions List Stores Individual Instructions
158             List<Instruction> instructions = Lists.newArrayList();
159             List<Instruction> instructions_tmp = Lists.newArrayList();
160
161             /* Strip vlan and store to tmp instruction space*/
162             InstructionUtils.createPopVlanInstructions(ib);
163             ib.setOrder(0);
164             ib.setKey(new InstructionKey(0));
165             instructions_tmp.add(ib.build());
166
167             // Set the Output Port/Iface
168             ib = new InstructionBuilder();
169             InstructionUtils.addOutputPortInstructions(ib, dpidLong, localPort, instructions_tmp);
170             ib.setOrder(1);
171             ib.setKey(new InstructionKey(0));
172             instructions.add(ib.build());
173
174             // Add InstructionBuilder to the Instruction(s)Builder List
175             isb.setInstruction(instructions);
176
177             // Add InstructionsBuilder to FlowBuilder
178             flowBuilder.setInstructions(isb.build());
179             writeFlow(flowBuilder, nodeBuilder);
180         } else {
181             removeFlow(flowBuilder, nodeBuilder);
182         }
183     }
184
185
186     /**
187      * Utility funcion used by the flooding logic to allow a flow to be resubmitted
188      * to the local port flooding rule, after being outputed to all available tunnel
189      * or VLAN egress ports.
190      */
191     private void appendResubmitLocalFlood(InstructionBuilder ib) {
192
193         //Update the ApplyActions instructions
194         ApplyActionsCase aac = (ApplyActionsCase) ib.getInstruction();
195         List<Action> actionList = aac.getApplyActions().getAction();
196
197         int index = actionList.size();
198         ActionBuilder ab = new ActionBuilder();
199         ab.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(ClassifierService.REG_FIELD).build(),
200                 BigInteger.valueOf(ClassifierService.REG_VALUE_FROM_REMOTE)));
201         ab.setOrder(index);
202         ab.setKey(new ActionKey(index));
203         actionList.add(ab.build());
204
205         index++;
206         ab = new ActionBuilder();
207         ab.setAction(ActionUtils.nxResubmitAction(null, this.getTable()));
208         ab.setOrder(index);
209         ab.setKey(new ActionKey(index));
210         actionList.add(ab.build());
211     }
212
213     /*
214      * (Table:2) Local Broadcast Flood
215      * Match: Tunnel ID and dMAC (::::FF:FF)
216      * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
217      * actions=output:2,3,4,5
218      */
219
220     @Override
221     public void programLocalBcastOut(Long dpidLong, String segmentationId, Long localPort, boolean write) {
222
223         String nodeName = OPENFLOW + dpidLong;
224
225         MatchBuilder matchBuilder = new MatchBuilder();
226         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
227         FlowBuilder flowBuilder = new FlowBuilder();
228
229         // Create the OF Match using MatchBuilder
230         MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(ClassifierService.REG_FIELD, ClassifierService.REG_VALUE_FROM_REMOTE));
231         flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
232         flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
233                 new MacAddress("01:00:00:00:00:00")).build());
234
235         String flowId = "BcastOut_"+segmentationId;
236         // Add Flow Attributes
237         flowBuilder.setId(new FlowId(flowId));
238         FlowKey key = new FlowKey(new FlowId(flowId));
239         flowBuilder.setStrict(true);
240         flowBuilder.setBarrier(false);
241         flowBuilder.setTableId(getTable());
242         flowBuilder.setKey(key);
243         flowBuilder.setPriority(16384);
244         flowBuilder.setFlowName(flowId);
245         flowBuilder.setHardTimeout(0);
246         flowBuilder.setIdleTimeout(0);
247         Flow flow = this.getFlow(flowBuilder, nodeBuilder);
248         // Instantiate the Builders for the OF Actions and Instructions
249         InstructionBuilder ib = new InstructionBuilder();
250         InstructionsBuilder isb = new InstructionsBuilder();
251         List<Instruction> instructions = Lists.newArrayList();
252         List<Instruction> existingInstructions = null;
253         if (flow != null) {
254             Instructions ins = flow.getInstructions();
255             if (ins != null) {
256                 existingInstructions = ins.getInstruction();
257             }
258         }
259
260         if (write) {
261             // Create output port list
262             createOutputPortInstructions(ib, dpidLong, localPort, existingInstructions);
263             ib.setOrder(0);
264             ib.setKey(new InstructionKey(0));
265
266             /* Alternative method to address Bug 2004 is to make a call
267              * here to appendResubmitLocalFlood(ib) so that we send the
268              * flow back to the local flood rule.
269              */
270             instructions.add(ib.build());
271
272             // Add InstructionBuilder to the Instruction(s)Builder List
273             isb.setInstruction(instructions);
274
275             // Add InstructionsBuilder to FlowBuilder
276             flowBuilder.setInstructions(isb.build());
277
278             writeFlow(flowBuilder, nodeBuilder);
279         } else {
280             boolean flowRemove = InstructionUtils.removeOutputPortFromInstructions(ib, dpidLong, localPort,
281                     existingInstructions);
282             if (flowRemove) {
283                 /* if all ports are removed, remove flow */
284                 removeFlow(flowBuilder, nodeBuilder);
285             } else {
286                 /* Install instruction with new output port list*/
287                 ib.setOrder(0);
288                 ib.setKey(new InstructionKey(0));
289                 instructions.add(ib.build());
290
291                 // Add InstructionBuilder to the Instruction(s)Builder List
292                 isb.setInstruction(instructions);
293
294                 // Add InstructionsBuilder to FlowBuilder
295                 flowBuilder.setInstructions(isb.build());
296                 writeFlow(flowBuilder, nodeBuilder);
297             }
298         }
299     }
300
301     /*
302      * (Table:2) Local VLAN Broadcast Flood
303      * Match: vlan ID and dMAC (::::FF:FF)
304      * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
305      * actions=strip_vlan, output:2,3,4,5
306      * table=110,dl_vlan=2001,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=output:2,pop_vlan,output:1,output:3,output:4
307      */
308
309     @Override
310     public void programLocalVlanBcastOut(Long dpidLong, String segmentationId,
311                                          Long localPort, Long ethPort, boolean write) {
312
313         String nodeName = OPENFLOW + dpidLong;
314
315         MatchBuilder matchBuilder = new MatchBuilder();
316         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
317         FlowBuilder flowBuilder = new FlowBuilder();
318
319         // Create the OF Match using MatchBuilder
320         flowBuilder.setMatch(
321                 MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true).build());
322         flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
323                 new MacAddress("01:00:00:00:00:00")).build());
324
325         String flowId = "VlanBcastOut_"+segmentationId+"_"+ethPort;
326         // Add Flow Attributes
327         flowBuilder.setId(new FlowId(flowId));
328         FlowKey key = new FlowKey(new FlowId(flowId));
329         flowBuilder.setStrict(true);
330         flowBuilder.setBarrier(false);
331         flowBuilder.setTableId(getTable());
332         flowBuilder.setKey(key);
333         flowBuilder.setPriority(16384);
334         flowBuilder.setFlowName(flowId);
335         flowBuilder.setHardTimeout(0);
336         flowBuilder.setIdleTimeout(0);
337         Flow flow = this.getFlow(flowBuilder, nodeBuilder);
338         // Instantiate the Builders for the OF Actions and Instructions
339         List<Instruction> existingInstructions = null;
340         if (flow != null) {
341             Instructions ins = flow.getInstructions();
342             if (ins != null) {
343                 existingInstructions = ins.getInstruction();
344             }
345         }
346
347         List<Instruction> instructions = Lists.newArrayList();
348         InstructionBuilder ib = new InstructionBuilder();
349         List<Action> actionList = null;
350         if (write) {
351             if (existingInstructions == null) {
352                 /* First time called there should be no instructions.
353                  * We can simply add the output:ethPort first, followed by
354                  * popVlan and then the local port. The next calls will append
355                  * the rest of the local ports.
356                  */
357                 ActionBuilder ab = new ActionBuilder();
358                 actionList = Lists.newArrayList();
359
360                 ab.setAction(ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + ethPort)));
361                 ab.setOrder(0);
362                 ab.setKey(new ActionKey(0));
363                 actionList.add(ab.build());
364
365                 ab.setAction(ActionUtils.popVlanAction());
366                 ab.setOrder(1);
367                 ab.setKey(new ActionKey(1));
368                 actionList.add(ab.build());
369
370                 ab.setAction(ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + localPort)));
371                 ab.setOrder(2);
372                 ab.setKey(new ActionKey(2));
373                 actionList.add(ab.build());
374             } else {
375                 /* Subsequent calls require appending any new local ports for this tenant. */
376                 ApplyActionsCase aac = (ApplyActionsCase) ib.getInstruction();
377                 Instruction in = existingInstructions.get(0);
378                 actionList = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
379
380                 NodeConnectorId ncid = new NodeConnectorId(nodeName + ":" + localPort);
381                 boolean addNew = true;
382
383                 /* Check if the port is already in the output list */
384                 for (Action action : actionList) {
385                     if (action.getAction() instanceof OutputActionCase) {
386                         OutputActionCase opAction = (OutputActionCase) action.getAction();
387                         if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
388                             addNew = false;
389                             break;
390                         }
391                     }
392                 }
393
394                 if (addNew) {
395                     ActionBuilder ab = new ActionBuilder();
396
397                     ab.setAction(ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + localPort)));
398                     ab.setOrder(actionList.size());
399                     ab.setKey(new ActionKey(actionList.size()));
400                     actionList.add(ab.build());
401                 }
402             }
403
404             ApplyActionsBuilder aab = new ApplyActionsBuilder();
405             aab.setAction(actionList);
406             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
407             ib.setOrder(0);
408             ib.setKey(new InstructionKey(0));
409             instructions.add(ib.build());
410
411             // Add InstructionBuilder to the Instruction(s)Builder List
412             InstructionsBuilder isb = new InstructionsBuilder();
413             isb.setInstruction(instructions);
414
415             // Add InstructionsBuilder to FlowBuilder
416             flowBuilder.setInstructions(isb.build());
417             writeFlow(flowBuilder, nodeBuilder);
418         } else {
419             //boolean flowRemove = removeOutputPortFromGroup(nodeBuilder, ib, dpidLong,
420             //                     localPort, existingInstructions);
421             boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong, localPort, ethPort,
422                     existingInstructions);
423             if (flowRemove) {
424                 /* if all ports are removed, remove flow */
425                 removeFlow(flowBuilder, nodeBuilder);
426             } else {
427                 /* Install instruction with new output port list*/
428                 ib.setOrder(0);
429                 ib.setKey(new InstructionKey(0));
430                 instructions.add(ib.build());
431
432                 // Add InstructionBuilder to the Instruction(s)Builder List
433                 InstructionsBuilder isb = new InstructionsBuilder();
434                 isb.setInstruction(instructions);
435
436                 // Add InstructionsBuilder to FlowBuilder
437                 flowBuilder.setInstructions(isb.build());
438                 writeFlow(flowBuilder, nodeBuilder);
439             }
440         }
441     }
442
443     private boolean removeOutputPortFromInstructions(InstructionBuilder ib, Long dpidLong, Long localPort,
444                                                      Long ethPort, List<Instruction> instructions) {
445         List<Action> actionList = Lists.newArrayList();
446         boolean removeFlow = true;
447
448         if (instructions != null) {
449             ApplyActionsCase aac = (ApplyActionsCase) ib.getInstruction();
450             Instruction in = instructions.get(0);
451             List<Action> oldActionList = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
452             NodeConnectorId ncid = new NodeConnectorId(OPENFLOW + dpidLong + ":" + localPort);
453             NodeConnectorId ncidEth = new NodeConnectorId(OPENFLOW + dpidLong + ":" + ethPort);
454
455             // Remove the port from the output list
456             ActionBuilder ab = new ActionBuilder();
457             int index = 2;
458             //for (ListIterator<Action> it = oldActionList.listIterator(oldActionList.size()); it.hasPrevious();) {
459             //    Action action = it.previous();
460             for (Action action : oldActionList) {
461                 if (action.getAction() instanceof OutputActionCase) {
462                     OutputActionCase opAction = (OutputActionCase) action.getAction();
463                     if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncidEth))) {
464                         actionList.add(action);
465                     } else if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid)) == false) {
466                         ab.setAction(action.getAction());
467                         ab.setOrder(index);
468                         ab.setKey(new ActionKey(index));
469                         actionList.add(ab.build());
470                         index++;
471                     }
472                 } else {
473                     actionList.add(action);
474                 }
475             }
476             ApplyActionsBuilder aab = new ApplyActionsBuilder();
477             aab.setAction(actionList);
478             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
479         }
480
481         if (actionList != null && actionList.size() > 2) {
482             // Add InstructionBuilder to the Instruction(s)Builder List
483             InstructionsBuilder isb = new InstructionsBuilder();
484             isb.setInstruction(instructions);
485             removeFlow = false;
486         }
487
488         return removeFlow;
489     }
490
491     /*
492      * (Table:1) Local Table Miss
493      * Match: Any Remaining Flows w/a TunID
494      * Action: Drop w/ a low priority
495      * table=2,priority=8192,tun_id=0x5 actions=drop
496      */
497
498     @Override
499     public void programLocalTableMiss(Long dpidLong, String segmentationId, boolean write) {
500
501         String nodeName = OPENFLOW + dpidLong;
502
503         MatchBuilder matchBuilder = new MatchBuilder();
504         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
505         FlowBuilder flowBuilder = new FlowBuilder();
506
507         // Create Match(es) and Set them in the FlowBuilder Object
508         flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
509
510         if (write) {
511             // Create the OF Actions and Instructions
512             InstructionBuilder ib = new InstructionBuilder();
513             InstructionsBuilder isb = new InstructionsBuilder();
514
515             // Instructions List Stores Individual Instructions
516             List<Instruction> instructions = Lists.newArrayList();
517
518             // Call the InstructionBuilder Methods Containing Actions
519             InstructionUtils.createDropInstructions(ib);
520             ib.setOrder(0);
521             ib.setKey(new InstructionKey(0));
522             instructions.add(ib.build());
523
524             // Add InstructionBuilder to the Instruction(s)Builder List
525             isb.setInstruction(instructions);
526
527             // Add InstructionsBuilder to FlowBuilder
528             flowBuilder.setInstructions(isb.build());
529         }
530
531         String flowId = "LocalTableMiss_"+segmentationId;
532         // Add Flow Attributes
533         flowBuilder.setId(new FlowId(flowId));
534         FlowKey key = new FlowKey(new FlowId(flowId));
535         flowBuilder.setStrict(true);
536         flowBuilder.setBarrier(false);
537         flowBuilder.setTableId(getTable());
538         flowBuilder.setKey(key);
539         flowBuilder.setPriority(8192);
540         flowBuilder.setFlowName(flowId);
541         flowBuilder.setHardTimeout(0);
542         flowBuilder.setIdleTimeout(0);
543         if (write) {
544             writeFlow(flowBuilder, nodeBuilder);
545         } else {
546             removeFlow(flowBuilder, nodeBuilder);
547         }
548     }
549
550     /*
551      * (Table:1) Local Table Miss
552      * Match: Any Remaining Flows w/a VLAN ID
553      * Action: Drop w/ a low priority
554      * table=2,priority=8192,vlan_id=0x5 actions=drop
555      */
556
557     @Override
558     public void programLocalVlanTableMiss(Long dpidLong, String segmentationId, boolean write) {
559
560         String nodeName = OPENFLOW + dpidLong;
561
562         MatchBuilder matchBuilder = new MatchBuilder();
563         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
564         FlowBuilder flowBuilder = new FlowBuilder();
565
566         // Create Match(es) and Set them in the FlowBuilder Object
567         flowBuilder.setMatch(
568                 MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true).build());
569
570         if (write) {
571             // Create the OF Actions and Instructions
572             InstructionBuilder ib = new InstructionBuilder();
573             InstructionsBuilder isb = new InstructionsBuilder();
574
575             // Instructions List Stores Individual Instructions
576             List<Instruction> instructions = Lists.newArrayList();
577
578             // Call the InstructionBuilder Methods Containing Actions
579             InstructionUtils.createDropInstructions(ib);
580             ib.setOrder(0);
581             ib.setKey(new InstructionKey(0));
582             instructions.add(ib.build());
583
584             // Add InstructionBuilder to the Instruction(s)Builder List
585             isb.setInstruction(instructions);
586
587             // Add InstructionsBuilder to FlowBuilder
588             flowBuilder.setInstructions(isb.build());
589         }
590
591         String flowId = "LocalTableMiss_"+segmentationId;
592         // Add Flow Attributes
593         flowBuilder.setId(new FlowId(flowId));
594         FlowKey key = new FlowKey(new FlowId(flowId));
595         flowBuilder.setStrict(true);
596         flowBuilder.setBarrier(false);
597         flowBuilder.setTableId(getTable());
598         flowBuilder.setKey(key);
599         flowBuilder.setPriority(8192);
600         flowBuilder.setFlowName(flowId);
601         flowBuilder.setHardTimeout(0);
602         flowBuilder.setIdleTimeout(0);
603         if (write) {
604             writeFlow(flowBuilder, nodeBuilder);
605         } else {
606             removeFlow(flowBuilder, nodeBuilder);
607         }
608     }
609
610
611     /*
612      * (Table:1) Egress Tunnel Traffic
613      * Match: Destination Ethernet Addr and Local InPort
614      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
615      * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
616      * actions=output:10,goto_table:2"
617      */
618     // TODO : Check on the reason why the original handleTunnelOut was chaining the traffic to table 2
619     @Override
620     public void programTunnelOut(Long dpidLong, String segmentationId, Long OFPortOut, String attachedMac, boolean write) {
621
622         String nodeName = OPENFLOW + dpidLong;
623
624         MatchBuilder matchBuilder = new MatchBuilder();
625         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
626         FlowBuilder flowBuilder = new FlowBuilder();
627
628         // Create the OF Match using MatchBuilder
629         flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
630         flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null).build());
631
632         String flowId = "TunnelOut_"+segmentationId+"_"+OFPortOut+"_"+attachedMac;
633         // Add Flow Attributes
634         flowBuilder.setId(new FlowId(flowId));
635         FlowKey key = new FlowKey(new FlowId(flowId));
636         flowBuilder.setStrict(true);
637         flowBuilder.setBarrier(false);
638         flowBuilder.setTableId(getTable());
639         flowBuilder.setKey(key);
640         flowBuilder.setFlowName(flowId);
641         flowBuilder.setHardTimeout(0);
642         flowBuilder.setIdleTimeout(0);
643
644         if (write) {
645             // Instantiate the Builders for the OF Actions and Instructions
646             InstructionBuilder ib = new InstructionBuilder();
647             InstructionsBuilder isb = new InstructionsBuilder();
648
649             // Instructions List Stores Individual Instructions
650             List<Instruction> instructions = Lists.newArrayList();
651
652             // Set the Output Port/Iface
653             InstructionUtils.createOutputPortInstructions(ib, dpidLong, OFPortOut);
654             ib.setOrder(0);
655             ib.setKey(new InstructionKey(1));
656             instructions.add(ib.build());
657
658             // Add InstructionBuilder to the Instruction(s)Builder List
659             isb.setInstruction(instructions);
660
661             // Add InstructionsBuilder to FlowBuilder
662             flowBuilder.setInstructions(isb.build());
663
664             writeFlow(flowBuilder, nodeBuilder);
665         } else {
666             removeFlow(flowBuilder, nodeBuilder);
667         }
668     }
669
670     /*
671      * (Table:1) Egress VLAN Traffic
672      * Match: Destination Ethernet Addr and VLAN id
673      * Instruction: GOTO Table Table 2
674      * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
675      * actions= goto_table:2"
676      */
677     // TODO : Check on the reason why the original handleTunnelOut was chaining the traffic to table 2
678     @Override
679     public void programVlanOut(Long dpidLong, String segmentationId, Long ethPort, String attachedMac, boolean write) {
680
681         String nodeName = OPENFLOW + dpidLong;
682
683         MatchBuilder matchBuilder = new MatchBuilder();
684         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
685         FlowBuilder flowBuilder = new FlowBuilder();
686
687         // Create the OF Match using MatchBuilder
688         flowBuilder.setMatch(
689                 MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true).build());
690         flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null).build());
691
692         String flowId = "VlanOut_"+segmentationId+"_"+ethPort+"_"+attachedMac;
693         // Add Flow Attributes
694         flowBuilder.setId(new FlowId(flowId));
695         FlowKey key = new FlowKey(new FlowId(flowId));
696         flowBuilder.setStrict(true);
697         flowBuilder.setBarrier(false);
698         flowBuilder.setTableId(getTable());
699         flowBuilder.setKey(key);
700         flowBuilder.setFlowName(flowId);
701         flowBuilder.setHardTimeout(0);
702         flowBuilder.setIdleTimeout(0);
703
704         if (write) {
705             // Instantiate the Builders for the OF Actions and Instructions
706             InstructionBuilder ib = new InstructionBuilder();
707             InstructionsBuilder isb = new InstructionsBuilder();
708
709             // Instructions List Stores Individual Instructions
710             List<Instruction> instructions = Lists.newArrayList();
711             InstructionUtils.createOutputPortInstructions(ib, dpidLong, ethPort);
712             ib.setOrder(0);
713             ib.setKey(new InstructionKey(1));
714             instructions.add(ib.build());
715
716             // Add InstructionBuilder to the Instruction(s)Builder List
717             isb.setInstruction(instructions);
718
719             // Add InstructionsBuilder to FlowBuilder
720             flowBuilder.setInstructions(isb.build());
721
722             writeFlow(flowBuilder, nodeBuilder);
723         } else {
724             removeFlow(flowBuilder, nodeBuilder);
725         }
726     }
727
728     /*
729      * (Table:1) Egress Tunnel Traffic
730      * Match: Destination Ethernet Addr and Local InPort
731      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
732      * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
733      * actions=output:10,output:11,goto_table:2
734      */
735     @Override
736     public void programTunnelFloodOut(Long dpidLong, String segmentationId, Long OFPortOut, boolean write) {
737
738         String nodeName = OPENFLOW + dpidLong;
739
740         MatchBuilder matchBuilder = new MatchBuilder();
741         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
742         FlowBuilder flowBuilder = new FlowBuilder();
743
744         // Create the OF Match using MatchBuilder
745         // Match TunnelID
746         MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(ClassifierService.REG_FIELD, ClassifierService.REG_VALUE_FROM_LOCAL));
747         flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
748         // Match DMAC
749         flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
750                 new MacAddress("01:00:00:00:00:00")).build());
751
752         String flowId = "TunnelFloodOut_"+segmentationId;
753         // Add Flow Attributes
754         flowBuilder.setId(new FlowId(flowId));
755         FlowKey key = new FlowKey(new FlowId(flowId));
756         flowBuilder.setBarrier(true);
757         flowBuilder.setTableId(getTable());
758         flowBuilder.setKey(key);
759         flowBuilder.setPriority(16384);
760         flowBuilder.setFlowName(flowId);
761         flowBuilder.setHardTimeout(0);
762         flowBuilder.setIdleTimeout(0);
763
764         Flow flow = this.getFlow(flowBuilder, nodeBuilder);
765         // Instantiate the Builders for the OF Actions and Instructions
766         InstructionBuilder ib = new InstructionBuilder();
767         InstructionsBuilder isb = new InstructionsBuilder();
768         List<Instruction> instructions = Lists.newArrayList();
769         List<Instruction> existingInstructions = null;
770         if (flow != null) {
771             Instructions ins = flow.getInstructions();
772             if (ins != null) {
773                 existingInstructions = ins.getInstruction();
774             }
775         }
776
777         if (write) {
778             // Set the Output Port/Iface
779             //createOutputGroupInstructions(nodeBuilder, ib, dpidLong, OFPortOut, existingInstructions);
780             createOutputPortInstructions(ib, dpidLong, OFPortOut, existingInstructions);
781             ib.setOrder(0);
782             ib.setKey(new InstructionKey(0));
783             instructions.add(ib.build());
784
785             // Add InstructionBuilder to the Instruction(s)Builder List
786             isb.setInstruction(instructions);
787
788             // Add InstructionsBuilder to FlowBuilder
789             flowBuilder.setInstructions(isb.build());
790
791             writeFlow(flowBuilder, nodeBuilder);
792         } else {
793             /* remove port from action list */
794             boolean flowRemove = InstructionUtils.removeOutputPortFromInstructions(ib, dpidLong,
795                     OFPortOut, existingInstructions);
796             if (flowRemove) {
797                 /* if all port are removed, remove the flow too. */
798                 removeFlow(flowBuilder, nodeBuilder);
799             } else {
800                 /* Install instruction with new output port list*/
801                 ib.setOrder(0);
802                 ib.setKey(new InstructionKey(0));
803                 instructions.add(ib.build());
804
805                 // Add InstructionBuilder to the Instruction(s)Builder List
806                 isb.setInstruction(instructions);
807
808                 // Add InstructionsBuilder to FlowBuilder
809                 flowBuilder.setInstructions(isb.build());
810                 writeFlow(flowBuilder, nodeBuilder);
811             }
812         }
813     }
814
815     /*
816      * (Table:1) Egress VLAN Traffic
817      * Match: Destination Ethernet Addr and VLAN id
818      * Instruction: GOTO table 2 and Output port eth interface
819      * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
820      * actions=output:eth1,goto_table:2
821      */
822
823     @Override
824     public void programVlanFloodOut(Long dpidLong, String segmentationId, Long ethPort, boolean write) {
825
826         String nodeName = OPENFLOW + dpidLong;
827
828         MatchBuilder matchBuilder = new MatchBuilder();
829         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
830         FlowBuilder flowBuilder = new FlowBuilder();
831
832         // Create the OF Match using MatchBuilder
833         // Match Vlan ID
834         flowBuilder.setMatch(
835                 MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true).build());
836         // Match DMAC
837         flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
838                 new MacAddress("01:00:00:00:00:00")).build());
839
840         String flowId = "VlanFloodOut_"+segmentationId+"_"+ethPort;
841         // Add Flow Attributes
842         flowBuilder.setId(new FlowId(flowId));
843         FlowKey key = new FlowKey(new FlowId(flowId));
844         flowBuilder.setBarrier(true);
845         flowBuilder.setTableId(getTable());
846         flowBuilder.setKey(key);
847         flowBuilder.setPriority(16384);
848         flowBuilder.setFlowName(flowId);
849         flowBuilder.setHardTimeout(0);
850         flowBuilder.setIdleTimeout(0);
851
852         //ToDo: Is there something to be done with result of the call to getFlow?
853
854         Flow flow = this.getFlow(flowBuilder, nodeBuilder);
855         // Instantiate the Builders for the OF Actions and Instructions
856         InstructionBuilder ib = new InstructionBuilder();
857         InstructionsBuilder isb = new InstructionsBuilder();
858         List<Instruction> instructions = Lists.newArrayList();
859
860         if (write) {
861             // Set the Output Port/Iface
862             InstructionUtils.createOutputPortInstructions(ib, dpidLong, ethPort);
863             ib.setOrder(0);
864             ib.setKey(new InstructionKey(0));
865             instructions.add(ib.build());
866
867             // Add InstructionBuilder to the Instruction(s)Builder List
868             isb.setInstruction(instructions);
869
870             // Add InstructionsBuilder to FlowBuilder
871             flowBuilder.setInstructions(isb.build());
872
873             writeFlow(flowBuilder, nodeBuilder);
874         } else {
875             removeFlow(flowBuilder, nodeBuilder);
876         }
877     }
878
879     /*
880      * (Table:1) Table Drain w/ Catch All
881      * Match: Tunnel ID
882      * Action: GOTO Local Table (10)
883      * table=2,priority=8192,tun_id=0x5 actions=drop
884      */
885     @Override
886     public void programTunnelMiss(Long dpidLong, String segmentationId, boolean write) {
887
888         String nodeName = OPENFLOW + dpidLong;
889
890         MatchBuilder matchBuilder = new MatchBuilder();
891         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
892         FlowBuilder flowBuilder = new FlowBuilder();
893
894         // Create Match(es) and Set them in the FlowBuilder Object
895         flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
896
897         if (write) {
898             // Create the OF Actions and Instructions
899             InstructionBuilder ib = new InstructionBuilder();
900             InstructionsBuilder isb = new InstructionsBuilder();
901
902             // Instructions List Stores Individual Instructions
903             List<Instruction> instructions = Lists.newArrayList();
904
905             // Call the InstructionBuilder Methods Containing Actions
906             ib = this.getMutablePipelineInstructionBuilder();
907             ib.setOrder(0);
908             ib.setKey(new InstructionKey(0));
909             instructions.add(ib.build());
910
911             // Add InstructionBuilder to the Instruction(s)Builder List
912             isb.setInstruction(instructions);
913
914             // Add InstructionsBuilder to FlowBuilder
915             flowBuilder.setInstructions(isb.build());
916         }
917
918         String flowId = "TunnelMiss_"+segmentationId;
919         // Add Flow Attributes
920         flowBuilder.setId(new FlowId(flowId));
921         FlowKey key = new FlowKey(new FlowId(flowId));
922         flowBuilder.setStrict(true);
923         flowBuilder.setBarrier(false);
924         flowBuilder.setTableId(getTable());
925         flowBuilder.setKey(key);
926         flowBuilder.setPriority(8192);
927         flowBuilder.setFlowName(flowId);
928         flowBuilder.setHardTimeout(0);
929         flowBuilder.setIdleTimeout(0);
930         if (write) {
931             writeFlow(flowBuilder, nodeBuilder);
932         } else {
933             removeFlow(flowBuilder, nodeBuilder);
934         }
935     }
936
937     /*
938      * (Table:1) Table Drain w/ Catch All
939      * Match: Vlan ID
940      * Action: Output port eth interface
941      * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
942      * table=110,priority=8192,dl_vlan=2001 actions=output:2
943      */
944
945     @Override
946     public void programVlanMiss(Long dpidLong, String segmentationId, Long ethPort, boolean write) {
947
948         String nodeName = OPENFLOW + dpidLong;
949
950         MatchBuilder matchBuilder = new MatchBuilder();
951         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
952         FlowBuilder flowBuilder = new FlowBuilder();
953
954         // Create Match(es) and Set them in the FlowBuilder Object
955         flowBuilder.setMatch(
956                 MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true).build());
957
958         if (write) {
959             // Create the OF Actions and Instructions
960             InstructionBuilder ib = new InstructionBuilder();
961             InstructionsBuilder isb = new InstructionsBuilder();
962
963             // Instructions List Stores Individual Instructions
964             List<Instruction> instructions = Lists.newArrayList();
965
966             // Set the Output Port/Iface
967             InstructionUtils.createOutputPortInstructions(ib, dpidLong, ethPort);
968             ib.setOrder(0);
969             ib.setKey(new InstructionKey(1));
970             instructions.add(ib.build());
971
972             // Add InstructionBuilder to the Instruction(s)Builder List
973             isb.setInstruction(instructions);
974
975             // Add InstructionsBuilder to FlowBuilder
976             flowBuilder.setInstructions(isb.build());
977         }
978
979         String flowId = "VlanMiss_"+segmentationId;
980         // Add Flow Attributes
981         flowBuilder.setId(new FlowId(flowId));
982         FlowKey key = new FlowKey(new FlowId(flowId));
983         flowBuilder.setStrict(true);
984         flowBuilder.setBarrier(false);
985         flowBuilder.setTableId(getTable());
986         flowBuilder.setKey(key);
987         flowBuilder.setPriority(8192);
988         flowBuilder.setFlowName(flowId);
989         flowBuilder.setHardTimeout(0);
990         flowBuilder.setIdleTimeout(0);
991         if (write) {
992             writeFlow(flowBuilder, nodeBuilder);
993         } else {
994             removeFlow(flowBuilder, nodeBuilder);
995         }
996     }
997
998     /**
999      * Create Output Port Group Instruction
1000      *
1001      * @param ib       Map InstructionBuilder without any instructions
1002      * @param dpidLong Long the datapath ID of a switch/node
1003      * @param port     Long representing a port on a switch/node
1004      * @return ib InstructionBuilder Map with instructions
1005      */
1006     protected InstructionBuilder createOutputPortInstructions(InstructionBuilder ib,
1007             Long dpidLong, Long port ,
1008             List<Instruction> instructions) {
1009         NodeConnectorId ncid = new NodeConnectorId(OPENFLOW + dpidLong + ":" + port);
1010         logger.debug("createOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1011
1012         List<Action> actionList = Lists.newArrayList();
1013         ActionBuilder ab = new ActionBuilder();
1014
1015         List<Action> existingActions;
1016         if (instructions != null && instructions.size() > 0) {
1017             /**
1018              * First instruction is the one containing the output ports.
1019              * So, only extract the actions from that.
1020              */
1021             Instruction in = instructions.get(0);
1022             if (in.getInstruction() instanceof ApplyActionsCase) {
1023                 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1024                 // Only include output actions
1025                 for (Action action : existingActions)
1026                     if (action.getAction() instanceof OutputActionCase)
1027                         actionList.add(action);
1028             }
1029         }
1030         /* Create output action for this port*/
1031         OutputActionBuilder oab = new OutputActionBuilder();
1032         oab.setOutputNodeConnector(ncid);
1033         ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1034         boolean addNew = true;
1035
1036         /* Find the group action and get the group */
1037         for (Action action : actionList) {
1038             OutputActionCase opAction = (OutputActionCase)action.getAction();
1039             /* If output port action already in the action list of one of the buckets, skip */
1040             if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1041                 addNew = false;
1042                 break;
1043             }
1044         }
1045         if (addNew) {
1046             ab.setOrder(actionList.size());
1047             ab.setKey(new ActionKey(actionList.size()));
1048             actionList.add(ab.build());
1049         }
1050         // Create an Apply Action
1051         ApplyActionsBuilder aab = new ApplyActionsBuilder();
1052         aab.setAction(actionList);
1053         ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1054         logger.debug("createOutputPortInstructions() : applyAction {}", aab.build());
1055         return ib;
1056     }
1057 }