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.util;
10 import com.google.common.base.Optional;
11 import org.apache.commons.lang3.StringUtils;
12 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
13 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
14 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.groupbasedpolicy.neutron.ovsdb.AbstractTunnelType;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfig;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfigBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.ExternalInterfaces;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.ExternalInterfacesBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.ExternalInterfacesKey;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.Tunnel;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.TunnelBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.TunnelKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 import java.util.ArrayList;
39 import java.util.HashSet;
40 import java.util.List;
43 import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getOvsdbBridgeFromTerminationPoint;
44 import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getOvsdbTerminationPoint;
45 import static org.opendaylight.groupbasedpolicy.util.DataStoreHelper.readFromDs;
46 import static org.opendaylight.groupbasedpolicy.util.DataStoreHelper.submitToDs;
48 public class InventoryHelper {
49 private static final Logger LOG = LoggerFactory.getLogger(InventoryHelper.class);
50 private static final String HEX = "0x";
53 * Convert an OpenFlow Datapath ID to a Long
55 * @param dpid The OpenFlow Datapath ID
56 * @return The Long representation of the DPID
58 public static Long getLongFromDpid(String dpid) {
59 String[] addressInBytes = dpid.split(":");
61 (Long.decode(HEX + addressInBytes[2]) << 40) |
62 (Long.decode(HEX + addressInBytes[3]) << 32) |
63 (Long.decode(HEX + addressInBytes[4]) << 24) |
64 (Long.decode(HEX + addressInBytes[5]) << 16) |
65 (Long.decode(HEX + addressInBytes[6]) << 8 ) |
66 (Long.decode(HEX + addressInBytes[7]));
70 private static final Long MAX_OF_PORT=65534L;
72 * Construct a String that can be used to create a
74 * The String is constructed by getting the Datapath ID from the OVSDB bridge
75 * augmentation, converting that to a Long, and prepending it with the
78 * @param ovsdbBridge The OVSDB bridge augmentation
79 * @return String representation of the Inventory NodeId, null if it fails
81 public static String getInventoryNodeIdString(OvsdbBridgeAugmentation ovsdbBridge,
82 InstanceIdentifier<OvsdbTerminationPointAugmentation> ovsdbTpIid, DataBroker dataBroker) {
83 DatapathId dpid = ovsdbBridge.getDatapathId();
85 OvsdbBridgeAugmentation bridgeData = getOvsdbBridgeFromTerminationPoint(ovsdbTpIid, dataBroker);
86 dpid = bridgeData.getDatapathId();
88 LOG.error("No Data Path ID for OVSDB Bridge {}", ovsdbBridge);
92 Long macLong = getLongFromDpid(ovsdbBridge.getDatapathId().getValue());
93 String nodeIdString = "openflow:" + String.valueOf(macLong);
94 if(StringUtils.countMatches(nodeIdString, ":") != 1) {
95 LOG.error("{} is not correct format for NodeId.",nodeIdString);
102 * Construct a string that can be used to create a
103 * {@link org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId}.
104 * The String is constructed by first getting the inventory Node ID string, and then
105 * adding the port number obtained by the OVSDB augmentation.
107 * @param inventoryNodeId The string representation of the Inventory NodeId
108 * @param ovsdbTp The {@link OvsdbTerminationPointAugmentation}
109 * @return String representation of the Inventory NodeConnectorId, null if it fails
111 public static String getInventoryNodeConnectorIdString(String inventoryNodeId,
112 OvsdbTerminationPointAugmentation ovsdbTp,
113 InstanceIdentifier<OvsdbTerminationPointAugmentation> tpIid,
114 DataBroker dataBroker) {
116 if (ovsdbTp.getOfport() != null && ovsdbTp.getOfport()>MAX_OF_PORT) {
117 LOG.debug("Invalid OpenFlow port {} for {}",ovsdbTp.getOfport(), ovsdbTp);
120 if (ovsdbTp.getOfport() == null) {
121 OvsdbTerminationPointAugmentation readOvsdbTp =
122 getOvsdbTerminationPoint(tpIid, dataBroker);
123 if (readOvsdbTp == null
124 || readOvsdbTp.getOfport() == null
125 || readOvsdbTp.getOfport() >MAX_OF_PORT) {
126 LOG.debug("Couldn't get OpenFlow port for {}",ovsdbTp);
129 ofport = readOvsdbTp.getOfport();
131 ofport = ovsdbTp.getOfport();
133 String nodeConnectorIdString = inventoryNodeId + ":" + String.valueOf(ofport);
135 if(StringUtils.countMatches(nodeConnectorIdString, ":") != 2) {
136 LOG.error("{} is not correct format for NodeConnectorId.",nodeConnectorIdString);
139 return nodeConnectorIdString;
143 * Read the {@link OfOverlayNodeConfig} augmentation from the
144 * Inventory Node, and verify that the tunnel types we need
147 * @return true if tunnel types are present, false otherwise
149 public static boolean checkOfOverlayConfig(String nodeIdString,
150 List<AbstractTunnelType> requiredTunnelTypes, DataBroker dataBroker) {
151 OfOverlayNodeConfig config = getOfOverlayConfig(nodeIdString, dataBroker);
152 if (config == null || config.getTunnel() == null) {
153 LOG.debug("No OfOverlay config for {}",nodeIdString);
158 * See if the OfOverlayNodeConfig has the
159 * tunnel type information.
161 for (AbstractTunnelType tunnelType: requiredTunnelTypes) {
162 boolean tunnelPresent = false;
163 for (Tunnel tunnel: config.getTunnel()) {
164 if (tunnelType.getTunnelType().equals(tunnel.getTunnelType())) {
165 tunnelPresent = true;
169 if (tunnelPresent == false) {
176 public static void addOfOverlayExternalPort(String nodeIdString, NodeConnectorId ncId, DataBroker dataBroker) {
177 InstanceIdentifier<ExternalInterfaces> nodeExternalInterfacesIid = InstanceIdentifier.builder(
179 .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
180 .augmentation(OfOverlayNodeConfig.class)
181 .child(ExternalInterfaces.class,new ExternalInterfacesKey(ncId))
184 ExternalInterfaces externalInterfaces = new ExternalInterfacesBuilder()
185 .setKey(new ExternalInterfacesKey(ncId))
186 .setNodeConnectorId(ncId)
188 WriteTransaction transaction = dataBroker.newReadWriteTransaction();
189 transaction.put(LogicalDatastoreType.CONFIGURATION, nodeExternalInterfacesIid, externalInterfaces, true);
190 submitToDs(transaction);
191 LOG.trace("Added external interface node connector {} to node {}", ncId.getValue(),nodeIdString);
194 public static OfOverlayNodeConfig getOfOverlayConfig(String nodeIdString, DataBroker dataBroker) {
195 InstanceIdentifier<OfOverlayNodeConfig> ofOverlayNodeIid = InstanceIdentifier.builder(
197 .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
198 .augmentation(OfOverlayNodeConfig.class)
201 ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();
202 Optional<OfOverlayNodeConfig> overlayConfig = readFromDs(LogicalDatastoreType.CONFIGURATION, ofOverlayNodeIid, transaction );
203 if (overlayConfig.isPresent()) {
204 return overlayConfig.get();
209 private static void addOfOverlayAugmentation(OfOverlayNodeConfig config, String nodeIdString, DataBroker dataBroker) {
210 InstanceIdentifier<OfOverlayNodeConfig> ofOverlayNodeIid = InstanceIdentifier.builder(
212 .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
213 .augmentation(OfOverlayNodeConfig.class)
216 WriteTransaction transaction = dataBroker.newReadWriteTransaction();
217 transaction.put(LogicalDatastoreType.CONFIGURATION, ofOverlayNodeIid, config, true);
218 submitToDs(transaction);
221 private static void addTunnelToOfOverlayAugmentation(Tunnel tunnel, String nodeIdString, DataBroker dataBroker) {
222 InstanceIdentifier<Tunnel> ofOverlayNodeIid = InstanceIdentifier.builder(
224 .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
225 .augmentation(OfOverlayNodeConfig.class)
226 .child(Tunnel.class, new TunnelKey(tunnel.getKey()))
229 WriteTransaction transaction = dataBroker.newReadWriteTransaction();
230 transaction.put(LogicalDatastoreType.CONFIGURATION, ofOverlayNodeIid, tunnel, true);
231 if(submitToDs(transaction)) {
232 LOG.info("addTunnelToOfOverlayAugmentation: Wrote tunnel {}",tunnel.getKey());
234 LOG.error("addTunnelToOfOverlayAugmentation: submitToDs failed for tunnel {}",tunnel.getKey());
239 * Update the {@link OfOverlayConfig} of an Inventory Node
240 * using the new tunnel state.
242 * @param nodeIdString
246 public static void updateOfOverlayConfig(IpAddress ip, String nodeIdString,
247 String nodeConnectorIdString, List<AbstractTunnelType> tunnels, DataBroker dataBroker) {
249 if ((ip == null) || (nodeIdString == null)
250 || (nodeConnectorIdString == null)) {
251 LOG.debug("Can't update OfOverlay: requisite information not present");
254 NodeConnectorId nodeConnectorId = new NodeConnectorId(nodeConnectorIdString);
255 List<Tunnel> tunnelList = new ArrayList<Tunnel>();
256 List<Tunnel> existingTunnels = new ArrayList<Tunnel>();
257 OfOverlayNodeConfig ofConfig = getOfOverlayConfig(nodeIdString, dataBroker);
258 if (ofConfig != null && ofConfig.getTunnel() != null) {
259 existingTunnels = ofConfig.getTunnel();
261 boolean tunnelsUpdated = false;
262 for (AbstractTunnelType tunnelType: tunnels) {
263 boolean tunnelFound = false;
264 for (Tunnel currentTun: existingTunnels) {
265 if (tunnelType.getTunnelType().equals(currentTun.getTunnelType())) {
267 TunnelBuilder tunnelBuilder = new TunnelBuilder(currentTun);
268 tunnelBuilder.setIp(ip);
269 tunnelBuilder.setPort(tunnelType.getPortNumber());
270 tunnelBuilder.setNodeConnectorId(nodeConnectorId);
271 tunnelList.add(tunnelBuilder.build());
273 tunnelsUpdated = true;
277 if (tunnelFound == false) {
278 TunnelBuilder tunnelBuilder = new TunnelBuilder();
279 tunnelBuilder.setIp(ip);
280 tunnelBuilder.setPort(tunnelType.getPortNumber());
281 tunnelBuilder.setNodeConnectorId(nodeConnectorId);
282 tunnelBuilder.setTunnelType(tunnelType.getTunnelType());
283 tunnelList.add(tunnelBuilder.build());
284 tunnelsUpdated = true;
287 if (tunnelsUpdated == true) {
288 for (Tunnel tunnel: tunnelList) {
289 addTunnelToOfOverlayAugmentation(tunnel, nodeIdString, dataBroker);
294 public static void removeTunnelsOfOverlayConfig(String nodeIdString,
295 List<AbstractTunnelType> tunnels,
296 DataBroker dataBroker) {
298 if (nodeIdString == null) {
299 LOG.debug("Can't update OfOverlay: requisite information not present");
302 List<Tunnel> existingTunnels = new ArrayList<>();
303 OfOverlayNodeConfig ofConfig = getOfOverlayConfig(nodeIdString, dataBroker);
304 if (ofConfig != null) {
305 existingTunnels = ofConfig.getTunnel();
307 Set<Tunnel> tunnelsToRemove = new HashSet<>();
308 for (AbstractTunnelType tunnelType : tunnels) {
309 for (Tunnel currentTun : existingTunnels) {
310 if (tunnelType.getTunnelType().equals(currentTun.getTunnelType())) {
311 tunnelsToRemove.add(currentTun);
316 // runs only if some tunnels were really removed
317 if (existingTunnels.removeAll(tunnelsToRemove)) {
318 OfOverlayNodeConfigBuilder ofOverlayBuilder;
319 if (ofConfig == null) {
320 ofOverlayBuilder = new OfOverlayNodeConfigBuilder();
322 ofOverlayBuilder = new OfOverlayNodeConfigBuilder(ofConfig);
324 ofOverlayBuilder.setTunnel(existingTunnels);
325 addOfOverlayAugmentation(ofOverlayBuilder.build(), nodeIdString, dataBroker);