2 * Copyright (C) 2013 Red Hat, Inc.
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
8 * Authors : Madhu Venugopal, Brent Salisbury, Sam Hague, Dave Tucker
10 package org.opendaylight.ovsdb.openstack.netvirt.providers;
12 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
13 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
14 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
15 import org.opendaylight.controller.sal.action.ActionType;
16 import org.opendaylight.controller.sal.core.Node;
17 import org.opendaylight.controller.sal.utils.EtherTypes;
18 import org.opendaylight.controller.sal.utils.HexEncode;
19 import org.opendaylight.controller.sal.utils.Status;
20 import org.opendaylight.controller.sal.utils.StatusCode;
21 import org.opendaylight.controller.switchmanager.ISwitchManager;
22 import org.opendaylight.controller.switchmanager.Switch;
23 import org.opendaylight.ovsdb.lib.notation.Row;
24 import org.opendaylight.ovsdb.lib.notation.UUID;
25 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
26 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
27 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
28 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
29 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
30 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
31 import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
32 import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
33 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
34 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
35 import org.opendaylight.ovsdb.schema.openvswitch.Port;
37 import com.google.common.collect.Lists;
38 import com.google.common.collect.Maps;
39 import org.apache.commons.lang3.tuple.ImmutablePair;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
43 import java.net.InetAddress;
44 import java.util.List;
49 * Open vSwitch OpenFlow 1.0 Networking Provider for OpenStack Neutron
51 public class OF10Provider implements NetworkingProvider {
52 private static final Logger logger = LoggerFactory.getLogger(OF10Provider.class);
53 private static final int INGRESS_TUNNEL_FLOW_PRIORITY = 100;
54 private static final int EGRESS_TUNNEL_FLOW_PRIORITY = 100;
55 private static final int DROP_FLOW_PRIORITY = 10;
56 private static final int FLOOD_TUNNEL_FLOW_PRIORITY = 50;
57 public static final int LLDP_PRIORITY = 1000;
58 public static final int NORMAL_PRIORITY = 0;
60 private volatile org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService configurationService;
61 private volatile BridgeConfigurationManager bridgeConfigurationManager;
62 private volatile TenantNetworkManager tenantNetworkManager;
63 private volatile OvsdbConfigurationService ovsdbConfigurationService;
64 private volatile OvsdbConnectionService connectionService;
65 private volatile IForwardingRulesManager forwardingRulesManager;
66 private volatile ISwitchManager switchManager;
68 public OF10Provider(){
72 public boolean hasPerTenantTunneling() {
76 private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
77 InetAddress srcTunnelEndPoint = configurationService.getTunnelEndPoint(node);
78 if (srcTunnelEndPoint == null) {
79 logger.error("Tunnel Endpoint not configured for Node {}", node);
80 return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
83 if (!bridgeConfigurationManager.isNodeOverlayReady(node)) {
84 logger.warn("{} is not Overlay ready. It might be an OpenStack Controller Node", node);
85 return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
88 if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, tunnelKey)) {
89 logger.debug(node+" has no network corresponding to segment "+ tunnelKey);
90 return new Status(StatusCode.NOTACCEPTABLE, node+" has no network corresponding to segment "+ tunnelKey);
92 return new Status(StatusCode.SUCCESS);
95 private Status getVlanReadinessStatus (Node node, String segmentationId) {
96 if (!bridgeConfigurationManager.isNodeOverlayReady(node)) {
97 logger.warn("{} is not Overlay ready. It might be an OpenStack Controller Node", node);
98 return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
101 if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, segmentationId)) {
102 logger.debug(node+" has no network corresponding to segment "+ segmentationId);
103 return new Status(StatusCode.NOTACCEPTABLE, node+" has no network corresponding to segment "+ segmentationId);
105 return new Status(StatusCode.SUCCESS);
109 * Program OF1.0 Flow rules on br-tun on the ingress direction from the network towards the br-int.
110 * The logic is to simply match on the incoming tunnel OF-Port (which carries the TenantNetwork GRE-Key)
111 * and rewrite the Corresponding internal Vlan and pass it on to br-int via the patch port.
113 private void programLocalIngressTunnelBridgeRules(Node node, long tunnelOFPort, int internalVlan, long patchPort) {
114 String brNetId = bridgeConfigurationManager.getBridgeUuid(node, configurationService.getNetworkBridgeName());
115 if (brNetId == null) {
116 logger.error("Failed to initialize Flow Rules for {}", node);
120 Row row = ovsdbConfigurationService
121 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brNetId);
122 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
123 Set<String> dpids = bridge.getDatapathIdColumn().getData();
124 if (dpids == null || dpids.size() == 0) return;
125 Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
126 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
127 String flowName = "TepMatch"+tunnelOFPort+""+internalVlan;
128 FlowConfig flow = new FlowConfig();
129 flow.setName(flowName);
130 flow.setNode(ofNode);
131 flow.setInstallInHw(true);
132 flow.setPriority(INGRESS_TUNNEL_FLOW_PRIORITY+"");
133 flow.setIngressPort(tunnelOFPort+"");
134 List<String> actions = Lists.newArrayList();
135 actions.add(ActionType.SET_VLAN_ID+"="+internalVlan);
136 actions.add(ActionType.OUTPUT.toString()+"="+patchPort);
137 flow.setActions(actions);
138 Status status = this.addStaticFlow(ofNode, flow);
139 logger.debug("Local Ingress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
140 } catch (Exception e) {
141 logger.error("Failed to initialize Flow Rules for {}", node, e);
145 private void removeLocalIngressTunnelBridgeRules(Node node, long tunnelOFPort, int internalVlan, long patchPort) {
146 String brNetId = bridgeConfigurationManager.getBridgeUuid(node, configurationService.getNetworkBridgeName());
147 if (brNetId == null) {
148 logger.error("Failed to remove Flow Rules for {}", node);
152 Row row = ovsdbConfigurationService
153 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brNetId);
154 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
155 Set<String> dpids = bridge.getDatapathIdColumn().getData();
156 if (dpids == null || dpids.size() == 0) return;
157 Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
158 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
159 String flowName = "TepMatch"+tunnelOFPort+""+internalVlan;
161 Status status = this.deleteStaticFlow(ofNode, flowName);
162 logger.debug("Local Ingress Flow Removal Status {} for Flow {} on {} / {}", status, flowName, ofNode, node);
163 } catch (Exception e) {
164 logger.error("Failed to Remove Flow Rules for {}", node, e);
169 * Program OF1.0 Flow rules on br-tun on the remote Node on its egress direction towards the overlay network
170 * for a VM (with the attachedMac).
171 * The logic is to simply match on the incoming vlan, mac from the patch-port connected to br-int (patch-int)
172 * and output the traffic to the appropriate GRE Tunnel (which carries the GRE-Key for that Tenant Network).
173 * Also perform the Strip-Vlan action.
175 private void programRemoteEgressTunnelBridgeRules(Node node, long patchPort, String attachedMac,
176 int internalVlan, long tunnelOFPort) {
177 String brNetId = bridgeConfigurationManager.getBridgeUuid(node, configurationService.getNetworkBridgeName());
178 if (brNetId == null) {
179 logger.error("Failed to initialize Flow Rules for {}", node);
183 Row row = ovsdbConfigurationService
184 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brNetId);
185 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
186 Set<String> dpids = bridge.getDatapathIdColumn().getData();
187 if (dpids == null || dpids.size() == 0) return;
188 Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
189 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
190 String flowName = "TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac);
191 FlowConfig flow = new FlowConfig();
192 flow.setName(flowName);
193 flow.setNode(ofNode);
194 flow.setInstallInHw(true);
195 flow.setPriority(EGRESS_TUNNEL_FLOW_PRIORITY+"");
196 flow.setDstMac(attachedMac);
197 flow.setIngressPort(patchPort+"");
198 flow.setVlanId(internalVlan+"");
199 List<String> actions = Lists.newArrayList();
200 actions.add(ActionType.POP_VLAN.toString());
201 actions.add(ActionType.OUTPUT.toString()+"="+tunnelOFPort);
202 flow.setActions(actions);
203 Status status = this.addStaticFlow(ofNode, flow);
204 logger.debug("Remote Egress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
205 } catch (Exception e) {
206 logger.error("Failed to initialize Flow Rules for {}", node, e);
210 private void removeRemoteEgressTunnelBridgeRules(Node node, long patchPort, String attachedMac,
211 int internalVlan, long tunnelOFPort) {
212 String brNetId = bridgeConfigurationManager.getBridgeUuid(node, configurationService.getNetworkBridgeName());
213 if (brNetId == null) {
214 logger.error("Failed to initialize Flow Rules for {}", node);
218 Row row = ovsdbConfigurationService
219 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brNetId);
220 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
221 Set<String> dpids = bridge.getDatapathIdColumn().getData();
222 if (dpids == null || dpids.size() == 0) return;
223 Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
224 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
225 String flowName = "TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac);
226 Status status = this.deleteStaticFlow(ofNode, flowName);
227 logger.debug("Remote Egress Flow Removal Status {} for Flow {} on {} / {}", status, flowName, ofNode, node);
228 } catch (Exception e) {
229 logger.error("Failed to Remove Flow Rules for {}", node, e);
234 * Program OF1.0 Flow rules to flood the broadcast & unknown-unicast traffic over br-tun on the egress direction
235 * towards the network on all the overlay tunnels that corresponds to the tenant network.
236 * The logic is to simply match on the incoming vlan, mac from the patch-port connected to br-int (patch-int)
237 * and output the traffic to all the GRE-Tunnels for this Tenant Network (which carries the GRE-Key).
238 * Also perform the Strip-Vlan action.
240 private void programFloodEgressTunnelBridgeRules(Node node, long patchPort, int internalVlan, long tunnelOFPort) {
241 String brNetId = bridgeConfigurationManager.getBridgeUuid(node, configurationService.getNetworkBridgeName());
242 if (brNetId == null) {
243 logger.error("Failed to initialize Flow Rules for {}", node);
247 Row row = ovsdbConfigurationService
248 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brNetId);
249 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
250 Set<String> dpids = bridge.getDatapathIdColumn().getData();
251 if (dpids == null || dpids.size() == 0) return;
252 Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
253 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
254 String flowName = "TepFlood"+internalVlan;
255 FlowConfig existingFlowConfig = forwardingRulesManager.getStaticFlow(flowName, ofNode);
256 FlowConfig flow = existingFlowConfig;
259 flow = new FlowConfig();
260 flow.setName(flowName);
261 flow.setNode(ofNode);
262 flow.setPriority(FLOOD_TUNNEL_FLOW_PRIORITY+"");
263 flow.setIngressPort(patchPort+"");
264 flow.setVlanId(internalVlan+"");
265 List<String> actions = Lists.newArrayList();
266 actions.add(ActionType.POP_VLAN.toString());
267 actions.add(ActionType.OUTPUT.toString()+"="+tunnelOFPort);
268 flow.setActions(actions);
269 status = forwardingRulesManager.addStaticFlow(flow);
270 logger.debug("Add Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
271 status, flow, ofNode, node);
273 flow = new FlowConfig(existingFlowConfig);
274 List<String> actions = flow.getActions();
275 String outputPort = ActionType.OUTPUT.toString()+"="+tunnelOFPort;
276 if (actions != null && !actions.contains(outputPort)) {
277 actions.add(outputPort);
278 flow.setActions(actions);
280 logger.debug("Flood Egress Flow already exists. Skipping modify for Flow {} on {} / {}",
284 status = forwardingRulesManager.modifyStaticFlow(flow);
285 logger.debug("Modify Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
286 status, flow, ofNode, node);
288 } catch (Exception e) {
289 logger.error("Failed to initialize Flow Rules for {}", node, e);
293 private void removeFloodEgressTunnelBridgeRules(Node node, long patchPort, int internalVlan, long tunnelOFPort) {
294 String brNetId = bridgeConfigurationManager.getBridgeUuid(node, configurationService.getNetworkBridgeName());
295 if (brNetId == null) {
296 logger.error("Failed to remove Flow Rules for {}", node);
300 Row row = ovsdbConfigurationService
301 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brNetId);
302 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
303 Set<String> dpids = bridge.getDatapathIdColumn().getData();
304 if (dpids == null || dpids.size() == 0) return;
305 Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
306 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
307 String flowName = "TepFlood"+internalVlan;
308 FlowConfig flow = forwardingRulesManager.getStaticFlow(flowName, ofNode);
311 status = forwardingRulesManager.removeStaticFlow(flowName, ofNode);
312 logger.debug("Remove Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
313 status, flow, ofNode, node);
316 logger.debug("Flood Egress Flow already removed. Skipping removal of flow on {} / {}",
319 } catch (Exception e) {
320 logger.error("Failed to remove Flow Rules for {}", node, e);
324 private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
325 Interface iface, boolean local) {
326 String networkId = tenantNetworkManager.getNetworkId(segmentationId);
327 if (networkId == null) {
328 logger.debug("Tenant Network not found with Segmentation-id {}", segmentationId);
331 int internalVlan = tenantNetworkManager.getInternalVlan(node, networkId);
332 if (internalVlan == 0) {
333 logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
336 Map<String, String> externalIds = iface.getExternalIdsColumn().getData();
337 if (externalIds == null) {
338 logger.error("No external_ids seen in {}", iface);
342 String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
343 if (attachedMac == null) {
344 logger.error("No AttachedMac seen in {}", iface);
347 String patchInt = configurationService
348 .getPatchPortName(new ImmutablePair<>(configurationService.getNetworkBridgeName(),
349 configurationService.getIntegrationBridgeName()));
351 long patchOFPort = -1;
353 Map<String, Row> ifaces = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
354 if (ifaces != null) {
355 for (Row row : ifaces.values()) {
356 Interface patchiface = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
357 if (patchiface.getName().equalsIgnoreCase(patchInt)) {
358 Set<Long> of_ports = patchiface.getOpenFlowPortColumn().getData();
359 if (of_ports == null || of_ports.size() <= 0) {
360 logger.trace("No port for patch interface {} on node {}", patchInt, node);
363 patchOFPort = (long)of_ports.toArray()[0];
364 logger.debug("Identified Patch port {} -> OF ({}) on {}", patchInt, patchOFPort, node);
368 if (patchOFPort == -1) {
369 logger.warn("Could not find port associated with patch interface {} on node {}. No flow rules to program", patchInt, node);
371 for (Row row : ifaces.values()) {
372 Interface tuniface = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
373 if (tuniface.getName().equals(this.getTunnelName(tunnelType, segmentationId, dst))) {
374 Set<Long> of_ports = tuniface.getOpenFlowPortColumn().getData();
375 if (of_ports == null || of_ports.size() <= 0) {
376 logger.warn("Could not Identify Tunnel port {} on {}. Don't panic. It might get converged soon...", tuniface.getName(), node);
379 long tunnelOFPort = (long)of_ports.toArray()[0];
381 if (tunnelOFPort == -1) {
382 logger.warn("Tunnel Port {} on node {}: OFPort = -1 . Don't panic. It might get converged soon...", tuniface.getName(), node);
385 logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tuniface.getName(), tunnelOFPort, node);
388 programRemoteEgressTunnelBridgeRules(node, patchOFPort, attachedMac, internalVlan, tunnelOFPort);
389 logger.trace("Programmed (non-local) EgressTunnelBridgeRules for attachedMac {} internalVlan {} tunnelOFPort {}",
390 attachedMac, internalVlan, tunnelOFPort);
392 programLocalIngressTunnelBridgeRules(node, tunnelOFPort, internalVlan, patchOFPort);
393 programFloodEgressTunnelBridgeRules(node, patchOFPort, internalVlan, tunnelOFPort);
394 logger.trace("Programmed ingress tunnel and flood rules for node {} tunnel {} tunnelOFPort {} internalVlan {} patchOFPort {}",
395 node, tuniface.getName(), tunnelOFPort, internalVlan, patchOFPort);
400 } catch (Exception e) {
405 private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
406 Interface iface, boolean local) {
407 String networkId = tenantNetworkManager.getNetworkId(segmentationId);
408 if (networkId == null) {
409 logger.debug("Tenant Network not found with Segmentation-id {}",segmentationId);
412 int internalVlan = tenantNetworkManager.getInternalVlan(node, networkId);
413 if (internalVlan == 0) {
414 logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
417 Map<String, String> externalIds = iface.getExternalIdsColumn().getData();
418 if (externalIds == null) {
419 logger.error("No external_ids seen in {}", iface);
423 String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
424 if (attachedMac == null) {
425 logger.error("No AttachedMac seen in {}", iface);
428 String patchInt = configurationService
429 .getPatchPortName(new ImmutablePair<>(configurationService.getNetworkBridgeName(),
430 configurationService.getIntegrationBridgeName()));
432 long patchOFPort = -1;
434 Map<String, Row> ifaces = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
435 if (ifaces != null) {
436 for (Row row : ifaces.values()) {
437 Interface patchiface = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
438 if (patchiface.getName().equalsIgnoreCase(patchInt)) {
439 Set<Long> of_ports = patchiface.getOpenFlowPortColumn().getData();
440 if (of_ports == null || of_ports.size() <= 0) {
441 logger.trace("Could NOT identify Patch port {} on {}", patchInt, node);
444 patchOFPort = (long)of_ports.toArray()[0];
445 logger.debug("Identified Patch port {} -> OF ({}) on {}", patchInt, patchOFPort, node);
449 if (patchOFPort == -1) {
450 logger.debug("Could not find port associated with patch interface {} on node {}", patchInt, node);
451 // return; // keep going; we assume that removal of rules does not really need patchOFPort
453 for (Row row : ifaces.values()) {
454 Interface tuniface = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
455 if (tuniface.getName().equals(this.getTunnelName(tunnelType, segmentationId, dst))) {
456 Set<Long> of_ports = tuniface.getOpenFlowPortColumn().getData();
457 if (of_ports == null || of_ports.size() <= 0) {
458 logger.error("Could NOT Identify Tunnel port {} on {}", tuniface.getName(), node);
461 long tunnelOFPort = (long)of_ports.toArray()[0];
463 if (tunnelOFPort == -1) {
464 logger.error("Could NOT Identify Tunnel port {} -> OF ({}) on {}: No flow rules to remove", tuniface.getName(), tunnelOFPort, node);
467 logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tuniface.getName(), tunnelOFPort, node);
470 removeRemoteEgressTunnelBridgeRules(node, patchOFPort, attachedMac, internalVlan, tunnelOFPort);
472 removeLocalIngressTunnelBridgeRules(node, tunnelOFPort, internalVlan, patchOFPort);
473 removeFloodEgressTunnelBridgeRules(node, patchOFPort, internalVlan, tunnelOFPort);
478 } catch (Exception e) {
483 private String getIntModVlanFlowName (long inOFPort, String fromVlan, String toVlan) {
484 return "int_mod_"+inOFPort+"_"+fromVlan+"_"+toVlan;
487 private String getIntDropFlowName (long inOFPort) {
488 return "int_drop_"+inOFPort;
491 private String getNetModVlanFlowName (long inOFPort, String fromVlan, String toVlan) {
492 return "net_mod_"+inOFPort+"_"+fromVlan+"_"+toVlan;
495 private String getNetDropFlowName (long inOFPort) {
496 return "net_drop_"+inOFPort;
499 private String getNetFwdFlowName (long inOFPort, long outOFPort, String vlan) {
500 return "net_fwd_"+vlan+"_"+inOFPort+"_"+outOFPort;
503 private void deleteRule (Node node, Node ofNode, String flowName) {
504 logger.debug("deleteRule: node: {} / {}, flowName: {}", node, ofNode, flowName);
507 this.deleteStaticFlow(ofNode, flowName);
508 } catch (Exception e) {
509 logger.error("deleteRule: Failed to delete Flow Rule for {} / {}", node, ofNode, e);
513 /* in_port=p actions=drop */
514 private void programDropRule (Node node, Node ofNode, long inOFPort, String flowName) {
515 logger.debug("programDropRule: node: {} / {}, inOfPort: {}, flowName: {}",
516 node, ofNode, inOFPort, flowName);
519 FlowConfig flow = new FlowConfig();
520 flow.setName(flowName);
521 flow.setNode(ofNode);
522 flow.setInstallInHw(true);
523 flow.setPriority(DROP_FLOW_PRIORITY+"");
524 flow.setIngressPort(inOFPort+"");
525 List<String> actions = Lists.newArrayList();
526 actions.add(ActionType.DROP+"");
527 flow.setActions(actions);
528 Status status = this.addStaticFlow(ofNode, flow);
529 logger.debug("programDropRule: Flow Programming Status {} for Flow {} on {} / {}",
530 status, flow, node, ofNode);
531 } catch (Exception e) {
532 logger.error("programDropRule: Failed to initialize Flow Rules for {} / {}", node, ofNode, e);
536 /* in_port=p1,dl_vlan=v actions=mod_vlan_vid,[NORMAL|output:p2] */
537 private void programModVlanRule (Node node, Node ofNode, long inOFPort, long outOFPort, String fromVlan,
538 String toVlan, String flowName) {
539 logger.debug("programModVlanRule: node: {} / {}, inOfPort: {}, fromVlan: {}, toVlan: {}, flowName: {}",
540 node, ofNode, inOFPort, fromVlan, toVlan, flowName);
543 FlowConfig flow = new FlowConfig();
544 flow.setName(flowName);
545 flow.setNode(ofNode);
546 flow.setInstallInHw(true);
547 flow.setPriority(INGRESS_TUNNEL_FLOW_PRIORITY+"");
548 flow.setIngressPort(inOFPort+"");
549 flow.setVlanId(fromVlan);
550 List<String> actions = Lists.newArrayList();
551 actions.add(ActionType.SET_VLAN_ID+"="+toVlan);
552 if (outOFPort == -1) {
553 actions.add(ActionType.HW_PATH.toString());
555 actions.add(ActionType.OUTPUT.toString()+"="+outOFPort);
557 flow.setActions(actions);
558 Status status = this.addStaticFlow(ofNode, flow);
559 logger.debug("programModVlanRule: Flow Programming Status {} for Flow {} on {} / {}",
560 status, flow, node, ofNode);
561 } catch (Exception e) {
562 logger.error("programModVlanRule: Failed to initialize Flow Rule for {} / {}", node, ofNode, e);
566 /* in_port=p1,dl_vlan=v actions=output:p2 */
567 private void programForwardRule (Node node, Node ofNode, long inOFPort, long outOFPort, String vlan, String flowName) {
568 logger.debug("programForwardRule: node: {} / {}, inOfPort: {}, outOFPort: {}, flowName: {}",
569 node, ofNode, inOFPort, outOFPort, flowName);
572 FlowConfig flow = new FlowConfig();
573 flow.setName(flowName);
574 flow.setNode(ofNode);
575 flow.setInstallInHw(true);
576 flow.setPriority(EGRESS_TUNNEL_FLOW_PRIORITY + "");
577 flow.setIngressPort(inOFPort + "");
578 flow.setVlanId(vlan);
579 List<String> actions = Lists.newArrayList();
580 actions.add(ActionType.OUTPUT.toString()+"="+outOFPort);
581 flow.setActions(actions);
582 Status status = this.addStaticFlow(ofNode, flow);
583 logger.debug("programForwardRule: Flow Programming Status {} for Flow {} on {} / {}",
584 status, flow, node, ofNode);
585 } catch (Exception e) {
586 logger.error("programForwardRule: Failed to initialize Flow Rules for {} / {}", node, ofNode, e);
590 public long getOFPort (Node node, String portName) {
593 Map<String, Row> ifaces = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
594 if (ifaces != null) {
595 for (Row row : ifaces.values()) {
596 Interface iface = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
597 if (iface.getName().equalsIgnoreCase(portName)) {
598 Set<Long> of_ports = iface.getOpenFlowPortColumn().getData();
599 if (of_ports == null || of_ports.size() <= 0) {
600 logger.error("Could not identify patch port {} on {}", portName, node);
603 ofPort = (Long)of_ports.toArray()[0];
604 logger.debug("Identified port {} -> OF ({}) on {}", portName, ofPort, node);
609 } catch (Exception e) {
617 * Transient class to return all the vlan network data needed for flow programming.
619 public class vlanNet {
620 public long patchIntOfPort;
621 public long patchNetOfPort;
622 public long physicalOfPort;
623 public int internalVlan;
625 public vlanNet (NeutronNetwork network, Node node, Interface iface) {
631 initializeVlanNet(network, node, iface);
634 public boolean isValid () {
635 return (patchIntOfPort != -1) && (patchNetOfPort != -1) && (physicalOfPort != -1) && (internalVlan != -1);
638 public long getPatchIntOfPort () {
639 return patchIntOfPort;
642 public long getPatchNetOfPort () {
643 return patchNetOfPort;
646 public long getphysicalOfPort () {
647 return physicalOfPort;
650 public int getInternalVlan () {
654 public void initializeVlanNet (NeutronNetwork network, Node node, Interface iface) {
655 internalVlan = tenantNetworkManager.getInternalVlan(node, network.getNetworkUUID());
656 if (internalVlan == 0) {
657 logger.debug("No InternalVlan provisioned for Tenant Network {}", network.getNetworkUUID());
661 /* Get ofports for patch ports and physical interface. */
662 String patchToNetworkName = configurationService
663 .getPatchPortName(new ImmutablePair<>(configurationService.getIntegrationBridgeName(),
664 configurationService.getNetworkBridgeName()));
666 String patchToIntegrationName = configurationService
667 .getPatchPortName(new ImmutablePair<>(configurationService.getNetworkBridgeName(),
668 configurationService.getIntegrationBridgeName()));
670 String physNetName = bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
672 patchIntOfPort = getOFPort(node, patchToNetworkName);
673 if (patchIntOfPort == -1) {
674 logger.error("Cannot identify {} interface on {}", patchToNetworkName, node);
678 patchNetOfPort = getOFPort(node, patchToIntegrationName);
679 if (patchNetOfPort == -1) {
680 logger.error("Cannot identify {} interface on {}", patchToIntegrationName, node);
684 physicalOfPort = getOFPort(node, physNetName);
685 if (physicalOfPort == -1) {
686 logger.error("Cannot identify {} interface on {}", physNetName, node);
691 private Node getOFNode (Node node, String bridgeName) {
692 String brUUID = bridgeConfigurationManager.getBridgeUuid(node, bridgeName);
693 if (brUUID == null) {
694 logger.error("getOFNode: Unable to find {} UUID on node {}", bridgeName, node);
699 Row row = ovsdbConfigurationService
700 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), brUUID);
701 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
702 Set<String> dpids = bridge.getDatapathIdColumn().getData();
703 if (dpids == null || dpids.size() == 0) {
706 Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
707 return new Node(Node.NodeIDType.OPENFLOW, dpidLong);
708 } catch (Exception e) {
709 logger.error("deleteRule: Failed to delete Flow Rule for {}", node, e);
716 * Vlan isolation uses a patch port between br-int and br-net. Anything received on one end of
717 * the patch is piped to the other end of the patch so the incoming packets from the network would
718 * arrive untouched at the patch port on br-int.
720 * Program OF1.0 Flow rules on br-net in the ingress direction from the network
721 * and egress direction towards the network.
722 * The logic is to simply match on the incoming patch OF-Port and internal vlan,
723 * rewrite the internal vlan to the external vlan and forward out the physical port.
724 * There is also a flow to match the externally tagged packets from the physical port
725 * rewrite the external tag to the internal tag and forward to the patch port.
727 * priority=100,in_port=1,dl_vlan=1 actions=mod_vlan_vid:2001,output:2
728 * priority=100,in_port=2,dl_vlan=2001 actions=mod_vlan_vid:1actions=output:1
731 private void programVlanRules (NeutronNetwork network, Node node, Interface iface) {
732 vlanNet vlanNet = new vlanNet(network, node, iface);
733 if (vlanNet.isValid()) {
734 String netBrName = configurationService.getNetworkBridgeName();
735 String intModVlanFlowName = getIntModVlanFlowName(vlanNet.getPatchNetOfPort(), vlanNet.getInternalVlan()+"", network.getProviderSegmentationID());
736 String netModVlanFlowName = getNetModVlanFlowName(vlanNet.getPatchNetOfPort(), network.getProviderSegmentationID(), vlanNet.getInternalVlan()+"");
738 Node netOFNode = getOFNode(node, netBrName);
739 if (netOFNode == null) {
740 logger.error("Unable to find {} ofNode, Failed to initialize Flow Rules for {}", netBrName, node);
744 /* Program flows on br-net */
745 deleteRule(node, netOFNode, "NORMAL");
746 programModVlanRule(node, netOFNode, vlanNet.getPatchNetOfPort(), vlanNet.getphysicalOfPort(),
747 vlanNet.getInternalVlan()+"", network.getProviderSegmentationID(), intModVlanFlowName);
748 programModVlanRule(node, netOFNode, vlanNet.getphysicalOfPort(), vlanNet.getPatchNetOfPort(),
749 network.getProviderSegmentationID(), vlanNet.getInternalVlan()+"", netModVlanFlowName);
753 private void removeVlanRules (NeutronNetwork network, Node node, Interface iface) {
754 vlanNet vlanNet = new vlanNet(network, node, iface);
755 if (vlanNet.isValid()) {
756 String netBrName = configurationService.getNetworkBridgeName();
757 String intModVlanFlowName = getIntModVlanFlowName(vlanNet.getPatchNetOfPort(), vlanNet.getInternalVlan()+"", network.getProviderSegmentationID());
758 String netModVlanFlowName = getNetModVlanFlowName(vlanNet.getPatchNetOfPort(), network.getProviderSegmentationID(), vlanNet.getInternalVlan()+"");
760 Node netOFNode = getOFNode(node, netBrName);
761 if (netOFNode == null) {
762 logger.error("Unable to find {} ofNode, Failed to initialize Flow Rules for {}", netBrName, node);
766 deleteRule(node, netOFNode, intModVlanFlowName);
767 deleteRule(node, netOFNode, netModVlanFlowName);
772 public Status handleInterfaceUpdate(NeutronNetwork network, Node srcNode, Interface iface) {
773 logger.debug("handleInterfaceUpdate: networkType: {}, segmentationId: {}, srcNode: {}, iface: {}",
774 network.getProviderNetworkType(), network.getProviderSegmentationID(), srcNode, iface.getName());
776 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
777 Status status = getVlanReadinessStatus(srcNode, network.getProviderSegmentationID());
778 if (!status.isSuccess()) {
781 this.programVlanRules(network, srcNode, iface);
782 return new Status(StatusCode.SUCCESS);
784 } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
785 network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
786 Status status = getTunnelReadinessStatus(srcNode, network.getProviderSegmentationID());
787 if (!status.isSuccess()) {
788 logger.debug("Interface update of networkType: {}, segmentationId: {}, srcNode: {} is not tunnel ready",
789 network.getProviderNetworkType(), network.getProviderSegmentationID(), srcNode);
793 List<Node> nodes = connectionService.getNodes();
794 nodes.remove(srcNode);
795 for (Node dstNode : nodes) {
796 status = getTunnelReadinessStatus(dstNode, network.getProviderSegmentationID());
797 if (!status.isSuccess()) {
798 logger.debug("Interface update of networkType: {}, segmentationId: {}, dstNode: {} is not tunnel ready",
799 network.getProviderNetworkType(), network.getProviderSegmentationID(), dstNode);
802 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
803 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
804 status = addTunnelPort(srcNode, network.getProviderNetworkType(), src, dst, network.getProviderSegmentationID());
805 if (status.isSuccess()) {
806 this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), dst, srcNode, iface, true);
807 status = addTunnelPort(dstNode, network.getProviderNetworkType(), dst, src, network.getProviderSegmentationID());
808 if (status.isSuccess()) {
809 this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), src, dstNode, iface, false);
813 return new Status(StatusCode.SUCCESS);
815 return new Status(StatusCode.BADREQUEST);
820 public Status handleInterfaceDelete(String tunnelType, NeutronNetwork network,
821 Node srcNode,Interface iface, boolean isLastInstanceOnNode) {
822 Status status = new Status(StatusCode.SUCCESS);
823 logger.debug("handleInterfaceDelete: srcNode: {}, networkType: {}, iface: {}, type: {}, isLast: {}",
824 srcNode, (network != null) ? network.getProviderNetworkType() : "",
825 iface.getName(), iface.getTypeColumn().getData(), isLastInstanceOnNode);
827 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
828 if ((network != null) && network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
829 if (isLastInstanceOnNode) {
830 this.removeVlanRules(network, srcNode, iface);
832 } else if (iface.getTypeColumn().getData().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
833 iface.getTypeColumn().getData().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
834 /* Delete tunnel port */
836 Map<String, String> options = iface.getOptionsColumn().getData();
837 InetAddress src = InetAddress.getByName(options.get("local_ip"));
838 InetAddress dst = InetAddress.getByName(options.get("remote_ip"));
839 String key = options.get("key");
840 status = deleteTunnelPort(srcNode, iface.getTypeColumn().getData(), src, dst, key);
841 } catch (Exception e) {
842 logger.error(e.getMessage(), e);
844 } else if (phyIfName.contains(iface.getName())) {
845 deletePhysicalPort(srcNode, iface.getName());
847 /* delete all other interfaces */
848 List<Node> nodes = connectionService.getNodes();
849 nodes.remove(srcNode);
850 for (Node dstNode : nodes) {
851 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
852 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
853 assert network != null;
854 this.removeTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), dst, srcNode, iface, true);
855 if (isLastInstanceOnNode) {
856 status = deleteTunnelPort(srcNode, network.getProviderNetworkType(), src, dst, network.getProviderSegmentationID());
858 this.removeTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), src, dstNode, iface, false);
859 if (status.isSuccess() && isLastInstanceOnNode) {
860 deleteTunnelPort(dstNode, network.getProviderNetworkType(), dst, src, network.getProviderSegmentationID());
867 private String getTunnelName(String tunnelType, String key, InetAddress dst) {
868 return tunnelType+"-"+key+"-"+dst.getHostAddress();
871 private Interface getTunnelInterface (Node node, String tunnelType, InetAddress dst, String key) {
873 String portName = getTunnelName(tunnelType, key, dst);
875 Map<String, Row> tunifaces = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
876 if (tunifaces != null) {
877 for (Row row : tunifaces.values()) {
878 Interface tuniface = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
879 if (tuniface.getName().equals(portName)) return tuniface;
883 } catch (Exception e) {
889 private boolean isTunnelPresent(Node node, String tunnelName, String bridgeUUID) throws Exception {
890 Row row = ovsdbConfigurationService
891 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
892 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
893 if (bridge != null) {
894 Set<UUID> ports = bridge.getPortsColumn().getData();
895 for (UUID portUUID : ports) {
896 Row portRow = ovsdbConfigurationService
897 .getRow(node, ovsdbConfigurationService.getTableName(node, Port.class), portUUID.toString());
898 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
899 if (port != null && port.getName().equalsIgnoreCase(tunnelName)) return true;
905 private String getPortUuid(Node node, String portName, String bridgeUUID) throws Exception {
906 Row row = ovsdbConfigurationService
907 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
908 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
909 if (bridge != null) {
910 Set<UUID> ports = bridge.getPortsColumn().getData();
911 for (UUID portUUID : ports) {
912 Row portRow = ovsdbConfigurationService
913 .getRow(node, ovsdbConfigurationService.getTableName(node, Port.class), portUUID.toString());
914 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
915 if (port != null && port.getName().equalsIgnoreCase(portName)) return portUUID.toString();
921 private Status addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
923 String bridgeUUID = null;
924 String tunnelBridgeName = configurationService.getNetworkBridgeName();
925 Map<String, Row> bridgeTable = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
926 if (bridgeTable != null) {
927 for (String uuid : bridgeTable.keySet()) {
928 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(uuid));
929 if (bridge.getName().equals(tunnelBridgeName)) {
935 if (bridgeUUID == null) {
936 logger.error("Could not find Bridge {} in {}", tunnelBridgeName, node);
937 return new Status(StatusCode.NOTFOUND, "Could not find "+tunnelBridgeName+" in "+node);
939 String portName = getTunnelName(tunnelType, key, dst);
941 if (this.isTunnelPresent(node, portName, bridgeUUID)) {
942 logger.trace("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node);
943 return new Status(StatusCode.SUCCESS);
946 Port tunnelPort = ovsdbConfigurationService.createTypedRow(node, Port.class);
947 tunnelPort.setName(portName);
948 StatusWithUuid statusWithUuid = ovsdbConfigurationService
949 .insertRow(node, ovsdbConfigurationService.getTableName(node, Port.class), bridgeUUID,
950 tunnelPort.getRow());
951 if (!statusWithUuid.isSuccess()) {
952 logger.error("Failed to insert Tunnel port {} in {}", portName, bridgeUUID);
953 return statusWithUuid;
956 String tunnelPortUUID = statusWithUuid.getUuid().toString();
957 String interfaceUUID = null;
959 while ((interfaceUUID == null) && (timeout > 0)) {
960 Row row = ovsdbConfigurationService
961 .getRow(node, ovsdbConfigurationService.getTableName(node, Port.class), tunnelPortUUID);
962 tunnelPort = ovsdbConfigurationService.getTypedRow(node, Port.class, row);
963 Set<UUID> interfaces = tunnelPort.getInterfacesColumn().getData();
964 if (interfaces == null || interfaces.size() == 0) {
965 // Wait for the OVSDB update to sync up the Local cache.
970 interfaceUUID = interfaces.toArray()[0].toString();
971 Row ifaceRow = ovsdbConfigurationService
972 .getRow(node, ovsdbConfigurationService.getTableName(node, Interface.class), interfaceUUID);
973 Interface iface = ovsdbConfigurationService.getTypedRow(node, Interface.class, ifaceRow);
974 if (iface == null) interfaceUUID = null;
977 if (interfaceUUID == null) {
978 logger.error("Cannot identify Tunnel Interface for port {}/{}", portName, tunnelPortUUID);
979 return new Status(StatusCode.INTERNALERROR);
982 Interface tunInterface = ovsdbConfigurationService.createTypedRow(node, Interface.class);
983 tunInterface.setType(tunnelType);
984 Map<String, String> options = Maps.newHashMap();
985 options.put("key", key);
986 options.put("local_ip", src.getHostAddress());
987 options.put("remote_ip", dst.getHostAddress());
988 tunInterface.setOptions(options);
989 Status status = ovsdbConfigurationService
990 .updateRow(node, ovsdbConfigurationService.getTableName(node, Interface.class), tunnelPortUUID,
991 interfaceUUID, tunInterface.getRow());
992 logger.debug("Tunnel {} add status : {}", tunInterface, status);
994 } catch (Exception e) {
995 logger.error("Exception in addTunnelPort", e);
996 return new Status(StatusCode.INTERNALERROR);
1000 private Status deletePort(Node node, String bridgeName, String portName) {
1002 String bridgeUUID = null;
1003 Map<String, Row> bridgeTable = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
1004 if (bridgeTable != null) {
1005 for (String uuid : bridgeTable.keySet()) {
1006 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(uuid));
1007 if (bridge.getName().equals(bridgeName)) {
1013 if (bridgeUUID == null) {
1014 logger.debug("Could not find Bridge {} in {}", bridgeName, node);
1015 return new Status(StatusCode.SUCCESS);
1017 String portUUID = this.getPortUuid(node, portName, bridgeUUID);
1018 Status status = new Status(StatusCode.SUCCESS);
1019 if (portUUID != null) {
1020 status = ovsdbConfigurationService
1021 .deleteRow(node, ovsdbConfigurationService.getTableName(node, Port.class), portUUID);
1022 if (!status.isSuccess()) {
1023 logger.error("Failed to delete port {} in {} status : {}", portName, bridgeUUID, status);
1026 logger.debug("Port {} delete status : {}", portName, status);
1029 } catch (Exception e) {
1030 logger.error("Exception in deleteTunnelPort", e);
1031 return new Status(StatusCode.INTERNALERROR);
1035 private Status deleteTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
1036 String tunnelBridgeName = configurationService.getNetworkBridgeName();
1037 String portName = getTunnelName(tunnelType, key, dst);
1038 return deletePort(node, tunnelBridgeName, portName);
1041 private Status deletePhysicalPort(Node node, String phyIfaceName) {
1042 String netBridgeName = configurationService.getNetworkBridgeName();
1043 return deletePort(node, netBridgeName, phyIfaceName);
1047 public Status handleInterfaceUpdate(String tunnelType, String tunnelKey) {
1048 List<Node> nodes = connectionService.getNodes();
1049 for (Node srcNode : nodes) {
1050 this.handleInterfaceUpdate(null, srcNode, null);
1052 return new Status(StatusCode.SUCCESS);
1056 public void initializeFlowRules(Node node) {
1057 this.initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1058 this.initializeFlowRules(node, configurationService.getExternalBridgeName());
1061 private void initializeFlowRules(Node node, String bridgeName) {
1062 String bridgeUuid = bridgeConfigurationManager.getBridgeUuid(node, bridgeName);
1063 if (bridgeUuid == null) {
1064 if (bridgeName.equals(configurationService.getExternalBridgeName())){
1065 logger.debug("Failed to initialize Flow Rules for bridge {} on node {}. Is the Neutron L3 agent running on this node?");
1068 logger.debug("Failed to initialize Flow Rules for bridge {} on node {}", bridgeName, node);
1074 Row row = ovsdbConfigurationService
1075 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUuid);
1076 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, row);
1077 Set<String> dpids = bridge.getDatapathIdColumn().getData();
1078 if (dpids == null || dpids.size() == 0) return;
1079 Long dpidLong = HexEncode.stringToLong((String) dpids.toArray()[0]);
1080 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
1081 List<Switch> nodes = switchManager.getNetworkDevices();
1082 if (nodes == null) {
1083 logger.debug("No OF nodes learned yet in {}", node);
1086 for (Switch device : nodes) {
1087 if (device.getNode().equals(ofNode)) {
1088 logger.debug("Initialize OF Flows on {}", ofNode);
1089 initializeNormalFlowRules(ofNode);
1093 logger.debug("Could not identify OF node {} for bridge {} in {}", ofNode.toString(), bridgeName, node.toString());
1094 } catch (Exception e) {
1095 logger.error("Failed to initialize Flow Rules for "+node.toString(), e);
1100 public void initializeOFFlowRules(Node openflowNode) {
1101 this.initializeNormalFlowRules(openflowNode);
1102 this.initializeLLDPFlowRules(openflowNode);
1105 private void initializeNormalFlowRules(Node ofNode) {
1106 String flowName = ActionType.HW_PATH.toString();
1107 FlowConfig flow = new FlowConfig();
1108 flow.setName("NORMAL");
1109 flow.setNode(ofNode);
1110 flow.setPriority(NORMAL_PRIORITY+"");
1111 flow.setInstallInHw(true);
1112 List<String> normalAction = Lists.newArrayList();
1113 normalAction.add(flowName);
1114 flow.setActions(normalAction);
1115 Status status = this.addStaticFlow(ofNode, flow);
1116 logger.debug("Flow Programming Add Status {} for Flow {} on {}", status, flow, ofNode);
1119 private void initializeLLDPFlowRules(Node ofNode) {
1120 String flowName = "PuntLLDP";
1121 List<String> puntAction = Lists.newArrayList();
1122 puntAction.add(ActionType.CONTROLLER.toString());
1124 FlowConfig allowLLDP = new FlowConfig();
1125 allowLLDP.setName(flowName);
1126 allowLLDP.setPriority(LLDP_PRIORITY+"");
1127 allowLLDP.setNode(ofNode);
1128 allowLLDP.setInstallInHw(true);
1129 allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue()).toUpperCase());
1130 allowLLDP.setActions(puntAction);
1131 Status status = this.addStaticFlow(ofNode, allowLLDP);
1132 logger.debug("LLDP Flow Add Status {} for Flow {} on {}", status, allowLLDP, ofNode);
1135 private Status addStaticFlow (Node ofNode, FlowConfig flowConfig) {
1136 String flowName = flowConfig.getName();
1137 if (forwardingRulesManager.getStaticFlow(flowName, ofNode) != null) {
1138 logger.debug("Flow already exists {} on {}. Skipping installation.", flowName, ofNode);
1139 return new Status(StatusCode.CONFLICT, "Flow with name "+flowName+" exists in node "+ofNode.toString());
1141 return forwardingRulesManager.addStaticFlow(flowConfig);
1144 private Status deleteStaticFlow (Node ofNode, String flowName) {
1145 if (forwardingRulesManager.getStaticFlow(flowName, ofNode) == null) {
1146 logger.debug("Flow does not exist {} on {}. Skipping deletion.", flowName, ofNode);
1147 return new Status(StatusCode.SUCCESS);
1149 return forwardingRulesManager.removeStaticFlow(flowName,ofNode);