Bump versions by x.(y+1).z
[ovsdb.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / providers / OF10Provider.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, Sam Hague, Dave Tucker
9  */
10 package org.opendaylight.ovsdb.openstack.netvirt.providers;
11
12 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
13 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
14 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
15 import org.opendaylight.controller.sal.action.ActionType;
16 import org.opendaylight.controller.sal.core.Node;
17 import org.opendaylight.controller.sal.utils.EtherTypes;
18 import org.opendaylight.controller.sal.utils.HexEncode;
19 import org.opendaylight.controller.sal.utils.Status;
20 import org.opendaylight.controller.sal.utils.StatusCode;
21 import org.opendaylight.controller.switchmanager.ISwitchManager;
22 import org.opendaylight.controller.switchmanager.Switch;
23 import org.opendaylight.ovsdb.lib.notation.Row;
24 import org.opendaylight.ovsdb.lib.notation.UUID;
25 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
26 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
27 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
28 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
29 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
30 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
31 import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
32 import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
33 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
34 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
35 import org.opendaylight.ovsdb.schema.openvswitch.Port;
36
37 import com.google.common.collect.Lists;
38 import com.google.common.collect.Maps;
39 import org.apache.commons.lang3.tuple.ImmutablePair;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 import java.net.InetAddress;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Set;
47
48 /**
49  * Open vSwitch OpenFlow 1.0 Networking Provider for OpenStack Neutron
50  */
51 public class OF10Provider implements NetworkingProvider {
52     private static final Logger logger = LoggerFactory.getLogger(OF10Provider.class);
53     private static final int INGRESS_TUNNEL_FLOW_PRIORITY = 100;
54     private static final int EGRESS_TUNNEL_FLOW_PRIORITY = 100;
55     private static final int DROP_FLOW_PRIORITY = 10;
56     private static final int FLOOD_TUNNEL_FLOW_PRIORITY = 50;
57     public static final int LLDP_PRIORITY = 1000;
58     public static final int NORMAL_PRIORITY = 0;
59
60     private volatile org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService configurationService;
61     private volatile BridgeConfigurationManager bridgeConfigurationManager;
62     private volatile TenantNetworkManager tenantNetworkManager;
63     private volatile OvsdbConfigurationService ovsdbConfigurationService;
64     private volatile OvsdbConnectionService connectionService;
65     private volatile IForwardingRulesManager forwardingRulesManager;
66     private volatile ISwitchManager switchManager;
67
68     public OF10Provider(){
69     }
70
71     @Override
72     public boolean hasPerTenantTunneling() {
73         return true;
74     }
75
76     private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
77         InetAddress srcTunnelEndPoint = configurationService.getTunnelEndPoint(node);
78         if (srcTunnelEndPoint == null) {
79             logger.error("Tunnel Endpoint not configured for Node {}", node);
80             return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
81         }
82
83         if (!bridgeConfigurationManager.isNodeOverlayReady(node)) {
84             logger.warn("{} is not Overlay ready. It might be an OpenStack Controller Node", node);
85             return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
86         }
87
88         if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, tunnelKey)) {
89             logger.debug(node+" has no network corresponding to segment "+ tunnelKey);
90             return new Status(StatusCode.NOTACCEPTABLE, node+" has no network corresponding to segment "+ tunnelKey);
91         }
92         return new Status(StatusCode.SUCCESS);
93     }
94
95     private Status getVlanReadinessStatus (Node node, String segmentationId) {
96         if (!bridgeConfigurationManager.isNodeOverlayReady(node)) {
97             logger.warn("{} is not Overlay ready. It might be an OpenStack Controller Node", node);
98             return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
99         }
100
101         if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, segmentationId)) {
102             logger.debug(node+" has no network corresponding to segment "+ segmentationId);
103             return new Status(StatusCode.NOTACCEPTABLE, node+" has no network corresponding to segment "+ segmentationId);
104         }
105         return new Status(StatusCode.SUCCESS);
106     }
107
108     /**
109      * Program OF1.0 Flow rules on br-tun on the ingress direction from the network towards the br-int.
110      * The logic is to simply match on the incoming tunnel OF-Port (which carries the TenantNetwork GRE-Key)
111      * and rewrite the Corresponding internal Vlan and pass it on to br-int via the patch port.
112      */
113     private void programLocalIngressTunnelBridgeRules(Node node, long tunnelOFPort, int internalVlan, long patchPort) {
114         String brNetId = bridgeConfigurationManager.getBridgeUuid(node, configurationService.getNetworkBridgeName());
115         if (brNetId == null) {
116             logger.error("Failed to initialize Flow Rules for {}", node);
117             return;
118         }
119         try {
120             Row row = ovsdbConfigurationService
121                     .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brNetId);
122             Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
123             Set<String> dpids = bridge.getDatapathIdColumn().getData();
124             if (dpids == null || dpids.size() ==  0) return;
125             Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
126             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
127             String flowName = "TepMatch"+tunnelOFPort+""+internalVlan;
128             FlowConfig flow = new FlowConfig();
129             flow.setName(flowName);
130             flow.setNode(ofNode);
131             flow.setInstallInHw(true);
132             flow.setPriority(INGRESS_TUNNEL_FLOW_PRIORITY+"");
133             flow.setIngressPort(tunnelOFPort+"");
134             List<String> actions = Lists.newArrayList();
135             actions.add(ActionType.SET_VLAN_ID+"="+internalVlan);
136             actions.add(ActionType.OUTPUT.toString()+"="+patchPort);
137             flow.setActions(actions);
138             Status status = this.addStaticFlow(ofNode, flow);
139             logger.debug("Local Ingress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
140         } catch (Exception e) {
141             logger.error("Failed to initialize Flow Rules for {}", node, e);
142         }
143     }
144
145     private void removeLocalIngressTunnelBridgeRules(Node node, long tunnelOFPort, int internalVlan, long patchPort) {
146         String brNetId = bridgeConfigurationManager.getBridgeUuid(node, configurationService.getNetworkBridgeName());
147         if (brNetId == null) {
148             logger.error("Failed to remove Flow Rules for {}", node);
149             return;
150         }
151         try {
152             Row row = ovsdbConfigurationService
153                     .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brNetId);
154             Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
155             Set<String> dpids = bridge.getDatapathIdColumn().getData();
156             if (dpids == null || dpids.size() ==  0) return;
157             Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
158             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
159             String flowName = "TepMatch"+tunnelOFPort+""+internalVlan;
160
161             Status status = this.deleteStaticFlow(ofNode, flowName);
162             logger.debug("Local Ingress Flow Removal Status {} for Flow {} on {} / {}", status, flowName, ofNode, node);
163         } catch (Exception e) {
164             logger.error("Failed to Remove Flow Rules for {}", node, e);
165         }
166     }
167
168     /**
169      * Program OF1.0 Flow rules on br-tun on the remote Node on its egress direction towards the overlay network
170      * for a VM (with the attachedMac).
171      * The logic is to simply match on the incoming vlan, mac from the patch-port connected to br-int (patch-int)
172      * and output the traffic to the appropriate GRE Tunnel (which carries the GRE-Key for that Tenant Network).
173      * Also perform the Strip-Vlan action.
174      */
175     private void programRemoteEgressTunnelBridgeRules(Node node, long patchPort, String attachedMac,
176             int internalVlan, long tunnelOFPort) {
177         String brNetId = bridgeConfigurationManager.getBridgeUuid(node, configurationService.getNetworkBridgeName());
178         if (brNetId == null) {
179             logger.error("Failed to initialize Flow Rules for {}", node);
180             return;
181         }
182         try {
183             Row row = ovsdbConfigurationService
184                     .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brNetId);
185             Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
186             Set<String> dpids = bridge.getDatapathIdColumn().getData();
187             if (dpids == null || dpids.size() ==  0) return;
188             Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
189             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
190             String flowName = "TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac);
191             FlowConfig flow = new FlowConfig();
192             flow.setName(flowName);
193             flow.setNode(ofNode);
194             flow.setInstallInHw(true);
195             flow.setPriority(EGRESS_TUNNEL_FLOW_PRIORITY+"");
196             flow.setDstMac(attachedMac);
197             flow.setIngressPort(patchPort+"");
198             flow.setVlanId(internalVlan+"");
199             List<String> actions = Lists.newArrayList();
200             actions.add(ActionType.POP_VLAN.toString());
201             actions.add(ActionType.OUTPUT.toString()+"="+tunnelOFPort);
202             flow.setActions(actions);
203             Status status = this.addStaticFlow(ofNode, flow);
204             logger.debug("Remote Egress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
205         } catch (Exception e) {
206             logger.error("Failed to initialize Flow Rules for {}", node, e);
207         }
208     }
209
210     private void removeRemoteEgressTunnelBridgeRules(Node node, long patchPort, String attachedMac,
211             int internalVlan, long tunnelOFPort) {
212         String brNetId = bridgeConfigurationManager.getBridgeUuid(node, configurationService.getNetworkBridgeName());
213         if (brNetId == null) {
214             logger.error("Failed to initialize Flow Rules for {}", node);
215             return;
216         }
217         try {
218             Row row = ovsdbConfigurationService
219                     .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brNetId);
220             Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
221             Set<String> dpids = bridge.getDatapathIdColumn().getData();
222             if (dpids == null || dpids.size() ==  0) return;
223             Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
224             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
225             String flowName = "TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac);
226             Status status = this.deleteStaticFlow(ofNode, flowName);
227             logger.debug("Remote Egress Flow Removal Status {} for Flow {} on {} / {}", status, flowName, ofNode, node);
228         } catch (Exception e) {
229             logger.error("Failed to Remove Flow Rules for {}", node, e);
230         }
231     }
232
233     /**
234      * Program OF1.0 Flow rules to flood the broadcast & unknown-unicast traffic over br-tun on the egress direction
235      * towards the network on all the overlay tunnels that corresponds to the tenant network.
236      * The logic is to simply match on the incoming vlan, mac from the patch-port connected to br-int (patch-int)
237      * and output the traffic to all the GRE-Tunnels for this Tenant Network (which carries the GRE-Key).
238      * Also perform the Strip-Vlan action.
239      */
240     private void programFloodEgressTunnelBridgeRules(Node node, long patchPort, int internalVlan, long tunnelOFPort) {
241         String brNetId = bridgeConfigurationManager.getBridgeUuid(node, configurationService.getNetworkBridgeName());
242         if (brNetId == null) {
243             logger.error("Failed to initialize Flow Rules for {}", node);
244             return;
245         }
246         try {
247             Row row = ovsdbConfigurationService
248                     .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brNetId);
249             Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
250             Set<String> dpids = bridge.getDatapathIdColumn().getData();
251             if (dpids == null || dpids.size() ==  0) return;
252             Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
253             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
254             String flowName = "TepFlood"+internalVlan;
255             FlowConfig existingFlowConfig = forwardingRulesManager.getStaticFlow(flowName, ofNode);
256             FlowConfig flow = existingFlowConfig;
257             Status status;
258             if (flow == null) {
259                 flow = new FlowConfig();
260                 flow.setName(flowName);
261                 flow.setNode(ofNode);
262                 flow.setPriority(FLOOD_TUNNEL_FLOW_PRIORITY+"");
263                 flow.setIngressPort(patchPort+"");
264                 flow.setVlanId(internalVlan+"");
265                 List<String> actions = Lists.newArrayList();
266                 actions.add(ActionType.POP_VLAN.toString());
267                 actions.add(ActionType.OUTPUT.toString()+"="+tunnelOFPort);
268                 flow.setActions(actions);
269                 status = forwardingRulesManager.addStaticFlow(flow);
270                 logger.debug("Add Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
271                               status, flow, ofNode, node);
272             } else {
273                 flow = new FlowConfig(existingFlowConfig);
274                 List<String> actions = flow.getActions();
275                 String outputPort = ActionType.OUTPUT.toString()+"="+tunnelOFPort;
276                 if (actions != null && !actions.contains(outputPort)) {
277                     actions.add(outputPort);
278                     flow.setActions(actions);
279                 } else {
280                     logger.debug("Flood Egress Flow already exists. Skipping modify for Flow {} on {} / {}",
281                                  flow, ofNode, node);
282                     return;
283                 }
284                 status = forwardingRulesManager.modifyStaticFlow(flow);
285                 logger.debug("Modify Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
286                               status, flow, ofNode, node);
287             }
288         } catch (Exception e) {
289             logger.error("Failed to initialize Flow Rules for {}", node, e);
290         }
291     }
292
293     private void removeFloodEgressTunnelBridgeRules(Node node, long patchPort, int internalVlan, long tunnelOFPort) {
294         String brNetId = bridgeConfigurationManager.getBridgeUuid(node, configurationService.getNetworkBridgeName());
295         if (brNetId == null) {
296             logger.error("Failed to remove Flow Rules for {}", node);
297             return;
298         }
299         try {
300             Row row = ovsdbConfigurationService
301                     .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brNetId);
302             Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
303             Set<String> dpids = bridge.getDatapathIdColumn().getData();
304             if (dpids == null || dpids.size() ==  0) return;
305             Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
306             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
307             String flowName = "TepFlood"+internalVlan;
308             FlowConfig flow = forwardingRulesManager.getStaticFlow(flowName, ofNode);
309             Status status;
310             if (flow != null) {
311                 status = forwardingRulesManager.removeStaticFlow(flowName, ofNode);
312                 logger.debug("Remove Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
313                               status, flow, ofNode, node);
314
315             } else {
316                 logger.debug("Flood Egress Flow already removed. Skipping removal of flow on {} / {}",
317                              ofNode, node);
318             }
319         } catch (Exception e) {
320             logger.error("Failed to remove Flow Rules for {}", node, e);
321         }
322     }
323
324     private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
325                                      Interface iface, boolean local) {
326         String networkId = tenantNetworkManager.getNetworkId(segmentationId);
327         if (networkId == null) {
328             logger.debug("Tenant Network not found with Segmentation-id {}", segmentationId);
329             return;
330         }
331         int internalVlan = tenantNetworkManager.getInternalVlan(node, networkId);
332         if (internalVlan == 0) {
333             logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
334             return;
335         }
336         Map<String, String> externalIds = iface.getExternalIdsColumn().getData();
337         if (externalIds == null) {
338             logger.error("No external_ids seen in {}", iface);
339             return;
340         }
341
342         String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
343         if (attachedMac == null) {
344             logger.error("No AttachedMac seen in {}", iface);
345             return;
346         }
347         String patchInt = configurationService
348                 .getPatchPortName(new ImmutablePair<>(configurationService.getNetworkBridgeName(),
349                                                       configurationService.getIntegrationBridgeName()));
350
351         long patchOFPort = -1;
352         try {
353             Map<String, Row> ifaces = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
354             if (ifaces != null) {
355                 for (Row row : ifaces.values()) {
356                     Interface patchiface = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
357                     if (patchiface.getName().equalsIgnoreCase(patchInt)) {
358                         Set<Long> of_ports = patchiface.getOpenFlowPortColumn().getData();
359                         if (of_ports == null || of_ports.size() <= 0) {
360                             logger.trace("No port for patch interface {} on node {}", patchInt, node);
361                             continue;
362                         }
363                         patchOFPort = (long)of_ports.toArray()[0];
364                         logger.debug("Identified Patch port {} -> OF ({}) on {}", patchInt, patchOFPort, node);
365                         break;
366                     }
367                 }
368                 if (patchOFPort == -1) {
369                     logger.warn("Could not find port associated with patch interface {} on node {}. No flow rules to program", patchInt, node);
370                 }
371                 for (Row row : ifaces.values()) {
372                     Interface tuniface = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
373                     if (tuniface.getName().equals(this.getTunnelName(tunnelType, segmentationId, dst))) {
374                         Set<Long> of_ports = tuniface.getOpenFlowPortColumn().getData();
375                         if (of_ports == null || of_ports.size() <= 0) {
376                             logger.warn("Could not Identify Tunnel port {} on {}. Don't panic. It might get converged soon...", tuniface.getName(), node);
377                             continue;
378                         }
379                         long tunnelOFPort = (long)of_ports.toArray()[0];
380
381                         if (tunnelOFPort == -1) {
382                             logger.warn("Tunnel Port {} on node {}: OFPort = -1 . Don't panic. It might get converged soon...", tuniface.getName(), node);
383                             return;
384                         }
385                         logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tuniface.getName(), tunnelOFPort, node);
386
387                         if (!local) {
388                             programRemoteEgressTunnelBridgeRules(node, patchOFPort, attachedMac, internalVlan, tunnelOFPort);
389                             logger.trace("Programmed (non-local) EgressTunnelBridgeRules for attachedMac {} internalVlan {} tunnelOFPort {}",
390                                     attachedMac, internalVlan, tunnelOFPort);
391                         }
392                         programLocalIngressTunnelBridgeRules(node, tunnelOFPort, internalVlan, patchOFPort);
393                         programFloodEgressTunnelBridgeRules(node, patchOFPort, internalVlan, tunnelOFPort);
394                         logger.trace("Programmed ingress tunnel and flood rules for node {} tunnel {} tunnelOFPort {} internalVlan {} patchOFPort {}",
395                                 node, tuniface.getName(), tunnelOFPort, internalVlan, patchOFPort);
396                         return;
397                     }
398                 }
399             }
400         } catch (Exception e) {
401             logger.error("", e);
402         }
403     }
404
405     private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
406             Interface iface, boolean local) {
407         String networkId = tenantNetworkManager.getNetworkId(segmentationId);
408         if (networkId == null) {
409             logger.debug("Tenant Network not found with Segmentation-id {}",segmentationId);
410             return;
411         }
412         int internalVlan = tenantNetworkManager.getInternalVlan(node, networkId);
413         if (internalVlan == 0) {
414             logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
415             return;
416         }
417         Map<String, String> externalIds = iface.getExternalIdsColumn().getData();
418         if (externalIds == null) {
419             logger.error("No external_ids seen in {}", iface);
420             return;
421         }
422
423         String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
424         if (attachedMac == null) {
425             logger.error("No AttachedMac seen in {}", iface);
426             return;
427         }
428         String patchInt = configurationService
429                 .getPatchPortName(new ImmutablePair<>(configurationService.getNetworkBridgeName(),
430                                                       configurationService.getIntegrationBridgeName()));
431
432         long patchOFPort = -1;
433         try {
434             Map<String, Row> ifaces = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
435             if (ifaces != null) {
436                 for (Row row : ifaces.values()) {
437                     Interface patchiface = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
438                     if (patchiface.getName().equalsIgnoreCase(patchInt)) {
439                         Set<Long> of_ports = patchiface.getOpenFlowPortColumn().getData();
440                         if (of_ports == null || of_ports.size() <= 0) {
441                             logger.trace("Could NOT identify Patch port {} on {}", patchInt, node);
442                             continue;
443                         }
444                         patchOFPort = (long)of_ports.toArray()[0];
445                         logger.debug("Identified Patch port {} -> OF ({}) on {}", patchInt, patchOFPort, node);
446                         break;
447                     }
448                 }
449                 if (patchOFPort == -1) {
450                     logger.debug("Could not find port associated with patch interface {} on node {}", patchInt, node);
451                     // return;  // keep going; we assume that removal of rules does not really need patchOFPort
452                 }
453                 for (Row row : ifaces.values()) {
454                     Interface tuniface = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
455                     if (tuniface.getName().equals(this.getTunnelName(tunnelType, segmentationId, dst))) {
456                         Set<Long> of_ports = tuniface.getOpenFlowPortColumn().getData();
457                         if (of_ports == null || of_ports.size() <= 0) {
458                             logger.error("Could NOT Identify Tunnel port {} on {}", tuniface.getName(), node);
459                             continue;
460                         }
461                         long tunnelOFPort = (long)of_ports.toArray()[0];
462
463                         if (tunnelOFPort == -1) {
464                             logger.error("Could NOT Identify Tunnel port {} -> OF ({}) on {}: No flow rules to remove", tuniface.getName(), tunnelOFPort, node);
465                             return;
466                         }
467                         logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tuniface.getName(), tunnelOFPort, node);
468
469                         if (!local) {
470                             removeRemoteEgressTunnelBridgeRules(node, patchOFPort, attachedMac, internalVlan, tunnelOFPort);
471                         }
472                         removeLocalIngressTunnelBridgeRules(node, tunnelOFPort, internalVlan, patchOFPort);
473                         removeFloodEgressTunnelBridgeRules(node, patchOFPort, internalVlan, tunnelOFPort);
474                         return;
475                     }
476                 }
477             }
478         } catch (Exception e) {
479             logger.error("", e);
480         }
481     }
482
483     private String getIntModVlanFlowName (long inOFPort, String fromVlan, String toVlan) {
484         return "int_mod_"+inOFPort+"_"+fromVlan+"_"+toVlan;
485     }
486
487     private String getIntDropFlowName (long inOFPort) {
488         return "int_drop_"+inOFPort;
489     }
490
491     private String getNetModVlanFlowName (long inOFPort, String fromVlan, String toVlan) {
492         return "net_mod_"+inOFPort+"_"+fromVlan+"_"+toVlan;
493     }
494
495     private String getNetDropFlowName (long inOFPort) {
496         return "net_drop_"+inOFPort;
497     }
498
499     private String getNetFwdFlowName (long inOFPort, long outOFPort, String vlan) {
500         return "net_fwd_"+vlan+"_"+inOFPort+"_"+outOFPort;
501     }
502
503     private void deleteRule (Node node, Node ofNode, String flowName) {
504         logger.debug("deleteRule: node: {} / {}, flowName: {}", node, ofNode, flowName);
505
506         try {
507             this.deleteStaticFlow(ofNode, flowName);
508         } catch (Exception e) {
509             logger.error("deleteRule: Failed to delete Flow Rule for {} / {}", node, ofNode, e);
510         }
511     }
512
513     /* in_port=p actions=drop */
514     private void programDropRule (Node node, Node ofNode, long inOFPort, String flowName) {
515         logger.debug("programDropRule: node: {} / {}, inOfPort: {}, flowName: {}",
516                 node, ofNode, inOFPort, flowName);
517
518         try {
519             FlowConfig flow = new FlowConfig();
520             flow.setName(flowName);
521             flow.setNode(ofNode);
522             flow.setInstallInHw(true);
523             flow.setPriority(DROP_FLOW_PRIORITY+"");
524             flow.setIngressPort(inOFPort+"");
525             List<String> actions = Lists.newArrayList();
526             actions.add(ActionType.DROP+"");
527             flow.setActions(actions);
528             Status status = this.addStaticFlow(ofNode, flow);
529             logger.debug("programDropRule: Flow Programming Status {} for Flow {} on {} / {}",
530                     status, flow, node, ofNode);
531         } catch (Exception e) {
532             logger.error("programDropRule: Failed to initialize Flow Rules for {} / {}", node, ofNode, e);
533         }
534     }
535
536     /* in_port=p1,dl_vlan=v actions=mod_vlan_vid,[NORMAL|output:p2] */
537     private void programModVlanRule (Node node, Node ofNode, long inOFPort, long outOFPort, String fromVlan,
538                                      String toVlan, String flowName) {
539         logger.debug("programModVlanRule: node: {} / {}, inOfPort: {}, fromVlan: {}, toVlan: {}, flowName: {}",
540                 node, ofNode, inOFPort, fromVlan, toVlan, flowName);
541
542         try {
543             FlowConfig flow = new FlowConfig();
544             flow.setName(flowName);
545             flow.setNode(ofNode);
546             flow.setInstallInHw(true);
547             flow.setPriority(INGRESS_TUNNEL_FLOW_PRIORITY+"");
548             flow.setIngressPort(inOFPort+"");
549             flow.setVlanId(fromVlan);
550             List<String> actions = Lists.newArrayList();
551             actions.add(ActionType.SET_VLAN_ID+"="+toVlan);
552             if (outOFPort == -1) {
553                 actions.add(ActionType.HW_PATH.toString());
554             } else {
555                 actions.add(ActionType.OUTPUT.toString()+"="+outOFPort);
556             }
557             flow.setActions(actions);
558             Status status = this.addStaticFlow(ofNode, flow);
559             logger.debug("programModVlanRule: Flow Programming Status {} for Flow {} on {} / {}",
560                     status, flow, node, ofNode);
561         } catch (Exception e) {
562             logger.error("programModVlanRule: Failed to initialize Flow Rule for {} / {}", node, ofNode, e);
563         }
564     }
565
566     /* in_port=p1,dl_vlan=v actions=output:p2 */
567     private void programForwardRule (Node node, Node ofNode, long inOFPort, long outOFPort, String vlan, String flowName) {
568         logger.debug("programForwardRule: node: {} / {}, inOfPort: {}, outOFPort: {}, flowName: {}",
569                 node, ofNode, inOFPort, outOFPort, flowName);
570
571         try {
572             FlowConfig flow = new FlowConfig();
573             flow.setName(flowName);
574             flow.setNode(ofNode);
575             flow.setInstallInHw(true);
576             flow.setPriority(EGRESS_TUNNEL_FLOW_PRIORITY + "");
577             flow.setIngressPort(inOFPort + "");
578             flow.setVlanId(vlan);
579             List<String> actions = Lists.newArrayList();
580             actions.add(ActionType.OUTPUT.toString()+"="+outOFPort);
581             flow.setActions(actions);
582             Status status = this.addStaticFlow(ofNode, flow);
583             logger.debug("programForwardRule: Flow Programming Status {} for Flow {} on {} / {}",
584                     status, flow, node, ofNode);
585         } catch (Exception e) {
586             logger.error("programForwardRule: Failed to initialize Flow Rules for {} / {}", node, ofNode, e);
587         }
588     }
589
590     public long getOFPort (Node node, String portName) {
591         long ofPort = -1;
592         try {
593             Map<String, Row> ifaces = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
594             if (ifaces != null) {
595                 for (Row row : ifaces.values()) {
596                     Interface iface = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
597                     if (iface.getName().equalsIgnoreCase(portName)) {
598                         Set<Long> of_ports = iface.getOpenFlowPortColumn().getData();
599                         if (of_ports == null || of_ports.size() <= 0) {
600                             logger.error("Could not identify patch port {} on {}", portName, node);
601                             continue;
602                         }
603                         ofPort = (Long)of_ports.toArray()[0];
604                         logger.debug("Identified port {} -> OF ({}) on {}", portName, ofPort, node);
605                         break;
606                     }
607                 }
608             }
609         } catch (Exception e) {
610             logger.error("", e);
611         }
612
613         return ofPort;
614     }
615
616     /*
617      * Transient class to return all the vlan network data needed for flow programming.
618      */
619     public class vlanNet {
620         public long patchIntOfPort;
621         public long patchNetOfPort;
622         public long physicalOfPort;
623         public int internalVlan;
624
625         public vlanNet (NeutronNetwork network, Node node, Interface iface) {
626             patchIntOfPort = -1;
627             patchNetOfPort = -1;
628             physicalOfPort = -1;
629             internalVlan = 0;
630
631             initializeVlanNet(network, node, iface);
632         }
633
634         public boolean isValid () {
635             return (patchIntOfPort != -1) && (patchNetOfPort != -1) && (physicalOfPort != -1) && (internalVlan != -1);
636         }
637
638         public long getPatchIntOfPort () {
639             return patchIntOfPort;
640         }
641
642         public long getPatchNetOfPort () {
643             return patchNetOfPort;
644         }
645
646         public long getphysicalOfPort () {
647             return physicalOfPort;
648         }
649
650         public int getInternalVlan () {
651             return internalVlan;
652         }
653
654         public void initializeVlanNet (NeutronNetwork network, Node node, Interface iface) {
655             internalVlan = tenantNetworkManager.getInternalVlan(node, network.getNetworkUUID());
656             if (internalVlan == 0) {
657                 logger.debug("No InternalVlan provisioned for Tenant Network {}", network.getNetworkUUID());
658                 return;
659             }
660
661             /* Get ofports for patch ports and physical interface. */
662             String patchToNetworkName = configurationService
663                     .getPatchPortName(new ImmutablePair<>(configurationService.getIntegrationBridgeName(),
664                                                           configurationService.getNetworkBridgeName()));
665
666             String patchToIntegrationName = configurationService
667                     .getPatchPortName(new ImmutablePair<>(configurationService.getNetworkBridgeName(),
668                                                           configurationService.getIntegrationBridgeName()));
669
670             String physNetName = bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
671
672             patchIntOfPort = getOFPort(node, patchToNetworkName);
673             if (patchIntOfPort == -1) {
674                 logger.error("Cannot identify {} interface on {}", patchToNetworkName, node);
675                 return;
676             }
677
678             patchNetOfPort = getOFPort(node, patchToIntegrationName);
679             if (patchNetOfPort == -1) {
680                 logger.error("Cannot identify {} interface on {}", patchToIntegrationName, node);
681                 return;
682             }
683
684             physicalOfPort = getOFPort(node, physNetName);
685             if (physicalOfPort == -1) {
686                 logger.error("Cannot identify {} interface on {}", physNetName, node);
687             }
688         }
689     }
690
691     private Node getOFNode (Node node, String bridgeName) {
692         String brUUID = bridgeConfigurationManager.getBridgeUuid(node, bridgeName);
693         if (brUUID == null) {
694             logger.error("getOFNode: Unable to find {} UUID on node {}", bridgeName, node);
695             return null;
696         }
697
698         try {
699             Row row = ovsdbConfigurationService
700                     .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brUUID);
701             Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
702             Set<String> dpids = bridge.getDatapathIdColumn().getData();
703             if (dpids == null || dpids.size() ==  0) {
704                 return null;
705             }
706             Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
707             return new Node(Node.NodeIDType.OPENFLOW, dpidLong);
708         } catch (Exception e) {
709             logger.error("deleteRule: Failed to delete Flow Rule for {}", node, e);
710         }
711
712         return null;
713     }
714
715     /*
716      * Vlan isolation uses a patch port between br-int and br-net. Anything received on one end of
717      * the patch is piped to the other end of the patch so the incoming packets from the network would
718      * arrive untouched at the patch port on br-int.
719      *
720      * Program OF1.0 Flow rules on br-net in the ingress direction from the network
721      * and egress direction towards the network.
722      * The logic is to simply match on the incoming patch OF-Port and internal vlan,
723      * rewrite the internal vlan to the external vlan and forward out the physical port.
724      * There is also a flow to match the externally tagged packets from the physical port
725      * rewrite the external tag to the internal tag and forward to the patch port.
726      *
727      * priority=100,in_port=1,dl_vlan=1 actions=mod_vlan_vid:2001,output:2
728      * priority=100,in_port=2,dl_vlan=2001 actions=mod_vlan_vid:1actions=output:1
729      */
730
731     private void programVlanRules (NeutronNetwork network, Node node, Interface iface) {
732         vlanNet vlanNet = new vlanNet(network, node, iface);
733         if (vlanNet.isValid()) {
734             String netBrName = configurationService.getNetworkBridgeName();
735             String intModVlanFlowName = getIntModVlanFlowName(vlanNet.getPatchNetOfPort(), vlanNet.getInternalVlan()+"", network.getProviderSegmentationID());
736             String netModVlanFlowName = getNetModVlanFlowName(vlanNet.getPatchNetOfPort(), network.getProviderSegmentationID(), vlanNet.getInternalVlan()+"");
737
738             Node netOFNode = getOFNode(node, netBrName);
739             if (netOFNode == null) {
740                 logger.error("Unable to find {} ofNode, Failed to initialize Flow Rules for {}", netBrName, node);
741                 return;
742             }
743
744             /* Program flows on br-net */
745             deleteRule(node, netOFNode, "NORMAL");
746             programModVlanRule(node, netOFNode, vlanNet.getPatchNetOfPort(), vlanNet.getphysicalOfPort(),
747                     vlanNet.getInternalVlan()+"", network.getProviderSegmentationID(), intModVlanFlowName);
748             programModVlanRule(node, netOFNode, vlanNet.getphysicalOfPort(), vlanNet.getPatchNetOfPort(),
749                     network.getProviderSegmentationID(), vlanNet.getInternalVlan()+"", netModVlanFlowName);
750         }
751     }
752
753     private void removeVlanRules (NeutronNetwork network, Node node, Interface iface) {
754         vlanNet vlanNet = new vlanNet(network, node, iface);
755         if (vlanNet.isValid()) {
756             String netBrName = configurationService.getNetworkBridgeName();
757             String intModVlanFlowName = getIntModVlanFlowName(vlanNet.getPatchNetOfPort(), vlanNet.getInternalVlan()+"", network.getProviderSegmentationID());
758             String netModVlanFlowName = getNetModVlanFlowName(vlanNet.getPatchNetOfPort(), network.getProviderSegmentationID(), vlanNet.getInternalVlan()+"");
759
760             Node netOFNode = getOFNode(node, netBrName);
761             if (netOFNode == null) {
762                 logger.error("Unable to find {} ofNode, Failed to initialize Flow Rules for {}", netBrName, node);
763                 return;
764             }
765
766             deleteRule(node, netOFNode, intModVlanFlowName);
767             deleteRule(node, netOFNode, netModVlanFlowName);
768         }
769     }
770
771     @Override
772     public Status handleInterfaceUpdate(NeutronNetwork network, Node srcNode, Interface iface) {
773         logger.debug("handleInterfaceUpdate: networkType: {}, segmentationId: {}, srcNode: {}, iface: {}",
774                      network.getProviderNetworkType(), network.getProviderSegmentationID(), srcNode, iface.getName());
775
776         if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
777             Status status = getVlanReadinessStatus(srcNode, network.getProviderSegmentationID());
778             if (!status.isSuccess()) {
779                 return status;
780             } else {
781                 this.programVlanRules(network, srcNode, iface);
782                 return new Status(StatusCode.SUCCESS);
783             }
784         } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
785                    network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
786             Status status = getTunnelReadinessStatus(srcNode, network.getProviderSegmentationID());
787             if (!status.isSuccess()) {
788                 logger.debug("Interface update of networkType: {}, segmentationId: {}, srcNode: {} is not tunnel ready",
789                         network.getProviderNetworkType(), network.getProviderSegmentationID(), srcNode);
790                 return status;
791             }
792
793             List<Node> nodes = connectionService.getNodes();
794             nodes.remove(srcNode);
795             for (Node dstNode : nodes) {
796                 status = getTunnelReadinessStatus(dstNode, network.getProviderSegmentationID());
797                 if (!status.isSuccess()) {
798                     logger.debug("Interface update of networkType: {}, segmentationId: {}, dstNode: {} is not tunnel ready",
799                             network.getProviderNetworkType(), network.getProviderSegmentationID(), dstNode);
800                     continue;
801                 }
802                 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
803                 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
804                 status = addTunnelPort(srcNode, network.getProviderNetworkType(), src, dst, network.getProviderSegmentationID());
805                 if (status.isSuccess()) {
806                     this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), dst, srcNode, iface, true);
807                     status = addTunnelPort(dstNode, network.getProviderNetworkType(), dst, src, network.getProviderSegmentationID());
808                     if (status.isSuccess()) {
809                         this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), src, dstNode, iface, false);
810                     }
811                 }
812             }
813             return new Status(StatusCode.SUCCESS);
814         } else {
815             return new Status(StatusCode.BADREQUEST);
816         }
817     }
818
819     @Override
820     public Status handleInterfaceDelete(String tunnelType, NeutronNetwork network,
821                                         Node srcNode,Interface iface, boolean isLastInstanceOnNode) {
822         Status status = new Status(StatusCode.SUCCESS);
823         logger.debug("handleInterfaceDelete: srcNode: {}, networkType: {}, iface: {}, type: {}, isLast: {}",
824                 srcNode, (network != null) ? network.getProviderNetworkType() : "",
825                 iface.getName(), iface.getTypeColumn().getData(), isLastInstanceOnNode);
826
827         List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
828         if ((network != null) && network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
829             if (isLastInstanceOnNode) {
830                 this.removeVlanRules(network, srcNode, iface);
831             }
832         } else if (iface.getTypeColumn().getData().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
833                    iface.getTypeColumn().getData().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
834             /* Delete tunnel port */
835             try {
836                 Map<String, String> options = iface.getOptionsColumn().getData();
837                 InetAddress src = InetAddress.getByName(options.get("local_ip"));
838                 InetAddress dst = InetAddress.getByName(options.get("remote_ip"));
839                 String key = options.get("key");
840                 status = deleteTunnelPort(srcNode, iface.getTypeColumn().getData(), src, dst, key);
841             } catch (Exception e) {
842                 logger.error(e.getMessage(), e);
843             }
844         } else if (phyIfName.contains(iface.getName())) {
845             deletePhysicalPort(srcNode, iface.getName());
846         } else {
847             /* delete all other interfaces */
848             List<Node> nodes = connectionService.getNodes();
849             nodes.remove(srcNode);
850             for (Node dstNode : nodes) {
851                 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
852                 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
853                 assert network != null;
854                 this.removeTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), dst, srcNode, iface, true);
855                 if (isLastInstanceOnNode) {
856                     status = deleteTunnelPort(srcNode, network.getProviderNetworkType(), src, dst, network.getProviderSegmentationID());
857                 }
858                 this.removeTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), src, dstNode, iface, false);
859                 if (status.isSuccess() && isLastInstanceOnNode) {
860                     deleteTunnelPort(dstNode, network.getProviderNetworkType(), dst, src, network.getProviderSegmentationID());
861                 }
862             }
863         }
864         return status;
865     }
866
867     private String getTunnelName(String tunnelType, String key, InetAddress dst) {
868         return tunnelType+"-"+key+"-"+dst.getHostAddress();
869     }
870
871     private Interface getTunnelInterface (Node node, String tunnelType, InetAddress dst, String key) {
872         try {
873             String portName = getTunnelName(tunnelType, key, dst);
874
875             Map<String, Row> tunifaces = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
876             if (tunifaces != null) {
877                 for (Row row : tunifaces.values()) {
878                     Interface tuniface = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
879                     if (tuniface.getName().equals(portName)) return tuniface;
880                 }
881
882             }
883         } catch (Exception e) {
884             logger.error("", e);
885         }
886         return null;
887     }
888
889     private boolean isTunnelPresent(Node node, String tunnelName, String bridgeUUID) throws Exception {
890         Row row = ovsdbConfigurationService
891                 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
892         Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
893         if (bridge != null) {
894             Set<UUID> ports = bridge.getPortsColumn().getData();
895             for (UUID portUUID : ports) {
896                 Row portRow = ovsdbConfigurationService
897                         .getRow(node, ovsdbConfigurationService.getTableName(node, Port.class), portUUID.toString());
898                 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
899                 if (port != null && port.getName().equalsIgnoreCase(tunnelName)) return true;
900             }
901         }
902         return false;
903     }
904
905     private String getPortUuid(Node node, String portName, String bridgeUUID) throws Exception {
906         Row row = ovsdbConfigurationService
907                 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
908         Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
909         if (bridge != null) {
910             Set<UUID> ports = bridge.getPortsColumn().getData();
911             for (UUID portUUID : ports) {
912                 Row portRow = ovsdbConfigurationService
913                         .getRow(node, ovsdbConfigurationService.getTableName(node, Port.class), portUUID.toString());
914                 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
915                 if (port != null && port.getName().equalsIgnoreCase(portName)) return portUUID.toString();
916             }
917         }
918         return null;
919     }
920
921     private Status addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
922         try {
923             String bridgeUUID = null;
924             String tunnelBridgeName = configurationService.getNetworkBridgeName();
925             Map<String, Row> bridgeTable = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
926             if (bridgeTable != null) {
927                 for (String uuid : bridgeTable.keySet()) {
928                     Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(uuid));
929                     if (bridge.getName().equals(tunnelBridgeName)) {
930                         bridgeUUID = uuid;
931                         break;
932                     }
933                 }
934             }
935             if (bridgeUUID == null) {
936                 logger.error("Could not find Bridge {} in {}", tunnelBridgeName, node);
937                 return new Status(StatusCode.NOTFOUND, "Could not find "+tunnelBridgeName+" in "+node);
938             }
939             String portName = getTunnelName(tunnelType, key, dst);
940
941             if (this.isTunnelPresent(node, portName, bridgeUUID)) {
942                 logger.trace("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node);
943                 return new Status(StatusCode.SUCCESS);
944             }
945
946             Port tunnelPort = ovsdbConfigurationService.createTypedRow(node, Port.class);
947             tunnelPort.setName(portName);
948             StatusWithUuid statusWithUuid = ovsdbConfigurationService
949                     .insertRow(node, ovsdbConfigurationService.getTableName(node, Port.class), bridgeUUID,
950                                tunnelPort.getRow());
951             if (!statusWithUuid.isSuccess()) {
952                 logger.error("Failed to insert Tunnel port {} in {}", portName, bridgeUUID);
953                 return statusWithUuid;
954             }
955
956             String tunnelPortUUID = statusWithUuid.getUuid().toString();
957             String interfaceUUID = null;
958             int timeout = 6;
959             while ((interfaceUUID == null) && (timeout > 0)) {
960                 Row row = ovsdbConfigurationService
961                         .getRow(node, ovsdbConfigurationService.getTableName(node, Port.class), tunnelPortUUID);
962                 tunnelPort = ovsdbConfigurationService.getTypedRow(node, Port.class, row);
963                 Set<UUID> interfaces = tunnelPort.getInterfacesColumn().getData();
964                 if (interfaces == null || interfaces.size() == 0) {
965                     // Wait for the OVSDB update to sync up the Local cache.
966                     Thread.sleep(500);
967                     timeout--;
968                     continue;
969                 }
970                 interfaceUUID = interfaces.toArray()[0].toString();
971                 Row ifaceRow = ovsdbConfigurationService
972                         .getRow(node, ovsdbConfigurationService.getTableName(node, Interface.class), interfaceUUID);
973                 Interface iface = ovsdbConfigurationService.getTypedRow(node, Interface.class, ifaceRow);
974                 if (iface == null) interfaceUUID = null;
975             }
976
977             if (interfaceUUID == null) {
978                 logger.error("Cannot identify Tunnel Interface for port {}/{}", portName, tunnelPortUUID);
979                 return new Status(StatusCode.INTERNALERROR);
980             }
981
982             Interface tunInterface = ovsdbConfigurationService.createTypedRow(node, Interface.class);
983             tunInterface.setType(tunnelType);
984             Map<String, String> options = Maps.newHashMap();
985             options.put("key", key);
986             options.put("local_ip", src.getHostAddress());
987             options.put("remote_ip", dst.getHostAddress());
988             tunInterface.setOptions(options);
989             Status status = ovsdbConfigurationService
990                     .updateRow(node, ovsdbConfigurationService.getTableName(node, Interface.class), tunnelPortUUID,
991                                interfaceUUID, tunInterface.getRow());
992             logger.debug("Tunnel {} add status : {}", tunInterface, status);
993             return status;
994         } catch (Exception e) {
995             logger.error("Exception in addTunnelPort", e);
996             return new Status(StatusCode.INTERNALERROR);
997         }
998     }
999
1000     private Status deletePort(Node node, String bridgeName, String portName) {
1001         try {
1002             String bridgeUUID = null;
1003             Map<String, Row> bridgeTable = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
1004             if (bridgeTable != null) {
1005                 for (String uuid : bridgeTable.keySet()) {
1006                     Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(uuid));
1007                     if (bridge.getName().equals(bridgeName)) {
1008                         bridgeUUID = uuid;
1009                         break;
1010                     }
1011                 }
1012             }
1013             if (bridgeUUID == null) {
1014                 logger.debug("Could not find Bridge {} in {}", bridgeName, node);
1015                 return new Status(StatusCode.SUCCESS);
1016             }
1017             String portUUID = this.getPortUuid(node, portName, bridgeUUID);
1018             Status status = new Status(StatusCode.SUCCESS);
1019             if (portUUID != null) {
1020                 status = ovsdbConfigurationService
1021                         .deleteRow(node, ovsdbConfigurationService.getTableName(node, Port.class), portUUID);
1022                 if (!status.isSuccess()) {
1023                     logger.error("Failed to delete port {} in {} status : {}", portName, bridgeUUID, status);
1024                     return status;
1025                 }
1026                 logger.debug("Port {} delete status : {}", portName, status);
1027             }
1028             return status;
1029         } catch (Exception e) {
1030             logger.error("Exception in deleteTunnelPort", e);
1031             return new Status(StatusCode.INTERNALERROR);
1032         }
1033     }
1034
1035     private Status deleteTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
1036         String tunnelBridgeName = configurationService.getNetworkBridgeName();
1037         String portName = getTunnelName(tunnelType, key, dst);
1038         return deletePort(node, tunnelBridgeName, portName);
1039     }
1040
1041     private Status deletePhysicalPort(Node node, String phyIfaceName) {
1042         String netBridgeName = configurationService.getNetworkBridgeName();
1043         return deletePort(node, netBridgeName, phyIfaceName);
1044     }
1045
1046     @Override
1047     public Status handleInterfaceUpdate(String tunnelType, String tunnelKey) {
1048         List<Node> nodes = connectionService.getNodes();
1049         for (Node srcNode : nodes) {
1050             this.handleInterfaceUpdate(null, srcNode, null);
1051         }
1052         return new Status(StatusCode.SUCCESS);
1053     }
1054
1055     @Override
1056     public void initializeFlowRules(Node node) {
1057         this.initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1058         this.initializeFlowRules(node, configurationService.getExternalBridgeName());
1059     }
1060
1061     private void initializeFlowRules(Node node, String bridgeName) {
1062         String bridgeUuid = bridgeConfigurationManager.getBridgeUuid(node, bridgeName);
1063         if (bridgeUuid == null) {
1064             if (bridgeName.equals(configurationService.getExternalBridgeName())){
1065                 logger.debug("Failed to initialize Flow Rules for bridge {} on node {}. Is the Neutron L3 agent running on this node?");
1066             }
1067             else {
1068                 logger.debug("Failed to initialize Flow Rules for bridge {} on node {}", bridgeName, node);
1069             }
1070             return;
1071         }
1072
1073         try {
1074             Row row = ovsdbConfigurationService
1075                     .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUuid);
1076             Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
1077             Set<String> dpids = bridge.getDatapathIdColumn().getData();
1078             if (dpids == null || dpids.size() ==  0) return;
1079             Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
1080             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
1081             List<Switch> nodes = switchManager.getNetworkDevices();
1082             if (nodes == null) {
1083                 logger.debug("No OF nodes learned yet in {}", node);
1084                 return;
1085             }
1086             for (Switch device : nodes) {
1087                 if (device.getNode().equals(ofNode)) {
1088                     logger.debug("Initialize OF Flows on {}", ofNode);
1089                     initializeNormalFlowRules(ofNode);
1090                     return;
1091                 }
1092             }
1093             logger.debug("Could not identify OF node {} for bridge {} in {}", ofNode.toString(), bridgeName, node.toString());
1094         } catch (Exception e) {
1095             logger.error("Failed to initialize Flow Rules for "+node.toString(), e);
1096         }
1097     }
1098
1099     @Override
1100     public void initializeOFFlowRules(Node openflowNode) {
1101         this.initializeNormalFlowRules(openflowNode);
1102         this.initializeLLDPFlowRules(openflowNode);
1103     }
1104
1105     private void initializeNormalFlowRules(Node ofNode) {
1106         String flowName = ActionType.HW_PATH.toString();
1107         FlowConfig flow = new FlowConfig();
1108         flow.setName("NORMAL");
1109         flow.setNode(ofNode);
1110         flow.setPriority(NORMAL_PRIORITY+"");
1111         flow.setInstallInHw(true);
1112         List<String> normalAction = Lists.newArrayList();
1113         normalAction.add(flowName);
1114         flow.setActions(normalAction);
1115         Status status = this.addStaticFlow(ofNode, flow);
1116         logger.debug("Flow Programming Add Status {} for Flow {} on {}", status, flow, ofNode);
1117     }
1118
1119     private void initializeLLDPFlowRules(Node ofNode) {
1120         String flowName = "PuntLLDP";
1121         List<String> puntAction = Lists.newArrayList();
1122         puntAction.add(ActionType.CONTROLLER.toString());
1123
1124         FlowConfig allowLLDP = new FlowConfig();
1125         allowLLDP.setName(flowName);
1126         allowLLDP.setPriority(LLDP_PRIORITY+"");
1127         allowLLDP.setNode(ofNode);
1128         allowLLDP.setInstallInHw(true);
1129         allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue()).toUpperCase());
1130         allowLLDP.setActions(puntAction);
1131         Status status = this.addStaticFlow(ofNode, allowLLDP);
1132         logger.debug("LLDP Flow Add Status {} for Flow {} on {}", status, allowLLDP, ofNode);
1133     }
1134
1135     private Status addStaticFlow (Node ofNode, FlowConfig flowConfig) {
1136         String flowName = flowConfig.getName();
1137         if (forwardingRulesManager.getStaticFlow(flowName, ofNode) != null) {
1138             logger.debug("Flow already exists {} on {}. Skipping installation.", flowName, ofNode);
1139             return new Status(StatusCode.CONFLICT, "Flow with name "+flowName+" exists in node "+ofNode.toString());
1140         }
1141         return forwardingRulesManager.addStaticFlow(flowConfig);
1142     }
1143
1144     private Status deleteStaticFlow (Node ofNode, String flowName) {
1145         if (forwardingRulesManager.getStaticFlow(flowName, ofNode) == null) {
1146             logger.debug("Flow does not exist {} on {}. Skipping deletion.", flowName, ofNode);
1147             return new Status(StatusCode.SUCCESS);
1148         }
1149         return forwardingRulesManager.removeStaticFlow(flowName,ofNode);
1150     }
1151
1152 }