2 * Copyright (c) 2013, 2016 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.netvirt.openstack.netvirt;
11 import java.util.List;
13 import org.opendaylight.netvirt.openstack.netvirt.api.Action;
14 import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
15 import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
16 import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
17 import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
18 import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
19 import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheListener;
20 import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
21 import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryListener;
22 import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryService;
23 import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
24 import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
25 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
26 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
27 import org.opendaylight.netvirt.openstack.netvirt.impl.DistributedArpService;
28 import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
29 import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
35 import org.opendaylight.yangtools.yang.binding.DataObject;
36 import org.osgi.framework.ServiceReference;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * @author Madhu Venugopal
42 * @author Brent Salisbury
44 * @author Sam Hague (shague@redhat.com)
46 public class SouthboundHandler extends AbstractHandler
47 implements ConfigInterface, NodeCacheListener, OvsdbInventoryListener {
48 private static final Logger LOG = LoggerFactory.getLogger(SouthboundHandler.class);
50 // The implementation for each of these services is resolved by the OSGi Service Manager
51 private volatile ConfigurationService configurationService;
52 private volatile BridgeConfigurationManager bridgeConfigurationManager;
53 private volatile TenantNetworkManager tenantNetworkManager;
54 private volatile NetworkingProviderManager networkingProviderManager;
55 private volatile NeutronL3Adapter neutronL3Adapter;
56 private volatile DistributedArpService distributedArpService;
57 private volatile NodeCacheManager nodeCacheManager;
58 private volatile OvsdbInventoryService ovsdbInventoryService;
59 private volatile Southbound southbound;
61 private SouthboundEvent.Type ovsdbTypeToSouthboundEventType(OvsdbType ovsdbType) {
62 SouthboundEvent.Type type = SouthboundEvent.Type.NODE;
66 type = SouthboundEvent.Type.NODE;
69 type = SouthboundEvent.Type.BRIDGE;
72 type = SouthboundEvent.Type.PORT;
75 type = SouthboundEvent.Type.CONTROLLER;
78 type = SouthboundEvent.Type.OPENVSWITCH;
81 LOG.warn("Invalid OvsdbType: {}", ovsdbType);
88 public void ovsdbUpdate(Node node, DataObject resourceAugmentationData, OvsdbType ovsdbType, Action action) {
89 LOG.info("ovsdbUpdate: {} - {} - <<{}>> <<{}>>", ovsdbType, action, node, resourceAugmentationData);
90 enqueueEvent(new SouthboundEvent(node, resourceAugmentationData,
91 ovsdbTypeToSouthboundEventType(ovsdbType), action));
94 private void handleInterfaceUpdate (Node node, OvsdbTerminationPointAugmentation tp) {
95 LOG.debug("handleInterfaceUpdate <{}> <{}>", node, tp);
96 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(tp);
97 if (network != null && !network.getRouterExternal()) {
98 LOG.trace("handleInterfaceUpdate <{}> <{}> network: {}", node, tp, network.getNetworkUUID());
99 if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
100 networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, tp);
103 LOG.debug("No tenant network found on node: <{}> for interface: <{}>", node, tp);
105 distributedArpService.processInterfaceEvent(node, tp, network, Action.UPDATE);
106 neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
109 private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
110 boolean isLastInstanceOnNode, NeutronNetwork network) {
111 LOG.debug("handleInterfaceDelete: node: <{}>, isLastInstanceOnNode: {}, interface: <{}>",
112 node, isLastInstanceOnNode, intf);
114 distributedArpService.processInterfaceEvent(node, intf, network, Action.DELETE);
115 neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
116 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
117 if (isInterfaceOfInterest(intf, phyIfName)) {
118 // delete tunnel or physical interfaces
119 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
120 network, node, intf, isLastInstanceOnNode);
121 } else if (network != null) {
122 // vlan doesn't need a tunnel endpoint
123 if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN) &&
124 configurationService.getTunnelEndPoint(node) == null) {
125 LOG.error("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table");
128 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
129 network, node, intf, isLastInstanceOnNode);
134 public void triggerUpdates() {
135 LOG.info("triggerUpdates");
136 List<Node> ovsdbNodes = southbound.readOvsdbTopologyNodes();
137 for (Node node : ovsdbNodes) {
138 ovsdbUpdate(node, node.getAugmentation(OvsdbNodeAugmentation.class),
139 OvsdbInventoryListener.OvsdbType.NODE, Action.ADD);
143 private void processPortDelete(Node node, OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation,
145 LOG.debug("processPortDelete <{}> <{}>", node, ovsdbTerminationPointAugmentation);
146 NeutronNetwork network;
147 if (context == null) {
148 network = tenantNetworkManager.getTenantNetwork(ovsdbTerminationPointAugmentation);
150 network = (NeutronNetwork)context;
152 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
153 if (isInterfaceOfInterest(ovsdbTerminationPointAugmentation, phyIfName)) {
154 if (network != null) {
155 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, false, network);
157 LOG.warn("processPortDelete: network was null, ignoring update");
159 } else if (network != null && !network.getRouterExternal()) {
160 LOG.debug("Network {}: Delete interface {} attached to bridge {}", network.getNetworkUUID(),
161 ovsdbTerminationPointAugmentation.getInterfaceUuid(), node.getNodeId());
163 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(node);
164 if (ovsdbBridgeAugmentation != null) {
165 List<TerminationPoint> terminationPoints = node.getTerminationPoint();
166 if (!terminationPoints.isEmpty()){
167 boolean isLastInstanceOnNode = true;
168 for (TerminationPoint terminationPoint : terminationPoints) {
169 OvsdbTerminationPointAugmentation tpAugmentation =
170 terminationPoint.getAugmentation( OvsdbTerminationPointAugmentation.class);
171 if (tpAugmentation.getInterfaceUuid().equals(
172 ovsdbTerminationPointAugmentation.getInterfaceUuid())) {
175 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(tpAugmentation);
176 if (neutronNetwork != null) {
177 String neutronNetworkSegId = neutronNetwork.getProviderSegmentationID();
178 String networkSegId = network.getProviderSegmentationID();
179 // vxlan ports should not be removed in table 110 flow entry
180 // unless last VM instance removed from the openstack node(Bug# 5813)
181 if (neutronNetworkSegId.equals(networkSegId)) {
182 isLastInstanceOnNode = false;
187 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation,
188 isLastInstanceOnNode, network);
191 } catch (Exception e) {
192 LOG.error("Error fetching Interface Rows for node {}", node, e);
195 //remove neutronPort from the CleanupCache, if it has the entry.
196 NeutronPort neutronPort = null;
197 String neutronPortId = southbound.getInterfaceExternalIdsValue(ovsdbTerminationPointAugmentation,
198 Constants.EXTERNAL_ID_INTERFACE_ID);
199 if (neutronPortId != null) {
200 LOG.trace("Clean up the NeutronPortCache for {} ", neutronPortId);
201 neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId);
203 if (neutronPort != null) {
204 LOG.debug("Clean up the NeutronPortCache ");
205 neutronL3Adapter.removePortFromCleanupCache(neutronPort);
206 neutronL3Adapter.removeNetworkFromCleanupCache(neutronPort.getNetworkUUID());
208 LOG.trace("Nothing to Clean up in the NeutronPortCache ");
213 private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint, List<String> phyIfName) {
214 LOG.trace("SouthboundHandler#isInterfaceOfInterest: Interface : {}", terminationPoint);
216 if(terminationPoint.getInterfaceType() == null){
217 // This is OK since eth ports don't have an interface type
218 LOG.info("No type found for the interface : {}", terminationPoint);
221 return MdsalHelper.createOvsdbInterfaceType(
222 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
224 MdsalHelper.createOvsdbInterfaceType(
225 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE)
227 phyIfName.contains(terminationPoint.getName());
231 * Notification about an OpenFlow Node
233 * @param node the {@link Node Node} of interest in the notification
234 * @param action the {@link Action}
235 * @see NodeCacheListener#notifyNode
238 public void notifyNode (Node node, Action action) {
239 LOG.info("notifyNode: action: {}, Node <{}>", action, node);
241 if ((action.equals(Action.ADD)) && (southbound.getBridge(node) != null)) {
242 networkingProviderManager.getProvider(node).initializeOFFlowRules(node);
249 * @param abstractEvent the {@link AbstractEvent} event to be handled.
250 * @see EventDispatcher
253 public void processEvent(AbstractEvent abstractEvent) {
254 if (!(abstractEvent instanceof SouthboundEvent)) {
255 LOG.error("processEvent: Unable to process abstract event {}", abstractEvent);
258 SouthboundEvent ev = (SouthboundEvent) abstractEvent;
259 LOG.trace("processEvent ({}): {}", ev, ev.getTransactionId());
260 switch (ev.getType()) {
262 processOvsdbNodeEvent(ev);
266 processBridgeEvent(ev);
270 processPortEvent(ev);
274 processOpenVSwitchEvent(ev);
278 LOG.warn("Unable to process type {} action {} for node {}", ev.getType(), ev.getAction(), ev.getNode());
281 LOG.trace("processEvent exit ({}): {}", ev, ev.getTransactionId());
284 private void processOvsdbNodeEvent(SouthboundEvent ev) {
285 switch (ev.getAction()) {
287 processOvsdbNodeCreate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
290 processOvsdbNodeUpdate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
293 processOvsdbNodeDelete(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
298 private void processOvsdbNodeCreate(Node node, OvsdbNodeAugmentation ovsdbNode) {
299 LOG.info("processOvsdbNodeCreate <{}> <{}>", node, ovsdbNode);
300 nodeCacheManager.nodeAdded(node);
301 bridgeConfigurationManager.prepareNode(node);
304 private void processOvsdbNodeUpdate(Node node, OvsdbNodeAugmentation ovsdbNode) {
305 LOG.info("processOvsdbNodeUpdate <{}> <{}>", node, ovsdbNode);
306 nodeCacheManager.nodeAdded(node);
309 private void processOvsdbNodeDelete(Node node, OvsdbNodeAugmentation ovsdbNode) {
310 LOG.info("processOvsdbNodeDelete <{}> <{}>", node, ovsdbNode);
311 nodeCacheManager.nodeRemoved(node);
313 * I don't think we want to do this yet
314 InstanceIdentifier<Node> bridgeNodeIid =
315 MdsalHelper.createInstanceIdentifier(ovsdbNode.getConnectionInfo(),
316 Constants.INTEGRATION_BRIDGE);
317 southbound.delete(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid);
321 private void processPortEvent(SouthboundEvent ev) {
322 switch (ev.getAction()) {
325 processPortUpdate(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData());
328 processPortDelete(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData(), null);
333 private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port) {
334 LOG.debug("processPortUpdate <{}> <{}>", node, port);
335 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
336 if (network != null && !network.getRouterExternal()) {
337 this.handleInterfaceUpdate(node, port);
341 private void processOpenVSwitchEvent(SouthboundEvent ev) {
342 switch (ev.getAction()) {
345 processOpenVSwitchUpdate(ev.getNode());
352 private void processOpenVSwitchUpdate(Node node) {
353 LOG.debug("processOpenVSwitchUpdate {}", node);
354 // TODO this node might be the OvsdbNode and not have termination points
355 // Would need to change listener or grab tp nodes in here.
356 List<TerminationPoint> terminationPoints = southbound.extractTerminationPoints(node);
357 for (TerminationPoint terminationPoint : terminationPoints) {
358 processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class));
362 private void processBridgeEvent(SouthboundEvent ev) {
363 switch (ev.getAction()) {
365 processBridgeCreate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
368 processBridgeUpdate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
371 processBridgeDelete(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
376 private void processBridgeCreate(Node node, OvsdbBridgeAugmentation bridge) {
377 LOG.debug("processBridgeCreate <{}> <{}>", node, bridge);
378 String datapathId = southbound.getDatapathId(bridge);
379 // Having a datapathId means the ovsdb node has connected to ODL
380 if (datapathId != null) {
381 nodeCacheManager.nodeAdded(node);
383 LOG.info("processBridgeCreate datapathId not found");
387 private void processBridgeUpdate(Node node, OvsdbBridgeAugmentation bridge) {
388 LOG.debug("processBridgeUpdate <{}> <{}>", node, bridge);
389 String datapathId = southbound.getDatapathId(bridge);
390 // Having a datapathId means the ovsdb node has connected to ODL
391 if (datapathId != null) {
392 nodeCacheManager.nodeAdded(node);
394 LOG.info("processBridgeUpdate datapathId not found");
398 private void processBridgeDelete(Node node, OvsdbBridgeAugmentation bridge) {
399 LOG.debug("processBridgeDelete: Delete bridge from config data store: <{}> <{}>",
401 nodeCacheManager.nodeRemoved(node);
403 // Not sure if we want to do this yet
404 southbound.deleteBridge(node);
408 public void setDependencies(ServiceReference serviceReference) {
409 configurationService =
410 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
411 networkingProviderManager =
412 (NetworkingProviderManager) ServiceHelper.getGlobalInstance(NetworkingProviderManager.class, this);
413 tenantNetworkManager =
414 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
415 bridgeConfigurationManager =
416 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
418 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
419 nodeCacheManager.cacheListenerAdded(serviceReference, this);
421 (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
422 distributedArpService =
423 (DistributedArpService) ServiceHelper.getGlobalInstance(DistributedArpService.class, this);
425 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
427 (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
428 eventDispatcher.eventHandlerAdded(serviceReference, this);
429 ovsdbInventoryService =
430 (OvsdbInventoryService) ServiceHelper.getGlobalInstance(OvsdbInventoryService.class, this);
431 ovsdbInventoryService.listenerAdded(this);
435 public void setDependencies(Object impl) {