Merge "Removed the floodEntries cache and relying on FRM's flow cache directly for...
[netvirt.git] / neutron / src / main / java / org / opendaylight / ovsdb / neutron / provider / OF10ProviderManager.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
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.sal.action.ActionType;
22 import org.opendaylight.controller.sal.core.Node;
23 import org.opendaylight.controller.sal.utils.EtherTypes;
24 import org.opendaylight.controller.sal.utils.HexEncode;
25 import org.opendaylight.controller.sal.utils.ServiceHelper;
26 import org.opendaylight.controller.sal.utils.Status;
27 import org.opendaylight.controller.sal.utils.StatusCode;
28 import org.opendaylight.controller.switchmanager.ISwitchManager;
29 import org.opendaylight.controller.switchmanager.Switch;
30 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
31 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
32 import org.opendaylight.ovsdb.lib.notation.UUID;
33 import org.opendaylight.ovsdb.lib.table.Bridge;
34 import org.opendaylight.ovsdb.lib.table.Interface;
35 import org.opendaylight.ovsdb.lib.table.Port;
36 import org.opendaylight.ovsdb.lib.table.internal.Table;
37 import org.opendaylight.ovsdb.neutron.AdminConfigManager;
38 import org.opendaylight.ovsdb.neutron.InternalNetworkManager;
39 import org.opendaylight.ovsdb.neutron.TenantNetworkManager;
40 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
41 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
42 import org.opendaylight.ovsdb.plugin.StatusWithUuid;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46
47 class OF10ProviderManager extends ProviderNetworkManager {
48     private static final Logger logger = LoggerFactory.getLogger(OF10ProviderManager.class);
49     private static final int INGRESS_TUNNEL_FLOW_PRIORITY = 100;
50     private static final int EGRESS_TUNNEL_FLOW_PRIORITY = 100;
51     private static final int FLOOD_TUNNEL_FLOW_PRIORITY = 1;
52
53     @Override
54     public boolean hasPerTenantTunneling() {
55         return true;
56     }
57
58     private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
59         InetAddress srcTunnelEndPoint = AdminConfigManager.getManager().getTunnelEndPoint(node);
60         if (srcTunnelEndPoint == null) {
61             logger.error("Tunnel Endpoint not configured for Node {}", node);
62             return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
63         }
64
65         if (!InternalNetworkManager.getManager().isInternalNetworkOverlayReady(node)) {
66             logger.error(node+" is not Overlay ready");
67             return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
68         }
69
70         if (!TenantNetworkManager.getManager().isTenantNetworkPresentInNode(node, tunnelKey)) {
71             logger.debug(node+" has no VM corresponding to segment "+ tunnelKey);
72             return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
73         }
74         return new Status(StatusCode.SUCCESS);
75     }
76
77     /**
78      * Program OF1.0 Flow rules on br-tun on the ingress direction from the network towards the br-int.
79      * The logic is to simply match on the incoming tunnel OF-Port (which carries the TenantNetwork GRE-Key)
80      * and rewrite the Corresponding internal Vlan and pass it on to br-int via the patch port.
81      */
82     private void programLocalIngressTunnelBridgeRules(Node node, int tunnelOFPort, int internalVlan, int patchPort) {
83         String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
84         if (brIntId == null) {
85             logger.error("Failed to initialize Flow Rules for {}", node);
86             return;
87         }
88         try {
89             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
90             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
91             Set<String> dpids = bridge.getDatapath_id();
92             if (dpids == null || dpids.size() ==  0) return;
93             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
94             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
95             String flowName = "TepMatch"+tunnelOFPort+""+internalVlan;
96             FlowConfig flow = new FlowConfig();
97             flow.setName(flowName);
98             flow.setNode(ofNode);
99             flow.setInstallInHw(true);
100             flow.setPriority(INGRESS_TUNNEL_FLOW_PRIORITY+"");
101             flow.setIngressPort(tunnelOFPort+"");
102             List<String> actions = new ArrayList<String>();
103             actions.add(ActionType.SET_VLAN_ID+"="+internalVlan);
104             actions.add(ActionType.OUTPUT.toString()+"="+patchPort);
105             flow.setActions(actions);
106             Status status = this.addStaticFlow(ofNode, flow);
107             logger.debug("Local Ingress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
108         } catch (Exception e) {
109             logger.error("Failed to initialize Flow Rules for {}", node, e);
110         }
111     }
112
113     /**
114      * Program OF1.0 Flow rules on br-tun on the remote Node on its egress direction towards the overlay network
115      * for a VM (with the attachedMac).
116      * The logic is to simply match on the incoming vlan, mac from the patch-port connected to br-int (patch-int)
117      * and output the traffic to the appropriate GRE Tunnel (which carries the GRE-Key for that Tenant Network).
118      * Also perform the Strip-Vlan action.
119      */
120     private void programRemoteEgressTunnelBridgeRules(Node node, int patchPort, String attachedMac,
121             int internalVlan, int tunnelOFPort) {
122         String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
123         if (brIntId == null) {
124             logger.error("Failed to initialize Flow Rules for {}", node);
125             return;
126         }
127         try {
128             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
129             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
130             Set<String> dpids = bridge.getDatapath_id();
131             if (dpids == null || dpids.size() ==  0) return;
132             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
133             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
134             String flowName = "TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac);
135             FlowConfig flow = new FlowConfig();
136             flow.setName(flowName);
137             flow.setNode(ofNode);
138             flow.setInstallInHw(true);
139             flow.setPriority(EGRESS_TUNNEL_FLOW_PRIORITY+"");
140             flow.setDstMac(attachedMac);
141             flow.setIngressPort(patchPort+"");
142             flow.setVlanId(internalVlan+"");
143             List<String> actions = new ArrayList<String>();
144             actions.add(ActionType.POP_VLAN.toString());
145             actions.add(ActionType.OUTPUT.toString()+"="+tunnelOFPort);
146             flow.setActions(actions);
147             Status status = this.addStaticFlow(ofNode, flow);
148             logger.debug("Remote Egress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
149         } catch (Exception e) {
150             logger.error("Failed to initialize Flow Rules for {}", node, e);
151         }
152     }
153
154     /**
155      * Program OF1.0 Flow rules to flood the broadcast & unknown-unicast traffic over br-tun on the egress direction
156      * towards the network on all the overlay tunnels that corresponds to the tenant network.
157      * The logic is to simply match on the incoming vlan, mac from the patch-port connected to br-int (patch-int)
158      * and output the traffic to all the GRE-Tunnels for this Tenant Network (which carries the GRE-Key).
159      * Also perform the Strip-Vlan action.
160      */
161     private void programFloodEgressTunnelBridgeRules(Node node, int patchPort, int internalVlan, int tunnelOFPort) {
162         String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
163         if (brIntId == null) {
164             logger.error("Failed to initialize Flow Rules for {}", node);
165             return;
166         }
167         try {
168             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
169             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
170             Set<String> dpids = bridge.getDatapath_id();
171             if (dpids == null || dpids.size() ==  0) return;
172             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
173             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
174             String flowName = "TepFlood"+internalVlan;
175             IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
176                     IForwardingRulesManager.class, "default", this);
177             FlowConfig existingFlowConfig = frm.getStaticFlow(flowName, ofNode);
178             FlowConfig flow = existingFlowConfig;
179             Status status = null;
180             if (flow == null) {
181                 flow = new FlowConfig();
182                 flow.setName(flowName);
183                 flow.setNode(ofNode);
184                 flow.setPriority(FLOOD_TUNNEL_FLOW_PRIORITY+"");
185                 flow.setIngressPort(patchPort+"");
186                 flow.setVlanId(internalVlan+"");
187                 List<String> actions = new ArrayList<String>();
188                 actions.add(ActionType.POP_VLAN.toString());
189                 actions.add(ActionType.OUTPUT.toString()+"="+tunnelOFPort);
190                 flow.setActions(actions);
191                 status = frm.addStaticFlow(flow);
192                 logger.debug("Add Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
193                               status, flow, ofNode, node);
194             } else {
195                 flow = new FlowConfig(existingFlowConfig);
196                 List<String> actions = flow.getActions();
197                 String outputPort = ActionType.OUTPUT.toString()+"="+tunnelOFPort;
198                 if (actions != null && !actions.contains(outputPort)) {
199                     actions.add(outputPort);
200                     flow.setActions(actions);
201                 } else {
202                     logger.debug("Flood Egress Flow already exists. Skipping modify for Flow {} on {} / {}",
203                                  flow, ofNode, node);
204                     return;
205                 }
206                 status = frm.modifyStaticFlow(flow);
207                 logger.debug("Modify Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
208                               status, flow, ofNode, node);
209             }
210         } catch (Exception e) {
211             logger.error("Failed to initialize Flow Rules for {}", node, e);
212         }
213     }
214
215     private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
216                                      Interface intf, boolean local) {
217         String networkId = TenantNetworkManager.getManager().getNetworkIdForSegmentationId(segmentationId);
218         if (networkId == null) {
219             logger.debug("Tenant Network not found with Segmenation-id {}",segmentationId);
220             return;
221         }
222         int internalVlan = TenantNetworkManager.getManager().getInternalVlan(networkId);
223         if (internalVlan == 0) {
224             logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
225             return;
226         }
227         Map<String, String> externalIds = intf.getExternal_ids();
228         if (externalIds == null) {
229             logger.error("No external_ids seen in {}", intf);
230             return;
231         }
232
233         String attachedMac = externalIds.get(TenantNetworkManager.EXTERNAL_ID_VM_MAC);
234         if (attachedMac == null) {
235             logger.error("No AttachedMac seen in {}", intf);
236             return;
237         }
238         String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
239
240         int patchOFPort = -1;
241         try {
242             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
243             Map<String, Table<?>> intfs = ovsdbTable.getRows(node, Interface.NAME.getName());
244             if (intfs != null) {
245                 for (Table<?> row : intfs.values()) {
246                     Interface patchIntf = (Interface)row;
247                     if (patchIntf.getName().equalsIgnoreCase(patchInt)) {
248                         Set<BigInteger> of_ports = patchIntf.getOfport();
249                         if (of_ports == null || of_ports.size() <= 0) {
250                             logger.error("Could NOT Identified Patch port {} on {}", patchInt, node);
251                             continue;
252                         }
253                         patchOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
254                         logger.debug("Identified Patch port {} -> OF ({}) on {}", patchInt, patchOFPort, node);
255                         break;
256                     }
257                 }
258                 if (patchOFPort == -1) {
259                     logger.error("Cannot identify {} interface on {}", patchInt, node);
260                 }
261                 for (Table<?> row : intfs.values()) {
262                     Interface tunIntf = (Interface)row;
263                     if (tunIntf.getName().equals(this.getTunnelName(tunnelType, segmentationId, dst))) {
264                         Set<BigInteger> of_ports = tunIntf.getOfport();
265                         if (of_ports == null || of_ports.size() <= 0) {
266                             logger.error("Could NOT Identify Tunnel port {} on {}", tunIntf.getName(), node);
267                             continue;
268                         }
269                         int tunnelOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
270
271                         if (tunnelOFPort == -1) {
272                             logger.error("Could NOT Identify Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
273                             return;
274                         }
275                         logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
276
277                         if (!local) {
278                             programRemoteEgressTunnelBridgeRules(node, patchOFPort, attachedMac, internalVlan, tunnelOFPort);
279                         }
280                         programLocalIngressTunnelBridgeRules(node, tunnelOFPort, internalVlan, patchOFPort);
281                         programFloodEgressTunnelBridgeRules(node, patchOFPort, internalVlan, tunnelOFPort);
282                         return;
283                     }
284                 }
285             }
286         } catch (Exception e) {
287             logger.error("", e);
288         }
289     }
290
291     @Override
292     public Status createTunnels(String tunnelType, String tunnelKey, Node srcNode, Interface intf) {
293         Status status = getTunnelReadinessStatus(srcNode, tunnelKey);
294         if (!status.isSuccess()) return status;
295
296         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
297         List<Node> nodes = connectionService.getNodes();
298         nodes.remove(srcNode);
299         for (Node dstNode : nodes) {
300             status = getTunnelReadinessStatus(dstNode, tunnelKey);
301             if (!status.isSuccess()) continue;
302             InetAddress src = AdminConfigManager.getManager().getTunnelEndPoint(srcNode);
303             InetAddress dst = AdminConfigManager.getManager().getTunnelEndPoint(dstNode);
304             status = addTunnelPort(srcNode, tunnelType, src, dst, tunnelKey);
305             if (status.isSuccess()) {
306                 this.programTunnelRules(tunnelType, tunnelKey, dst, srcNode, intf, true);
307             }
308             addTunnelPort(dstNode, tunnelType, dst, src, tunnelKey);
309             if (status.isSuccess()) {
310                 this.programTunnelRules(tunnelType, tunnelKey, src, dstNode, intf, false);
311             }
312         }
313         return new Status(StatusCode.SUCCESS);
314     }
315
316     private String getTunnelName(String tunnelType, String key, InetAddress dst) {
317         return tunnelType+"-"+key+"-"+dst.getHostAddress();
318     }
319
320     private Interface getTunnelInterface (Node node, String tunnelType, InetAddress dst, String key) {
321         try {
322             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
323             String portName = getTunnelName(tunnelType, key, dst);
324
325             Map<String, Table<?>> tunIntfs = ovsdbTable.getRows(node, Interface.NAME.getName());
326             if (tunIntfs != null) {
327                 for (Table<?> row : tunIntfs.values()) {
328                     Interface tunIntf = (Interface)row;
329                     if (tunIntf.getName().equals(portName)) return tunIntf;
330                 }
331
332             }
333         } catch (Exception e) {
334             logger.error("", e);
335         }
336         return null;
337     }
338
339     private boolean isTunnelPresent(Node node, String tunnelName, String bridgeUUID) throws Exception {
340         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
341         Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
342         if (bridge != null) {
343             Set<UUID> ports = bridge.getPorts();
344             for (UUID portUUID : ports) {
345                 Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID.toString());
346                 if (port != null && port.getName().equalsIgnoreCase(tunnelName)) return true;
347             }
348         }
349         return false;
350     }
351
352     private Status addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
353         try {
354             String bridgeUUID = null;
355             String tunnelBridgeName = AdminConfigManager.getManager().getTunnelBridgeName();
356             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
357             Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
358             if (bridgeTable != null) {
359                 for (String uuid : bridgeTable.keySet()) {
360                     Bridge bridge = (Bridge)bridgeTable.get(uuid);
361                     if (bridge.getName().equals(tunnelBridgeName)) {
362                         bridgeUUID = uuid;
363                         break;
364                     }
365                 }
366             }
367             if (bridgeUUID == null) {
368                 logger.error("Could not find Bridge {} in {}", tunnelBridgeName, node);
369                 return new Status(StatusCode.NOTFOUND, "Could not find "+tunnelBridgeName+" in "+node);
370             }
371             String portName = getTunnelName(tunnelType, key, dst);
372
373             if (this.isTunnelPresent(node, portName, bridgeUUID)) {
374                 logger.trace("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node);
375                 return new Status(StatusCode.SUCCESS);
376             }
377
378             Port tunnelPort = new Port();
379             tunnelPort.setName(portName);
380             StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, tunnelPort);
381             if (!statusWithUuid.isSuccess()) {
382                 logger.error("Failed to insert Tunnel port {} in {}", portName, bridgeUUID);
383                 return statusWithUuid;
384             }
385
386             String tunnelPortUUID = statusWithUuid.getUuid().toString();
387             String interfaceUUID = null;
388             int timeout = 6;
389             while ((interfaceUUID == null) && (timeout > 0)) {
390                 tunnelPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), tunnelPortUUID);
391                 OvsDBSet<UUID> interfaces = tunnelPort.getInterfaces();
392                 if (interfaces == null || interfaces.size() == 0) {
393                     // Wait for the OVSDB update to sync up the Local cache.
394                     Thread.sleep(500);
395                     timeout--;
396                     continue;
397                 }
398                 interfaceUUID = interfaces.toArray()[0].toString();
399                 Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), interfaceUUID);
400                 if (intf == null) interfaceUUID = null;
401             }
402
403             if (interfaceUUID == null) {
404                 logger.error("Cannot identify Tunnel Interface for port {}/{}", portName, tunnelPortUUID);
405                 return new Status(StatusCode.INTERNALERROR);
406             }
407
408             Interface tunInterface = new Interface();
409             tunInterface.setType(tunnelType);
410             OvsDBMap<String, String> options = new OvsDBMap<String, String>();
411             options.put("key", key);
412             options.put("local_ip", src.getHostAddress());
413             options.put("remote_ip", dst.getHostAddress());
414             tunInterface.setOptions(options);
415             Status status = ovsdbTable.updateRow(node, Interface.NAME.getName(), tunnelPortUUID, interfaceUUID, tunInterface);
416             logger.debug("Tunnel {} add status : {}", tunInterface, status);
417             return status;
418         } catch (Exception e) {
419             logger.error("Exception in addTunnelPort", e);
420             return new Status(StatusCode.INTERNALERROR);
421         }
422     }
423
424     @Override
425     public Status createTunnels(String tunnelType, String tunnelKey) {
426         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
427         List<Node> nodes = connectionService.getNodes();
428         for (Node srcNode : nodes) {
429             this.createTunnels(tunnelType, tunnelKey, srcNode, null);
430         }
431         return new Status(StatusCode.SUCCESS);
432     }
433
434     @Override
435     public void initializeFlowRules(Node node) {
436         this.initializeFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
437         this.initializeFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
438         this.initializeFlowRules(node, AdminConfigManager.getManager().getExternalBridgeName());
439     }
440
441     private void initializeFlowRules(Node node, String bridgeName) {
442         String brIntId = this.getInternalBridgeUUID(node, bridgeName);
443         if (brIntId == null) {
444             logger.error("Failed to initialize Flow Rules for {}", node);
445             return;
446         }
447
448         try {
449             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
450             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
451             Set<String> dpids = bridge.getDatapath_id();
452             if (dpids == null || dpids.size() ==  0) return;
453             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
454             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
455             ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, "default", this);
456             List<Switch> nodes = switchManager.getNetworkDevices();
457             if (nodes == null) {
458                 logger.debug("No OF nodes learned yet in {}", node);
459                 return;
460             }
461             for (Switch device : nodes) {
462                 if (device.getNode().equals(ofNode)) {
463                     logger.debug("Initialize OF Flows on {}", ofNode);
464                     return;
465                 }
466             }
467             logger.debug("Could not identify OF node {} for bridge {} in {}", ofNode.toString(), bridgeName, node.toString());
468         } catch (Exception e) {
469             logger.error("Failed to initialize Flow Rules for "+node.toString(), e);
470         }
471     }
472
473     @Override
474     public void initializeOFFlowRules(Node openflowNode) {
475         this.initializeNormalFlowRules(openflowNode);
476         this.initializeLLDPFlowRules(openflowNode);
477     }
478
479     private void initializeNormalFlowRules(Node ofNode) {
480         String flowName = ActionType.HW_PATH.toString();
481         FlowConfig flow = new FlowConfig();
482         flow.setName("NORMAL");
483         flow.setNode(ofNode);
484         flow.setPriority(NORMAL_PRIORITY+"");
485         flow.setInstallInHw(true);
486         List<String> normalAction = new ArrayList<String>();
487         normalAction.add(flowName);
488         flow.setActions(normalAction);
489         Status status = this.addStaticFlow(ofNode, flow);
490         logger.debug("Flow Programming Add Status {} for Flow {} on {}", status, flow, ofNode);
491     }
492
493     private void initializeLLDPFlowRules(Node ofNode) {
494         String flowName = "PuntLLDP";
495         List<String> puntAction = new ArrayList<String>();
496         puntAction.add(ActionType.CONTROLLER.toString());
497
498         FlowConfig allowLLDP = new FlowConfig();
499         allowLLDP.setName(flowName);
500         allowLLDP.setPriority(LLDP_PRIORITY+"");
501         allowLLDP.setNode(ofNode);
502         allowLLDP.setInstallInHw(true);
503         allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue()).toUpperCase());
504         allowLLDP.setActions(puntAction);
505         Status status = this.addStaticFlow(ofNode, allowLLDP);
506         logger.debug("LLDP Flow Add Status {} for Flow {} on {}", status, allowLLDP, ofNode);
507     }
508
509     private Status addStaticFlow (Node ofNode, FlowConfig flowConfig) {
510         IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
511                 IForwardingRulesManager.class, "default", this);
512         String flowName = flowConfig.getName();
513         if (frm.getStaticFlow(flowName, ofNode) != null) {
514             logger.debug("Flow already exists {} on {}. Skipping installation.", flowName, ofNode);
515             return new Status(StatusCode.CONFLICT, "Flow with name "+flowName+" exists in node "+ofNode.toString());
516         }
517         return frm.addStaticFlow(flowConfig);
518     }
519 }