2 * Copyright (c) 2015 Cisco Systems, 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
8 package org.opendaylight.groupbasedpolicy.neutron.ovsdb;
10 import java.util.HashMap;
11 import java.util.HashSet;
15 import javax.annotation.Nonnull;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
19 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper;
22 import org.opendaylight.groupbasedpolicy.util.DataTreeChangeHandler;
23 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigsKey;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
38 import org.opendaylight.yangtools.yang.binding.DataObject;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
43 import com.google.common.base.Strings;
45 public class OvsdbNodeListener extends DataTreeChangeHandler<Node> {
47 private static final Logger LOG = LoggerFactory.getLogger(OvsdbNodeListener.class);
48 public static final String NEUTRON_PROVIDER_MAPPINGS_KEY = "provider_mappings";
49 private static final String OF_SEPARATOR = ":";
50 private static final String OF_INVENTORY_PREFIX = "openflow";
52 private final Map<OvsdbBridgeRef, String> providerPortNameByBridgeRef = new HashMap<>();
53 private final Map<InstanceIdentifier<Node>, NeutronBridgeWithExtPort> bridgeByNodeIid = new HashMap<>();
55 public OvsdbNodeListener(DataBroker dataProvider) {
57 new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
58 InstanceIdentifier.create(NetworkTopology.class)
59 .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
64 protected void onWrite(DataObjectModification<Node> rootNode, InstanceIdentifier<Node> rootIdentifier) {
65 Node node = rootNode.getDataAfter();
66 OvsdbNodeAugmentation ovsdbNode = node.getAugmentation(OvsdbNodeAugmentation.class);
67 if (ovsdbNode != null) {
68 LOG.trace("OVSDB node created: {} \n {}", rootIdentifier, node);
69 DataObjectModification<OpenvswitchOtherConfigs> ovsOtherConfigModification =
70 getProviderMappingsModification(rootNode);
71 if (isProviderPortNameChanged(ovsOtherConfigModification) && ovsdbNode.getManagedNodeEntry() != null) {
72 String newProviderPortName = getProviderPortName(ovsOtherConfigModification.getDataAfter());
73 LOG.debug("provider_mappings created {} on node {}", newProviderPortName, node.getNodeId().getValue());
74 for (ManagedNodeEntry mngdNodeEntry : ovsdbNode.getManagedNodeEntry()) {
75 providerPortNameByBridgeRef.put(mngdNodeEntry.getBridgeRef(), newProviderPortName);
76 LOG.trace("Added Provider port name {} by OVSDB bridge ref {}", newProviderPortName,
77 mngdNodeEntry.getBridgeRef());
82 OvsdbBridgeAugmentation ovsdbBridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
83 if (ovsdbBridge != null) {
84 LOG.trace("OVSDB bridge created: {} \n {}", rootIdentifier, node);
85 Set<DataObjectModification<OvsdbTerminationPointAugmentation>> ovsdbTpModifications =
86 getOvsdbTpModifications(rootNode);
87 NodeId ofNodeId = buildOfNodeId(ovsdbBridge);
88 if (!ovsdbTpModifications.isEmpty() && ofNodeId != null) {
89 NeutronBridgeWithExtPort bridge = getBridge(rootIdentifier);
90 bridge.ofNodeId = ofNodeId;
91 LOG.trace("OF node {} representing OVSDB bridge {}", ofNodeId.getValue(), node.getNodeId().getValue());
93 for (DataObjectModification<OvsdbTerminationPointAugmentation> ovsdbTpModification : ovsdbTpModifications) {
94 OvsdbTerminationPointAugmentation newOvsdbTp = ovsdbTpModification.getDataAfter();
95 if (ovsdbBridge.getBridgeName().getValue().equals(newOvsdbTp.getName())) {
96 LOG.trace("Termination Point {} same as Bridge {}. Not processing", newOvsdbTp.getName(),
97 ovsdbBridge.getBridgeName().getValue());
100 String portName = newOvsdbTp.getName();
101 Long ofport = newOvsdbTp.getOfport();
102 if (isOfportOrNameChanged(ovsdbTpModification) && portName != null && ofport != null) {
103 NeutronBridgeWithExtPort bridge = getBridge(rootIdentifier);
104 bridge.ofportByName.put(ofport, portName);
105 LOG.trace("OVSDB termination point with ofport {} and port-name {} created.", ofport, portName);
106 // port name is same as provider port name so the termination point represents
108 if (portName.equals(providerPortNameByBridgeRef.get(new OvsdbBridgeRef(rootIdentifier)))) {
109 NodeConnectorId ofNcId = buildOfNodeConnectorId(newOvsdbTp, ofNodeId);
110 bridge.externalIfaces.add(ofNcId);
111 InventoryHelper.addOfOverlayExternalPort(bridge.ofNodeId, ofNcId, dataProvider);
112 LOG.debug("Added of-overlay external-interface {} to node {}", ofNcId.getValue(),
114 traceBridge(rootIdentifier);
122 protected void onDelete(DataObjectModification<Node> rootNode, InstanceIdentifier<Node> rootIdentifier) {
123 LOG.trace("Not implemented - OVSDB element deleted: {} \n {}", rootIdentifier, rootNode.getDataBefore());
127 protected void onSubtreeModified(DataObjectModification<Node> rootNode, InstanceIdentifier<Node> rootIdentifier) {
128 Node node = rootNode.getDataAfter();
129 OvsdbBridgeAugmentation ovsdbBridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
130 if (ovsdbBridge != null) {
131 LOG.trace("OVSDB bridge updated: {} \n before {} \n after {}", rootIdentifier, rootNode.getDataBefore(),
132 rootNode.getDataAfter());
133 Set<DataObjectModification<OvsdbTerminationPointAugmentation>> ovsdbTpModifications =
134 getOvsdbTpModifications(rootNode);
135 NodeId ofNodeId = buildOfNodeId(ovsdbBridge);
136 if (!ovsdbTpModifications.isEmpty() && ofNodeId != null) {
137 NeutronBridgeWithExtPort bridge = getBridge(rootIdentifier);
138 if (bridge.ofNodeId != null && !bridge.ofNodeId.equals(ofNodeId)) {
139 LOG.debug("OVSDB bridge {} has changed datapath-id. \n Old: {} \n New: {}",
140 node.getNodeId().getValue(), bridge.ofNodeId.getValue(), ofNodeId.getValue());
141 bridge.ofNodeId = ofNodeId;
144 for (DataObjectModification<OvsdbTerminationPointAugmentation> ovsdbTpModification : ovsdbTpModifications) {
145 OvsdbTerminationPointAugmentation newOvsdbTp = ovsdbTpModification.getDataAfter();
147 if (newOvsdbTp == null) {
148 LOG.trace("Termination Point is null. Not processing");
152 if (ovsdbBridge.getBridgeName().getValue().equals(newOvsdbTp.getName())) {
153 LOG.trace("Termination Point {} same as Bridge {}. Not processing", newOvsdbTp.getName(),
154 ovsdbBridge.getBridgeName().getValue());
157 String portName = newOvsdbTp.getName();
158 Long ofport = newOvsdbTp.getOfport();
159 if (isOfportOrNameChanged(ovsdbTpModification) && portName != null && ofport != null) {
160 NeutronBridgeWithExtPort bridge = getBridge(rootIdentifier);
161 bridge.ofportByName.put(ofport, portName);
162 LOG.trace("OVSDB termination point with ofport {} and port-name {} created.", ofport, portName);
163 // port name is same as provider port name so the termination point represents
165 if (portName.equals(providerPortNameByBridgeRef.get(new OvsdbBridgeRef(rootIdentifier)))) {
166 NodeConnectorId ofNcId = buildOfNodeConnectorId(newOvsdbTp, ofNodeId);
167 bridge.externalIfaces.add(ofNcId);
168 InventoryHelper.addOfOverlayExternalPort(bridge.ofNodeId, ofNcId, dataProvider);
169 LOG.debug("Added of-overlay external-interface {} to node {}", ofNcId.getValue(),
171 traceBridge(rootIdentifier);
178 private NeutronBridgeWithExtPort getBridge(InstanceIdentifier<Node> nodeIid) {
179 NeutronBridgeWithExtPort bridge = bridgeByNodeIid.get(nodeIid);
180 if (bridge == null) {
181 bridge = new NeutronBridgeWithExtPort();
182 bridgeByNodeIid.put(nodeIid, bridge);
187 @SuppressWarnings("unchecked")
188 private static Set<DataObjectModification<OvsdbTerminationPointAugmentation>> getOvsdbTpModifications(
189 DataObjectModification<Node> rootNode) {
190 Set<DataObjectModification<OvsdbTerminationPointAugmentation>> modifications = new HashSet<>();
191 for (DataObjectModification<? extends DataObject> modifiedChild : rootNode.getModifiedChildren()) {
192 if (TerminationPoint.class.isAssignableFrom(modifiedChild.getDataType())) {
193 DataObjectModification<OvsdbTerminationPointAugmentation> modifiedAugmentation =
194 ((DataObjectModification<TerminationPoint>) modifiedChild)
195 .getModifiedAugmentation(OvsdbTerminationPointAugmentation.class);
196 if (modifiedAugmentation != null) {
197 modifications.add(modifiedAugmentation);
201 return modifications;
204 private static boolean isOfportOrNameChanged(
205 DataObjectModification<OvsdbTerminationPointAugmentation> ovsdbTpModification) {
206 if (ovsdbTpModification == null) {
209 OvsdbTerminationPointAugmentation oldTp = ovsdbTpModification.getDataBefore();
210 OvsdbTerminationPointAugmentation newTp = ovsdbTpModification.getDataAfter();
211 if (oldTp != null && newTp != null) {
212 if (oldTp.getOfport() != null && newTp.getOfport() != null && oldTp.getOfport() != newTp.getOfport()) {
215 if (!(Strings.nullToEmpty(oldTp.getName())).equals(Strings.nullToEmpty(newTp.getName()))) {
219 if (isOfportOrNameNotNull(oldTp)) {
222 if (isOfportOrNameNotNull(newTp)) {
228 private static boolean isOfportOrNameNotNull(OvsdbTerminationPointAugmentation tp) {
230 if (tp.getOfport() != null) {
233 if (tp.getName() != null) {
240 private static DataObjectModification<OpenvswitchOtherConfigs> getProviderMappingsModification(
241 DataObjectModification<Node> rootNode) {
242 DataObjectModification<OvsdbNodeAugmentation> modifiedOvsdbNode =
243 rootNode.getModifiedAugmentation(OvsdbNodeAugmentation.class);
244 if (modifiedOvsdbNode == null) {
247 return modifiedOvsdbNode.getModifiedChildListItem(OpenvswitchOtherConfigs.class,
248 new OpenvswitchOtherConfigsKey(NEUTRON_PROVIDER_MAPPINGS_KEY));
251 private static boolean isProviderPortNameChanged(DataObjectModification<OpenvswitchOtherConfigs> ovsConfig) {
252 if (ovsConfig == null) {
255 OpenvswitchOtherConfigs oldConfig = ovsConfig.getDataBefore();
256 OpenvswitchOtherConfigs newConfig = ovsConfig.getDataAfter();
257 if (oldConfig != null && newConfig != null) {
258 if (!(Strings.nullToEmpty(oldConfig.getOtherConfigValue())
259 .equals(Strings.nullToEmpty(newConfig.getOtherConfigValue())))) {
262 } else if (oldConfig != null && !Strings.isNullOrEmpty(oldConfig.getOtherConfigValue())) {
264 } else if (newConfig != null && !Strings.isNullOrEmpty(newConfig.getOtherConfigValue())) {
270 private static @Nonnull String getProviderPortName(OpenvswitchOtherConfigs config) {
271 if (NEUTRON_PROVIDER_MAPPINGS_KEY.equals(config.getOtherConfigKey()) && config.getOtherConfigValue() != null) {
272 String otherConfig = config.getOtherConfigValue();
273 String[] elements = otherConfig.split(":");
274 if (elements.length == 2) {
281 private static NodeId buildOfNodeId(OvsdbBridgeAugmentation ovsdbBridge) {
282 if (ovsdbBridge.getDatapathId() == null) {
285 Long macLong = InventoryHelper.getLongFromDpid(ovsdbBridge.getDatapathId().getValue());
286 return new NodeId(OF_INVENTORY_PREFIX + OF_SEPARATOR + String.valueOf(macLong));
289 private static NodeConnectorId buildOfNodeConnectorId(OvsdbTerminationPointAugmentation terminationPoint,
291 if (terminationPoint.getOfport() == null) {
294 return new NodeConnectorId(nodeId.getValue() + OF_SEPARATOR + String.valueOf(terminationPoint.getOfport()));
297 private void traceBridge(InstanceIdentifier<Node> identifier) {
298 if (LOG.isTraceEnabled()) {
299 NeutronBridgeWithExtPort bridge = bridgeByNodeIid.get(identifier);
300 if (bridge == null) {
301 LOG.trace("Bridge does not exist: {}", identifier);
304 String providerPortName = providerPortNameByBridgeRef.get(new OvsdbBridgeRef(identifier));
305 LOG.trace("State of bridge:\n ID: {} \n providerPortName: {} \n {}", identifier, providerPortName,
310 private class NeutronBridgeWithExtPort {
313 Set<NodeConnectorId> externalIfaces = new HashSet<>();
314 Map<Long, String> ofportByName = new HashMap<>();
317 public String toString() {
318 return "NeutronBridgeWithExtPort:\n ofNodeId=" + ofNodeId + "\n externalIfaces=" + externalIfaces
319 + ",\n ofportByName=" + ofportByName;