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 OvsdbConnectionService connectionService;
40 private volatile NeutronL3Adapter neutronL3Adapter;
41 private volatile NodeCacheManager nodeCacheManager = null;
44 this.triggerUpdates();
48 logger.info(">>>>>> init {}", this.getClass());
51 private SouthboundEvent.Type ovsdbTypeToSouthboundEventType(OvsdbType ovsdbType) {
52 SouthboundEvent.Type type = SouthboundEvent.Type.NODE;
56 type = SouthboundEvent.Type.NODE;
59 type = SouthboundEvent.Type.BRIDGE;
62 type = SouthboundEvent.Type.PORT;
65 type = SouthboundEvent.Type.CONTROLLER;
68 type = SouthboundEvent.Type.OPENVSWITCH;
71 logger.warn("Invalid OvsdbType: {}", ovsdbType);
78 public void ovsdbUpdate(Node node, DataObject resourceAugmentationData, OvsdbType ovsdbType, Action action) {
79 logger.info("ovsdbUpdate: {} - {} - {}", ovsdbType, action, node);
80 this.enqueueEvent(new SouthboundEvent(node, resourceAugmentationData,
81 ovsdbTypeToSouthboundEventType(ovsdbType), action));
84 private void handleInterfaceUpdate (Node node, OvsdbTerminationPointAugmentation tp) {
85 logger.debug("handleInterfaceUpdate node: {}, tp: {}", node, tp);
86 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(tp);
87 if (network != null && !network.getRouterExternal()) {
88 logger.trace("handleInterfaceUpdate node: {}, tp: {}, network: {}", node, tp, network.getNetworkUUID());
89 tenantNetworkManager.programInternalVlan(node, tp, network);
90 neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
91 if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
92 networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, tp);
95 logger.debug("No tenant network found on node: {} for interface: {}", node, tp);
99 private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
100 boolean isLastInstanceOnNode, NeutronNetwork network) {
101 logger.debug("handleInterfaceDelete: node: {}, isLastInstanceOnNode: {}, interface: {}",
102 node, isLastInstanceOnNode, intf);
104 neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
105 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
106 if (isInterfaceOfInterest(intf, phyIfName)) {
107 // delete tunnel or physical interfaces
108 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
109 network, node, intf, isLastInstanceOnNode);
110 } else if (network != null) {
111 // vlan doesn't need a tunnel endpoint
112 if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
113 if (configurationService.getTunnelEndPoint(node) == null) {
114 logger.error("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table");
118 if (isLastInstanceOnNode & networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
119 tenantNetworkManager.reclaimInternalVlan(node, network);
121 networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
122 network, node, intf, isLastInstanceOnNode);
126 private void triggerUpdates() {
127 List<Node> nodes = connectionService.getNodes();
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");
161 } else if (network != null && !network.getRouterExternal()) {
162 logger.debug("Network {} : Delete interface {} attached to bridge {}", network.getNetworkUUID(),
163 ovsdbTerminationPointAugmentation.getInterfaceUuid(), node);
165 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class);
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(ovsdbTerminationPointAugmentation.getInterfaceUuid())) continue;
174 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(tpAugmentation);
175 if (neutronNetwork != null && neutronNetwork.equals(network)) {
176 isLastInstanceOnNode = false;
180 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation,
181 isLastInstanceOnNode, network);
184 } catch (Exception e) {
185 logger.error("Error fetching Interface Rows for node " + node, e);
190 private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint, List<String> phyIfName) {
191 return (MdsalHelper.createOvsdbInterfaceType(
192 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
194 MdsalHelper.createOvsdbInterfaceType(
195 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE)
197 phyIfName.contains(terminationPoint.getName()));
201 * Notification about an OpenFlow Node
203 * @param node the {@link Node Node} of interest in the notification
204 * @param action the {@link Action}
205 * @see NodeCacheListener#notifyNode
208 public void notifyNode (Node node, Action action) {
209 logger.info("notifyNode: Node {} update {}", node, action);
211 if (action.equals(Action.ADD)) {
212 if (MdsalUtils.getBridge(node) != null) {
213 networkingProviderManager.getProvider(node).initializeOFFlowRules(node);
221 * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
222 * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
225 public void processEvent(AbstractEvent abstractEvent) {
226 if (!(abstractEvent instanceof SouthboundEvent)) {
227 logger.error("Unable to process abstract event " + abstractEvent);
230 SouthboundEvent ev = (SouthboundEvent) abstractEvent;
231 logger.info("processEvent: {}", ev);
232 switch (ev.getType()) {
234 processOvsdbNodeEvent(ev);
237 processBridgeEvent(ev);
241 processPortEvent(ev);
245 processOpenVSwitchEvent(ev);
249 logger.warn("Unable to process type " + ev.getType() +
250 " action " + ev.getAction() + " for node " + ev.getNode());
255 private void processOvsdbNodeEvent(SouthboundEvent ev) {
256 switch (ev.getAction()) {
258 processOvsdbNodeCreate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
261 processOvsdbNodeUpdate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
264 processOvsdbNodeDelete(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
269 private void processOvsdbNodeCreate(Node node, OvsdbNodeAugmentation ovsdbNode) {
270 logger.info("processOvsdbNodeCreate {} - {}", node, ovsdbNode);
271 nodeCacheManager.nodeAdded(node);
272 bridgeConfigurationManager.prepareNode(node);
275 private void processOvsdbNodeUpdate(Node node, OvsdbNodeAugmentation ovsdbNode) {
276 logger.info("processOvsdbNodeUpdate {} - {}", node, ovsdbNode);
277 nodeCacheManager.nodeAdded(node);
280 private void processOvsdbNodeDelete(Node node, OvsdbNodeAugmentation ovsdbNode) {
281 logger.info("processOvsdbNodeDelete {} - {}", node, ovsdbNode);
282 nodeCacheManager.nodeRemoved(node);
284 * I don't think we want to do this yet
285 InstanceIdentifier<Node> bridgeNodeIid =
286 MdsalHelper.createInstanceIdentifier(ovsdbNode.getConnectionInfo(),
287 Constants.INTEGRATION_BRIDGE);
288 MdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid);
292 private void processPortEvent(SouthboundEvent ev) {
293 switch (ev.getAction()) {
296 processPortUpdate(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData());
299 processPortDelete(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData(), null);
304 private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port) {
305 logger.debug("processPortUpdate {} - {}", node, port);
306 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
307 if (network != null && !network.getRouterExternal()) {
308 this.handleInterfaceUpdate(node, port);
313 private void processOpenVSwitchEvent(SouthboundEvent ev) {
314 switch (ev.getAction()) {
317 processOpenVSwitchUpdate(ev.getNode());
324 private void processOpenVSwitchUpdate(Node node) {
325 logger.debug("processOpenVSwitchUpdate {}", node);
326 // TODO this node might be the OvsdbNode and not have termination points
327 // Would need to change listener or grab tp nodes in here.
328 List<TerminationPoint> terminationPoints = MdsalUtils.extractTerminationPoints(node);
329 for (TerminationPoint terminationPoint : terminationPoints) {
330 processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class));
334 private void processBridgeEvent(SouthboundEvent ev) {
335 switch (ev.getAction()) {
338 processBridgeUpdate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
341 processBridgeDelete(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
346 private void processBridgeUpdate(Node node, OvsdbBridgeAugmentation bridge) {
347 logger.debug("processBridgeUpdate {}, {}", node, bridge);
348 String datapathId = MdsalUtils.getDatapathId(bridge);
349 // Having a datapathId means the bridge has connected so it exists
350 if (datapathId != null) {
351 nodeCacheManager.nodeAdded(node);
353 logger.info("dataPathId not found");
357 private void processBridgeDelete(Node node, OvsdbBridgeAugmentation bridge) {
358 logger.debug("processBridgeDelete: Delete bridge from config data store : {}", node.getNodeId());
359 nodeCacheManager.nodeRemoved(node);
361 // Not sure if we want to do this yet
362 //MdsalUtils.deleteBridge(node);