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