Use Felix DM for OVSDB Neutron Services
[ovsdb.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         if ((network != null) && network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
809             if (isLastInstanceOnNode) {
810                 this.removeVlanRules(network, srcNode, intf);
811             }
812         } else if (intf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) || intf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
813             /* Delete tunnel port */
814             try {
815                 OvsDBMap<String, String> options = intf.getOptions();
816                 InetAddress src = InetAddress.getByName(options.get("local_ip"));
817                 InetAddress dst = InetAddress.getByName(options.get("remote_ip"));
818                 String key = options.get("key");
819                 status = deleteTunnelPort(srcNode, intf.getType(), src, dst, key);
820             } catch (Exception e) {
821                 logger.error(e.getMessage(), e);
822             }
823         } else {
824             /* delete all other interfaces */
825             IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
826             List<Node> nodes = connectionService.getNodes();
827             nodes.remove(srcNode);
828             for (Node dstNode : nodes) {
829                 InetAddress src = adminConfigManager.getTunnelEndPoint(srcNode);
830                 InetAddress dst = adminConfigManager.getTunnelEndPoint(dstNode);
831                 this.removeTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), dst, srcNode, intf, true);
832                 if (isLastInstanceOnNode) {
833                     status = deleteTunnelPort(srcNode, network.getProviderNetworkType(), src, dst, network.getProviderSegmentationID());
834                 }
835                 this.removeTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), src, dstNode, intf, false);
836                 if (status.isSuccess() && isLastInstanceOnNode) {
837                     deleteTunnelPort(dstNode, network.getProviderNetworkType(), dst, src, network.getProviderSegmentationID());
838                 }
839             }
840         }
841
842         return status;
843     }
844
845     private String getTunnelName(String tunnelType, String key, InetAddress dst) {
846         return tunnelType+"-"+key+"-"+dst.getHostAddress();
847     }
848
849     private Interface getTunnelInterface (Node node, String tunnelType, InetAddress dst, String key) {
850         try {
851             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
852             String portName = getTunnelName(tunnelType, key, dst);
853
854             Map<String, Table<?>> tunIntfs = ovsdbTable.getRows(node, Interface.NAME.getName());
855             if (tunIntfs != null) {
856                 for (Table<?> row : tunIntfs.values()) {
857                     Interface tunIntf = (Interface)row;
858                     if (tunIntf.getName().equals(portName)) return tunIntf;
859                 }
860
861             }
862         } catch (Exception e) {
863             logger.error("", e);
864         }
865         return null;
866     }
867
868     private boolean isTunnelPresent(Node node, String tunnelName, String bridgeUUID) throws Exception {
869         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
870         Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
871         if (bridge != null) {
872             Set<UUID> ports = bridge.getPorts();
873             for (UUID portUUID : ports) {
874                 Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID.toString());
875                 if (port != null && port.getName().equalsIgnoreCase(tunnelName)) return true;
876             }
877         }
878         return false;
879     }
880
881     private String getTunnelPortUuid(Node node, String tunnelName, String bridgeUUID) throws Exception {
882         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
883         Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
884         if (bridge != null) {
885             Set<UUID> ports = bridge.getPorts();
886             for (UUID portUUID : ports) {
887                 Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID.toString());
888                 if (port != null && port.getName().equalsIgnoreCase(tunnelName)) return portUUID.toString();
889             }
890         }
891         return null;
892     }
893
894     private Status addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
895         try {
896             String bridgeUUID = null;
897             String tunnelBridgeName = adminConfigManager.getNetworkBridgeName();
898             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
899             Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
900             if (bridgeTable != null) {
901                 for (String uuid : bridgeTable.keySet()) {
902                     Bridge bridge = (Bridge)bridgeTable.get(uuid);
903                     if (bridge.getName().equals(tunnelBridgeName)) {
904                         bridgeUUID = uuid;
905                         break;
906                     }
907                 }
908             }
909             if (bridgeUUID == null) {
910                 logger.error("Could not find Bridge {} in {}", tunnelBridgeName, node);
911                 return new Status(StatusCode.NOTFOUND, "Could not find "+tunnelBridgeName+" in "+node);
912             }
913             String portName = getTunnelName(tunnelType, key, dst);
914
915             if (this.isTunnelPresent(node, portName, bridgeUUID)) {
916                 logger.trace("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node);
917                 return new Status(StatusCode.SUCCESS);
918             }
919
920             Port tunnelPort = new Port();
921             tunnelPort.setName(portName);
922             StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, tunnelPort);
923             if (!statusWithUuid.isSuccess()) {
924                 logger.error("Failed to insert Tunnel port {} in {}", portName, bridgeUUID);
925                 return statusWithUuid;
926             }
927
928             String tunnelPortUUID = statusWithUuid.getUuid().toString();
929             String interfaceUUID = null;
930             int timeout = 6;
931             while ((interfaceUUID == null) && (timeout > 0)) {
932                 tunnelPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), tunnelPortUUID);
933                 OvsDBSet<UUID> interfaces = tunnelPort.getInterfaces();
934                 if (interfaces == null || interfaces.size() == 0) {
935                     // Wait for the OVSDB update to sync up the Local cache.
936                     Thread.sleep(500);
937                     timeout--;
938                     continue;
939                 }
940                 interfaceUUID = interfaces.toArray()[0].toString();
941                 Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), interfaceUUID);
942                 if (intf == null) interfaceUUID = null;
943             }
944
945             if (interfaceUUID == null) {
946                 logger.error("Cannot identify Tunnel Interface for port {}/{}", portName, tunnelPortUUID);
947                 return new Status(StatusCode.INTERNALERROR);
948             }
949
950             Interface tunInterface = new Interface();
951             tunInterface.setType(tunnelType);
952             OvsDBMap<String, String> options = new OvsDBMap<String, String>();
953             options.put("key", key);
954             options.put("local_ip", src.getHostAddress());
955             options.put("remote_ip", dst.getHostAddress());
956             tunInterface.setOptions(options);
957             Status status = ovsdbTable.updateRow(node, Interface.NAME.getName(), tunnelPortUUID, interfaceUUID, tunInterface);
958             logger.debug("Tunnel {} add status : {}", tunInterface, status);
959             return status;
960         } catch (Exception e) {
961             logger.error("Exception in addTunnelPort", e);
962             return new Status(StatusCode.INTERNALERROR);
963         }
964     }
965
966     private Status deleteTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
967         try {
968             String bridgeUUID = null;
969             String tunnelBridgeName = adminConfigManager.getNetworkBridgeName();
970             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
971             Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
972             if (bridgeTable != null) {
973                 for (String uuid : bridgeTable.keySet()) {
974                     Bridge bridge = (Bridge)bridgeTable.get(uuid);
975                     if (bridge.getName().equals(tunnelBridgeName)) {
976                         bridgeUUID = uuid;
977                         break;
978                     }
979                 }
980             }
981             if (bridgeUUID == null) {
982                 logger.debug("Could not find Bridge {} in {}", tunnelBridgeName, node);
983                 return new Status(StatusCode.SUCCESS);
984             }
985             String portName = getTunnelName(tunnelType, key, dst);
986             String tunnelPortUUID = this.getTunnelPortUuid(node, portName, bridgeUUID);
987             Status status = ovsdbTable.deleteRow(node, Port.NAME.getName(), tunnelPortUUID);
988             if (!status.isSuccess()) {
989                 logger.error("Failed to delete Tunnel port {} in {} status : {}", portName, bridgeUUID, status);
990                 return status;
991             }
992
993             logger.debug("Tunnel {} delete status : {}", portName, status);
994             return status;
995         } catch (Exception e) {
996             logger.error("Exception in deleteTunnelPort", e);
997             return new Status(StatusCode.INTERNALERROR);
998         }
999     }
1000
1001     @Override
1002     public Status handleInterfaceUpdate(String tunnelType, String tunnelKey) {
1003         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
1004         List<Node> nodes = connectionService.getNodes();
1005         for (Node srcNode : nodes) {
1006             this.handleInterfaceUpdate(null, srcNode, null);
1007         }
1008         return new Status(StatusCode.SUCCESS);
1009     }
1010
1011     @Override
1012     public void initializeFlowRules(Node node) {
1013         this.initializeFlowRules(node, adminConfigManager.getIntegrationBridgeName());
1014         this.initializeFlowRules(node, adminConfigManager.getExternalBridgeName());
1015     }
1016
1017     private void initializeFlowRules(Node node, String bridgeName) {
1018         String brIntId = this.getInternalBridgeUUID(node, bridgeName);
1019         if (brIntId == null) {
1020             if (bridgeName == adminConfigManager.getExternalBridgeName()){
1021                 logger.debug("Failed to initialize Flow Rules for bridge {} on node {}. Is the Neutron L3 agent running on this node?");
1022             }
1023             else {
1024                 logger.debug("Failed to initialize Flow Rules for bridge {} on node {}", bridgeName, node);
1025             }
1026             return;
1027         }
1028
1029         try {
1030             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
1031             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
1032             Set<String> dpids = bridge.getDatapath_id();
1033             if (dpids == null || dpids.size() ==  0) return;
1034             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
1035             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
1036             ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, "default", this);
1037             List<Switch> nodes = switchManager.getNetworkDevices();
1038             if (nodes == null) {
1039                 logger.debug("No OF nodes learned yet in {}", node);
1040                 return;
1041             }
1042             for (Switch device : nodes) {
1043                 if (device.getNode().equals(ofNode)) {
1044                     logger.debug("Initialize OF Flows on {}", ofNode);
1045                     initializeNormalFlowRules(ofNode);
1046                     return;
1047                 }
1048             }
1049             logger.debug("Could not identify OF node {} for bridge {} in {}", ofNode.toString(), bridgeName, node.toString());
1050         } catch (Exception e) {
1051             logger.error("Failed to initialize Flow Rules for "+node.toString(), e);
1052         }
1053     }
1054
1055     @Override
1056     public void initializeOFFlowRules(Node openflowNode) {
1057         this.initializeNormalFlowRules(openflowNode);
1058         this.initializeLLDPFlowRules(openflowNode);
1059     }
1060
1061     private void initializeNormalFlowRules(Node ofNode) {
1062         String flowName = ActionType.HW_PATH.toString();
1063         FlowConfig flow = new FlowConfig();
1064         flow.setName("NORMAL");
1065         flow.setNode(ofNode);
1066         flow.setPriority(NORMAL_PRIORITY+"");
1067         flow.setInstallInHw(true);
1068         List<String> normalAction = new ArrayList<String>();
1069         normalAction.add(flowName);
1070         flow.setActions(normalAction);
1071         Status status = this.addStaticFlow(ofNode, flow);
1072         logger.debug("Flow Programming Add Status {} for Flow {} on {}", status, flow, ofNode);
1073     }
1074
1075     private void initializeLLDPFlowRules(Node ofNode) {
1076         String flowName = "PuntLLDP";
1077         List<String> puntAction = new ArrayList<String>();
1078         puntAction.add(ActionType.CONTROLLER.toString());
1079
1080         FlowConfig allowLLDP = new FlowConfig();
1081         allowLLDP.setName(flowName);
1082         allowLLDP.setPriority(LLDP_PRIORITY+"");
1083         allowLLDP.setNode(ofNode);
1084         allowLLDP.setInstallInHw(true);
1085         allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue()).toUpperCase());
1086         allowLLDP.setActions(puntAction);
1087         Status status = this.addStaticFlow(ofNode, allowLLDP);
1088         logger.debug("LLDP Flow Add Status {} for Flow {} on {}", status, allowLLDP, ofNode);
1089     }
1090
1091     private Status addStaticFlow (Node ofNode, FlowConfig flowConfig) {
1092         IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
1093                 IForwardingRulesManager.class, "default", this);
1094         String flowName = flowConfig.getName();
1095         if (frm.getStaticFlow(flowName, ofNode) != null) {
1096             logger.debug("Flow already exists {} on {}. Skipping installation.", flowName, ofNode);
1097             return new Status(StatusCode.CONFLICT, "Flow with name "+flowName+" exists in node "+ofNode.toString());
1098         }
1099         return frm.addStaticFlow(flowConfig);
1100     }
1101
1102     private Status deleteStaticFlow (Node ofNode, String flowName) {
1103         IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
1104                 IForwardingRulesManager.class, "default", this);
1105         if (frm.getStaticFlow(flowName, ofNode) == null) {
1106             logger.debug("Flow does not exist {} on {}. Skipping deletion.", flowName, ofNode);
1107             return new Status(StatusCode.SUCCESS);
1108         }
1109         return frm.removeStaticFlow(flowName,ofNode);
1110     }
1111
1112     private String getInternalBridgeUUID (Node node, String bridgeName) {
1113         try {
1114             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
1115             Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
1116             if (bridgeTable == null) return null;
1117             for (String key : bridgeTable.keySet()) {
1118                 Bridge bridge = (Bridge)bridgeTable.get(key);
1119                 if (bridge.getName().equals(bridgeName)) return key;
1120             }
1121         } catch (Exception e) {
1122             logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
1123         }
1124         return null;
1125     }
1126
1127 }