Remove OvsdbConfigurationService
[ovsdb.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / providers / openflow13 / OF13Provider.java
1 /**
2  * Copyright (C) 2013 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 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
9
10 import java.net.InetAddress;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Set;
14 import java.util.concurrent.ExecutionException;
15
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
18 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
19 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
22 import org.opendaylight.neutron.spi.NeutronNetwork;
23 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
24 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
25 import org.opendaylight.ovsdb.openstack.netvirt.api.*;
26 import org.opendaylight.ovsdb.openstack.netvirt.impl.MdsalUtils;
27 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
28 import org.opendaylight.ovsdb.utils.mdsal.node.StringConvertor;
29 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
72 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
75 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
79
80 import com.google.common.base.Optional;
81 import com.google.common.base.Preconditions;
82 import com.google.common.collect.Lists;
83 import com.google.common.collect.Maps;
84 import com.google.common.util.concurrent.CheckedFuture;
85
86 /**
87  * Open vSwitch OpenFlow 1.3 Networking Provider for OpenStack Neutron
88  *
89  * @author Madhu Venugopal
90  * @author Brent Salisbury
91  * @author Dave Tucker
92  * @author Sam Hague
93  */
94 public class OF13Provider implements NetworkingProvider {
95     private static final Logger logger = LoggerFactory.getLogger(OF13Provider.class);
96     private DataBroker dataBroker;
97     private static final short TABLE_0_DEFAULT_INGRESS = 0;
98     private static final short TABLE_1_ISOLATE_TENANT = 10;
99     private static final short TABLE_2_LOCAL_FORWARD = 20;
100     private static Long groupId = 1L;
101
102     private volatile ConfigurationService configurationService;
103     private volatile BridgeConfigurationManager bridgeConfigurationManager;
104     private volatile TenantNetworkManager tenantNetworkManager;
105     private volatile SecurityServicesManager securityServicesManager;
106     private volatile OvsdbConnectionService connectionService;
107     private volatile MdsalConsumer mdsalConsumer;
108     private volatile ClassifierProvider classifierProvider;
109     private volatile IngressAclProvider ingressAclProvider;
110     //private volatile EgressAclProvider egressAclProvider;
111     private volatile L2ForwardingProvider l2ForwardingProvider;
112
113     public static final String NAME = "OF13Provider";
114
115     public void init() {
116         logger.info(">>>>>> init OF13Provider {}", this.getClass());
117     }
118
119     @Override
120     public String getName() {
121         return NAME;
122     }
123
124     @Override
125     public boolean supportsServices() {
126         return true;
127     }
128
129     @Override
130     public boolean hasPerTenantTunneling() {
131         return false;
132     }
133
134     private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
135         InetAddress srcTunnelEndPoint = configurationService.getTunnelEndPoint(node);
136         if (srcTunnelEndPoint == null) {
137             logger.error("Tunnel Endpoint not configured for Node {}", node);
138             return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
139         }
140
141         if (!bridgeConfigurationManager.isNodeNeutronReady(node)) {
142             logger.error(node+" is not Overlay ready");
143             return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
144         }
145
146         if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, tunnelKey)) {
147             logger.debug(node+" has no VM corresponding to segment "+ tunnelKey);
148             return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
149         }
150         return new Status(StatusCode.SUCCESS);
151     }
152
153     private String getTunnelName(String tunnelType, InetAddress dst) {
154         return tunnelType+"-"+dst.getHostAddress();
155     }
156
157     private boolean addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst) {
158         String tunnelBridgeName = configurationService.getIntegrationBridgeName();
159         String portName = getTunnelName(tunnelType, dst);
160         if (MdsalUtils.getPort(node, portName) != null) {
161             logger.trace("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node);
162             return true;
163         }
164
165         Map<String, String> options = Maps.newHashMap();
166         options.put("key", "flow");
167         options.put("local_ip", src.getHostAddress());
168         options.put("remote_ip", dst.getHostAddress());
169
170         if (!MdsalUtils.addTunnelPort(node, tunnelBridgeName, portName, tunnelType, options)) {
171             logger.error("Failed to insert Tunnel port {} in {}", portName, tunnelBridgeName);
172             return false;
173         }
174
175         return true;
176     }
177
178     /* delete port from ovsdb port table */
179     private boolean deletePort(Node node, String bridgeName, String portName) {
180         // TODO SB_MIGRATION
181         // might need to convert from ovsdb node to bridge node
182         return MdsalUtils.deletePort(node, portName);
183     }
184
185     private boolean deleteTunnelPort(Node node, String tunnelType, InetAddress src, InetAddress dst) {
186         String tunnelBridgeName = configurationService.getIntegrationBridgeName();
187         String portName = getTunnelName(tunnelType, dst);
188         return deletePort(node, tunnelBridgeName, portName);
189     }
190
191     private boolean deletePhysicalPort(Node node, String phyIntfName) {
192         String intBridgeName = configurationService.getIntegrationBridgeName();
193         return deletePort(node, intBridgeName, phyIntfName);
194     }
195
196     private void programLocalBridgeRules(Node node, Long dpid, String segmentationId,
197                                          String attachedMac, long localPort) {
198         /*
199          * Table(0) Rule #3
200          * ----------------
201          * Match: VM sMac and Local Ingress Port
202          * Action:Action: Set Tunnel ID and GOTO Local Table (5)
203          */
204
205         handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT,
206                 segmentationId, localPort, attachedMac, true);
207
208         /*
209          * Table(0) Rule #4
210          * ----------------
211          * Match: Drop any remaining Ingress Local VM Packets
212          * Action: Drop w/ a low priority
213          */
214
215         handleDropSrcIface(dpid, localPort, true);
216
217         /*
218          * Table(2) Rule #1
219          * ----------------
220          * Match: Match TunID and Destination DL/dMAC Addr
221          * Action: Output Port
222          * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
223          */
224
225         handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, true);
226
227         /*
228          * Table(2) Rule #2
229          * ----------------
230          * Match: Tunnel ID and dMAC (::::FF:FF)
231          * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
232          * actions=output:2,3,4,5
233          */
234
235         handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
236         handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
237
238         /*
239          * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
240          */
241         /*
242          * Table(1) Rule #3
243          * ----------------
244          * Match:  Any remaining Ingress Local VM Packets
245          * Action: Drop w/ a low priority
246          * -------------------------------------------
247          * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
248          */
249
250         handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, true);
251
252         /*
253          * Table(2) Rule #3
254          * ----------------
255          * Match: Any Remaining Flows w/a TunID
256          * Action: Drop w/ a low priority
257          * table=2,priority=8192,tun_id=0x5 actions=drop
258          */
259
260         handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, true);
261     }
262
263     private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
264         /*
265          * Table(0) Rule #3
266          * ----------------
267          * Match: VM sMac and Local Ingress Port
268          * Action:Action: Set Tunnel ID and GOTO Local Table (5)
269          */
270
271         handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
272
273         /*
274          * Table(0) Rule #4
275          * ----------------
276          * Match: Drop any remaining Ingress Local VM Packets
277          * Action: Drop w/ a low priority
278          */
279
280         handleDropSrcIface(dpid, localPort, false);
281
282         /*
283          * Table(2) Rule #1
284          * ----------------
285          * Match: Match TunID and Destination DL/dMAC Addr
286          * Action: Output Port
287          * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
288          */
289
290         handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
291
292         /*
293          * Table(2) Rule #2
294          * ----------------
295          * Match: Tunnel ID and dMAC (::::FF:FF)
296          * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
297          * actions=output:2,3,4,5
298          */
299
300         handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
301         handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
302     }
303
304     private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
305         /*
306          * Table(0) Rule #2
307          * ----------------
308          * Match: Ingress Port, Tunnel ID
309          * Action: GOTO Local Table (20)
310          */
311
312         handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
313
314         /*
315          * Table(1) Rule #2
316          * ----------------
317          * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
318          * Action: Flood to selected destination TEPs
319          * -------------------------------------------
320          * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
321          * actions=output:10,output:11,goto_table:2
322          */
323
324         handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
325
326     }
327
328     private void programRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
329         /*
330          * Table(1) Rule #1
331          * ----------------
332          * Match: Drop any remaining Ingress Local VM Packets
333          * Action: Drop w/ a low priority
334          * -------------------------------------------
335          * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
336          * actions=output:11,goto_table:2
337          */
338
339         handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, true);
340     }
341
342     private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
343         /*
344          * Table(1) Rule #1
345          * ----------------
346          * Match: Drop any remaining Ingress Local VM Packets
347          * Action: Drop w/ a low priority
348          * -------------------------------------------
349          * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
350          * actions=output:11,goto_table:2
351          */
352
353         handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
354     }
355
356     /* Remove tunnel rules if last node in this tenant network */
357     private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) {
358         /*
359          * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
360          */
361         /*
362          * Table(1) Rule #3
363          * ----------------
364          * Match:  Any remaining Ingress Local VM Packets
365          * Action: Drop w/ a low priority
366          * -------------------------------------------
367          * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
368          */
369
370         handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, false);
371
372         /*
373          * Table(2) Rule #3
374          * ----------------
375          * Match: Any Remaining Flows w/a TunID
376          * Action: Drop w/ a low priority
377          * table=2,priority=8192,tun_id=0x5 actions=drop
378          */
379
380         handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
381
382         /*
383          * Table(0) Rule #2
384          * ----------------
385          * Match: Ingress Port, Tunnel ID
386          * Action: GOTO Local Table (10)
387          */
388
389         handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
390
391         /*
392          * Table(1) Rule #2
393          * ----------------
394          * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
395          * Action: Flood to selected destination TEPs
396          * -------------------------------------------
397          * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
398          * actions=output:10,output:11,goto_table:2
399          */
400
401         handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
402     }
403
404     private void programLocalVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
405         /*
406          * Table(0) Rule #1
407          * ----------------
408          * Tag traffic coming from the local port and vm srcmac
409          * Match: VM sMac and Local Ingress Port
410          * Action: Set VLAN ID and GOTO Local Table 1
411          */
412
413         handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
414                 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
415                 attachedMac, true);
416
417         /*
418          * Table(0) Rule #3
419          * ----------------
420          * Drop all other traffic coming from the local port
421          * Match: Drop any remaining Ingress Local VM Packets
422          * Action: Drop w/ a low priority
423          */
424
425         handleDropSrcIface(dpid, localPort, true);
426
427         /*
428          * Table(2) Rule #1
429          * ----------------
430          * Forward unicast traffic destined to the local port after stripping tag
431          * Match: Match VLAN ID and Destination DL/dMAC Addr
432          * Action: strip vlan, output to local port
433          * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
434          */
435
436         handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
437                 localPort, attachedMac, true);
438
439         /*
440          * Table(2) Rule #2
441          * ----------------
442          * Match: VLAN ID and dMAC (::::FF:FF)
443          * Action: strip vlan, output to all local ports in this vlan
444          * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
445          * actions= strip_vlan, output:2,3,4,5
446          */
447
448         //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
449         //        localPort, ethPort, true);
450         //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
451         //        segmentationId, localPort, ethport, true);
452
453         /*
454          * Table(2) Rule #3
455          * ----------------
456          * Match: Any Remaining Flows w/a VLAN ID
457          * Action: Drop w/ a low priority
458          * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
459          */
460
461         //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
462         //        true);
463     }
464
465     private void removeLocalVlanRules(Node node, Long dpid,
466                                       String segmentationId, String attachedMac, long localPort) {
467         /*
468          * Table(0) Rule #1
469          * ----------------
470          * Match: VM sMac and Local Ingress Port
471          * Action: Set VLAN ID and GOTO Local Table 1
472          */
473
474         handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
475                 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
476                 attachedMac, false);
477
478         /*
479          * Table(0) Rule #3
480          * ----------------
481          * Match: Drop any remaining Ingress Local VM Packets
482          * Action: Drop w/ a low priority
483          */
484
485         handleDropSrcIface(dpid, localPort, false);
486
487         /*
488          * Table(2) Rule #1
489          * ----------------
490          * Match: Match VLAN ID and Destination DL/dMAC Addr
491          * Action: strip vlan, output to local port
492          * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
493          */
494
495         handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
496                 localPort, attachedMac, false);
497
498         /*
499          * Table(2) Rule #2
500          * ----------------
501          * Match: VLAN ID and dMAC (::::FF:FF)
502          * Action: strip vlan, output to all local ports in this vlan
503          * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
504          * actions= strip_vlan, output:2,3,4,5
505          */
506
507         //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
508         //        localPort, ethPort, false);
509         //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
510         //        segmentationId, localPort, false);
511
512     }
513
514     private void programLocalIngressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac,
515                                               long localPort, long ethPort) {
516         /*
517          * Table(0) Rule #2
518          * ----------------
519          * Match: Ingress port = physical interface, Vlan ID
520          * Action: GOTO Local Table 2
521          */
522
523         handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD,
524                 segmentationId, ethPort, true);
525
526         /*
527          * Table(1) Rule #2
528          * ----------------
529          * Match: Match VLAN ID and L2 ::::FF:FF Flooding
530          * Action: Flood to local and remote VLAN members
531          * -------------------------------------------
532          * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
533          * actions=output:10 (eth port),goto_table:2
534          * table=110, priority=16384,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
535          */
536
537         handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, true);
538
539         /*
540          * Table(1) Rule #2
541          * ----------------
542          * Match: Match VLAN ID and L2 ::::FF:FF Flooding
543          * Action: Flood to local and remote VLAN members
544          * -------------------------------------------
545          * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
546          * actions=output:10 (eth port),goto_table:2
547          */
548
549         //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
550         //        segmentationId, ethPort, true);
551     }
552
553     private void programRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
554                                               String attachedMac, long ethPort) {
555         /*
556          * Table(1) Rule #1
557          * ----------------
558          * Match: Destination MAC is local VM MAC and vlan id
559          * Action: go to table 2
560          * -------------------------------------------
561          * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
562          * actions=goto_table:2
563          */
564
565         //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
566         //        segmentationId, ethPort, attachedMac, true);
567
568         /*
569          * Table(1) Rule #3
570          * ----------------
571          * Match:  VLAN ID
572          * Action: Go to table 2
573          * -------------------------------------------
574          * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
575          * table=110,priority=8192,dl_vlan=2001 actions=output:2
576          */
577
578         handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, true);
579     }
580
581     private void removeRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
582                                              String attachedMac, long localPort, long ethPort) {
583         /*
584          * Table(1) Rule #1
585          * ----------------
586          * Match: Destination MAC is local VM MAC and vlan id
587          * Action: go to table 2
588          * -------------------------------------------
589          * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
590          * actions=goto_table:2
591          */
592
593         //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
594         //        segmentationId, ethPort, attachedMac, false);
595
596         /*
597          * Table(1) Rule #2
598          * ----------------
599          * Match: Match VLAN ID and L2 ::::FF:FF Flooding
600          * Action: Flood to local and remote VLAN members
601          * -------------------------------------------
602          * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
603          * actions=output:10 (eth port),goto_table:2
604          * table=110, priority=16384,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
605          */
606
607         handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
608     }
609
610     private void removePerVlanRules(Node node, Long dpid, String segmentationId, long localPort, long ethPort) {
611         /*
612          * Table(2) Rule #3
613          * ----------------
614          * Match: Any Remaining Flows w/a VLAN ID
615          * Action: Drop w/ a low priority
616          * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
617          */
618
619         //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
620
621         /*
622          * Table(0) Rule #2
623          * ----------------
624          * Match: Ingress port = physical interface, Vlan ID
625          * Action: GOTO Local Table 2
626          */
627
628         handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
629
630         /*
631          * Table(1) Rule #2
632          * ----------------
633          * Match: Match VLAN ID and L2 ::::FF:FF Flooding
634          * Action: Flood to local and remote VLAN members
635          * -------------------------------------------
636          * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
637          * actions=output:10 (eth port),goto_table:2
638          * table=110, priority=16384,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
639          */
640
641         //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
642
643         /*
644          * Table(1) Rule #2
645          * ----------------
646          * Match: Match VLAN ID and L2 ::::FF:FF Flooding
647          * Action: Flood to local and remote VLAN members
648          * -------------------------------------------
649          * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
650          * actions=output:10 (eth port),goto_table:2
651          */
652
653         //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
654         //        segmentationId, ethPort, false);
655
656         /*
657          * Table(1) Rule #3
658          * ----------------
659          * Match:  VLAN ID
660          * Action: Go to table 2
661          * -------------------------------------------
662          * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
663          * table=110,priority=8192,dl_vlan=2001 actions=output:2
664          */
665
666         handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
667     }
668
669     private Long getDpid (Node node) {
670         String datapathIdString = node.getAugmentation(OvsdbBridgeAugmentation.class).getDatapathId().getValue();
671         Long dpidLong = StringConvertor.dpidStringToLong(datapathIdString);
672         return dpidLong;
673     }
674
675     private Long getIntegrationBridgeOFDPID (Node node) {
676         Long dpid = 0L;
677         if (getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
678             dpid = getDpid(node);
679         }
680         return dpid;
681     }
682
683     private Long getExternalBridgeDpid (Node node) {
684         Long dpid = 0L;
685         if (getBridgeName(node).equals(configurationService.getExternalBridgeName())) {
686             dpid = getDpid(node);
687         }
688         return dpid;
689     }
690
691     private void programLocalRules (String networkType, String segmentationId, Node node,
692                                     OvsdbTerminationPointAugmentation intf) {
693         try {
694             Long dpid = this.getIntegrationBridgeOFDPID(node);
695             if (dpid == 0L) {
696                 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
697                 return;
698             }
699
700             long localPort = (Long)intf.getOfport();
701
702             String attachedMac = MdsalUtils.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
703             if (attachedMac == null) {
704                 logger.warn("No AttachedMac seen in {}", intf);
705                 return;
706             }
707
708             /* Program local rules based on network type */
709             if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
710                 logger.debug("Program local vlan rules for interface {}", intf.getName());
711                 programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
712             }
713             /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
714             /* TODO SB_MIGRATION */
715             /*if ((networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
716                     (NetworkHandler.NETWORK_TYPE_VXLAN)) && securityServicesManager.isPortSecurityReady(intf)) {
717                 logger.debug("Neutron port has a Port Security Group");
718                 // Retrieve the security group UUID from the Neutron Port
719                 NeutronSecurityGroup securityGroupInPort = securityServicesManager.getSecurityGroupInPort(intf);
720                 logger.debug("Program Local rules for networkType: {} does contain a Port Security Group: {} " +
721                         "to be installed on DPID: {}", networkType, securityGroupInPort, dpid);
722                 ingressAclProvider.programPortSecurityACL(dpid, segmentationId, attachedMac, localPort,
723                         securityGroupInPort);
724                 egressAclProvider.programPortSecurityACL(dpid, segmentationId, attachedMac, localPort,
725                         securityGroupInPort);
726             }*/
727             if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
728                     networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
729                 logger.debug("Program local bridge rules for interface {}", intf.getName());
730                 programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
731             }
732         } catch (Exception e) {
733             logger.error("Exception in programming Local Rules for "+intf+" on "+node, e);
734         }
735     }
736
737     private void removeLocalRules (String networkType, String segmentationId, Node node,
738                                    OvsdbTerminationPointAugmentation intf) {
739         try {
740             Long dpid = this.getIntegrationBridgeOFDPID(node);
741             if (dpid == 0L) {
742                 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
743                 return;
744             }
745
746             long localPort = (Long)intf.getOfport();
747
748             String attachedMac = MdsalUtils.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
749             if (attachedMac == null) {
750                 logger.warn("No AttachedMac seen in {}", intf);
751                 return;
752             }
753
754             /* Program local rules based on network type */
755             if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
756                 logger.debug("Remove local vlan rules for interface {}", intf.getName());
757                 removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
758             } else if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
759                     networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
760                 logger.debug("Remove local bridge rules for interface {}", intf.getName());
761                 removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
762             }
763         } catch (Exception e) {
764             logger.error("Exception in removing Local Rules for "+intf+" on "+node, e);
765         }
766     }
767
768     private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
769                                      OvsdbTerminationPointAugmentation intf, boolean local) {
770         try {
771             Long dpid = this.getIntegrationBridgeOFDPID(node);
772             if (dpid == 0L) {
773                 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
774                 return;
775             }
776
777             long localPort = (Long)intf.getOfport();
778
779             String attachedMac = MdsalUtils.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
780             if (attachedMac == null) {
781                 logger.warn("No AttachedMac seen in {}", intf);
782                 return;
783             }
784
785             List<OvsdbTerminationPointAugmentation> intfs = MdsalUtils.getPorts(node);
786             for (OvsdbTerminationPointAugmentation tunIntf : intfs) {
787                 Long ofPort = 0L;
788                 if (tunIntf.getName().equals(this.getTunnelName(tunnelType, dst))) {
789                     long tunnelOFPort = (Long)intf.getOfport();
790
791                     if (tunnelOFPort == -1) {
792                         logger.error("Could not Identify Tunnel port {} -> OF ({}) on {}",
793                                 tunIntf.getName(), tunnelOFPort, node);
794                         return;
795                     }
796                     logger.debug("Identified Tunnel port {} -> OF ({}) on {}",
797                             tunIntf.getName(), tunnelOFPort, node);
798
799                     if (!local) {
800                         programRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
801                                 tunnelOFPort, localPort);
802                     }
803                     logger.trace("program local ingress tunnel rules: node {}, intf {}",
804                             node.getNodeId().getValue(), intf.getName());
805                     if (local) {
806                         programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
807                                 tunnelOFPort, localPort);
808                     }
809                     return;
810                 }
811             }
812         } catch (Exception e) {
813             logger.error("", e);
814         }
815     }
816
817     private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
818                                     OvsdbTerminationPointAugmentation intf,
819                                     boolean local, boolean isLastInstanceOnNode) {
820         try {
821             Long dpid = this.getIntegrationBridgeOFDPID(node);
822             if (dpid == 0L) {
823                 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
824                 return;
825             }
826
827             long localPort = (Long)intf.getOfport();
828
829             String attachedMac = MdsalUtils.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
830             if (attachedMac == null) {
831                 logger.error("No AttachedMac seen in {}", intf);
832                 return;
833             }
834
835             List<OvsdbTerminationPointAugmentation> intfs = MdsalUtils.getPorts(node);
836             for (OvsdbTerminationPointAugmentation tunIntf : intfs) {
837                 Long ofPort = 0L;
838                 if (tunIntf.getName().equals(this.getTunnelName(tunnelType, dst))) {
839                     long tunnelOFPort = (Long)intf.getOfport();
840
841                     if (tunnelOFPort == -1) {
842                         logger.error("Could not Identify Tunnel port {} -> OF ({}) on {}",
843                                 tunIntf.getName(), tunnelOFPort, node);
844                         return;
845                     }
846                     logger.debug("Identified Tunnel port {} -> OF ({}) on {}",
847                             tunIntf.getName(), tunnelOFPort, node);
848
849                     if (!local) {
850                         removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
851                                 tunnelOFPort, localPort);
852                     }
853                     if (local && isLastInstanceOnNode) {
854                         removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort);
855                     }
856                     return;
857                 }
858             }
859         } catch (Exception e) {
860             logger.error("", e);
861         }
862     }
863
864     private void programVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf) {
865         logger.debug("Program vlan rules for interface {}", intf.getName());
866         Long dpid = getIntegrationBridgeOFDPID(node);
867         if (dpid == 0L) {
868             logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
869             return;
870         }
871
872         long localPort = (Long)intf.getOfport();
873
874         String attachedMac = MdsalUtils.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
875         if (attachedMac == null) {
876             logger.error("No AttachedMac seen in {}", intf);
877             return;
878         }
879
880         List<OvsdbTerminationPointAugmentation> intfs = MdsalUtils.getPorts(node);
881         for (OvsdbTerminationPointAugmentation ethIntf : intfs) {
882             Long ofPort = 0L;
883             if (ethIntf.getName().equalsIgnoreCase(bridgeConfigurationManager.getPhysicalInterfaceName(
884                     node, network.getProviderPhysicalNetwork()))) {
885                 long ethOFPort = (Long)ethIntf.getOfport();
886                 logger.debug("Identified eth port {} -> OF ({}) on {}",
887                         ethIntf.getName(), ethOFPort, node);
888                 // TODO: add logic to only add rule on remote nodes
889                 programRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
890                         attachedMac, ethOFPort);
891                 programLocalIngressVlanRules(node, dpid, network.getProviderSegmentationID(),
892                         attachedMac, localPort, ethOFPort);
893                 return;
894             }
895         }
896     }
897
898     private void removeVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf,
899                                   boolean isLastInstanceOnNode) {
900         logger.debug("Program vlan rules for interface {}", intf.getName());
901         Long dpid = this.getIntegrationBridgeOFDPID(node);
902         if (dpid == 0L) {
903             logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
904             return;
905         }
906
907         long localPort = (Long)intf.getOfport();
908
909         String attachedMac = MdsalUtils.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
910         if (attachedMac == null) {
911             logger.error("No AttachedMac seen in {}", intf);
912             return;
913         }
914
915         List<OvsdbTerminationPointAugmentation> intfs = MdsalUtils.getPorts(node);
916         for (OvsdbTerminationPointAugmentation ethIntf : intfs) {
917             Long ofPort = 0L;
918             if (ethIntf.getName().equalsIgnoreCase(bridgeConfigurationManager.getPhysicalInterfaceName(
919                     node, network.getProviderPhysicalNetwork()))) {
920                 long ethOFPort = (Long)ethIntf.getOfport();
921                 logger.debug("Identified eth port {} -> OF ({}) on {}",
922                         ethIntf.getName(), ethOFPort, node);
923                 removeRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
924                         attachedMac, localPort, ethOFPort);
925                 if (isLastInstanceOnNode) {
926                     removePerVlanRules(node, dpid, network.getProviderSegmentationID(), localPort, ethOFPort);
927                 }
928                 return;
929             }
930         }
931     }
932
933     @Override
934     public boolean handleInterfaceUpdate(NeutronNetwork network, Node srcNode,
935                                          OvsdbTerminationPointAugmentation intf) {
936         Preconditions.checkNotNull(connectionService);
937         List<Node> nodes = connectionService.getNodes();
938         nodes.remove(srcNode);
939         String networkType = network.getProviderNetworkType();
940         String segmentationId = network.getProviderSegmentationID();
941         programLocalRules(networkType, network.getProviderSegmentationID(), srcNode, intf);
942
943         if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
944             programVlanRules(network, srcNode, intf);
945         } else if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
946                 || networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)){
947             for (Node dstNode : nodes) {
948                 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
949                 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
950                 if ((src != null) && (dst != null)) {
951                     if (addTunnelPort(srcNode, networkType, src, dst)) {
952                         programTunnelRules(networkType, segmentationId, dst, srcNode, intf, true);
953                     }
954                     if (addTunnelPort(dstNode, networkType, dst, src)) {
955                         programTunnelRules(networkType, segmentationId, src, dstNode, intf, false);
956                     }
957                 } else {
958                     logger.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
959                                     + "Check source {} or destination {}",
960                             src != null ? src.getHostAddress() : "null",
961                             dst != null ? dst.getHostAddress() : "null");
962                 }
963             }
964         }
965
966         return true;
967     }
968
969     private void triggerInterfaceUpdates(Node node) {
970         List<TerminationPoint> tps = MdsalUtils.getTerminationPoints(node);
971         for (TerminationPoint tp : tps) {
972             OvsdbTerminationPointAugmentation port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
973             if (port != null) {
974                 logger.debug("Trigger Interface update for {}", port);
975                 handleInterfaceUpdate(tenantNetworkManager.getTenantNetwork(port), node, port);
976             }
977         }
978     }
979
980     @Override
981     public boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
982                                          OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
983         Preconditions.checkNotNull(connectionService);
984         List<Node> nodes = connectionService.getNodes();
985         nodes.remove(srcNode);
986
987         logger.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
988         List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
989         if (MdsalUtils.isTunnel(intf)) {
990             // Delete tunnel port
991             try {
992                 InetAddress src = InetAddress.getByName(
993                         MdsalUtils.getOptionsValue(intf.getOptions(), "local_ip"));
994                 InetAddress dst = InetAddress.getByName(
995                         MdsalUtils.getOptionsValue(intf.getOptions(), "remote_ip"));
996                 deleteTunnelPort(srcNode,
997                         SouthboundMapper.createOvsdbInterfaceType(intf.getInterfaceType()),
998                         src, dst);
999             } catch (Exception e) {
1000                 logger.error(e.getMessage(), e);
1001             }
1002         } else if (phyIfName.contains(intf.getName())) {
1003             deletePhysicalPort(srcNode, intf.getName());
1004         } else {
1005             // delete all other interfaces
1006             removeLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(),
1007                     srcNode, intf);
1008
1009             if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
1010                 removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
1011             } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
1012                     || network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
1013
1014                 for (Node dstNode : nodes) {
1015                     InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1016                     InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1017                     if ((src != null) && (dst != null)) {
1018                         logger.info("Remove tunnel rules for interface "
1019                                 + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
1020                         this.removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1021                                 dst, srcNode, intf, true, isLastInstanceOnNode);
1022                         logger.info("Remove tunnel rules for interface "
1023                                 + intf.getName() + " on dstNode " + dstNode.getNodeId().getValue());
1024                         this.removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1025                                 src, dstNode, intf, false, isLastInstanceOnNode);
1026                     } else {
1027                         logger.warn("Tunnel end-point configuration missing. Please configure it in "
1028                                 + "OpenVSwitch Table. "
1029                                 + "Check source {} or destination {}",
1030                                 src != null ? src.getHostAddress() : "null",
1031                                 dst != null ? dst.getHostAddress() : "null");
1032                     }
1033                 }
1034             }
1035         }
1036         return true;
1037     }
1038
1039     @Override
1040     public void initializeFlowRules(Node node) {
1041         initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1042         initializeFlowRules(node, configurationService.getExternalBridgeName());
1043         triggerInterfaceUpdates(node);
1044     }
1045
1046     private void initializeFlowRules(Node node, String bridgeName) {
1047         Long dpid = getDpid(node);
1048         logger.info("initializeFlowRules: bridgeName: {}, dpid: {}", bridgeName, dpid);
1049
1050         if (dpid == 0L) {
1051             logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1052             return;
1053         }
1054
1055         /*
1056          * Table(0) Rule #1
1057          * ----------------
1058          * Match: LLDP (0x88CCL)
1059          * Action: Packet_In to Controller Reserved Port
1060          */
1061
1062         writeLLDPRule(dpid);
1063
1064         if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1065             writeNormalRule(dpid);
1066         }
1067     }
1068
1069     /*
1070      * Create an LLDP Flow Rule to encapsulate into
1071      * a packet_in that is sent to the controller
1072      * for topology handling.
1073      * Match: Ethertype 0x88CCL
1074      * Action: Punt to Controller in a Packet_In msg
1075      */
1076
1077     private void writeLLDPRule(Long dpidLong) {
1078         classifierProvider.programLLDPPuntRule(dpidLong);
1079     }
1080
1081     /*
1082      * Create a NORMAL Table Miss Flow Rule
1083      * Match: any
1084      * Action: forward to NORMAL pipeline
1085      */
1086
1087     private void writeNormalRule(Long dpidLong) {
1088
1089         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
1090
1091         MatchBuilder matchBuilder = new MatchBuilder();
1092         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
1093         FlowBuilder flowBuilder = new FlowBuilder();
1094
1095         // Create the OF Actions and Instructions
1096         InstructionBuilder ib = new InstructionBuilder();
1097         InstructionsBuilder isb = new InstructionsBuilder();
1098
1099         // Instructions List Stores Individual Instructions
1100         List<Instruction> instructions = Lists.newArrayList();
1101
1102         // Call the InstructionBuilder Methods Containing Actions
1103         InstructionUtils.createNormalInstructions(nodeName, ib);
1104         ib.setOrder(0);
1105         ib.setKey(new InstructionKey(0));
1106         instructions.add(ib.build());
1107
1108         // Add InstructionBuilder to the Instruction(s)Builder List
1109         isb.setInstruction(instructions);
1110
1111         // Add InstructionsBuilder to FlowBuilder
1112         flowBuilder.setInstructions(isb.build());
1113
1114         String flowId = "NORMAL";
1115         flowBuilder.setId(new FlowId(flowId));
1116         FlowKey key = new FlowKey(new FlowId(flowId));
1117         flowBuilder.setMatch(matchBuilder.build());
1118         flowBuilder.setPriority(0);
1119         flowBuilder.setBarrier(true);
1120         flowBuilder.setTableId((short) 0);
1121         flowBuilder.setKey(key);
1122         flowBuilder.setFlowName(flowId);
1123         flowBuilder.setHardTimeout(0);
1124         flowBuilder.setIdleTimeout(0);
1125         writeFlow(flowBuilder, nodeBuilder);
1126     }
1127
1128     /*
1129      * (Table:0) Ingress Tunnel Traffic
1130      * Match: OpenFlow InPort and Tunnel ID
1131      * Action: GOTO Local Table (10)
1132      * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1133      */
1134
1135     private void handleTunnelIn(Long dpidLong, Short writeTable,
1136             Short goToTableId, String segmentationId,
1137             Long ofPort, boolean write) {
1138         classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1139     }
1140
1141     /*
1142      * (Table:0) Ingress VLAN Traffic
1143      * Match: OpenFlow InPort and vlan ID
1144      * Action: GOTO Local Table (20)
1145      * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1146      */
1147
1148     private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1149             String segmentationId,  Long ethPort, boolean write) {
1150         classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1151     }
1152
1153     /*
1154      * (Table:0) Egress VM Traffic Towards TEP
1155      * Match: Destination Ethernet Addr and OpenFlow InPort
1156      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1157      * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1158      * actions=set_field:5->tun_id,goto_table=1"
1159      */
1160
1161     private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1162             String segmentationId, Long inPort, String attachedMac,
1163             boolean write) {
1164         classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1165     }
1166
1167     /*
1168      * (Table:0) Egress VM Traffic Towards TEP
1169      * Match: Source Ethernet Addr and OpenFlow InPort
1170      * Instruction: Set VLANID and GOTO Table Egress (n)
1171      * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1172      * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1173      */
1174
1175     private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1176             Short goToTableId, String segmentationId,
1177             Long inPort, String attachedMac,
1178             boolean write) {
1179         classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1180     }
1181
1182     /*
1183      * (Table:0) Drop frames source from a VM that do not
1184      * match the associated MAC address of the local VM.
1185      * Match: Low priority anything not matching the VM SMAC
1186      * Instruction: Drop
1187      * table=0,priority=16384,in_port=1 actions=drop"
1188      */
1189
1190     private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1191         classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1192     }
1193
1194     /*
1195      * (Table:1) Egress Tunnel Traffic
1196      * Match: Destination Ethernet Addr and Local InPort
1197      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1198      * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1199      * actions=output:10,goto_table:2"
1200      */
1201     private void handleTunnelOut(Long dpidLong, Short writeTable,
1202             Short goToTableId, String segmentationId,
1203             Long OFPortOut, String attachedMac,
1204             boolean write) {
1205         l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1206     }
1207
1208     /*
1209      * (Table:1) Egress VLAN Traffic
1210      * Match: Destination Ethernet Addr and VLAN id
1211      * Instruction: GOTO Table Table 2
1212      * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1213      * actions= goto_table:2"
1214      */
1215
1216     private void handleVlanOut(Long dpidLong, Short writeTable,
1217             Short goToTableId, String segmentationId,
1218             Long ethPort, String attachedMac, boolean write) {
1219         l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
1220     }
1221
1222     /*
1223      * (Table:1) Egress Tunnel Traffic
1224      * Match: Destination Ethernet Addr and Local InPort
1225      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1226      * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1227      * actions=output:10,output:11,goto_table:2
1228      */
1229
1230     private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1231             Short localTable, String segmentationId,
1232             Long OFPortOut, boolean write) {
1233         l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1234     }
1235
1236     /*
1237      * (Table:1) Egress VLAN Traffic
1238      * Match: Destination Ethernet Addr and VLAN id
1239      * Instruction: GOTO table 2 and Output port eth interface
1240      * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1241      * actions=output:eth1,goto_table:2
1242      */
1243
1244     private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1245             Short localTable, String segmentationId,
1246             Long localPort, Long ethPort, boolean write) {
1247         //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1248     }
1249
1250     /*
1251      * (Table:1) Table Drain w/ Catch All
1252      * Match: Tunnel ID
1253      * Action: GOTO Local Table (10)
1254      * table=2,priority=8192,tun_id=0x5 actions=drop
1255      */
1256
1257     private void handleTunnelMiss(Long dpidLong, Short writeTable,
1258             Short goToTableId, String segmentationId,
1259             boolean write) {
1260         l2ForwardingProvider.programTunnelMiss(dpidLong, segmentationId, write);
1261     }
1262
1263
1264     /*
1265      * (Table:1) Table Drain w/ Catch All
1266      * Match: Vlan ID
1267      * Action: Output port eth interface
1268      * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1269      * table=110,priority=8192,dl_vlan=2001 actions=output:2
1270      */
1271
1272     private void handleVlanMiss(Long dpidLong, Short writeTable,
1273             Short goToTableId, String segmentationId,
1274             Long ethPort, boolean write) {
1275         l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1276     }
1277
1278     /*
1279      * (Table:1) Local Broadcast Flood
1280      * Match: Tunnel ID and dMAC
1281      * Action: Output Port
1282      * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1283      */
1284
1285     private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1286             String segmentationId, Long localPort,
1287             String attachedMac, boolean write) {
1288         l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1289     }
1290
1291     /*
1292      * (Table:2) Local VLAN unicast
1293      * Match: VLAN ID and dMAC
1294      * Action: Output Port
1295      * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1296      */
1297
1298     private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1299             String segmentationId, Long localPort,
1300             String attachedMac, boolean write) {
1301         l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1302     }
1303
1304     /*
1305      * (Table:2) Local Broadcast Flood
1306      * Match: Tunnel ID and dMAC (::::FF:FF)
1307      * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1308      * actions=output:2,3,4,5
1309      */
1310
1311     private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1312             String segmentationId, Long localPort,
1313             boolean write) {
1314         l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1315     }
1316
1317     /*
1318      * (Table:2) Local VLAN Broadcast Flood
1319      * Match: vlan ID and dMAC (::::FF:FF)
1320      * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1321      * actions=strip_vlan, output:2,3,4,5
1322      * 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
1323      */
1324
1325     private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1326                                          Long localPort, Long ethPort, boolean write) {
1327         l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1328     }
1329
1330     /*
1331      * (Table:1) Local Table Miss
1332      * Match: Any Remaining Flows w/a TunID
1333      * Action: Drop w/ a low priority
1334      * table=2,priority=8192,tun_id=0x5 actions=drop
1335      */
1336
1337     private void handleLocalTableMiss(Long dpidLong, Short writeTable,
1338             String segmentationId, boolean write) {
1339         l2ForwardingProvider.programLocalTableMiss(dpidLong, segmentationId, write);
1340     }
1341
1342     /*
1343      * (Table:1) Local Table Miss
1344      * Match: Any Remaining Flows w/a VLAN ID
1345      * Action: Drop w/ a low priority
1346      * table=2,priority=8192,vlan_id=0x5 actions=drop
1347      */
1348
1349     private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1350             String segmentationId, boolean write) {
1351         l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1352     }
1353
1354     private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1355         Preconditions.checkNotNull(mdsalConsumer);
1356         if (mdsalConsumer == null) {
1357             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1358             return null;
1359         }
1360
1361         dataBroker = mdsalConsumer.getDataBroker();
1362         if (dataBroker == null) {
1363             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1364             return null;
1365         }
1366
1367         InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1368                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1369                         new GroupKey(groupBuilder.getGroupId())).build();
1370         ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1371         try {
1372             Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1373             if (data.isPresent()) {
1374                 return data.get();
1375             }
1376         } catch (InterruptedException|ExecutionException e) {
1377             logger.error(e.getMessage(), e);
1378         }
1379
1380         logger.debug("Cannot find data for Group " + groupBuilder.getGroupName());
1381         return null;
1382     }
1383
1384     private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1385         Preconditions.checkNotNull(mdsalConsumer);
1386         if (mdsalConsumer == null) {
1387             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1388             return;
1389         }
1390
1391         dataBroker = mdsalConsumer.getDataBroker();
1392         if (dataBroker == null) {
1393             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1394             return;
1395         }
1396
1397         ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1398         InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1399                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1400                         new GroupKey(groupBuilder.getGroupId())).build();
1401         modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1402
1403         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1404         try {
1405             commitFuture.get();  // TODO: Make it async (See bug 1362)
1406             logger.debug("Transaction success for write of Group "+groupBuilder.getGroupName());
1407         } catch (InterruptedException|ExecutionException e) {
1408             logger.error(e.getMessage(), e);
1409         }
1410     }
1411
1412     private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1413         Preconditions.checkNotNull(mdsalConsumer);
1414         if (mdsalConsumer == null) {
1415             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1416             return;
1417         }
1418
1419         dataBroker = mdsalConsumer.getDataBroker();
1420         if (dataBroker == null) {
1421             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1422             return;
1423         }
1424
1425         WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1426         InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1427                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1428                         new GroupKey(groupBuilder.getGroupId())).build();
1429         modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1430         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1431
1432         try {
1433             commitFuture.get();  // TODO: Make it async (See bug 1362)
1434             logger.debug("Transaction success for deletion of Group "+groupBuilder.getGroupName());
1435         } catch (InterruptedException|ExecutionException e) {
1436             logger.error(e.getMessage(), e);
1437         }
1438     }
1439     private Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1440         Preconditions.checkNotNull(mdsalConsumer);
1441         if (mdsalConsumer == null) {
1442             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1443             return null;
1444         }
1445
1446         dataBroker = mdsalConsumer.getDataBroker();
1447         if (dataBroker == null) {
1448             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1449             return null;
1450         }
1451
1452         InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1453                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1454                         new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1455
1456         ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1457         try {
1458             Optional<Flow> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1459             if (data.isPresent()) {
1460                 return data.get();
1461             }
1462         } catch (InterruptedException|ExecutionException e) {
1463             logger.error(e.getMessage(), e);
1464         }
1465
1466         logger.debug("Cannot find data for Flow " + flowBuilder.getFlowName());
1467         return null;
1468     }
1469
1470     private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1471         Preconditions.checkNotNull(mdsalConsumer);
1472         if (mdsalConsumer == null) {
1473             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1474             return;
1475         }
1476
1477         dataBroker = mdsalConsumer.getDataBroker();
1478         if (dataBroker == null) {
1479             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1480             return;
1481         }
1482
1483         ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1484         InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1485                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1486                         new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1487
1488         //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1489         modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(), true /*createMissingParents*/);
1490
1491
1492         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1493         try {
1494             commitFuture.get();  // TODO: Make it async (See bug 1362)
1495             logger.debug("Transaction success for write of Flow "+flowBuilder.getFlowName());
1496         } catch (InterruptedException|ExecutionException e) {
1497             logger.error(e.getMessage(), e);
1498         }
1499     }
1500
1501     private void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1502         Preconditions.checkNotNull(mdsalConsumer);
1503         if (mdsalConsumer == null) {
1504             logger.error("ERROR finding MDSAL Service.");
1505             return;
1506         }
1507
1508         dataBroker = mdsalConsumer.getDataBroker();
1509         if (dataBroker == null) {
1510             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1511             return;
1512         }
1513
1514         WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1515         InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class)
1516                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1517                         .rev130819.nodes.Node.class, nodeBuilder.getKey())
1518                         .augmentation(FlowCapableNode.class).child(Table.class,
1519                                 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1520         //modification.delete(LogicalDatastoreType.OPERATIONAL, nodeBuilderToInstanceId(nodeBuilder));
1521         //modification.delete(LogicalDatastoreType.OPERATIONAL, path1);
1522         //modification.delete(LogicalDatastoreType.CONFIGURATION, nodeBuilderToInstanceId(nodeBuilder));
1523         modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1524
1525         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1526         try {
1527             commitFuture.get();  // TODO: Make it async (See bug 1362)
1528             logger.debug("Transaction success for deletion of Flow "+flowBuilder.getFlowName());
1529         } catch (InterruptedException|ExecutionException e) {
1530             logger.error(e.getMessage(), e);
1531         }
1532     }
1533
1534     /**
1535      * Create Output Port Group Instruction
1536      *
1537      * @param ib       Map InstructionBuilder without any instructions
1538      * @param dpidLong Long the datapath ID of a switch/node
1539      * @param port     Long representing a port on a switch/node
1540      * @return ib InstructionBuilder Map with instructions
1541      */
1542     protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1543             InstructionBuilder ib,
1544             Long dpidLong, Long port ,
1545             List<Instruction> instructions) {
1546         NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1547         logger.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1548
1549         List<Action> actionList = Lists.newArrayList();
1550         ActionBuilder ab = new ActionBuilder();
1551
1552         List<Action> existingActions;
1553         if (instructions != null) {
1554             for (Instruction in : instructions) {
1555                 if (in.getInstruction() instanceof ApplyActionsCase) {
1556                     existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1557                     actionList.addAll(existingActions);
1558                 }
1559             }
1560         }
1561
1562         GroupBuilder groupBuilder = new GroupBuilder();
1563         Group group = null;
1564
1565         /* Create output action for this port*/
1566         OutputActionBuilder oab = new OutputActionBuilder();
1567         oab.setOutputNodeConnector(ncid);
1568         ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1569         logger.debug("createOutputGroupInstructions(): output action {}", ab.build());
1570         boolean addNew = true;
1571         boolean groupActionAdded = false;
1572
1573         /* Find the group action and get the group */
1574         for (Action action : actionList) {
1575             if (action.getAction() instanceof GroupActionCase) {
1576                 groupActionAdded = true;
1577                 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1578                 Long id = groupAction.getGroupAction().getGroupId();
1579                 String groupName = groupAction.getGroupAction().getGroup();
1580                 GroupKey key = new GroupKey(new GroupId(id));
1581
1582                 groupBuilder.setGroupId(new GroupId(id));
1583                 groupBuilder.setGroupName(groupName);
1584                 groupBuilder.setGroupType(GroupTypes.GroupAll);
1585                 groupBuilder.setKey(key);
1586                 group = getGroup(groupBuilder, nodeBuilder);
1587                 logger.debug("createOutputGroupInstructions: group {}", group);
1588                 break;
1589             }
1590         }
1591
1592         logger.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1593         if (groupActionAdded) {
1594             /* modify the action bucket in group */
1595             groupBuilder = new GroupBuilder(group);
1596             Buckets buckets = groupBuilder.getBuckets();
1597             for (Bucket bucket : buckets.getBucket()) {
1598                 List<Action> bucketActions = bucket.getAction();
1599                 logger.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1600                 for (Action action : bucketActions) {
1601                     if (action.getAction() instanceof OutputActionCase) {
1602                         OutputActionCase opAction = (OutputActionCase)action.getAction();
1603                         /* If output port action already in the action list of one of the buckets, skip */
1604                         if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1605                             addNew = false;
1606                             break;
1607                         }
1608                     }
1609                 }
1610             }
1611             logger.debug("createOutputGroupInstructions: addNew {}", addNew);
1612             if (addNew) {
1613                 /* the new output action is not in the bucket, add to bucket */
1614                 if (!buckets.getBucket().isEmpty()) {
1615                     Bucket bucket = buckets.getBucket().get(0);
1616                     List<Action> bucketActionList = Lists.newArrayList();
1617                     bucketActionList.addAll(bucket.getAction());
1618                     /* set order for new action and add to action list */
1619                     ab.setOrder(bucketActionList.size());
1620                     ab.setKey(new ActionKey(bucketActionList.size()));
1621                     bucketActionList.add(ab.build());
1622
1623                     /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1624                     BucketsBuilder bucketsBuilder = new BucketsBuilder();
1625                     List<Bucket> bucketList = Lists.newArrayList();
1626                     BucketBuilder bucketBuilder = new BucketBuilder();
1627                     bucketBuilder.setBucketId(new BucketId((long) 1));
1628                     bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1629                     bucketBuilder.setAction(bucketActionList);
1630                     bucketList.add(bucketBuilder.build());
1631                     bucketsBuilder.setBucket(bucketList);
1632                     groupBuilder.setBuckets(bucketsBuilder.build());
1633                     logger.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1634                 }
1635             }
1636         } else {
1637             /* create group */
1638             groupBuilder = new GroupBuilder();
1639             groupBuilder.setGroupType(GroupTypes.GroupAll);
1640             groupBuilder.setGroupId(new GroupId(groupId));
1641             groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1642             groupBuilder.setGroupName("Output port group " + groupId);
1643             groupBuilder.setBarrier(false);
1644
1645             BucketsBuilder bucketBuilder = new BucketsBuilder();
1646             List<Bucket> bucketList = Lists.newArrayList();
1647             BucketBuilder bucket = new BucketBuilder();
1648             bucket.setBucketId(new BucketId((long) 1));
1649             bucket.setKey(new BucketKey(new BucketId((long) 1)));
1650
1651             /* put output action to the bucket */
1652             List<Action> bucketActionList = Lists.newArrayList();
1653             /* set order for new action and add to action list */
1654             ab.setOrder(bucketActionList.size());
1655             ab.setKey(new ActionKey(bucketActionList.size()));
1656             bucketActionList.add(ab.build());
1657
1658             bucket.setAction(bucketActionList);
1659             bucketList.add(bucket.build());
1660             bucketBuilder.setBucket(bucketList);
1661             groupBuilder.setBuckets(bucketBuilder.build());
1662
1663             /* Add new group action */
1664             GroupActionBuilder groupActionB = new GroupActionBuilder();
1665             groupActionB.setGroupId(groupId);
1666             groupActionB.setGroup("Output port group " + groupId);
1667             ab = new ActionBuilder();
1668             ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1669             ab.setOrder(actionList.size());
1670             ab.setKey(new ActionKey(actionList.size()));
1671             actionList.add(ab.build());
1672
1673             groupId++;
1674         }
1675         logger.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1676         logger.debug("createOutputGroupInstructions: actionList {}", actionList);
1677
1678         if (addNew) {
1679             /* rewrite the group to group table */
1680             writeGroup(groupBuilder, nodeBuilder);
1681         }
1682
1683         // Create an Apply Action
1684         ApplyActionsBuilder aab = new ApplyActionsBuilder();
1685         aab.setAction(actionList);
1686         ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1687
1688         return ib;
1689     }
1690
1691     /**
1692      * Remove Output Port from action list in group bucket
1693      *
1694      * @param ib       Map InstructionBuilder without any instructions
1695      * @param dpidLong Long the datapath ID of a switch/node
1696      * @param port     Long representing a port on a switch/node
1697      * @return ib InstructionBuilder Map with instructions
1698      */
1699     protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
1700             Long dpidLong, Long port , List<Instruction> instructions) {
1701
1702         NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1703         logger.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1704
1705         List<Action> actionList = Lists.newArrayList();
1706         ActionBuilder ab;
1707
1708         List<Action> existingActions;
1709         if (instructions != null) {
1710             for (Instruction in : instructions) {
1711                 if (in.getInstruction() instanceof ApplyActionsCase) {
1712                     existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1713                     actionList.addAll(existingActions);
1714                     break;
1715                 }
1716             }
1717         }
1718
1719         GroupBuilder groupBuilder = new GroupBuilder();
1720         Group group = null;
1721         boolean groupActionAdded = false;
1722         /* Find the group action and get the group */
1723         for (Action action : actionList) {
1724             if (action.getAction() instanceof GroupActionCase) {
1725                 groupActionAdded = true;
1726                 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1727                 Long id = groupAction.getGroupAction().getGroupId();
1728                 String groupName = groupAction.getGroupAction().getGroup();
1729                 GroupKey key = new GroupKey(new GroupId(id));
1730
1731                 groupBuilder.setGroupId(new GroupId(id));
1732                 groupBuilder.setGroupName(groupName);
1733                 groupBuilder.setGroupType(GroupTypes.GroupAll);
1734                 groupBuilder.setKey(key);
1735                 group = getGroup(groupBuilder, nodeBuilder);
1736                 break;
1737             }
1738         }
1739
1740         if (groupActionAdded) {
1741             /* modify the action bucket in group */
1742             groupBuilder = new GroupBuilder(group);
1743             Buckets buckets = groupBuilder.getBuckets();
1744             List<Action> bucketActions = Lists.newArrayList();
1745             for (Bucket bucket : buckets.getBucket()) {
1746                 int index = 0;
1747                 boolean isPortDeleted = false;
1748                 bucketActions = bucket.getAction();
1749                 for (Action action : bucketActions) {
1750                     if (action.getAction() instanceof OutputActionCase) {
1751                         OutputActionCase opAction = (OutputActionCase)action.getAction();
1752                         if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1753                             /* Find the output port in action list and remove */
1754                             index = bucketActions.indexOf(action);
1755                             bucketActions.remove(action);
1756                             isPortDeleted = true;
1757                             break;
1758                         }
1759                     }
1760                 }
1761                 if (isPortDeleted && !bucketActions.isEmpty()) {
1762                     for (int i = index; i< bucketActions.size(); i++) {
1763                         Action action = bucketActions.get(i);
1764                         if (action.getOrder() != i) {
1765                             /* Shift the action order */
1766                             ab = new ActionBuilder();
1767                             ab.setAction(action.getAction());
1768                             ab.setOrder(i);
1769                             ab.setKey(new ActionKey(i));
1770                             Action actionNewOrder = ab.build();
1771                             bucketActions.remove(action);
1772                             bucketActions.add(i, actionNewOrder);
1773                         }
1774                     }
1775
1776                 } else if (bucketActions.isEmpty()) {
1777                     /* remove bucket with empty action list */
1778                     buckets.getBucket().remove(bucket);
1779                     break;
1780                 }
1781             }
1782             if (!buckets.getBucket().isEmpty()) {
1783                 /* rewrite the group to group table */
1784                 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1785                 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1786                 List<Bucket> bucketList = Lists.newArrayList();
1787                 BucketBuilder bucketBuilder = new BucketBuilder();
1788                 bucketBuilder.setBucketId(new BucketId((long) 1));
1789                 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1790                 bucketBuilder.setAction(bucketActions);
1791                 bucketList.add(bucketBuilder.build());
1792                 bucketsBuilder.setBucket(bucketList);
1793                 groupBuilder.setBuckets(bucketsBuilder.build());
1794                 logger.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
1795
1796                 writeGroup(groupBuilder, nodeBuilder);
1797                 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1798                 aab.setAction(actionList);
1799                 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1800                 return false;
1801             } else {
1802                 /* remove group with empty bucket. return true to delete flow */
1803                 removeGroup(groupBuilder, nodeBuilder);
1804                 return true;
1805             }
1806         } else {
1807             /* no group for port list. flow can be removed */
1808             return true;
1809         }
1810     }
1811
1812     private String getBridgeName(Node node) {
1813         return (node.getAugmentation(OvsdbBridgeAugmentation.class).getBridgeName().getValue());
1814     }
1815
1816     @Override
1817     public void initializeOFFlowRules(Node openflowNode) {
1818         String bridgeName = getBridgeName(openflowNode);
1819         logger.info("initializeOFFlowRules: bridgeName: {}", bridgeName);
1820         if (bridgeName.equals(configurationService.getIntegrationBridgeName())) {
1821             initializeFlowRules(openflowNode, configurationService.getIntegrationBridgeName());
1822             triggerInterfaceUpdates(openflowNode);
1823         } else if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1824             initializeFlowRules(openflowNode, configurationService.getExternalBridgeName());
1825             triggerInterfaceUpdates(openflowNode);
1826         }
1827     }
1828
1829     public static NodeBuilder createNodeBuilder(String nodeId) {
1830         NodeBuilder builder = new NodeBuilder();
1831         builder.setId(new NodeId(nodeId));
1832         builder.setKey(new NodeKey(builder.getId()));
1833         return builder;
1834     }
1835 }