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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
18 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
19 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
20 import org.opendaylight.yangtools.yang.binding.DataObject;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
25 * @author Madhu Venugopal
26 * @author Brent Salisbury
28 * @author Sam Hague (shague@redhat.com)
30 public class SouthboundHandler extends AbstractHandler
31 implements NodeCacheListener, OvsdbInventoryListener {
32 static final Logger logger = LoggerFactory.getLogger(SouthboundHandler.class);
34 // The implementation for each of these services is resolved by the OSGi Service Manager
35 private volatile ConfigurationService configurationService;
36 private volatile BridgeConfigurationManager bridgeConfigurationManager;
37 private volatile TenantNetworkManager tenantNetworkManager;
38 private volatile NetworkingProviderManager networkingProviderManager;
39 private volatile NeutronL3Adapter neutronL3Adapter;
40 private volatile NodeCacheManager nodeCacheManager = null;
43 this.triggerUpdates();
47 logger.info(">>>>>> init {}", this.getClass());
50 private SouthboundEvent.Type ovsdbTypeToSouthboundEventType(OvsdbType ovsdbType) {
51 SouthboundEvent.Type type = SouthboundEvent.Type.NODE;
55 type = SouthboundEvent.Type.NODE;
58 type = SouthboundEvent.Type.BRIDGE;
61 type = SouthboundEvent.Type.PORT;
64 type = SouthboundEvent.Type.CONTROLLER;
67 type = SouthboundEvent.Type.OPENVSWITCH;
70 logger.warn("Invalid OvsdbType: {}", ovsdbType);
77 public void ovsdbUpdate(Node node, DataObject resourceAugmentationData, OvsdbType ovsdbType, Action action) {
78 logger.info("ovsdbUpdate: {} - {} - <<{}>> <<{}>>", ovsdbType, action, node, resourceAugmentationData);
79 this.enqueueEvent(new SouthboundEvent(node, resourceAugmentationData,
80 ovsdbTypeToSouthboundEventType(ovsdbType), action));
83 private void handleInterfaceUpdate (Node node, OvsdbTerminationPointAugmentation tp) {
84 logger.debug("handleInterfaceUpdate <{}> <{}>", node, tp);
85 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(tp);
86 if (network != null && !network.getRouterExternal()) {
87 logger.trace("handleInterfaceUpdate <{}> <{}> network: {}", node, tp, network.getNetworkUUID());
88 neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
89 if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
90 networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, tp);
93 logger.debug("No tenant network found on node: <{}> for interface: <{}>", node, tp);
97 private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
98 boolean isLastInstanceOnNode, NeutronNetwork network) {
99 logger.debug("handleInterfaceDelete: node: <{}>, isLastInstanceOnNode: {}, interface: <{}>",
100 node, isLastInstanceOnNode, intf);
102 neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
103 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
104 if (isInterfaceOfInterest(intf, phyIfName)) {
105 // delete tunnel or physical interfaces
106 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
107 network, node, intf, isLastInstanceOnNode);
108 } else if (network != null) {
109 // vlan doesn't need a tunnel endpoint
110 if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
111 if (configurationService.getTunnelEndPoint(node) == null) {
112 logger.error("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table");
116 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
117 network, node, intf, isLastInstanceOnNode);
121 private void triggerUpdates() {
122 List<Node> nodes = null; // nodeCacheManager.getBridgeNodes();
123 if (nodes == null) return;
124 for (Node node : nodes) {
125 OvsdbBridgeAugmentation bridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
126 if (bridge != null) {
127 processBridgeUpdate(node, bridge);
130 List<TerminationPoint> tps = MdsalUtils.extractTerminationPoints(node);
131 for (TerminationPoint tp : tps) {
132 OvsdbTerminationPointAugmentation port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
134 processPortUpdate(node, port);
140 private void processPortDelete(Node node, OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation,
142 logger.debug("processPortDelete <{}> <{}>", node, ovsdbTerminationPointAugmentation);
143 NeutronNetwork network = null;
144 if (context == null) {
145 network = tenantNetworkManager.getTenantNetwork(ovsdbTerminationPointAugmentation);
147 network = (NeutronNetwork)context;
149 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
150 if (isInterfaceOfInterest(ovsdbTerminationPointAugmentation, phyIfName)) {
151 if (network != null) {
152 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, false, network);
154 logger.warn("processPortDelete: network was null, ignoring update");
156 } else if (network != null && !network.getRouterExternal()) {
157 logger.debug("Network {}: Delete interface {} attached to bridge {}", network.getNetworkUUID(),
158 ovsdbTerminationPointAugmentation.getInterfaceUuid(), node.getNodeId());
160 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = MdsalUtils.getBridge(node);
161 if (ovsdbBridgeAugmentation != null) {
162 List<TerminationPoint> terminationPoints = node.getTerminationPoint();
163 if (!terminationPoints.isEmpty()){
164 boolean isLastInstanceOnNode = true;
165 for (TerminationPoint terminationPoint : terminationPoints) {
166 OvsdbTerminationPointAugmentation tpAugmentation =
167 terminationPoint.getAugmentation( OvsdbTerminationPointAugmentation.class);
168 if (tpAugmentation.getInterfaceUuid().equals(
169 ovsdbTerminationPointAugmentation.getInterfaceUuid())) {
172 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(tpAugmentation);
173 if (neutronNetwork != null && neutronNetwork.equals(network)) {
174 isLastInstanceOnNode = false;
178 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation,
179 isLastInstanceOnNode, network);
182 } catch (Exception e) {
183 logger.error("Error fetching Interface Rows for node " + node, e);
188 private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint, List<String> phyIfName) {
189 logger.trace("SouthboundHandler#isInterfaceOfInterest: Interface : {}", terminationPoint);
191 if(terminationPoint.getInterfaceType() == null){
192 logger.warn("No type found for the interface : {}", terminationPoint);
195 return (MdsalHelper.createOvsdbInterfaceType(
196 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
198 MdsalHelper.createOvsdbInterfaceType(
199 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE)
201 phyIfName.contains(terminationPoint.getName()));
205 * Notification about an OpenFlow Node
207 * @param node the {@link Node Node} of interest in the notification
208 * @param action the {@link Action}
209 * @see NodeCacheListener#notifyNode
212 public void notifyNode (Node node, Action action) {
213 logger.info("notifyNode: action: {}, Node <{}>", action, node);
215 if (action.equals(Action.ADD)) {
216 if (MdsalUtils.getBridge(node) != null) {
217 networkingProviderManager.getProvider(node).initializeOFFlowRules(node);
225 * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
226 * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
229 public void processEvent(AbstractEvent abstractEvent) {
230 if (!(abstractEvent instanceof SouthboundEvent)) {
231 logger.error("processEvent: Unable to process abstract event {}", abstractEvent);
234 SouthboundEvent ev = (SouthboundEvent) abstractEvent;
235 logger.debug("processEvent: {}", ev);
236 switch (ev.getType()) {
238 processOvsdbNodeEvent(ev);
242 processBridgeEvent(ev);
246 processPortEvent(ev);
250 processOpenVSwitchEvent(ev);
254 logger.warn("Unable to process type " + ev.getType() +
255 " action " + ev.getAction() + " for node " + ev.getNode());
258 logger.warn("processEvent done");
261 private void processOvsdbNodeEvent(SouthboundEvent ev) {
262 switch (ev.getAction()) {
264 processOvsdbNodeCreate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
267 processOvsdbNodeUpdate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
270 processOvsdbNodeDelete(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
275 private void processOvsdbNodeCreate(Node node, OvsdbNodeAugmentation ovsdbNode) {
276 logger.info("processOvsdbNodeCreate <{}> <{}>", node, ovsdbNode);
277 nodeCacheManager.nodeAdded(node);
278 bridgeConfigurationManager.prepareNode(node);
281 private void processOvsdbNodeUpdate(Node node, OvsdbNodeAugmentation ovsdbNode) {
282 logger.info("processOvsdbNodeUpdate <{}> <{}>", node, ovsdbNode);
283 nodeCacheManager.nodeAdded(node);
286 private void processOvsdbNodeDelete(Node node, OvsdbNodeAugmentation ovsdbNode) {
287 logger.info("processOvsdbNodeDelete <{}> <{}>", node, ovsdbNode);
288 nodeCacheManager.nodeRemoved(node);
290 * I don't think we want to do this yet
291 InstanceIdentifier<Node> bridgeNodeIid =
292 MdsalHelper.createInstanceIdentifier(ovsdbNode.getConnectionInfo(),
293 Constants.INTEGRATION_BRIDGE);
294 MdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid);
298 private void processPortEvent(SouthboundEvent ev) {
299 switch (ev.getAction()) {
302 processPortUpdate(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData());
305 processPortDelete(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData(), null);
310 private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port) {
311 logger.debug("processPortUpdate <{}> <{}>", node, port);
312 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
313 if (network != null && !network.getRouterExternal()) {
314 this.handleInterfaceUpdate(node, port);
318 private void processOpenVSwitchEvent(SouthboundEvent ev) {
319 switch (ev.getAction()) {
322 processOpenVSwitchUpdate(ev.getNode());
329 private void processOpenVSwitchUpdate(Node node) {
330 logger.debug("processOpenVSwitchUpdate {}", node);
331 // TODO this node might be the OvsdbNode and not have termination points
332 // Would need to change listener or grab tp nodes in here.
333 List<TerminationPoint> terminationPoints = MdsalUtils.extractTerminationPoints(node);
334 for (TerminationPoint terminationPoint : terminationPoints) {
335 processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class));
339 private void processBridgeEvent(SouthboundEvent ev) {
340 switch (ev.getAction()) {
342 processBridgeCreate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
345 processBridgeUpdate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
348 processBridgeDelete(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
353 private boolean isMainBridge(Node node, OvsdbBridgeAugmentation bridge) {
355 String nodeIdStr = node.getNodeId().getValue();
356 String bridgeName = nodeIdStr.substring(nodeIdStr.lastIndexOf('/') + 1);
357 List<TerminationPoint> terminationPoints = MdsalUtils.extractTerminationPoints(node);
358 if (terminationPoints != null && terminationPoints.size() == 1) {
360 OvsdbTerminationPointAugmentation port = MdsalUtils.extractTerminationPointAugmentation(node, bridgeName);
362 String datapathId = MdsalUtils.getDatapathId(bridge);
363 // Having a datapathId means the ovsdb node has connected to ODL
364 if (datapathId != null) {
367 logger.info("datapathId not found");
373 private void processBridgeCreate(Node node, OvsdbBridgeAugmentation bridge) {
374 logger.debug("processBridgeCreate <{}> <{}>", node, bridge);
375 String datapathId = MdsalUtils.getDatapathId(bridge);
376 // Having a datapathId means the ovsdb node has connected to ODL
377 if (datapathId != null) {
378 nodeCacheManager.nodeAdded(node);
380 logger.info("processBridgeCreate datapathId not found");
384 private void processBridgeUpdate(Node node, OvsdbBridgeAugmentation bridge) {
385 logger.debug("processBridgeUpdate <{}> <{}>", node, bridge);
386 String datapathId = MdsalUtils.getDatapathId(bridge);
387 // Having a datapathId means the ovsdb node has connected to ODL
388 if (datapathId != null) {
389 nodeCacheManager.nodeAdded(node);
391 logger.info("processBridgeUpdate datapathId not found");
395 private void processBridgeDelete(Node node, OvsdbBridgeAugmentation bridge) {
396 logger.debug("processBridgeDelete: Delete bridge from config data store: <{}> <{}>",
398 nodeCacheManager.nodeRemoved(node);
400 // Not sure if we want to do this yet
401 MdsalUtils.deleteBridge(node);