Bug 7606: Fix for missed tunnel flows, after VM live migration
[netvirt.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / netvirt / openstack / netvirt / providers / openflow13 / services / L2ForwardingService.java
1 /*
2  * Copyright (c) 2014, 2015 Red Hat, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services;
10
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15
16 import org.opendaylight.netvirt.openstack.netvirt.api.L2ForwardingProvider;
17 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
18 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
19 import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
20 import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
21 import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
22 import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
23 import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
48 import org.osgi.framework.BundleContext;
49 import org.osgi.framework.ServiceReference;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 public class L2ForwardingService extends AbstractServiceInstance implements ConfigInterface, L2ForwardingProvider {
54     private static final Logger LOG = LoggerFactory.getLogger(L2ForwardingService.class);
55     public L2ForwardingService() {
56         super(Service.L2_FORWARDING);
57     }
58
59     public L2ForwardingService(Service service) {
60         super(service);
61     }
62
63     /*
64      * (Table:L2Forwarding) Local Unicast
65      * Match: Tunnel ID and dMAC
66      * Action: Output Port
67      * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2 goto:<next-table>
68      */
69     @Override
70     public void programLocalUcastOut(Long dpidLong, String segmentationId,
71             Long localPort, String attachedMac, boolean write) {
72
73         String nodeName = OPENFLOW + dpidLong;
74
75         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
76         FlowBuilder flowBuilder = new FlowBuilder();
77
78         // Create the OF Match using MatchBuilder
79         MatchBuilder matchBuilder = new MatchBuilder();
80         MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
81         MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null);
82         flowBuilder.setMatch(matchBuilder.build());
83
84         // Add Flow Attributes
85         String flowName = "UcastOut_" + segmentationId + "_" + attachedMac;
86         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
87
88         if (write) {
89             // Set the Output Port/Iface
90             Instruction setOutputPortInstruction =
91                     InstructionUtils.createOutputPortInstructions(new InstructionBuilder(), dpidLong, localPort)
92                             .setOrder(0)
93                             .setKey(new InstructionKey(0))
94                             .build();
95
96             // Add InstructionsBuilder to FlowBuilder
97             InstructionUtils.setFlowBuilderInstruction(flowBuilder, setOutputPortInstruction);
98             writeFlow(flowBuilder, nodeBuilder);
99         } else {
100             removeFlow(flowBuilder, nodeBuilder);
101         }
102     }
103
104     /*
105      * (Table:2) Local VLAN unicast
106      * Match: VLAN ID and dMAC
107      * Action: Output Port
108      * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
109      * table=110,dl_vlan=2001,dl_dst=fa:16:3e:a3:3b:cc actions=pop_vlan,output:1
110      */
111
112     @Override
113     public void programLocalVlanUcastOut (Long dpidLong, String segmentationId, Long localPort, String attachedMac, boolean write) {
114
115         String nodeName = OPENFLOW + dpidLong;
116
117         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
118         FlowBuilder flowBuilder = new FlowBuilder();
119
120         // Create the OF Match using MatchBuilder
121         MatchBuilder matchBuilder = new MatchBuilder();
122         MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
123         MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null);
124         flowBuilder.setMatch(matchBuilder.build());
125
126         // Add Flow Attributes
127         String flowName = "VlanUcastOut_" + segmentationId + "_" + localPort + "_" + attachedMac;
128         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
129
130         if (write) {
131             /* Strip vlan and store to tmp instruction space*/
132             Instruction stripVlanInstruction = InstructionUtils.createPopVlanInstructions(new InstructionBuilder())
133                     .setOrder(0)
134                     .setKey(new InstructionKey(0))
135                     .build();
136
137             // Set the Output Port/Iface
138             Instruction setOutputPortInstruction =
139                     InstructionUtils.addOutputPortInstructions(new InstructionBuilder(), dpidLong, localPort,
140                             Collections.singletonList(stripVlanInstruction))
141                             .setOrder(1)
142                             .setKey(new InstructionKey(0))
143                             .build();
144
145             // Add InstructionsBuilder to FlowBuilder
146             InstructionUtils.setFlowBuilderInstruction(flowBuilder, setOutputPortInstruction);
147             writeFlow(flowBuilder, nodeBuilder);
148         } else {
149             removeFlow(flowBuilder, nodeBuilder);
150         }
151     }
152
153
154     /*
155      * (Table:2) Local Broadcast Flood
156      * Match: Tunnel ID and dMAC (::::FF:FF)
157      * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
158      * actions=output:2,3,4,5
159      */
160
161     @Override
162     public void programLocalBcastOut(Long dpidLong, String segmentationId, Long localPort, boolean write) {
163
164         String nodeName = OPENFLOW + dpidLong;
165
166         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
167         FlowBuilder flowBuilder = new FlowBuilder();
168
169         // Create the OF Match using MatchBuilder
170         MatchBuilder matchBuilder = new MatchBuilder();
171         MatchUtils.addNxRegMatch(matchBuilder,
172                 new MatchUtils.RegMatch(ClassifierService.REG_FIELD, ClassifierService.REG_VALUE_FROM_REMOTE));
173         MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
174         MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
175                 new MacAddress("01:00:00:00:00:00"));
176         flowBuilder.setMatch(matchBuilder.build());
177
178         // Add Flow Attributes
179         String flowName = "BcastOut_" + segmentationId;
180         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable())
181                 .setPriority(16384);
182
183         Flow flow = this.getFlow(flowBuilder, nodeBuilder);
184
185         // Retrieve the existing instructions
186         List<Instruction> existingInstructions = InstructionUtils.extractExistingInstructions(flow);
187
188         if (write) {
189             // Create output port list
190             Instruction outputPortInstruction =
191                     createOutputPortInstructions(new InstructionBuilder(), dpidLong, localPort, existingInstructions)
192                             .setOrder(0)
193                             .setKey(new InstructionKey(0))
194                             .build();
195
196             /* Alternative method to address Bug 2004 is to use appendResubmitLocalFlood(ib) so that we send the
197              * flow back to the local flood rule. (See git history.) */
198
199             // Add InstructionsBuilder to FlowBuilder
200             InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
201
202             writeFlow(flowBuilder, nodeBuilder);
203         } else {
204             InstructionBuilder ib = new InstructionBuilder();
205             boolean flowRemove = InstructionUtils.removeOutputPortFromInstructions(ib, dpidLong, localPort,
206                     existingInstructions);
207             if (flowRemove) {
208                 /* if all ports are removed, remove flow */
209                 removeFlow(flowBuilder, nodeBuilder);
210             } else {
211                 /* Install instruction with new output port list*/
212                 Instruction outputPortInstruction = ib
213                         .setOrder(0)
214                         .setKey(new InstructionKey(0))
215                         .build();
216
217                 // Add InstructionsBuilder to FlowBuilder
218                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
219
220                 writeFlow(flowBuilder, nodeBuilder);
221             }
222         }
223     }
224
225     /*
226      * (Table:2) Local VLAN Broadcast Flood
227      * Match: vlan ID and dMAC (::::FF:FF)
228      * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
229      * actions=strip_vlan, output:2,3,4,5
230      * 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
231      */
232
233     @Override
234     public void programLocalVlanBcastOut(Long dpidLong, String segmentationId,
235                                          Long localPort, Long ethPort, boolean write) {
236
237         String nodeName = OPENFLOW + dpidLong;
238
239         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
240         FlowBuilder flowBuilder = new FlowBuilder();
241
242         // Create the OF Match using MatchBuilder
243         MatchBuilder matchBuilder = new MatchBuilder();
244         MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
245         MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
246                 new MacAddress("01:00:00:00:00:00"));
247         flowBuilder.setMatch(matchBuilder.build());
248
249         // Add Flow Attributes
250         String flowName = "VlanBcastOut_" + segmentationId + "_" + ethPort;
251         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable())
252                 .setPriority(16384);
253         Flow flow = this.getFlow(flowBuilder, nodeBuilder);
254
255         // Retrieve the existing instructions
256         List<Instruction> existingInstructions = InstructionUtils.extractExistingInstructions(flow);
257
258         if (write) {
259             List<Action> actionList;
260             if (existingInstructions == null || existingInstructions.isEmpty()) {
261                 /* First time called there should be no instructions.
262                  * We can simply add the output:ethPort first, followed by
263                  * popVlan and then the local port. The next calls will append
264                  * the rest of the local ports.
265                  */
266                 actionList = new ArrayList<>();
267
268                 actionList.add(
269                         new ActionBuilder()
270                                 .setAction(ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + ethPort)))
271                                 .setOrder(0)
272                                 .setKey(new ActionKey(0))
273                                 .build());
274
275                 actionList.add(
276                         new ActionBuilder()
277                                 .setAction(ActionUtils.popVlanAction())
278                                 .setOrder(1)
279                                 .setKey(new ActionKey(1))
280                                 .build());
281
282                 actionList.add(
283                         new ActionBuilder()
284                                 .setAction(ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + localPort)))
285                                 .setOrder(2)
286                                 .setKey(new ActionKey(2))
287                                 .build());
288             } else {
289                 /* Subsequent calls require appending any new local ports for this tenant. */
290                 Instruction in = existingInstructions.get(0);
291                 actionList = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
292
293                 NodeConnectorId ncid = new NodeConnectorId(nodeName + ":" + localPort);
294                 final Uri nodeConnectorUri = new Uri(ncid);
295                 boolean addNew = true;
296
297                 /* Check if the port is already in the output list */
298                 for (Action action : actionList) {
299                     if (action.getAction() instanceof OutputActionCase) {
300                         OutputActionCase opAction = (OutputActionCase) action.getAction();
301                         if (opAction.getOutputAction().getOutputNodeConnector().equals(nodeConnectorUri)) {
302                             addNew = false;
303                             break;
304                         }
305                     }
306                 }
307
308                 if (addNew) {
309                     actionList.add(
310                             new ActionBuilder()
311                                     .setAction(
312                                             ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + localPort)))
313                                     .setOrder(actionList.size())
314                                     .setKey(new ActionKey(actionList.size()))
315                                     .build());
316                 }
317             }
318
319             ApplyActions applyActions = new ApplyActionsBuilder().setAction(actionList).build();
320             Instruction applyActionsInstruction =
321                     new InstructionBuilder()
322                             .setInstruction(new ApplyActionsCaseBuilder().setApplyActions(applyActions).build())
323                             .setOrder(0)
324                             .setKey(new InstructionKey(0))
325                             .build();
326
327             // Add InstructionsBuilder to FlowBuilder
328             InstructionUtils.setFlowBuilderInstruction(flowBuilder, applyActionsInstruction);
329             writeFlow(flowBuilder, nodeBuilder);
330         } else {
331             InstructionBuilder ib = new InstructionBuilder();
332             boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong, localPort, ethPort,
333                     existingInstructions);
334             if (flowRemove) {
335                 /* if all ports are removed, remove flow */
336                 removeFlow(flowBuilder, nodeBuilder);
337             } else {
338                 /* Install instruction with new output port list*/
339                 Instruction outputPortInstruction = ib
340                         .setOrder(0)
341                         .setKey(new InstructionKey(0))
342                         .build();
343
344                 // Add InstructionsBuilder to FlowBuilder
345                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
346                 writeFlow(flowBuilder, nodeBuilder);
347             }
348         }
349     }
350
351     private boolean removeOutputPortFromInstructions(InstructionBuilder ib, Long dpidLong, Long localPort,
352                                                      Long ethPort, List<Instruction> instructions) {
353         List<Action> actionList = new ArrayList<>();
354         boolean removeFlow = true;
355
356         if (instructions != null && !instructions.isEmpty()) {
357             Instruction in = instructions.get(0);
358             List<Action> oldActionList = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
359             NodeConnectorId ncid = new NodeConnectorId(OPENFLOW + dpidLong + ":" + localPort);
360             final Uri localNodeConnectorUri = new Uri(ncid);
361             NodeConnectorId ncidEth = new NodeConnectorId(OPENFLOW + dpidLong + ":" + ethPort);
362             final Uri ethNodeConnectorUri = new Uri(ncidEth);
363
364             // Remove the port from the output list
365             int index = 2;
366             for (Action action : oldActionList) {
367                 if (action.getAction() instanceof OutputActionCase) {
368                     OutputActionCase opAction = (OutputActionCase) action.getAction();
369                     if (opAction.getOutputAction().getOutputNodeConnector().equals(ethNodeConnectorUri)) {
370                         actionList.add(action);
371                     } else if (!opAction.getOutputAction().getOutputNodeConnector().equals(localNodeConnectorUri)) {
372                         actionList.add(
373                                 new ActionBuilder()
374                                         .setAction(action.getAction())
375                                         .setOrder(index)
376                                         .setKey(new ActionKey(index))
377                                         .build());
378                         index++;
379                     }
380                 } else {
381                     actionList.add(action);
382                 }
383             }
384             ApplyActions applyActions = new ApplyActionsBuilder().setAction(actionList).build();
385             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(applyActions).build());
386         }
387
388         if (actionList.size() > 2) {
389             // Add InstructionBuilder to the Instruction(s)Builder List
390             // TODO This doesn't actually do anything
391             InstructionsBuilder isb = new InstructionsBuilder();
392             isb.setInstruction(instructions);
393             removeFlow = false;
394         }
395
396         return removeFlow;
397     }
398
399     /*
400      * (Table:1) Local Table Miss
401      * Match: Any Remaining Flows w/a VLAN ID
402      * Action: Drop w/ a low priority
403      * table=2,priority=8192,vlan_id=0x5 actions=drop
404      */
405
406     @Override
407     public void programLocalVlanTableMiss(Long dpidLong, String segmentationId, boolean write) {
408
409         String nodeName = OPENFLOW + dpidLong;
410
411         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
412         FlowBuilder flowBuilder = new FlowBuilder();
413
414         // Create Match(es) and Set them in the FlowBuilder Object
415         flowBuilder.setMatch(
416                 MatchUtils.createVlanIdMatch(new MatchBuilder(), new VlanId(Integer.valueOf(segmentationId)),
417                         true).build());
418
419         if (write) {
420             // Call the InstructionBuilder Methods Containing Actions
421             Instruction dropInstruction = InstructionUtils.createDropInstructions(new InstructionBuilder())
422                     .setOrder(0)
423                     .setKey(new InstructionKey(0))
424                     .build();
425
426             // Add InstructionsBuilder to FlowBuilder
427             InstructionUtils.setFlowBuilderInstruction(flowBuilder, dropInstruction);
428         }
429
430         // Add Flow Attributes
431         String flowName = "LocalTableMiss_" + segmentationId;
432         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable())
433                 .setPriority(8192);
434         if (write) {
435             writeFlow(flowBuilder, nodeBuilder);
436         } else {
437             removeFlow(flowBuilder, nodeBuilder);
438         }
439     }
440
441
442     /*
443      * (Table:1) Egress Tunnel Traffic
444      * Match: Destination Ethernet Addr and Local InPort
445      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
446      * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
447      * actions=output:10,goto_table:2"
448      */
449     // TODO : Check on the reason why the original handleTunnelOut was chaining the traffic to table 2
450     @Override
451     public void programTunnelOut(Long dpidLong, String segmentationId, Long OFPortOut, String attachedMac, boolean write) {
452
453         String nodeName = OPENFLOW + dpidLong;
454
455         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
456         FlowBuilder flowBuilder = new FlowBuilder();
457
458         // Create the OF Match using MatchBuilder
459         MatchBuilder matchBuilder = new MatchBuilder();
460         MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
461         MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null);
462         flowBuilder.setMatch(matchBuilder.build());
463
464         // Add Flow Attributes
465         String flowName = "UcastOut_" + segmentationId + "_" + attachedMac;
466         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
467
468         if (write) {
469             // Set the Output Port/Iface
470             Instruction outputPortInstruction =
471                     InstructionUtils.createOutputPortInstructions(new InstructionBuilder(), dpidLong, OFPortOut)
472                             .setOrder(0)
473                             .setKey(new InstructionKey(1))
474                             .build();
475
476             // Add InstructionsBuilder to FlowBuilder
477             InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
478
479             writeFlow(flowBuilder, nodeBuilder);
480         } else {
481             removeFlow(flowBuilder, nodeBuilder);
482         }
483     }
484
485     /*
486      * (Table:1) Egress VLAN Traffic
487      * Match: Destination Ethernet Addr and VLAN id
488      * Instruction: GOTO Table Table 2
489      * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
490      * actions= goto_table:2"
491      */
492     // TODO : Check on the reason why the original handleTunnelOut was chaining the traffic to table 2
493     @Override
494     public void programVlanOut(Long dpidLong, String segmentationId, Long ethPort, String attachedMac, boolean write) {
495
496         String nodeName = OPENFLOW + dpidLong;
497
498         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
499         FlowBuilder flowBuilder = new FlowBuilder();
500
501         // Create the OF Match using MatchBuilder
502         MatchBuilder matchBuilder = new MatchBuilder();
503         MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
504         MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null);
505         flowBuilder.setMatch(matchBuilder.build());
506
507         // Add Flow Attributes
508         String flowName = "VlanOut_" + segmentationId + "_" + ethPort + "_" + attachedMac;
509         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
510
511         if (write) {
512             // Instructions List Stores Individual Instructions
513             Instruction outputPortInstruction =
514                     InstructionUtils.createOutputPortInstructions(new InstructionBuilder(), dpidLong, ethPort)
515                             .setOrder(0)
516                             .setKey(new InstructionKey(1))
517                             .build();
518
519             // Add InstructionsBuilder to FlowBuilder
520             InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
521
522             writeFlow(flowBuilder, nodeBuilder);
523         } else {
524             removeFlow(flowBuilder, nodeBuilder);
525         }
526     }
527
528     /*
529      * (Table:1) Egress Tunnel Traffic
530      * Match: Destination Ethernet Addr and Local InPort
531      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
532      * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
533      * actions=output:10,output:11,goto_table:2
534      */
535     @Override
536     public void programTunnelFloodOut(Long dpidLong, String segmentationId, Long OFPortOut, boolean write) {
537
538         String nodeName = OPENFLOW + dpidLong;
539
540         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
541         FlowBuilder flowBuilder = new FlowBuilder();
542
543         // Create the OF Match using MatchBuilder
544         MatchBuilder matchBuilder = new MatchBuilder();
545         // Match TunnelID
546         MatchUtils.addNxRegMatch(matchBuilder,
547                 new MatchUtils.RegMatch(ClassifierService.REG_FIELD, ClassifierService.REG_VALUE_FROM_LOCAL));
548         MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
549         // Match DMAC
550         MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
551                 new MacAddress("01:00:00:00:00:00"));
552         flowBuilder.setMatch(matchBuilder.build());
553
554         // Add Flow Attributes
555         String flowName = "TunnelFloodOut_" + segmentationId;
556         final FlowId flowId = new FlowId(flowName);
557         flowBuilder
558                 .setId(flowId)
559                 .setBarrier(true)
560                 .setTableId(getTable())
561                 .setKey(new FlowKey(flowId))
562                 .setPriority(16383)  // FIXME: change it back to 16384 once bug 3005 is fixed.
563                 .setFlowName(flowName)
564                 .setHardTimeout(0)
565                 .setIdleTimeout(0);
566
567         Flow flow = this.getFlow(flowBuilder, nodeBuilder);
568         // Instantiate the Builders for the OF Actions and Instructions
569         List<Instruction> existingInstructions = InstructionUtils.extractExistingInstructions(flow);
570
571         if (write) {
572             // Set the Output Port/Iface
573             Instruction outputPortInstruction =
574                     createOutputPortInstructions(new InstructionBuilder(), dpidLong, OFPortOut, existingInstructions)
575                             .setOrder(0)
576                             .setKey(new InstructionKey(0))
577                             .build();
578
579             // Add InstructionsBuilder to FlowBuilder
580             InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
581
582             writeFlow(flowBuilder, nodeBuilder);
583         } else {
584             InstructionBuilder ib = new InstructionBuilder();
585             /* remove port from action list */
586             boolean flowRemove = InstructionUtils.removeOutputPortFromInstructions(ib, dpidLong,
587                     OFPortOut, existingInstructions);
588             if (flowRemove) {
589                 /* if all port are removed, remove the flow too. */
590                 removeFlow(flowBuilder, nodeBuilder);
591             } else {
592                 /* Install instruction with new output port list*/
593                 Instruction instruction = ib
594                         .setOrder(0)
595                         .setKey(new InstructionKey(0))
596                         .build();
597
598                 // Add InstructionsBuilder to FlowBuilder
599                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, instruction);
600                 writeFlow(flowBuilder, nodeBuilder);
601             }
602         }
603     }
604
605     /*
606      * (Table:110) Flooding local unknown unicast Traffic
607      * Match: TunnelID and Unknown unicast and Local InPort
608      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
609      * table=110,priority=16380,tun_id=0x5,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 \
610      * actions=output:10,output:11
611      */
612     @Override
613     public void programTunnelUnknownUcastFloodOut(Long dpidLong, String segmentationId, Long OFPortOut, boolean write) {
614
615         String nodeName = OPENFLOW + dpidLong;
616
617         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
618         FlowBuilder flowBuilder = new FlowBuilder();
619
620         // Create the OF Match using MatchBuilder
621         MatchBuilder matchBuilder = new MatchBuilder();
622         // Match TunnelID
623         MatchUtils.addNxRegMatch(matchBuilder,
624                 new MatchUtils.RegMatch(ClassifierService.REG_FIELD, ClassifierService.REG_VALUE_FROM_LOCAL));
625         MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
626         // Match DMAC
627         MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("00:00:00:00:00:00"),
628                 new MacAddress("01:00:00:00:00:00"));
629         flowBuilder.setMatch(matchBuilder.build());
630
631         // Add Flow Attributes
632         String flowName = "TunnelUnknownUcastFloodOut_" + segmentationId;
633         final FlowId flowId = new FlowId(flowName);
634         flowBuilder
635                 .setId(flowId)
636                 .setBarrier(true)
637                 .setTableId(getTable())
638                 .setKey(new FlowKey(flowId))
639                 .setPriority(16380)
640                 .setFlowName(flowName)
641                 .setHardTimeout(0)
642                 .setIdleTimeout(0);
643
644         Flow flow = this.getFlow(flowBuilder, nodeBuilder);
645         // Instantiate the Builders for the OF Actions and Instructions
646         List<Instruction> existingInstructions = InstructionUtils.extractExistingInstructions(flow);
647
648         if (write) {
649             // Set the Output Port/Iface
650             Instruction outputPortInstruction =
651                     createOutputPortInstructions(new InstructionBuilder(), dpidLong, OFPortOut, existingInstructions)
652                             .setOrder(0)
653                             .setKey(new InstructionKey(0))
654                             .build();
655
656             // Add InstructionsBuilder to FlowBuilder
657             InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
658
659             writeFlow(flowBuilder, nodeBuilder);
660         } else {
661             InstructionBuilder ib = new InstructionBuilder();
662             /* remove port from action list */
663             boolean flowRemove = InstructionUtils.removeOutputPortFromInstructions(ib, dpidLong,
664                     OFPortOut, existingInstructions);
665             if (flowRemove) {
666                 /* if all port are removed, remove the flow too. */
667                 removeFlow(flowBuilder, nodeBuilder);
668             } else {
669                 /* Install instruction with new output port list*/
670                 Instruction instruction = ib
671                         .setOrder(0)
672                         .setKey(new InstructionKey(0))
673                         .build();
674
675                 // Add InstructionsBuilder to FlowBuilder
676                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, instruction);
677                 writeFlow(flowBuilder, nodeBuilder);
678             }
679         }
680     }
681     
682     /*
683      * (Table:1) Table Drain w/ Catch All
684      * Match: Vlan ID
685      * Action: Output port eth interface
686      * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
687      * table=110,priority=8192,dl_vlan=2001 actions=output:2
688      */
689
690     @Override
691     public void programVlanMiss(Long dpidLong, String segmentationId, Long ethPort, boolean write) {
692
693         String nodeName = OPENFLOW + dpidLong;
694
695         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
696         FlowBuilder flowBuilder = new FlowBuilder();
697
698         // Create Match(es) and Set them in the FlowBuilder Object
699         flowBuilder.setMatch(
700                 MatchUtils.createVlanIdMatch(new MatchBuilder(), new VlanId(Integer.valueOf(segmentationId)),
701                         true).build());
702
703         if (write) {
704             // Set the Output Port/Iface
705             Instruction outputPortInstruction =
706                     InstructionUtils.createOutputPortInstructions(new InstructionBuilder(), dpidLong, ethPort)
707                             .setOrder(0)
708                             .setKey(new InstructionKey(1))
709                             .build();
710
711             // Add InstructionsBuilder to FlowBuilder
712             InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
713         }
714
715         // Add Flow Attributes
716         String flowName = "VlanMiss_" + segmentationId;
717         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable())
718                 .setPriority(8192);
719         if (write) {
720             writeFlow(flowBuilder, nodeBuilder);
721         } else {
722             removeFlow(flowBuilder, nodeBuilder);
723         }
724     }
725
726     /**
727      * Create Output Port Group Instruction
728      *
729      * @param ib       Map InstructionBuilder without any instructions
730      * @param dpidLong Long the datapath ID of a switch/node
731      * @param port     Long representing a port on a switch/node
732      * @param instructions List of instructions
733      * @return ib InstructionBuilder Map with instructions
734      */
735     protected InstructionBuilder createOutputPortInstructions(InstructionBuilder ib,
736             Long dpidLong, Long port ,
737             List<Instruction> instructions) {
738         NodeConnectorId ncid = new NodeConnectorId(OPENFLOW + dpidLong + ":" + port);
739         LOG.debug("createOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
740
741         List<Action> actionList = new ArrayList<>();
742         ActionBuilder ab = new ActionBuilder();
743
744         List<Action> existingActions;
745         if (instructions != null && instructions.size() > 0) {
746             /**
747              * First instruction is the one containing the output ports.
748              * So, only extract the actions from that.
749              */
750             Instruction in = instructions.get(0);
751             if (in.getInstruction() instanceof ApplyActionsCase) {
752                 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
753                 // Only include output actions
754                 for (Action action : existingActions) {
755                     if (action.getAction() instanceof OutputActionCase) {
756                         actionList.add(action);
757                     }
758                 }
759             }
760         }
761         /* Create output action for this port*/
762         OutputActionBuilder oab = new OutputActionBuilder();
763         oab.setOutputNodeConnector(ncid);
764         ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
765         boolean addNew = true;
766
767         /* Find the group action and get the group */
768         for (Action action : actionList) {
769             OutputActionCase opAction = (OutputActionCase)action.getAction();
770             /* If output port action already in the action list of one of the buckets, skip */
771             if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
772                 addNew = false;
773                 break;
774             }
775         }
776         if (addNew) {
777             ab.setOrder(actionList.size());
778             ab.setKey(new ActionKey(actionList.size()));
779             actionList.add(ab.build());
780         }
781         // Create an Apply Action
782         ApplyActionsBuilder aab = new ApplyActionsBuilder();
783         aab.setAction(actionList);
784         ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
785         LOG.debug("createOutputPortInstructions() : applyAction {}", aab.build());
786         return ib;
787     }
788
789     @Override
790     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
791         super.setDependencies(bundleContext.getServiceReference(L2ForwardingProvider.class.getName()), this);
792     }
793
794     @Override
795     public void setDependencies(Object impl) {
796
797     }
798 }