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 package org.opendaylight.ovsdb.openstack.netvirt;
10 import java.util.List;
11 import java.util.concurrent.ConcurrentMap;
13 import org.opendaylight.neutron.spi.NeutronNetwork;
14 import org.opendaylight.ovsdb.lib.notation.Row;
15 import org.opendaylight.ovsdb.openstack.netvirt.api.*;
16 import org.opendaylight.ovsdb.openstack.netvirt.impl.MdsalUtils;
17 import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
18 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
19 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
20 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
23 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
24 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * @author Madhu Venugopal
30 * @author Brent Salisbury
32 * @author Sam Hague (shague@redhat.com)
34 public class SouthboundHandler extends AbstractHandler
35 implements NodeCacheListener, OvsdbInventoryListener {
36 static final Logger logger = LoggerFactory.getLogger(SouthboundHandler.class);
38 // The implementation for each of these services is resolved by the OSGi Service Manager
39 private volatile ConfigurationService configurationService;
40 private volatile BridgeConfigurationManager bridgeConfigurationManager;
41 private volatile TenantNetworkManager tenantNetworkManager;
42 private volatile NetworkingProviderManager networkingProviderManager;
43 private volatile OvsdbConfigurationService ovsdbConfigurationService;
44 private volatile OvsdbConnectionService connectionService;
45 private volatile NeutronL3Adapter neutronL3Adapter;
48 this.triggerUpdates();
51 private SouthboundEvent.Type ovsdbTypeToSouthboundEventType(OvsdbType ovsdbType) {
52 SouthboundEvent.Type type = SouthboundEvent.Type.NODE;
56 type = SouthboundEvent.Type.NODE;
59 type = SouthboundEvent.Type.BRIDGE;
62 type = SouthboundEvent.Type.PORT;
65 type = SouthboundEvent.Type.CONTROLLER;
68 type = SouthboundEvent.Type.OPENVSWITCH;
71 logger.warn("Invalid OvsdbType: {}", ovsdbType);
78 public void ovsdbUpdate(Node node, OvsdbType ovsdbType, Action action) {
79 logger.info("ovsdbUpdate: {} - {} - {}", node, ovsdbType, action);
80 this.enqueueEvent(new SouthboundEvent(node, ovsdbTypeToSouthboundEventType(ovsdbType), action));
83 public void processOvsdbNodeUpdate(Node node, Action action) {
84 if (action == Action.ADD) {
85 logger.info("processOvsdbNodeUpdate {}", node);
86 bridgeConfigurationManager.prepareNode(node);
88 logger.info("Not implemented yet: {}", action);
92 private void processRowUpdate(Node node, String tableName, String uuid, Row row,
93 Object context, Action action) {
94 /* TODO SB_MIGRATION */
95 if (action == Action.DELETE) {
96 if (tableName.equalsIgnoreCase(ovsdbConfigurationService.getTableName(node, Interface.class))) {
97 logger.debug("Processing update of {}. Deleted node: {}, uuid: {}, row: {}", tableName, node, uuid, row);
98 Interface deletedIntf = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
99 NeutronNetwork network = null;
100 if (context == null) {
101 network = tenantNetworkManager.getTenantNetwork(deletedIntf);
103 network = (NeutronNetwork)context;
105 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
106 logger.info("Delete interface " + deletedIntf.getName());
108 if (deletedIntf.getTypeColumn().getData().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
109 deletedIntf.getTypeColumn().getData().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
110 phyIfName.contains(deletedIntf.getName())) {
111 /* delete tunnel interfaces or physical interfaces */
112 //this.handleInterfaceDelete(node, uuid, deletedIntf, false, null);
113 } else if (network != null && !network.getRouterExternal()) {
114 logger.debug("Processing update of {}:{} node {} intf {} network {}",
115 tableName, action, node, uuid, network.getNetworkUUID());
117 ConcurrentMap<String, Row> interfaces = this.ovsdbConfigurationService
118 .getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
119 if (interfaces != null) {
120 boolean isLastInstanceOnNode = true;
121 for (String intfUUID : interfaces.keySet()) {
122 if (intfUUID.equals(uuid)) continue;
123 Interface intf = this.ovsdbConfigurationService.getTypedRow(node, Interface.class, interfaces.get(intfUUID));
124 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(intf);
125 if (neutronNetwork != null && neutronNetwork.equals(network)) isLastInstanceOnNode = false;
127 //this.handleInterfaceDelete(node, uuid, deletedIntf, isLastInstanceOnNode, network);
129 } catch (Exception e) {
130 logger.error("Error fetching Interface Rows for node " + node, e);
134 } else if (tableName.equalsIgnoreCase(ovsdbConfigurationService.getTableName(node, OpenVSwitch.class))) {
135 logger.debug("Processing update of {}:{} node: {}, ovs uuid: {}, row: {}", tableName, action, node, uuid, row);
137 ConcurrentMap<String, Row> interfaces = this.ovsdbConfigurationService
138 .getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
139 if (interfaces != null) {
140 for (String intfUUID : interfaces.keySet()) {
141 Interface intf = ovsdbConfigurationService.getTypedRow(node, Interface.class, interfaces.get(intfUUID));
142 //this.handleInterfaceUpdate(node, intfUUID, intf);
145 } catch (Exception e) {
146 logger.error("Error fetching Interface Rows for node " + node, e);
151 private void handleInterfaceUpdate (Node node, OvsdbTerminationPointAugmentation tp) {
152 logger.trace("handleInterfaceUpdate node: {}, tp: {}", node, tp);
153 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(tp);
154 if (network != null && !network.getRouterExternal()) {
155 logger.trace("handleInterfaceUpdate node: {}, tp: {}, network: {}", node, tp, network.getNetworkUUID());
156 tenantNetworkManager.programInternalVlan(node, tp, network);
157 neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
158 if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
159 networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, tp);
162 logger.debug("No tenant network found on node: {} for interface: {}", node, tp);
166 private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode,
167 NeutronNetwork network) {
168 logger.debug("handleInterfaceDelete: node: {}, isLastInstanceOnNode: {}, interface: {}",
169 node, isLastInstanceOnNode, intf);
171 neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
172 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
173 if (isInterfaceOfInterest(intf, phyIfName)) {
174 /* delete tunnel or physical interfaces */
175 //networkingProviderManager.getProvider(node).handleInterfaceDelete(intf.getTypeColumn().getData(), null,
176 // node, intf, isLastInstanceOnNode);
177 } else if (network != null) {
178 if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) { /* vlan doesn't need a tunnel endpoint */
179 if (configurationService.getTunnelEndPoint(node) == null) {
180 logger.error("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table");
184 if (isLastInstanceOnNode & networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
185 tenantNetworkManager.reclaimInternalVlan(node, network);
187 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(), network, node, intf, isLastInstanceOnNode);
191 private void triggerUpdates() {
192 List<Node> nodes = connectionService.getNodes();
193 if (nodes == null) return;
194 for (Node node : nodes) {
195 OvsdbBridgeAugmentation bridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
196 if (bridge != null) {
197 processBridgeUpdate(node, bridge);
200 List<TerminationPoint> tps = MdsalUtils.getTerminationPoints(node);
201 for (TerminationPoint tp : tps) {
202 OvsdbTerminationPointAugmentation port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
204 processPortUpdate(node, port);
210 private void processInterfaceDelete(Node node, String portName, Object context, Action action) {
211 OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
212 MdsalUtils.getTerminationPointAugmentation(node, portName);
213 logger.debug("processInterfaceDelete {}: {}", node, portName);
214 NeutronNetwork network = null;
215 if (context == null) {
216 network = tenantNetworkManager.getTenantNetwork(ovsdbTerminationPointAugmentation);
218 network = (NeutronNetwork)context;
220 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
221 if (isInterfaceOfInterest(ovsdbTerminationPointAugmentation, phyIfName)) {
222 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, false, null);
223 } else if (network != null && !network.getRouterExternal()) {
224 logger.debug("Network {} : Delete interface {} attached to bridge {}", network.getNetworkUUID(),
225 ovsdbTerminationPointAugmentation.getInterfaceUuid(), node);
227 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class);
228 if (ovsdbBridgeAugmentation != null) {
229 List<TerminationPoint> terminationPoints = node.getTerminationPoint();
230 if(!terminationPoints.isEmpty()){
231 boolean isLastInstanceOnNode = true;
232 for(TerminationPoint terminationPoint : terminationPoints) {
233 OvsdbTerminationPointAugmentation tpAugmentation =
234 terminationPoint.getAugmentation( OvsdbTerminationPointAugmentation.class);
235 if(tpAugmentation.getInterfaceUuid().equals(ovsdbTerminationPointAugmentation.getInterfaceUuid())) continue;
236 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(tpAugmentation);
237 if (neutronNetwork != null && neutronNetwork.equals(network)) {
238 isLastInstanceOnNode = false;
242 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, isLastInstanceOnNode, network);
245 } catch (Exception e) {
246 logger.error("Error fetching Interface Rows for node " + node, e);
251 private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint, List<String> phyIfName) {
252 return (SouthboundMapper.createOvsdbInterfaceType(
253 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
255 SouthboundMapper.createOvsdbInterfaceType(
256 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE)
258 phyIfName.contains(terminationPoint.getName()));
262 * Notification about an OpenFlow Node
264 * @param openFlowNode the {@link Node Node} of interest in the notification
265 * @param action the {@link Action}
266 * @see NodeCacheListener#notifyNode
269 public void notifyNode (Node openFlowNode, Action action) {
270 logger.info("notifyNode: Node {} update {}", openFlowNode, action);
272 if (action.equals(Action.ADD)) {
273 networkingProviderManager.getProvider(openFlowNode).initializeOFFlowRules(openFlowNode);
280 * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
281 * @see EventDispatcher
284 public void processEvent(AbstractEvent abstractEvent) {
285 if (!(abstractEvent instanceof SouthboundEvent)) {
286 logger.error("Unable to process abstract event " + abstractEvent);
289 SouthboundEvent ev = (SouthboundEvent) abstractEvent;
290 logger.info("processEvent: {}", ev);
291 switch (ev.getType()) {
293 processOvsdbNodeUpdate(ev.getNode(), ev.getAction());
296 processBridgeUpdate(ev.getNode(), ev.getAction());
300 processPortUpdate(ev.getNode(), ev.getAction());
304 processOpenVSwitchUpdate(ev.getNode(), ev.getAction());
309 processRowUpdate(ev.getNode(), ev.getTableName(), ev.getUuid(), ev.getRow(),
310 ev.getContext(), ev.getAction());
311 } catch (Exception e) {
312 logger.error("Exception caught in ProcessRowUpdate for node " + ev.getNode(), e);
316 logger.warn("Unable to process type " + ev.getType() +
317 " action " + ev.getAction() + " for node " + ev.getNode());
322 private void processPortUpdate(Node node, Action action) {
326 processPortUpdate(node);
329 processPortDelete(node);
334 private void processPortDelete(Node node) {
337 private void processPortUpdate(Node node) {
338 List<TerminationPoint> terminationPoints = MdsalUtils.getTerminationPoints(node);
339 for (TerminationPoint terminationPoint : terminationPoints) {
340 processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class));
344 private void processOpenVSwitchUpdate(Node node, Action action) {
345 //do the work that rowUpdate(table=openvswith) would have done
348 private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port) {
349 logger.debug("processPortUpdate {} - {}", node, port);
350 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
351 if (network != null && !network.getRouterExternal()) {
352 this.handleInterfaceUpdate(node, port);
357 private void processBridgeUpdate(Node node, Action action) {
358 OvsdbBridgeAugmentation bridge = MdsalUtils.getBridge(node);
362 processBridgeUpdate(node, bridge);
365 processBridgeDelete(node, bridge);
370 private void processBridgeDelete(Node node, OvsdbBridgeAugmentation bridge) {
371 logger.debug("processBridgeUpdate {}, {}", node, bridge);
374 private void processBridgeUpdate(Node node, OvsdbBridgeAugmentation bridge) {
375 logger.debug("processBridgeUpdate {}, {}", node, bridge);