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;
12 import org.opendaylight.neutron.spi.NeutronNetwork;
13 import org.opendaylight.ovsdb.openstack.netvirt.api.*;
14 import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
15 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
19 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
20 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
21 import org.opendaylight.yangtools.yang.binding.DataObject;
22 import org.osgi.framework.BundleContext;
23 import org.osgi.framework.ServiceReference;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 * @author Madhu Venugopal
29 * @author Brent Salisbury
31 * @author Sam Hague (shague@redhat.com)
33 public class SouthboundHandler extends AbstractHandler
34 implements ConfigInterface, NodeCacheListener, OvsdbInventoryListener {
35 private static final Logger LOGGER = LoggerFactory.getLogger(SouthboundHandler.class);
37 // The implementation for each of these services is resolved by the OSGi Service Manager
38 private volatile ConfigurationService configurationService;
39 private volatile BridgeConfigurationManager bridgeConfigurationManager;
40 private volatile TenantNetworkManager tenantNetworkManager;
41 private volatile NetworkingProviderManager networkingProviderManager;
42 private volatile NeutronL3Adapter neutronL3Adapter;
43 private volatile NodeCacheManager nodeCacheManager;
44 private volatile OvsdbInventoryService ovsdbInventoryService;
45 private volatile Southbound southbound;
47 private SouthboundEvent.Type ovsdbTypeToSouthboundEventType(OvsdbType ovsdbType) {
48 SouthboundEvent.Type type = SouthboundEvent.Type.NODE;
52 type = SouthboundEvent.Type.NODE;
55 type = SouthboundEvent.Type.BRIDGE;
58 type = SouthboundEvent.Type.PORT;
61 type = SouthboundEvent.Type.CONTROLLER;
64 type = SouthboundEvent.Type.OPENVSWITCH;
67 LOGGER.warn("Invalid OvsdbType: {}", ovsdbType);
74 public void ovsdbUpdate(Node node, DataObject resourceAugmentationData, OvsdbType ovsdbType, Action action) {
75 LOGGER.info("ovsdbUpdate: {} - {} - <<{}>> <<{}>>", ovsdbType, action, node, resourceAugmentationData);
76 enqueueEvent(new SouthboundEvent(node, resourceAugmentationData,
77 ovsdbTypeToSouthboundEventType(ovsdbType), action));
80 private void handleInterfaceUpdate (Node node, OvsdbTerminationPointAugmentation tp) {
81 LOGGER.debug("handleInterfaceUpdate <{}> <{}>", node, tp);
82 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(tp);
83 if (network != null && !network.getRouterExternal()) {
84 LOGGER.trace("handleInterfaceUpdate <{}> <{}> network: {}", node, tp, network.getNetworkUUID());
85 if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
86 networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, tp);
89 LOGGER.debug("No tenant network found on node: <{}> for interface: <{}>", node, tp);
91 neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
94 private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
95 boolean isLastInstanceOnNode, NeutronNetwork network) {
96 LOGGER.debug("handleInterfaceDelete: node: <{}>, isLastInstanceOnNode: {}, interface: <{}>",
97 node, isLastInstanceOnNode, intf);
99 neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
100 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
101 if (isInterfaceOfInterest(intf, phyIfName)) {
102 // delete tunnel or physical interfaces
103 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
104 network, node, intf, isLastInstanceOnNode);
105 } else if (network != null) {
106 // vlan doesn't need a tunnel endpoint
107 if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN) &&
108 configurationService.getTunnelEndPoint(node) == null) {
109 LOGGER.error("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table");
112 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
113 network, node, intf, isLastInstanceOnNode);
118 public void triggerUpdates() {
119 LOGGER.info("triggerUpdates");
120 List<Node> ovsdbNodes = southbound.readOvsdbTopologyNodes();
121 for (Node node : ovsdbNodes) {
122 ovsdbUpdate(node, node.getAugmentation(OvsdbNodeAugmentation.class),
123 OvsdbInventoryListener.OvsdbType.NODE, Action.ADD);
127 private void processPortDelete(Node node, OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation,
129 LOGGER.debug("processPortDelete <{}> <{}>", node, ovsdbTerminationPointAugmentation);
130 NeutronNetwork network = null;
131 if (context == null) {
132 network = tenantNetworkManager.getTenantNetwork(ovsdbTerminationPointAugmentation);
134 network = (NeutronNetwork)context;
136 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
137 if (isInterfaceOfInterest(ovsdbTerminationPointAugmentation, phyIfName)) {
138 if (network != null) {
139 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, false, network);
141 LOGGER.warn("processPortDelete: network was null, ignoring update");
143 } else if (network != null && !network.getRouterExternal()) {
144 LOGGER.debug("Network {}: Delete interface {} attached to bridge {}", network.getNetworkUUID(),
145 ovsdbTerminationPointAugmentation.getInterfaceUuid(), node.getNodeId());
147 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(node);
148 if (ovsdbBridgeAugmentation != null) {
149 List<TerminationPoint> terminationPoints = node.getTerminationPoint();
150 if (!terminationPoints.isEmpty()){
151 boolean isLastInstanceOnNode = true;
152 for (TerminationPoint terminationPoint : terminationPoints) {
153 OvsdbTerminationPointAugmentation tpAugmentation =
154 terminationPoint.getAugmentation( OvsdbTerminationPointAugmentation.class);
155 if (tpAugmentation.getInterfaceUuid().equals(
156 ovsdbTerminationPointAugmentation.getInterfaceUuid())) {
159 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(tpAugmentation);
160 if (neutronNetwork != null && neutronNetwork.equals(network)) {
161 isLastInstanceOnNode = false;
165 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation,
166 isLastInstanceOnNode, network);
169 } catch (Exception e) {
170 LOGGER.error("Error fetching Interface Rows for node " + node, e);
175 private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint, List<String> phyIfName) {
176 LOGGER.trace("SouthboundHandler#isInterfaceOfInterest: Interface : {}", terminationPoint);
178 if(terminationPoint.getInterfaceType() == null){
179 // This is OK since eth ports don't have an interface type
180 LOGGER.info("No type found for the interface : {}", terminationPoint);
183 return MdsalHelper.createOvsdbInterfaceType(
184 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
186 MdsalHelper.createOvsdbInterfaceType(
187 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE)
189 phyIfName.contains(terminationPoint.getName());
193 * Notification about an OpenFlow Node
195 * @param node the {@link Node Node} of interest in the notification
196 * @param action the {@link Action}
197 * @see NodeCacheListener#notifyNode
200 public void notifyNode (Node node, Action action) {
201 LOGGER.info("notifyNode: action: {}, Node <{}>", action, node);
203 if ((action.equals(Action.ADD)) && (southbound.getBridge(node) != null)) {
204 networkingProviderManager.getProvider(node).initializeOFFlowRules(node);
211 * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
212 * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
215 public void processEvent(AbstractEvent abstractEvent) {
216 if (!(abstractEvent instanceof SouthboundEvent)) {
217 LOGGER.error("processEvent: Unable to process abstract event {}", abstractEvent);
220 SouthboundEvent ev = (SouthboundEvent) abstractEvent;
221 LOGGER.trace("processEvent: {}", ev);
222 switch (ev.getType()) {
224 processOvsdbNodeEvent(ev);
228 processBridgeEvent(ev);
232 processPortEvent(ev);
236 processOpenVSwitchEvent(ev);
240 LOGGER.warn("Unable to process type " + ev.getType() +
241 " action " + ev.getAction() + " for node " + ev.getNode());
246 private void processOvsdbNodeEvent(SouthboundEvent ev) {
247 switch (ev.getAction()) {
249 processOvsdbNodeCreate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
252 processOvsdbNodeUpdate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
255 processOvsdbNodeDelete(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
260 private void processOvsdbNodeCreate(Node node, OvsdbNodeAugmentation ovsdbNode) {
261 LOGGER.info("processOvsdbNodeCreate <{}> <{}>", node, ovsdbNode);
262 nodeCacheManager.nodeAdded(node);
263 bridgeConfigurationManager.prepareNode(node);
266 private void processOvsdbNodeUpdate(Node node, OvsdbNodeAugmentation ovsdbNode) {
267 LOGGER.info("processOvsdbNodeUpdate <{}> <{}>", node, ovsdbNode);
268 nodeCacheManager.nodeAdded(node);
271 private void processOvsdbNodeDelete(Node node, OvsdbNodeAugmentation ovsdbNode) {
272 LOGGER.info("processOvsdbNodeDelete <{}> <{}>", node, ovsdbNode);
273 nodeCacheManager.nodeRemoved(node);
275 * I don't think we want to do this yet
276 InstanceIdentifier<Node> bridgeNodeIid =
277 MdsalHelper.createInstanceIdentifier(ovsdbNode.getConnectionInfo(),
278 Constants.INTEGRATION_BRIDGE);
279 southbound.delete(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid);
283 private void processPortEvent(SouthboundEvent ev) {
284 switch (ev.getAction()) {
287 processPortUpdate(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData());
290 processPortDelete(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData(), null);
295 private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port) {
296 LOGGER.debug("processPortUpdate <{}> <{}>", node, port);
297 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
298 if (network != null && !network.getRouterExternal()) {
299 this.handleInterfaceUpdate(node, port);
303 private void processOpenVSwitchEvent(SouthboundEvent ev) {
304 switch (ev.getAction()) {
307 processOpenVSwitchUpdate(ev.getNode());
314 private void processOpenVSwitchUpdate(Node node) {
315 LOGGER.debug("processOpenVSwitchUpdate {}", node);
316 // TODO this node might be the OvsdbNode and not have termination points
317 // Would need to change listener or grab tp nodes in here.
318 List<TerminationPoint> terminationPoints = southbound.extractTerminationPoints(node);
319 for (TerminationPoint terminationPoint : terminationPoints) {
320 processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class));
324 private void processBridgeEvent(SouthboundEvent ev) {
325 switch (ev.getAction()) {
327 processBridgeCreate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
330 processBridgeUpdate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
333 processBridgeDelete(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
338 private boolean isMainBridge(Node node, OvsdbBridgeAugmentation bridge) {
340 String nodeIdStr = node.getNodeId().getValue();
341 String bridgeName = nodeIdStr.substring(nodeIdStr.lastIndexOf('/') + 1);
342 List<TerminationPoint> terminationPoints = southbound.extractTerminationPoints(node);
343 if (terminationPoints != null && terminationPoints.size() == 1) {
344 // TODO: Either do something or remove this if statement.
345 // If there's only one termination point, is it a 1-port bridge?
347 OvsdbTerminationPointAugmentation port = southbound.extractTerminationPointAugmentation(node, bridgeName);
349 String datapathId = southbound.getDatapathId(bridge);
350 // Having a datapathId means the ovsdb node has connected to ODL
351 if (datapathId != null) {
354 LOGGER.info("datapathId not found");
360 private void processBridgeCreate(Node node, OvsdbBridgeAugmentation bridge) {
361 LOGGER.debug("processBridgeCreate <{}> <{}>", node, bridge);
362 String datapathId = southbound.getDatapathId(bridge);
363 // Having a datapathId means the ovsdb node has connected to ODL
364 if (datapathId != null) {
365 nodeCacheManager.nodeAdded(node);
367 LOGGER.info("processBridgeCreate datapathId not found");
371 private void processBridgeUpdate(Node node, OvsdbBridgeAugmentation bridge) {
372 LOGGER.debug("processBridgeUpdate <{}> <{}>", node, bridge);
373 String datapathId = southbound.getDatapathId(bridge);
374 // Having a datapathId means the ovsdb node has connected to ODL
375 if (datapathId != null) {
376 nodeCacheManager.nodeAdded(node);
378 LOGGER.info("processBridgeUpdate datapathId not found");
382 private void processBridgeDelete(Node node, OvsdbBridgeAugmentation bridge) {
383 LOGGER.debug("processBridgeDelete: Delete bridge from config data store: <{}> <{}>",
385 nodeCacheManager.nodeRemoved(node);
387 // Not sure if we want to do this yet
388 southbound.deleteBridge(node);
392 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
393 configurationService =
394 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
395 networkingProviderManager =
396 (NetworkingProviderManager) ServiceHelper.getGlobalInstance(NetworkingProviderManager.class, this);
397 tenantNetworkManager =
398 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
399 bridgeConfigurationManager =
400 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
402 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
403 nodeCacheManager.cacheListenerAdded(
404 bundleContext.getServiceReference(OvsdbInventoryListener.class.getName()), this);
406 (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
408 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
410 (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
411 eventDispatcher.eventHandlerAdded(
412 bundleContext.getServiceReference(OvsdbInventoryListener.class.getName()), this);
413 ovsdbInventoryService =
414 (OvsdbInventoryService) ServiceHelper.getGlobalInstance(OvsdbInventoryService.class, this);
415 ovsdbInventoryService.listenerAdded(this);
419 public void setDependencies(Object impl) {