2 * Copyright (c) 2013, 2015 Red Hat, Inc. and others. All rights reserved.
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
9 package org.opendaylight.ovsdb.openstack.netvirt;
11 import java.util.List;
13 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
14 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
15 import org.opendaylight.ovsdb.openstack.netvirt.api.*;
16 import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
17 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
21 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
22 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
23 import org.opendaylight.yangtools.yang.binding.DataObject;
24 import org.osgi.framework.ServiceReference;
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 ConfigInterface, NodeCacheListener, OvsdbInventoryListener {
36 private static final Logger LOG = 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 NeutronL3Adapter neutronL3Adapter;
44 private volatile NodeCacheManager nodeCacheManager;
45 private volatile OvsdbInventoryService ovsdbInventoryService;
46 private volatile Southbound southbound;
48 private SouthboundEvent.Type ovsdbTypeToSouthboundEventType(OvsdbType ovsdbType) {
49 SouthboundEvent.Type type = SouthboundEvent.Type.NODE;
53 type = SouthboundEvent.Type.NODE;
56 type = SouthboundEvent.Type.BRIDGE;
59 type = SouthboundEvent.Type.PORT;
62 type = SouthboundEvent.Type.CONTROLLER;
65 type = SouthboundEvent.Type.OPENVSWITCH;
68 LOG.warn("Invalid OvsdbType: {}", ovsdbType);
75 public void ovsdbUpdate(Node node, DataObject resourceAugmentationData, OvsdbType ovsdbType, Action action) {
76 LOG.info("ovsdbUpdate: {} - {} - <<{}>> <<{}>>", ovsdbType, action, node, resourceAugmentationData);
77 enqueueEvent(new SouthboundEvent(node, resourceAugmentationData,
78 ovsdbTypeToSouthboundEventType(ovsdbType), action));
81 private void handleInterfaceUpdate (Node node, OvsdbTerminationPointAugmentation tp) {
82 LOG.debug("handleInterfaceUpdate <{}> <{}>", node, tp);
83 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(tp);
84 if (network != null && !network.getRouterExternal()) {
85 LOG.trace("handleInterfaceUpdate <{}> <{}> network: {}", node, tp, network.getNetworkUUID());
86 if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
87 networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, tp);
90 LOG.debug("No tenant network found on node: <{}> for interface: <{}>", node, tp);
92 neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
95 private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
96 boolean isLastInstanceOnNode, NeutronNetwork network) {
97 LOG.debug("handleInterfaceDelete: node: <{}>, isLastInstanceOnNode: {}, interface: <{}>",
98 node, isLastInstanceOnNode, intf);
100 neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
101 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
102 if (isInterfaceOfInterest(intf, phyIfName)) {
103 // delete tunnel or physical interfaces
104 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
105 network, node, intf, isLastInstanceOnNode);
106 } else if (network != null) {
107 // vlan doesn't need a tunnel endpoint
108 if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN) &&
109 configurationService.getTunnelEndPoint(node) == null) {
110 LOG.error("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table");
113 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
114 network, node, intf, isLastInstanceOnNode);
119 public void triggerUpdates() {
120 LOG.info("triggerUpdates");
121 List<Node> ovsdbNodes = southbound.readOvsdbTopologyNodes();
122 for (Node node : ovsdbNodes) {
123 ovsdbUpdate(node, node.getAugmentation(OvsdbNodeAugmentation.class),
124 OvsdbInventoryListener.OvsdbType.NODE, Action.ADD);
128 private void processPortDelete(Node node, OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation,
130 LOG.debug("processPortDelete <{}> <{}>", node, ovsdbTerminationPointAugmentation);
131 NeutronNetwork network;
132 if (context == null) {
133 network = tenantNetworkManager.getTenantNetwork(ovsdbTerminationPointAugmentation);
135 network = (NeutronNetwork)context;
137 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
138 if (isInterfaceOfInterest(ovsdbTerminationPointAugmentation, phyIfName)) {
139 if (network != null) {
140 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, false, network);
142 LOG.warn("processPortDelete: network was null, ignoring update");
144 } else if (network != null && !network.getRouterExternal()) {
145 LOG.debug("Network {}: Delete interface {} attached to bridge {}", network.getNetworkUUID(),
146 ovsdbTerminationPointAugmentation.getInterfaceUuid(), node.getNodeId());
148 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(node);
149 if (ovsdbBridgeAugmentation != null) {
150 List<TerminationPoint> terminationPoints = node.getTerminationPoint();
151 if (!terminationPoints.isEmpty()){
152 boolean isLastInstanceOnNode = true;
153 for (TerminationPoint terminationPoint : terminationPoints) {
154 OvsdbTerminationPointAugmentation tpAugmentation =
155 terminationPoint.getAugmentation( OvsdbTerminationPointAugmentation.class);
156 if (tpAugmentation.getInterfaceUuid().equals(
157 ovsdbTerminationPointAugmentation.getInterfaceUuid())) {
160 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(tpAugmentation);
161 if (neutronNetwork != null && neutronNetwork.equals(network)) {
162 isLastInstanceOnNode = false;
166 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation,
167 isLastInstanceOnNode, network);
170 } catch (Exception e) {
171 LOG.error("Error fetching Interface Rows for node {}", node, e);
174 //remove neutronPort from the CleanupCache, if it has the entry.
175 NeutronPort neutronPort = null;
176 String neutronPortId = southbound.getInterfaceExternalIdsValue(ovsdbTerminationPointAugmentation,
177 Constants.EXTERNAL_ID_INTERFACE_ID);
178 if (neutronPortId != null) {
179 LOG.trace("Clean up the NeutronPortCache for {} ", neutronPortId);
180 neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId);
182 if (neutronPort != null) {
183 LOG.debug("Clean up the NeutronPortCache ");
184 neutronL3Adapter.removePortFromCleanupCache(neutronPort);
186 LOG.trace("Nothing to Clean up in the NeutronPortCache ");
191 private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint, List<String> phyIfName) {
192 LOG.trace("SouthboundHandler#isInterfaceOfInterest: Interface : {}", terminationPoint);
194 if(terminationPoint.getInterfaceType() == null){
195 // This is OK since eth ports don't have an interface type
196 LOG.info("No type found for the interface : {}", terminationPoint);
199 return MdsalHelper.createOvsdbInterfaceType(
200 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
202 MdsalHelper.createOvsdbInterfaceType(
203 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE)
205 phyIfName.contains(terminationPoint.getName());
209 * Notification about an OpenFlow Node
211 * @param node the {@link Node Node} of interest in the notification
212 * @param action the {@link Action}
213 * @see NodeCacheListener#notifyNode
216 public void notifyNode (Node node, Action action) {
217 LOG.info("notifyNode: action: {}, Node <{}>", action, node);
219 if ((action.equals(Action.ADD)) && (southbound.getBridge(node) != null)) {
220 networkingProviderManager.getProvider(node).initializeOFFlowRules(node);
227 * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
228 * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
231 public void processEvent(AbstractEvent abstractEvent) {
232 if (!(abstractEvent instanceof SouthboundEvent)) {
233 LOG.error("processEvent: Unable to process abstract event {}", abstractEvent);
236 SouthboundEvent ev = (SouthboundEvent) abstractEvent;
237 LOG.trace("processEvent ({}): {}", ev, ev.getTransactionId());
238 switch (ev.getType()) {
240 processOvsdbNodeEvent(ev);
244 processBridgeEvent(ev);
248 processPortEvent(ev);
252 processOpenVSwitchEvent(ev);
256 LOG.warn("Unable to process type {} action {} for node {}", ev.getType(), ev.getAction(), ev.getNode());
259 LOG.trace("processEvent exit ({}): {}", ev, ev.getTransactionId());
262 private void processOvsdbNodeEvent(SouthboundEvent ev) {
263 switch (ev.getAction()) {
265 processOvsdbNodeCreate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
268 processOvsdbNodeUpdate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
271 processOvsdbNodeDelete(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
276 private void processOvsdbNodeCreate(Node node, OvsdbNodeAugmentation ovsdbNode) {
277 LOG.info("processOvsdbNodeCreate <{}> <{}>", node, ovsdbNode);
278 nodeCacheManager.nodeAdded(node);
279 bridgeConfigurationManager.prepareNode(node);
282 private void processOvsdbNodeUpdate(Node node, OvsdbNodeAugmentation ovsdbNode) {
283 LOG.info("processOvsdbNodeUpdate <{}> <{}>", node, ovsdbNode);
284 nodeCacheManager.nodeAdded(node);
287 private void processOvsdbNodeDelete(Node node, OvsdbNodeAugmentation ovsdbNode) {
288 LOG.info("processOvsdbNodeDelete <{}> <{}>", node, ovsdbNode);
289 nodeCacheManager.nodeRemoved(node);
291 * I don't think we want to do this yet
292 InstanceIdentifier<Node> bridgeNodeIid =
293 MdsalHelper.createInstanceIdentifier(ovsdbNode.getConnectionInfo(),
294 Constants.INTEGRATION_BRIDGE);
295 southbound.delete(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid);
299 private void processPortEvent(SouthboundEvent ev) {
300 switch (ev.getAction()) {
303 processPortUpdate(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData());
306 processPortDelete(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData(), null);
311 private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port) {
312 LOG.debug("processPortUpdate <{}> <{}>", node, port);
313 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
314 if (network != null && !network.getRouterExternal()) {
315 this.handleInterfaceUpdate(node, port);
319 private void processOpenVSwitchEvent(SouthboundEvent ev) {
320 switch (ev.getAction()) {
323 processOpenVSwitchUpdate(ev.getNode());
330 private void processOpenVSwitchUpdate(Node node) {
331 LOG.debug("processOpenVSwitchUpdate {}", node);
332 // TODO this node might be the OvsdbNode and not have termination points
333 // Would need to change listener or grab tp nodes in here.
334 List<TerminationPoint> terminationPoints = southbound.extractTerminationPoints(node);
335 for (TerminationPoint terminationPoint : terminationPoints) {
336 processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class));
340 private void processBridgeEvent(SouthboundEvent ev) {
341 switch (ev.getAction()) {
343 processBridgeCreate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
346 processBridgeUpdate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
349 processBridgeDelete(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
354 private void processBridgeCreate(Node node, OvsdbBridgeAugmentation bridge) {
355 LOG.debug("processBridgeCreate <{}> <{}>", node, bridge);
356 String datapathId = southbound.getDatapathId(bridge);
357 // Having a datapathId means the ovsdb node has connected to ODL
358 if (datapathId != null) {
359 nodeCacheManager.nodeAdded(node);
361 LOG.info("processBridgeCreate datapathId not found");
365 private void processBridgeUpdate(Node node, OvsdbBridgeAugmentation bridge) {
366 LOG.debug("processBridgeUpdate <{}> <{}>", node, bridge);
367 String datapathId = southbound.getDatapathId(bridge);
368 // Having a datapathId means the ovsdb node has connected to ODL
369 if (datapathId != null) {
370 nodeCacheManager.nodeAdded(node);
372 LOG.info("processBridgeUpdate datapathId not found");
376 private void processBridgeDelete(Node node, OvsdbBridgeAugmentation bridge) {
377 LOG.debug("processBridgeDelete: Delete bridge from config data store: <{}> <{}>",
379 nodeCacheManager.nodeRemoved(node);
381 // Not sure if we want to do this yet
382 southbound.deleteBridge(node);
386 public void setDependencies(ServiceReference serviceReference) {
387 configurationService =
388 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
389 networkingProviderManager =
390 (NetworkingProviderManager) ServiceHelper.getGlobalInstance(NetworkingProviderManager.class, this);
391 tenantNetworkManager =
392 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
393 bridgeConfigurationManager =
394 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
396 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
397 nodeCacheManager.cacheListenerAdded(serviceReference, this);
399 (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
401 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
403 (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
404 eventDispatcher.eventHandlerAdded(serviceReference, this);
405 ovsdbInventoryService =
406 (OvsdbInventoryService) ServiceHelper.getGlobalInstance(OvsdbInventoryService.class, this);
407 ovsdbInventoryService.listenerAdded(this);
411 public void setDependencies(Object impl) {