Migrate net-virt from adsal Node to mdsal Node
[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.neutron.spi.NeutronNetwork;
25 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
26 import org.opendaylight.controller.sal.utils.HexEncode;
27 import org.opendaylight.ovsdb.lib.notation.Row;
28 import org.opendaylight.ovsdb.lib.notation.UUID;
29 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
30 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
31 import org.opendaylight.ovsdb.openstack.netvirt.api.ClassifierProvider;
32 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
33 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
34 import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
35 import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
36 import org.opendaylight.ovsdb.openstack.netvirt.api.L2ForwardingProvider;
37 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
38 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
39 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
40 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
41 import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
42 import org.opendaylight.ovsdb.plugin.api.Status;
43 import org.opendaylight.ovsdb.plugin.api.StatusCode;
44 import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
45 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
46 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
47 import org.opendaylight.ovsdb.schema.openvswitch.Port;
48 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
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"
999                                 + node.getId().getValue() + " intf " + intf.getName());
1000                         if (local) {
1001                             programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort);
1002                         }
1003                         return;
1004                     }
1005                 }
1006             }
1007         } catch (Exception e) {
1008             logger.error("", e);
1009         }
1010     }
1011
1012     private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
1013             Interface intf, boolean local, boolean isLastInstanceOnNode) {
1014
1015         Preconditions.checkNotNull(ovsdbConfigurationService);
1016         try {
1017
1018             Long dpid = this.getIntegrationBridgeOFDPID(node);
1019             if (dpid == 0L) {
1020                 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1021                 return;
1022             }
1023
1024             Set<Long> of_ports = intf.getOpenFlowPortColumn().getData();
1025             if (of_ports == null || of_ports.size() <= 0) {
1026                 logger.error("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
1027                 return;
1028             }
1029             long localPort = (Long)of_ports.toArray()[0];
1030
1031             Map<String, String> externalIds = intf.getExternalIdsColumn().getData();
1032             if (externalIds == null) {
1033                 logger.error("No external_ids seen in {}", intf);
1034                 return;
1035             }
1036
1037             String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
1038             if (attachedMac == null) {
1039                 logger.error("No AttachedMac seen in {}", intf);
1040                 return;
1041             }
1042
1043             Map<String, Row> intfs = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
1044             if (intfs != null) {
1045                 for (Row row : intfs.values()) {
1046                     Interface tunIntf = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
1047                     if (tunIntf.getName().equals(this.getTunnelName(tunnelType, dst))) {
1048                         of_ports = tunIntf.getOpenFlowPortColumn().getData();
1049                         if (of_ports == null || of_ports.size() <= 0) {
1050                             logger.error("Could NOT Identify Tunnel port {} on {}", tunIntf.getName(), node);
1051                             continue;
1052                         }
1053                         long tunnelOFPort = (Long)of_ports.toArray()[0];
1054
1055                         if (tunnelOFPort == -1) {
1056                             logger.error("Could NOT Identify Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
1057                             return;
1058                         }
1059                         logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
1060
1061                         if (!local) {
1062                             removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort);
1063                         }
1064                         if (local && isLastInstanceOnNode) {
1065                             removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort);
1066                         }
1067                         return;
1068                     }
1069                 }
1070             }
1071         } catch (Exception e) {
1072             logger.error("", e);
1073         }
1074     }
1075
1076     private void programVlanRules (NeutronNetwork network, Node node, Interface intf) {
1077         Preconditions.checkNotNull(ovsdbConfigurationService);
1078         logger.debug("Program vlan rules for interface {}", intf.getName());
1079         try {
1080
1081             Long dpid = this.getIntegrationBridgeOFDPID(node);
1082             if (dpid == 0L) {
1083                 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1084                 return;
1085             }
1086
1087             Set<Long> of_ports = intf.getOpenFlowPortColumn().getData();
1088             int timeout = 6;
1089             while ((of_ports == null) && (timeout > 0)) {
1090                 of_ports = intf.getOpenFlowPortColumn().getData();
1091                 if (of_ports == null || of_ports.size() <= 0) {
1092                     // Wait for the OVSDB update to sync up the Local cache.
1093                     Thread.sleep(500);
1094                     timeout--;
1095                 }
1096             }
1097             if (of_ports == null || of_ports.size() <= 0) {
1098                 logger.error("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
1099                 return;
1100             }
1101             long localPort = (Long)of_ports.toArray()[0];
1102
1103             Map<String, String> externalIds = intf.getExternalIdsColumn().getData();
1104             if (externalIds == null) {
1105                 logger.error("No external_ids seen in {}", intf);
1106                 return;
1107             }
1108
1109             String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
1110             if (attachedMac == null) {
1111                 logger.error("No AttachedMac seen in {}", intf);
1112                 return;
1113             }
1114
1115             Map<String, Row> intfs = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
1116             if (intfs != null) {
1117                 for (Row row : intfs.values()) {
1118                     Interface ethIntf = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
1119                     if (ethIntf.getName().equalsIgnoreCase(bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork()))) {
1120                         of_ports = ethIntf.getOpenFlowPortColumn().getData();
1121                         timeout = 6;
1122                         while ((of_ports == null) && (timeout > 0)) {
1123                             of_ports = ethIntf.getOpenFlowPortColumn().getData();
1124                             if (of_ports == null || of_ports.size() <= 0) {
1125                                 // Wait for the OVSDB update to sync up the Local cache.
1126                                 Thread.sleep(500);
1127                                         timeout--;
1128                             }
1129                         }
1130
1131                         if (of_ports == null || of_ports.size() <= 0) {
1132                             logger.error("Could NOT Identify eth port {} on {}", ethIntf.getName(), node);
1133                             continue;
1134                         }
1135                         long ethOFPort = (Long)of_ports.toArray()[0];
1136
1137                         if (ethOFPort == -1) {
1138                             logger.error("Could NOT Identify eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
1139                             throw new Exception("port number < 0");
1140                         }
1141                         logger.debug("Identified eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
1142                         // TODO: add logic to only add rule on remote nodes
1143                         programRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(), attachedMac, ethOFPort);
1144                         programLocalIngressVlanRules(node, dpid, network.getProviderSegmentationID(), attachedMac, localPort, ethOFPort);
1145                         return;
1146                     }
1147                 }
1148             }
1149         } catch (Exception e) {
1150             logger.error("", e);
1151         }
1152     }
1153
1154     private void removeVlanRules (NeutronNetwork network, Node node,
1155             Interface intf, boolean isLastInstanceOnNode) {
1156         Preconditions.checkNotNull(ovsdbConfigurationService);
1157         logger.debug("Remove vlan rules for interface {}", intf.getName());
1158
1159         try {
1160
1161             Long dpid = this.getIntegrationBridgeOFDPID(node);
1162             if (dpid == 0L) {
1163                 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1164                 return;
1165             }
1166
1167             Set<Long> of_ports = intf.getOpenFlowPortColumn().getData();
1168             if (of_ports == null || of_ports.size() <= 0) {
1169                 logger.error("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
1170                 return;
1171             }
1172             long localPort = (Long)of_ports.toArray()[0];
1173
1174             Map<String, String> externalIds = intf.getExternalIdsColumn().getData();
1175             if (externalIds == null) {
1176                 logger.error("No external_ids seen in {}", intf);
1177                 return;
1178             }
1179
1180             String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
1181             if (attachedMac == null) {
1182                 logger.error("No AttachedMac seen in {}", intf);
1183                 return;
1184             }
1185
1186             Map<String, Row> intfs = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
1187             if (intfs != null) {
1188                 for (Row row : intfs.values()) {
1189                     Interface ethIntf = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
1190                     if (ethIntf.getName().equalsIgnoreCase(bridgeConfigurationManager.getPhysicalInterfaceName(node,
1191                             network.getProviderPhysicalNetwork()))) {
1192                         of_ports = ethIntf.getOpenFlowPortColumn().getData();
1193                         if (of_ports == null || of_ports.size() <= 0) {
1194                             logger.error("Could NOT Identify eth port {} on {}", ethIntf.getName(), node);
1195                             continue;
1196                         }
1197                         long ethOFPort = (Long)of_ports.toArray()[0];
1198
1199                         if (ethOFPort == -1) {
1200                             logger.error("Could NOT Identify eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
1201                             throw new Exception("port number < 0");
1202                         }
1203                         logger.debug("Identified eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
1204
1205                         removeRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(), attachedMac, localPort, ethOFPort);
1206                         if (isLastInstanceOnNode) {
1207                             removePerVlanRules(node, dpid, network.getProviderSegmentationID(), localPort, ethOFPort);
1208                         }
1209                         return;
1210                     }
1211                 }
1212             }
1213         } catch (Exception e) {
1214             logger.error("", e);
1215         }
1216     }
1217
1218     @Override
1219     public Status handleInterfaceUpdate(NeutronNetwork network, Node srcNode, Interface intf) {
1220         Preconditions.checkNotNull(connectionService);
1221         List<Node> nodes = connectionService.getNodes();
1222         nodes.remove(srcNode);
1223         this.programLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), srcNode, intf);
1224
1225         if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
1226             this.programVlanRules(network, srcNode, intf);
1227         } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
1228                 || network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)){
1229             for (Node dstNode : nodes) {
1230                 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1231                 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1232                 if ((src != null) && (dst != null)) {
1233                     Status status = addTunnelPort(srcNode, network.getProviderNetworkType(), src, dst);
1234                     if (status.isSuccess()) {
1235                         this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), dst, srcNode, intf, true);
1236                     }
1237                     addTunnelPort(dstNode, network.getProviderNetworkType(), dst, src);
1238                     if (status.isSuccess()) {
1239                         this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), src, dstNode, intf, false);
1240                     }
1241                 } else {
1242                     logger.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. " +
1243                             "Check source {} or destination {}",
1244                             src != null ? src.getHostAddress() : "null",
1245                             dst != null ? dst.getHostAddress() : "null");
1246                 }
1247             }
1248         }
1249
1250         return new Status(StatusCode.SUCCESS);
1251     }
1252
1253     private Status triggerInterfaceUpdates(Node node) {
1254         Preconditions.checkNotNull(ovsdbConfigurationService);
1255         try {
1256             Map<String, Row> intfs = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
1257             if (intfs != null) {
1258                 for (Row row : intfs.values()) {
1259                     Interface intf = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
1260                     NeutronNetwork network = tenantNetworkManager.getTenantNetwork(intf);
1261                     logger.debug("Trigger Interface update for {}", intf);
1262                     if (network != null) {
1263                         this.handleInterfaceUpdate(network, node, intf);
1264                     }
1265                 }
1266             }
1267         } catch (Exception e) {
1268             logger.error("Error Triggering the lost interface updates for "+ node, e);
1269             return new Status(StatusCode.INTERNALERROR, e.getLocalizedMessage());
1270         }
1271         return new Status(StatusCode.SUCCESS);
1272     }
1273     @Override
1274     public Status handleInterfaceUpdate(String tunnelType, String tunnelKey) {
1275         // TODO Auto-generated method stub
1276         return null;
1277     }
1278
1279     @Override
1280     public Status handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode, Interface intf,
1281             boolean isLastInstanceOnNode) {
1282         Preconditions.checkNotNull(connectionService);
1283         Status status = new Status(StatusCode.SUCCESS);
1284         List<Node> nodes = connectionService.getNodes();
1285         nodes.remove(srcNode);
1286
1287         logger.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
1288         List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
1289         if (intf.getTypeColumn().getData().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)
1290                 || intf.getTypeColumn().getData().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
1291             /* Delete tunnel port */
1292             try {
1293                 Map<String, String> options = intf.getOptionsColumn().getData();
1294                 InetAddress src = InetAddress.getByName(options.get("local_ip"));
1295                 InetAddress dst = InetAddress.getByName(options.get("remote_ip"));
1296                 status = deleteTunnelPort(srcNode, intf.getTypeColumn().getData(), src, dst);
1297             } catch (Exception e) {
1298                 logger.error(e.getMessage(), e);
1299             }
1300         } else if (phyIfName.contains(intf.getName())) {
1301             deletePhysicalPort(srcNode, intf.getName());
1302         } else {
1303             /* delete all other interfaces */
1304             this.removeLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(),
1305                     srcNode, intf);
1306
1307             if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
1308                 this.removeVlanRules(network, srcNode,
1309                         intf, isLastInstanceOnNode);
1310             } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
1311                     || network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
1312
1313                 for (Node dstNode : nodes) {
1314                     InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1315                     InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1316                     if ((src != null) && (dst != null)) {
1317                         logger.info("Remove tunnel rules for interface "
1318                                 + intf.getName() + " on srcNode " + srcNode.getId().getValue());
1319                         this.removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1320                                 dst, srcNode, intf, true, isLastInstanceOnNode);
1321                         logger.info("Remove tunnel rules for interface "
1322                                 + intf.getName() + " on dstNode " + dstNode.getId().getValue());
1323                         this.removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1324                                 src, dstNode, intf, false, isLastInstanceOnNode);
1325                     } else {
1326                         logger.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. ",
1327                                 "Check source {} or destination {}",
1328                                 src != null ? src.getHostAddress() : "null",
1329                                 dst != null ? dst.getHostAddress() : "null");
1330                     }
1331                 }
1332             }
1333         }
1334         return status;
1335     }
1336
1337     @Override
1338     public void initializeFlowRules(Node node) {
1339         this.initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1340         this.initializeFlowRules(node, configurationService.getExternalBridgeName());
1341         this.triggerInterfaceUpdates(node);
1342     }
1343
1344     private void initializeFlowRules(Node node, String bridgeName) {
1345         String bridgeUuid = this.getInternalBridgeUUID(node, bridgeName);
1346         if (bridgeUuid == null) {
1347             return;
1348         }
1349
1350         Long dpid = getDpid(node, bridgeUuid);
1351
1352         if (dpid == 0L) {
1353             logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1354             return;
1355         }
1356
1357         /*
1358          * Table(0) Rule #1
1359          * ----------------
1360          * Match: LLDP (0x88CCL)
1361          * Action: Packet_In to Controller Reserved Port
1362          */
1363
1364         writeLLDPRule(dpid);
1365         if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1366             writeNormalRule(dpid);
1367         }
1368     }
1369
1370     /*
1371      * Create an LLDP Flow Rule to encapsulate into
1372      * a packet_in that is sent to the controller
1373      * for topology handling.
1374      * Match: Ethertype 0x88CCL
1375      * Action: Punt to Controller in a Packet_In msg
1376      */
1377
1378     private void writeLLDPRule(Long dpidLong) {
1379         classifierProvider.programLLDPPuntRule(dpidLong);
1380     }
1381
1382     /*
1383      * Create a NORMAL Table Miss Flow Rule
1384      * Match: any
1385      * Action: forward to NORMAL pipeline
1386      */
1387
1388     private void writeNormalRule(Long dpidLong) {
1389
1390         String nodeName = OPENFLOW + dpidLong;
1391
1392         MatchBuilder matchBuilder = new MatchBuilder();
1393         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
1394         FlowBuilder flowBuilder = new FlowBuilder();
1395
1396         // Create the OF Actions and Instructions
1397         InstructionBuilder ib = new InstructionBuilder();
1398         InstructionsBuilder isb = new InstructionsBuilder();
1399
1400         // Instructions List Stores Individual Instructions
1401         List<Instruction> instructions = Lists.newArrayList();
1402
1403         // Call the InstructionBuilder Methods Containing Actions
1404         InstructionUtils.createNormalInstructions(nodeName, ib);
1405         ib.setOrder(0);
1406         ib.setKey(new InstructionKey(0));
1407         instructions.add(ib.build());
1408
1409         // Add InstructionBuilder to the Instruction(s)Builder List
1410         isb.setInstruction(instructions);
1411
1412         // Add InstructionsBuilder to FlowBuilder
1413         flowBuilder.setInstructions(isb.build());
1414
1415         String flowId = "NORMAL";
1416         flowBuilder.setId(new FlowId(flowId));
1417         FlowKey key = new FlowKey(new FlowId(flowId));
1418         flowBuilder.setMatch(matchBuilder.build());
1419         flowBuilder.setPriority(0);
1420         flowBuilder.setBarrier(true);
1421         flowBuilder.setTableId((short) 0);
1422         flowBuilder.setKey(key);
1423         flowBuilder.setFlowName(flowId);
1424         flowBuilder.setHardTimeout(0);
1425         flowBuilder.setIdleTimeout(0);
1426         writeFlow(flowBuilder, nodeBuilder);
1427     }
1428
1429     /*
1430      * (Table:0) Ingress Tunnel Traffic
1431      * Match: OpenFlow InPort and Tunnel ID
1432      * Action: GOTO Local Table (10)
1433      * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1434      */
1435
1436     private void handleTunnelIn(Long dpidLong, Short writeTable,
1437             Short goToTableId, String segmentationId,
1438             Long ofPort, boolean write) {
1439         classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1440     }
1441
1442     /*
1443      * (Table:0) Ingress VLAN Traffic
1444      * Match: OpenFlow InPort and vlan ID
1445      * Action: GOTO Local Table (20)
1446      * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1447      */
1448
1449     private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1450             String segmentationId,  Long ethPort, boolean write) {
1451         classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1452     }
1453
1454     /*
1455      * (Table:0) Egress VM Traffic Towards TEP
1456      * Match: Destination Ethernet Addr and OpenFlow InPort
1457      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1458      * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1459      * actions=set_field:5->tun_id,goto_table=1"
1460      */
1461
1462     private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1463             String segmentationId, Long inPort, String attachedMac,
1464             boolean write) {
1465         classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1466     }
1467
1468     /*
1469      * (Table:0) Egress VM Traffic Towards TEP
1470      * Match: Source Ethernet Addr and OpenFlow InPort
1471      * Instruction: Set VLANID and GOTO Table Egress (n)
1472      * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1473      * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1474      */
1475
1476     private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1477             Short goToTableId, String segmentationId,
1478             Long inPort, String attachedMac,
1479             boolean write) {
1480         classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1481     }
1482
1483     /*
1484      * (Table:0) Drop frames source from a VM that do not
1485      * match the associated MAC address of the local VM.
1486      * Match: Low priority anything not matching the VM SMAC
1487      * Instruction: Drop
1488      * table=0,priority=16384,in_port=1 actions=drop"
1489      */
1490
1491     private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1492         classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1493     }
1494
1495     /*
1496      * (Table:1) Egress Tunnel Traffic
1497      * Match: Destination Ethernet Addr and Local InPort
1498      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1499      * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1500      * actions=output:10,goto_table:2"
1501      */
1502     private void handleTunnelOut(Long dpidLong, Short writeTable,
1503             Short goToTableId, String segmentationId,
1504             Long OFPortOut, String attachedMac,
1505             boolean write) {
1506         l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1507     }
1508
1509     /*
1510      * (Table:1) Egress VLAN Traffic
1511      * Match: Destination Ethernet Addr and VLAN id
1512      * Instruction: GOTO Table Table 2
1513      * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1514      * actions= goto_table:2"
1515      */
1516
1517     private void handleVlanOut(Long dpidLong, Short writeTable,
1518             Short goToTableId, String segmentationId,
1519             Long ethPort, String attachedMac, boolean write) {
1520         l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
1521     }
1522
1523     /*
1524      * (Table:1) Egress Tunnel Traffic
1525      * Match: Destination Ethernet Addr and Local InPort
1526      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1527      * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1528      * actions=output:10,output:11,goto_table:2
1529      */
1530
1531     private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1532             Short localTable, String segmentationId,
1533             Long OFPortOut, boolean write) {
1534         l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1535     }
1536
1537     /*
1538      * (Table:1) Egress VLAN Traffic
1539      * Match: Destination Ethernet Addr and VLAN id
1540      * Instruction: GOTO table 2 and Output port eth interface
1541      * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1542      * actions=output:eth1,goto_table:2
1543      */
1544
1545     private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1546             Short localTable, String segmentationId,
1547             Long localPort, Long ethPort, boolean write) {
1548         //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1549     }
1550
1551     /*
1552      * (Table:1) Table Drain w/ Catch All
1553      * Match: Tunnel ID
1554      * Action: GOTO Local Table (10)
1555      * table=2,priority=8192,tun_id=0x5 actions=drop
1556      */
1557
1558     private void handleTunnelMiss(Long dpidLong, Short writeTable,
1559             Short goToTableId, String segmentationId,
1560             boolean write) {
1561         l2ForwardingProvider.programTunnelMiss(dpidLong, segmentationId, write);
1562     }
1563
1564
1565     /*
1566      * (Table:1) Table Drain w/ Catch All
1567      * Match: Vlan ID
1568      * Action: Output port eth interface
1569      * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1570      * table=110,priority=8192,dl_vlan=2001 actions=output:2
1571      */
1572
1573     private void handleVlanMiss(Long dpidLong, Short writeTable,
1574             Short goToTableId, String segmentationId,
1575             Long ethPort, boolean write) {
1576         l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1577     }
1578
1579     /*
1580      * (Table:1) Local Broadcast Flood
1581      * Match: Tunnel ID and dMAC
1582      * Action: Output Port
1583      * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1584      */
1585
1586     private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1587             String segmentationId, Long localPort,
1588             String attachedMac, boolean write) {
1589         l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1590     }
1591
1592     /*
1593      * (Table:2) Local VLAN unicast
1594      * Match: VLAN ID and dMAC
1595      * Action: Output Port
1596      * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1597      */
1598
1599     private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1600             String segmentationId, Long localPort,
1601             String attachedMac, boolean write) {
1602         l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1603     }
1604
1605     /*
1606      * (Table:2) Local Broadcast Flood
1607      * Match: Tunnel ID and dMAC (::::FF:FF)
1608      * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1609      * actions=output:2,3,4,5
1610      */
1611
1612     private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1613             String segmentationId, Long localPort,
1614             boolean write) {
1615         l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1616     }
1617
1618     /*
1619      * (Table:2) Local VLAN Broadcast Flood
1620      * Match: vlan ID and dMAC (::::FF:FF)
1621      * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1622      * actions=strip_vlan, output:2,3,4,5
1623      * 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
1624      */
1625
1626     private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1627                                          Long localPort, Long ethPort, boolean write) {
1628         l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1629     }
1630
1631     /*
1632      * (Table:1) Local Table Miss
1633      * Match: Any Remaining Flows w/a TunID
1634      * Action: Drop w/ a low priority
1635      * table=2,priority=8192,tun_id=0x5 actions=drop
1636      */
1637
1638     private void handleLocalTableMiss(Long dpidLong, Short writeTable,
1639             String segmentationId, boolean write) {
1640         l2ForwardingProvider.programLocalTableMiss(dpidLong, segmentationId, write);
1641     }
1642
1643     /*
1644      * (Table:1) Local Table Miss
1645      * Match: Any Remaining Flows w/a VLAN ID
1646      * Action: Drop w/ a low priority
1647      * table=2,priority=8192,vlan_id=0x5 actions=drop
1648      */
1649
1650     private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1651             String segmentationId, boolean write) {
1652         l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1653     }
1654
1655     private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1656         Preconditions.checkNotNull(mdsalConsumer);
1657         if (mdsalConsumer == null) {
1658             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1659             return null;
1660         }
1661
1662         dataBroker = mdsalConsumer.getDataBroker();
1663         if (dataBroker == null) {
1664             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1665             return null;
1666         }
1667
1668         InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1669                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1670                         new GroupKey(groupBuilder.getGroupId())).build();
1671         ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1672         try {
1673             Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1674             if (data.isPresent()) {
1675                 return data.get();
1676             }
1677         } catch (InterruptedException|ExecutionException e) {
1678             logger.error(e.getMessage(), e);
1679         }
1680
1681         logger.debug("Cannot find data for Group " + groupBuilder.getGroupName());
1682         return null;
1683     }
1684
1685     private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1686         Preconditions.checkNotNull(mdsalConsumer);
1687         if (mdsalConsumer == null) {
1688             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1689             return;
1690         }
1691
1692         dataBroker = mdsalConsumer.getDataBroker();
1693         if (dataBroker == null) {
1694             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1695             return;
1696         }
1697
1698         ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1699         InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1700                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1701                         new GroupKey(groupBuilder.getGroupId())).build();
1702         modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1703
1704         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1705         try {
1706             commitFuture.get();  // TODO: Make it async (See bug 1362)
1707             logger.debug("Transaction success for write of Group "+groupBuilder.getGroupName());
1708         } catch (InterruptedException|ExecutionException e) {
1709             logger.error(e.getMessage(), e);
1710         }
1711     }
1712
1713     private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1714         Preconditions.checkNotNull(mdsalConsumer);
1715         if (mdsalConsumer == null) {
1716             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1717             return;
1718         }
1719
1720         dataBroker = mdsalConsumer.getDataBroker();
1721         if (dataBroker == null) {
1722             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1723             return;
1724         }
1725
1726         WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1727         InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1728                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1729                         new GroupKey(groupBuilder.getGroupId())).build();
1730         modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1731         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1732
1733         try {
1734             commitFuture.get();  // TODO: Make it async (See bug 1362)
1735             logger.debug("Transaction success for deletion of Group "+groupBuilder.getGroupName());
1736         } catch (InterruptedException|ExecutionException e) {
1737             logger.error(e.getMessage(), e);
1738         }
1739     }
1740     private Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1741         Preconditions.checkNotNull(mdsalConsumer);
1742         if (mdsalConsumer == null) {
1743             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1744             return null;
1745         }
1746
1747         dataBroker = mdsalConsumer.getDataBroker();
1748         if (dataBroker == null) {
1749             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1750             return null;
1751         }
1752
1753         InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1754                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1755                         new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1756
1757         ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1758         try {
1759             Optional<Flow> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1760             if (data.isPresent()) {
1761                 return data.get();
1762             }
1763         } catch (InterruptedException|ExecutionException e) {
1764             logger.error(e.getMessage(), e);
1765         }
1766
1767         logger.debug("Cannot find data for Flow " + flowBuilder.getFlowName());
1768         return null;
1769     }
1770
1771     private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1772         Preconditions.checkNotNull(mdsalConsumer);
1773         if (mdsalConsumer == null) {
1774             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1775             return;
1776         }
1777
1778         dataBroker = mdsalConsumer.getDataBroker();
1779         if (dataBroker == null) {
1780             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1781             return;
1782         }
1783
1784         ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1785         InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1786                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1787                         new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1788
1789         //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1790         modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(), true /*createMissingParents*/);
1791
1792
1793         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1794         try {
1795             commitFuture.get();  // TODO: Make it async (See bug 1362)
1796             logger.debug("Transaction success for write of Flow "+flowBuilder.getFlowName());
1797         } catch (InterruptedException|ExecutionException e) {
1798             logger.error(e.getMessage(), e);
1799         }
1800     }
1801
1802     private void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1803         Preconditions.checkNotNull(mdsalConsumer);
1804         if (mdsalConsumer == null) {
1805             logger.error("ERROR finding MDSAL Service.");
1806             return;
1807         }
1808
1809         dataBroker = mdsalConsumer.getDataBroker();
1810         if (dataBroker == null) {
1811             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1812             return;
1813         }
1814
1815         WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1816         InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class)
1817                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1818                         .rev130819.nodes.Node.class, nodeBuilder.getKey())
1819                         .augmentation(FlowCapableNode.class).child(Table.class,
1820                                 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1821         //modification.delete(LogicalDatastoreType.OPERATIONAL, nodeBuilderToInstanceId(nodeBuilder));
1822         //modification.delete(LogicalDatastoreType.OPERATIONAL, path1);
1823         //modification.delete(LogicalDatastoreType.CONFIGURATION, nodeBuilderToInstanceId(nodeBuilder));
1824         modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1825
1826         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1827         try {
1828             commitFuture.get();  // TODO: Make it async (See bug 1362)
1829             logger.debug("Transaction success for deletion of Flow "+flowBuilder.getFlowName());
1830         } catch (InterruptedException|ExecutionException e) {
1831             logger.error(e.getMessage(), e);
1832         }
1833     }
1834
1835     /**
1836      * Create Output Port Group Instruction
1837      *
1838      * @param ib       Map InstructionBuilder without any instructions
1839      * @param dpidLong Long the datapath ID of a switch/node
1840      * @param port     Long representing a port on a switch/node
1841      * @return ib InstructionBuilder Map with instructions
1842      */
1843     protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1844             InstructionBuilder ib,
1845             Long dpidLong, Long port ,
1846             List<Instruction> instructions) {
1847         NodeConnectorId ncid = new NodeConnectorId(OPENFLOW + dpidLong + ":" + port);
1848         logger.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1849
1850         List<Action> actionList = Lists.newArrayList();
1851         ActionBuilder ab = new ActionBuilder();
1852
1853         List<Action> existingActions;
1854         if (instructions != null) {
1855             for (Instruction in : instructions) {
1856                 if (in.getInstruction() instanceof ApplyActionsCase) {
1857                     existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1858                     actionList.addAll(existingActions);
1859                 }
1860             }
1861         }
1862
1863         GroupBuilder groupBuilder = new GroupBuilder();
1864         Group group = null;
1865
1866         /* Create output action for this port*/
1867         OutputActionBuilder oab = new OutputActionBuilder();
1868         oab.setOutputNodeConnector(ncid);
1869         ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1870         logger.debug("createOutputGroupInstructions(): output action {}", ab.build());
1871         boolean addNew = true;
1872         boolean groupActionAdded = false;
1873
1874         /* Find the group action and get the group */
1875         for (Action action : actionList) {
1876             if (action.getAction() instanceof GroupActionCase) {
1877                 groupActionAdded = true;
1878                 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1879                 Long id = groupAction.getGroupAction().getGroupId();
1880                 String groupName = groupAction.getGroupAction().getGroup();
1881                 GroupKey key = new GroupKey(new GroupId(id));
1882
1883                 groupBuilder.setGroupId(new GroupId(id));
1884                 groupBuilder.setGroupName(groupName);
1885                 groupBuilder.setGroupType(GroupTypes.GroupAll);
1886                 groupBuilder.setKey(key);
1887                 group = getGroup(groupBuilder, nodeBuilder);
1888                 logger.debug("createOutputGroupInstructions: group {}", group);
1889                 break;
1890             }
1891         }
1892
1893         logger.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1894         if (groupActionAdded) {
1895             /* modify the action bucket in group */
1896             groupBuilder = new GroupBuilder(group);
1897             Buckets buckets = groupBuilder.getBuckets();
1898             for (Bucket bucket : buckets.getBucket()) {
1899                 List<Action> bucketActions = bucket.getAction();
1900                 logger.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1901                 for (Action action : bucketActions) {
1902                     if (action.getAction() instanceof OutputActionCase) {
1903                         OutputActionCase opAction = (OutputActionCase)action.getAction();
1904                         /* If output port action already in the action list of one of the buckets, skip */
1905                         if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1906                             addNew = false;
1907                             break;
1908                         }
1909                     }
1910                 }
1911             }
1912             logger.debug("createOutputGroupInstructions: addNew {}", addNew);
1913             if (addNew) {
1914                 /* the new output action is not in the bucket, add to bucket */
1915                 if (!buckets.getBucket().isEmpty()) {
1916                     Bucket bucket = buckets.getBucket().get(0);
1917                     List<Action> bucketActionList = Lists.newArrayList();
1918                     bucketActionList.addAll(bucket.getAction());
1919                     /* set order for new action and add to action list */
1920                     ab.setOrder(bucketActionList.size());
1921                     ab.setKey(new ActionKey(bucketActionList.size()));
1922                     bucketActionList.add(ab.build());
1923
1924                     /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1925                     BucketsBuilder bucketsBuilder = new BucketsBuilder();
1926                     List<Bucket> bucketList = Lists.newArrayList();
1927                     BucketBuilder bucketBuilder = new BucketBuilder();
1928                     bucketBuilder.setBucketId(new BucketId((long) 1));
1929                     bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1930                     bucketBuilder.setAction(bucketActionList);
1931                     bucketList.add(bucketBuilder.build());
1932                     bucketsBuilder.setBucket(bucketList);
1933                     groupBuilder.setBuckets(bucketsBuilder.build());
1934                     logger.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1935                 }
1936             }
1937         } else {
1938             /* create group */
1939             groupBuilder = new GroupBuilder();
1940             groupBuilder.setGroupType(GroupTypes.GroupAll);
1941             groupBuilder.setGroupId(new GroupId(groupId));
1942             groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1943             groupBuilder.setGroupName("Output port group " + groupId);
1944             groupBuilder.setBarrier(false);
1945
1946             BucketsBuilder bucketBuilder = new BucketsBuilder();
1947             List<Bucket> bucketList = Lists.newArrayList();
1948             BucketBuilder bucket = new BucketBuilder();
1949             bucket.setBucketId(new BucketId((long) 1));
1950             bucket.setKey(new BucketKey(new BucketId((long) 1)));
1951
1952             /* put output action to the bucket */
1953             List<Action> bucketActionList = Lists.newArrayList();
1954             /* set order for new action and add to action list */
1955             ab.setOrder(bucketActionList.size());
1956             ab.setKey(new ActionKey(bucketActionList.size()));
1957             bucketActionList.add(ab.build());
1958
1959             bucket.setAction(bucketActionList);
1960             bucketList.add(bucket.build());
1961             bucketBuilder.setBucket(bucketList);
1962             groupBuilder.setBuckets(bucketBuilder.build());
1963
1964             /* Add new group action */
1965             GroupActionBuilder groupActionB = new GroupActionBuilder();
1966             groupActionB.setGroupId(groupId);
1967             groupActionB.setGroup("Output port group " + groupId);
1968             ab = new ActionBuilder();
1969             ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1970             ab.setOrder(actionList.size());
1971             ab.setKey(new ActionKey(actionList.size()));
1972             actionList.add(ab.build());
1973
1974             groupId++;
1975         }
1976         logger.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1977         logger.debug("createOutputGroupInstructions: actionList {}", actionList);
1978
1979         if (addNew) {
1980             /* rewrite the group to group table */
1981             writeGroup(groupBuilder, nodeBuilder);
1982         }
1983
1984         // Create an Apply Action
1985         ApplyActionsBuilder aab = new ApplyActionsBuilder();
1986         aab.setAction(actionList);
1987         ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1988
1989         return ib;
1990     }
1991
1992     /**
1993      * Remove Output Port from action list in group bucket
1994      *
1995      * @param ib       Map InstructionBuilder without any instructions
1996      * @param dpidLong Long the datapath ID of a switch/node
1997      * @param port     Long representing a port on a switch/node
1998      * @return ib InstructionBuilder Map with instructions
1999      */
2000     protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
2001             Long dpidLong, Long port , List<Instruction> instructions) {
2002
2003         NodeConnectorId ncid = new NodeConnectorId(OPENFLOW + dpidLong + ":" + port);
2004         logger.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
2005
2006         List<Action> actionList = Lists.newArrayList();
2007         ActionBuilder ab;
2008
2009         List<Action> existingActions;
2010         if (instructions != null) {
2011             for (Instruction in : instructions) {
2012                 if (in.getInstruction() instanceof ApplyActionsCase) {
2013                     existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
2014                     actionList.addAll(existingActions);
2015                     break;
2016                 }
2017             }
2018         }
2019
2020         GroupBuilder groupBuilder = new GroupBuilder();
2021         Group group = null;
2022         boolean groupActionAdded = false;
2023         /* Find the group action and get the group */
2024         for (Action action : actionList) {
2025             if (action.getAction() instanceof GroupActionCase) {
2026                 groupActionAdded = true;
2027                 GroupActionCase groupAction = (GroupActionCase) action.getAction();
2028                 Long id = groupAction.getGroupAction().getGroupId();
2029                 String groupName = groupAction.getGroupAction().getGroup();
2030                 GroupKey key = new GroupKey(new GroupId(id));
2031
2032                 groupBuilder.setGroupId(new GroupId(id));
2033                 groupBuilder.setGroupName(groupName);
2034                 groupBuilder.setGroupType(GroupTypes.GroupAll);
2035                 groupBuilder.setKey(key);
2036                 group = getGroup(groupBuilder, nodeBuilder);
2037                 break;
2038             }
2039         }
2040
2041         if (groupActionAdded) {
2042             /* modify the action bucket in group */
2043             groupBuilder = new GroupBuilder(group);
2044             Buckets buckets = groupBuilder.getBuckets();
2045             List<Action> bucketActions = Lists.newArrayList();
2046             for (Bucket bucket : buckets.getBucket()) {
2047                 int index = 0;
2048                 boolean isPortDeleted = false;
2049                 bucketActions = bucket.getAction();
2050                 for (Action action : bucketActions) {
2051                     if (action.getAction() instanceof OutputActionCase) {
2052                         OutputActionCase opAction = (OutputActionCase)action.getAction();
2053                         if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
2054                             /* Find the output port in action list and remove */
2055                             index = bucketActions.indexOf(action);
2056                             bucketActions.remove(action);
2057                             isPortDeleted = true;
2058                             break;
2059                         }
2060                     }
2061                 }
2062                 if (isPortDeleted && !bucketActions.isEmpty()) {
2063                     for (int i = index; i< bucketActions.size(); i++) {
2064                         Action action = bucketActions.get(i);
2065                         if (action.getOrder() != i) {
2066                             /* Shift the action order */
2067                             ab = new ActionBuilder();
2068                             ab.setAction(action.getAction());
2069                             ab.setOrder(i);
2070                             ab.setKey(new ActionKey(i));
2071                             Action actionNewOrder = ab.build();
2072                             bucketActions.remove(action);
2073                             bucketActions.add(i, actionNewOrder);
2074                         }
2075                     }
2076
2077                 } else if (bucketActions.isEmpty()) {
2078                     /* remove bucket with empty action list */
2079                     buckets.getBucket().remove(bucket);
2080                     break;
2081                 }
2082             }
2083             if (!buckets.getBucket().isEmpty()) {
2084                 /* rewrite the group to group table */
2085                 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
2086                 BucketsBuilder bucketsBuilder = new BucketsBuilder();
2087                 List<Bucket> bucketList = Lists.newArrayList();
2088                 BucketBuilder bucketBuilder = new BucketBuilder();
2089                 bucketBuilder.setBucketId(new BucketId((long) 1));
2090                 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
2091                 bucketBuilder.setAction(bucketActions);
2092                 bucketList.add(bucketBuilder.build());
2093                 bucketsBuilder.setBucket(bucketList);
2094                 groupBuilder.setBuckets(bucketsBuilder.build());
2095                 logger.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
2096
2097                 writeGroup(groupBuilder, nodeBuilder);
2098                 ApplyActionsBuilder aab = new ApplyActionsBuilder();
2099                 aab.setAction(actionList);
2100                 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
2101                 return false;
2102             } else {
2103                 /* remove group with empty bucket. return true to delete flow */
2104                 removeGroup(groupBuilder, nodeBuilder);
2105                 return true;
2106             }
2107         } else {
2108             /* no group for port list. flow can be removed */
2109             return true;
2110         }
2111     }
2112
2113     @Override
2114     public void initializeOFFlowRules(org.opendaylight.controller.sal.core.Node openflowNode) {
2115         Preconditions.checkNotNull(connectionService);
2116         List<Node> ovsNodes = connectionService.getNodes();
2117         if (ovsNodes == null) return;
2118         for (Node ovsNode : ovsNodes) {
2119             Long brIntDpid = this.getIntegrationBridgeOFDPID(ovsNode);
2120             Long brExDpid = this.getExternalBridgeDpid(ovsNode);
2121             logger.debug("Compare openflowNode to OVS node {} vs {} and {}", openflowNode.getID(), brIntDpid, brExDpid);
2122             String openflowID = openflowNode.getID().toString();
2123             if (openflowID.contains(brExDpid.toString())) {
2124                 this.initializeFlowRules(ovsNode, configurationService.getExternalBridgeName());
2125                 this.triggerInterfaceUpdates(ovsNode);
2126             }
2127             if (openflowID.contains(brIntDpid.toString())) {
2128                 this.initializeFlowRules(ovsNode, configurationService.getIntegrationBridgeName());
2129                 this.triggerInterfaceUpdates(ovsNode);
2130             }
2131         }
2132     }
2133
2134     public static NodeBuilder createNodeBuilder(String nodeId) {
2135         NodeBuilder builder = new NodeBuilder();
2136         builder.setId(new NodeId(nodeId));
2137         builder.setKey(new NodeKey(builder.getId()));
2138         return builder;
2139     }
2140
2141     private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeBuilderToInstanceId(NodeBuilder
2142             node) {
2143         return InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
2144                 node.getKey()).toInstance();
2145     }
2146
2147     private String getInternalBridgeUUID (Node node, String bridgeName) {
2148         Preconditions.checkNotNull(ovsdbConfigurationService);
2149         try {
2150             Map<String, Row> bridgeTable = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
2151             if (bridgeTable == null) return null;
2152             for (String key : bridgeTable.keySet()) {
2153                 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
2154                 if (bridge.getName().equals(bridgeName)) return key;
2155             }
2156         } catch (Exception e) {
2157             logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
2158         }
2159         return null;
2160     }
2161 }