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