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