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 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 = null;
44 private volatile EventDispatcher eventDispatcher;
45 private volatile OvsdbInventoryService ovsdbInventoryService;
48 this.triggerUpdates();
52 logger.info(">>>>>> init {}", this.getClass());
55 private SouthboundEvent.Type ovsdbTypeToSouthboundEventType(OvsdbType ovsdbType) {
56 SouthboundEvent.Type type = SouthboundEvent.Type.NODE;
60 type = SouthboundEvent.Type.NODE;
63 type = SouthboundEvent.Type.BRIDGE;
66 type = SouthboundEvent.Type.PORT;
69 type = SouthboundEvent.Type.CONTROLLER;
72 type = SouthboundEvent.Type.OPENVSWITCH;
75 logger.warn("Invalid OvsdbType: {}", ovsdbType);
82 public void ovsdbUpdate(Node node, DataObject resourceAugmentationData, OvsdbType ovsdbType, Action action) {
83 logger.info("ovsdbUpdate: {} - {} - <<{}>> <<{}>>", ovsdbType, action, node, resourceAugmentationData);
84 enqueueEvent(new SouthboundEvent(node, resourceAugmentationData,
85 ovsdbTypeToSouthboundEventType(ovsdbType), action));
88 private void handleInterfaceUpdate (Node node, OvsdbTerminationPointAugmentation tp) {
89 logger.debug("handleInterfaceUpdate <{}> <{}>", node, tp);
90 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(tp);
91 if (network != null && !network.getRouterExternal()) {
92 logger.trace("handleInterfaceUpdate <{}> <{}> network: {}", node, tp, network.getNetworkUUID());
93 neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
94 if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
95 networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, tp);
98 logger.debug("No tenant network found on node: <{}> for interface: <{}>", node, tp);
102 private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
103 boolean isLastInstanceOnNode, NeutronNetwork network) {
104 logger.debug("handleInterfaceDelete: node: <{}>, isLastInstanceOnNode: {}, interface: <{}>",
105 node, isLastInstanceOnNode, intf);
107 neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
108 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
109 if (isInterfaceOfInterest(intf, phyIfName)) {
110 // delete tunnel or physical interfaces
111 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
112 network, node, intf, isLastInstanceOnNode);
113 } else if (network != null) {
114 // vlan doesn't need a tunnel endpoint
115 if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
116 if (configurationService.getTunnelEndPoint(node) == null) {
117 logger.error("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table");
121 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
122 network, node, intf, isLastInstanceOnNode);
126 private void triggerUpdates() {
127 List<Node> nodes = null; // nodeCacheManager.getBridgeNodes();
128 if (nodes == null) return;
129 for (Node node : nodes) {
130 OvsdbBridgeAugmentation bridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
131 if (bridge != null) {
132 processBridgeUpdate(node, bridge);
135 List<TerminationPoint> tps = MdsalUtils.extractTerminationPoints(node);
136 for (TerminationPoint tp : tps) {
137 OvsdbTerminationPointAugmentation port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
139 processPortUpdate(node, port);
145 private void processPortDelete(Node node, OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation,
147 logger.debug("processPortDelete <{}> <{}>", node, ovsdbTerminationPointAugmentation);
148 NeutronNetwork network = null;
149 if (context == null) {
150 network = tenantNetworkManager.getTenantNetwork(ovsdbTerminationPointAugmentation);
152 network = (NeutronNetwork)context;
154 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
155 if (isInterfaceOfInterest(ovsdbTerminationPointAugmentation, phyIfName)) {
156 if (network != null) {
157 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, false, network);
159 logger.warn("processPortDelete: network was null, ignoring update");
161 } else if (network != null && !network.getRouterExternal()) {
162 logger.debug("Network {}: Delete interface {} attached to bridge {}", network.getNetworkUUID(),
163 ovsdbTerminationPointAugmentation.getInterfaceUuid(), node.getNodeId());
165 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = MdsalUtils.getBridge(node);
166 if (ovsdbBridgeAugmentation != null) {
167 List<TerminationPoint> terminationPoints = node.getTerminationPoint();
168 if (!terminationPoints.isEmpty()){
169 boolean isLastInstanceOnNode = true;
170 for (TerminationPoint terminationPoint : terminationPoints) {
171 OvsdbTerminationPointAugmentation tpAugmentation =
172 terminationPoint.getAugmentation( OvsdbTerminationPointAugmentation.class);
173 if (tpAugmentation.getInterfaceUuid().equals(
174 ovsdbTerminationPointAugmentation.getInterfaceUuid())) {
177 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(tpAugmentation);
178 if (neutronNetwork != null && neutronNetwork.equals(network)) {
179 isLastInstanceOnNode = false;
183 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation,
184 isLastInstanceOnNode, network);
187 } catch (Exception e) {
188 logger.error("Error fetching Interface Rows for node " + node, e);
193 private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint, List<String> phyIfName) {
194 logger.trace("SouthboundHandler#isInterfaceOfInterest: Interface : {}", terminationPoint);
196 if(terminationPoint.getInterfaceType() == null){
197 // This is OK since eth ports don't have an interface type
198 logger.info("No type found for the interface : {}", terminationPoint);
201 return (MdsalHelper.createOvsdbInterfaceType(
202 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
204 MdsalHelper.createOvsdbInterfaceType(
205 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE)
207 phyIfName.contains(terminationPoint.getName()));
211 * Notification about an OpenFlow Node
213 * @param node the {@link Node Node} of interest in the notification
214 * @param action the {@link Action}
215 * @see NodeCacheListener#notifyNode
218 public void notifyNode (Node node, Action action) {
219 logger.info("notifyNode: action: {}, Node <{}>", action, node);
221 if (action.equals(Action.ADD)) {
222 if (MdsalUtils.getBridge(node) != null) {
223 networkingProviderManager.getProvider(node).initializeOFFlowRules(node);
231 * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
232 * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
235 public void processEvent(AbstractEvent abstractEvent) {
236 if (!(abstractEvent instanceof SouthboundEvent)) {
237 logger.error("processEvent: Unable to process abstract event {}", abstractEvent);
240 SouthboundEvent ev = (SouthboundEvent) abstractEvent;
241 logger.trace("processEvent: {}", ev);
242 switch (ev.getType()) {
244 processOvsdbNodeEvent(ev);
248 processBridgeEvent(ev);
252 processPortEvent(ev);
256 processOpenVSwitchEvent(ev);
260 logger.warn("Unable to process type " + ev.getType() +
261 " action " + ev.getAction() + " for node " + ev.getNode());
266 private void processOvsdbNodeEvent(SouthboundEvent ev) {
267 switch (ev.getAction()) {
269 processOvsdbNodeCreate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
272 processOvsdbNodeUpdate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
275 processOvsdbNodeDelete(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
280 private void processOvsdbNodeCreate(Node node, OvsdbNodeAugmentation ovsdbNode) {
281 logger.info("processOvsdbNodeCreate <{}> <{}>", node, ovsdbNode);
282 nodeCacheManager.nodeAdded(node);
283 bridgeConfigurationManager.prepareNode(node);
286 private void processOvsdbNodeUpdate(Node node, OvsdbNodeAugmentation ovsdbNode) {
287 logger.info("processOvsdbNodeUpdate <{}> <{}>", node, ovsdbNode);
288 nodeCacheManager.nodeAdded(node);
291 private void processOvsdbNodeDelete(Node node, OvsdbNodeAugmentation ovsdbNode) {
292 logger.info("processOvsdbNodeDelete <{}> <{}>", node, ovsdbNode);
293 nodeCacheManager.nodeRemoved(node);
295 * I don't think we want to do this yet
296 InstanceIdentifier<Node> bridgeNodeIid =
297 MdsalHelper.createInstanceIdentifier(ovsdbNode.getConnectionInfo(),
298 Constants.INTEGRATION_BRIDGE);
299 MdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid);
303 private void processPortEvent(SouthboundEvent ev) {
304 switch (ev.getAction()) {
307 processPortUpdate(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData());
310 processPortDelete(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData(), null);
315 private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port) {
316 logger.debug("processPortUpdate <{}> <{}>", node, port);
317 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
318 if (network != null && !network.getRouterExternal()) {
319 this.handleInterfaceUpdate(node, port);
323 private void processOpenVSwitchEvent(SouthboundEvent ev) {
324 switch (ev.getAction()) {
327 processOpenVSwitchUpdate(ev.getNode());
334 private void processOpenVSwitchUpdate(Node node) {
335 logger.debug("processOpenVSwitchUpdate {}", node);
336 // TODO this node might be the OvsdbNode and not have termination points
337 // Would need to change listener or grab tp nodes in here.
338 List<TerminationPoint> terminationPoints = MdsalUtils.extractTerminationPoints(node);
339 for (TerminationPoint terminationPoint : terminationPoints) {
340 processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class));
344 private void processBridgeEvent(SouthboundEvent ev) {
345 switch (ev.getAction()) {
347 processBridgeCreate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
350 processBridgeUpdate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
353 processBridgeDelete(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
358 private boolean isMainBridge(Node node, OvsdbBridgeAugmentation bridge) {
360 String nodeIdStr = node.getNodeId().getValue();
361 String bridgeName = nodeIdStr.substring(nodeIdStr.lastIndexOf('/') + 1);
362 List<TerminationPoint> terminationPoints = MdsalUtils.extractTerminationPoints(node);
363 if (terminationPoints != null && terminationPoints.size() == 1) {
365 OvsdbTerminationPointAugmentation port = MdsalUtils.extractTerminationPointAugmentation(node, bridgeName);
367 String datapathId = MdsalUtils.getDatapathId(bridge);
368 // Having a datapathId means the ovsdb node has connected to ODL
369 if (datapathId != null) {
372 logger.info("datapathId not found");
378 private void processBridgeCreate(Node node, OvsdbBridgeAugmentation bridge) {
379 logger.debug("processBridgeCreate <{}> <{}>", node, bridge);
380 String datapathId = MdsalUtils.getDatapathId(bridge);
381 // Having a datapathId means the ovsdb node has connected to ODL
382 if (datapathId != null) {
383 nodeCacheManager.nodeAdded(node);
385 logger.info("processBridgeCreate datapathId not found");
389 private void processBridgeUpdate(Node node, OvsdbBridgeAugmentation bridge) {
390 logger.debug("processBridgeUpdate <{}> <{}>", node, bridge);
391 String datapathId = MdsalUtils.getDatapathId(bridge);
392 // Having a datapathId means the ovsdb node has connected to ODL
393 if (datapathId != null) {
394 nodeCacheManager.nodeAdded(node);
396 logger.info("processBridgeUpdate datapathId not found");
400 private void processBridgeDelete(Node node, OvsdbBridgeAugmentation bridge) {
401 logger.debug("processBridgeDelete: Delete bridge from config data store: <{}> <{}>",
403 nodeCacheManager.nodeRemoved(node);
405 // Not sure if we want to do this yet
406 MdsalUtils.deleteBridge(node);
410 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
411 configurationService =
412 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
413 networkingProviderManager =
414 (NetworkingProviderManager) ServiceHelper.getGlobalInstance(NetworkingProviderManager.class, this);
415 tenantNetworkManager =
416 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
417 bridgeConfigurationManager =
418 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
420 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
421 nodeCacheManager.cacheListenerAdded(
422 bundleContext.getServiceReference(OvsdbInventoryListener.class.getName()), this);
424 (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
426 (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
427 eventDispatcher.eventHandlerAdded(
428 bundleContext.getServiceReference(OvsdbInventoryListener.class.getName()), this);
429 super.setDispatcher(eventDispatcher);
430 ovsdbInventoryService =
431 (OvsdbInventoryService) ServiceHelper.getGlobalInstance(OvsdbInventoryService.class, this);
432 ovsdbInventoryService.listenerAdded(this);
436 public void setDependencies(Object impl) {}