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 static org.opendaylight.groupbasedpolicy.util.DataStoreHelper.readFromDs;
11 import static org.opendaylight.groupbasedpolicy.util.DataStoreHelper.submitToDs;
12 import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getOvsdbBridgeFromTerminationPoint;
13 import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getOvsdbTerminationPoint;
15 import java.util.ArrayList;
16 import java.util.List;
18 import org.apache.commons.lang3.StringUtils;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.groupbasedpolicy.neutron.ovsdb.AbstractTunnelType;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfig;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfigBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.ExternalInterfaces;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.ExternalInterfacesBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.ExternalInterfacesKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.Tunnel;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.TunnelBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.TunnelKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
45 import com.google.common.base.Optional;
47 public class InventoryHelper {
48 private static final Logger LOG = LoggerFactory.getLogger(InventoryHelper.class);
49 private static final String HEX = "0x";
52 * Convert an OpenFlow Datapath ID to a Long
54 * @param dpid The OpenFlow Datapath ID
55 * @return The Long representation of the DPID
57 public static Long getLongFromDpid(String dpid) {
58 String[] addressInBytes = dpid.split(":");
60 (Long.decode(HEX + addressInBytes[2]) << 40) |
61 (Long.decode(HEX + addressInBytes[3]) << 32) |
62 (Long.decode(HEX + addressInBytes[4]) << 24) |
63 (Long.decode(HEX + addressInBytes[5]) << 16) |
64 (Long.decode(HEX + addressInBytes[6]) << 8 ) |
65 (Long.decode(HEX + addressInBytes[7]));
69 private static final Long MAX_OF_PORT=65534L;
71 * Construct a String that can be used to create a
73 * The String is constructed by getting the Datapath ID from the OVSDB bridge
74 * augmentation, converting that to a Long, and prepending it with the
77 * @param ovsdbBridge The OVSDB bridge augmentation
78 * @return String representation of the Inventory NodeId, null if it fails
80 public static String getInventoryNodeIdString(OvsdbBridgeAugmentation ovsdbBridge,
81 InstanceIdentifier<OvsdbTerminationPointAugmentation> ovsdbTpIid, DataBroker dataBroker) {
82 DatapathId dpid = ovsdbBridge.getDatapathId();
84 OvsdbBridgeAugmentation bridgeData = getOvsdbBridgeFromTerminationPoint(ovsdbTpIid, dataBroker);
85 dpid = bridgeData.getDatapathId();
87 LOG.error("No Data Path ID for OVSDB Bridge {}", ovsdbBridge);
91 Long macLong = getLongFromDpid(ovsdbBridge.getDatapathId().getValue());
92 String nodeIdString = "openflow:" + String.valueOf(macLong);
93 if(StringUtils.countMatches(nodeIdString, ":") != 1) {
94 LOG.error("{} is not correct format for NodeId.",nodeIdString);
101 * Construct a string that can be used to create a
102 * {@link org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId}.
103 * The String is constructed by first getting the inventory Node ID string, and then
104 * adding the port number obtained by the OVSDB augmentation.
106 * @param inventoryNodeId The string representation of the Inventory NodeId
107 * @param ovsdbTp The {@link OvsdbTerminationPointAugmentation}
108 * @return String representation of the Inventory NodeConnectorId, null if it fails
110 public static String getInventoryNodeConnectorIdString(String inventoryNodeId,
111 OvsdbTerminationPointAugmentation ovsdbTp,
112 InstanceIdentifier<OvsdbTerminationPointAugmentation> tpIid,
113 DataBroker dataBroker) {
115 if (ovsdbTp.getOfport() != null && ovsdbTp.getOfport()>MAX_OF_PORT) {
116 LOG.debug("Invalid OpenFlow port {} for {}",ovsdbTp.getOfport(), ovsdbTp);
119 if (ovsdbTp.getOfport() == null) {
120 OvsdbTerminationPointAugmentation readOvsdbTp =
121 getOvsdbTerminationPoint(tpIid, dataBroker);
122 if (readOvsdbTp == null
123 || readOvsdbTp.getOfport() == null
124 || readOvsdbTp.getOfport() >MAX_OF_PORT) {
125 LOG.debug("Couldn't get OpenFlow port for {}",ovsdbTp);
128 ofport = readOvsdbTp.getOfport();
130 ofport = ovsdbTp.getOfport();
132 String nodeConnectorIdString = inventoryNodeId + ":" + String.valueOf(ofport);
134 if(StringUtils.countMatches(nodeConnectorIdString, ":") != 2) {
135 LOG.error("{} is not correct format for NodeConnectorId.",nodeConnectorIdString);
138 return nodeConnectorIdString;
142 * Read the {@link OfOverlayNodeConfig} augmentation from the
143 * Inventory Node, and verify that the tunnel types we need
146 * @return true if tunnel types are present, false otherwise
148 public static boolean checkOfOverlayConfig(String nodeIdString,
149 List<AbstractTunnelType> requiredTunnelTypes, DataBroker dataBroker) {
150 OfOverlayNodeConfig config = getOfOverlayConfig(nodeIdString, dataBroker);
151 if (config == null || config.getTunnel() == null) {
152 LOG.debug("No OfOverlay config for {}",nodeIdString);
157 * See if the OfOverlayNodeConfig has the
158 * tunnel type information.
160 for (AbstractTunnelType tunnelType: requiredTunnelTypes) {
161 boolean tunnelPresent = false;
162 for (Tunnel tunnel: config.getTunnel()) {
163 if (tunnelType.getTunnelType().equals(tunnel.getTunnelType())) {
164 tunnelPresent = true;
168 if (tunnelPresent == false) {
175 public static void addOfOverlayExternalPort(String nodeIdString, NodeConnectorId ncId, DataBroker dataBroker) {
176 InstanceIdentifier<ExternalInterfaces> nodeExternalInterfacesIid = InstanceIdentifier.builder(
178 .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
179 .augmentation(OfOverlayNodeConfig.class)
180 .child(ExternalInterfaces.class,new ExternalInterfacesKey(ncId))
183 ExternalInterfaces externalInterfaces = new ExternalInterfacesBuilder()
184 .setKey(new ExternalInterfacesKey(ncId))
185 .setNodeConnectorId(ncId)
187 WriteTransaction transaction = dataBroker.newReadWriteTransaction();
188 transaction.put(LogicalDatastoreType.CONFIGURATION, nodeExternalInterfacesIid, externalInterfaces, true);
189 submitToDs(transaction);
190 LOG.trace("Added external interface node connector {} to node {}", ncId.getValue(),nodeIdString);
193 public static OfOverlayNodeConfig getOfOverlayConfig(String nodeIdString, DataBroker dataBroker) {
194 InstanceIdentifier<OfOverlayNodeConfig> ofOverlayNodeIid = InstanceIdentifier.builder(
196 .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
197 .augmentation(OfOverlayNodeConfig.class)
200 ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();
201 Optional<OfOverlayNodeConfig> overlayConfig = readFromDs(LogicalDatastoreType.OPERATIONAL, ofOverlayNodeIid, transaction );
202 if (overlayConfig.isPresent()) {
203 return overlayConfig.get();
208 private static void addOfOverlayAugmentation(OfOverlayNodeConfig config, String nodeIdString, DataBroker dataBroker) {
209 InstanceIdentifier<OfOverlayNodeConfig> ofOverlayNodeIid = InstanceIdentifier.builder(
211 .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
212 .augmentation(OfOverlayNodeConfig.class)
215 WriteTransaction transaction = dataBroker.newReadWriteTransaction();
216 transaction.put(LogicalDatastoreType.CONFIGURATION, ofOverlayNodeIid, config, true);
217 submitToDs(transaction);
220 private static void addTunnelToOfOverlayAugmentation(Tunnel tunnel, String nodeIdString, DataBroker dataBroker) {
221 InstanceIdentifier<Tunnel> ofOverlayNodeIid = InstanceIdentifier.builder(
223 .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
224 .augmentation(OfOverlayNodeConfig.class)
225 .child(Tunnel.class, new TunnelKey(tunnel.getKey()))
228 WriteTransaction transaction = dataBroker.newReadWriteTransaction();
229 transaction.merge(LogicalDatastoreType.CONFIGURATION, ofOverlayNodeIid, tunnel, true);
230 submitToDs(transaction);
234 * Update the {@link OfOverlayConfig} of an Inventory Node
235 * using the new tunnel state.
237 * @param nodeIdString
241 public static void updateOfOverlayConfig(IpAddress ip, String nodeIdString,
242 String nodeConnectorIdString, List<AbstractTunnelType> tunnels, DataBroker dataBroker) {
244 if ((ip == null) || (nodeIdString == null)
245 || (nodeConnectorIdString == null)) {
246 LOG.debug("Can't update OfOverlay: requisite information not present");
249 NodeConnectorId nodeConnectorId = new NodeConnectorId(nodeConnectorIdString);
250 List<Tunnel> tunnelList = new ArrayList<Tunnel>();
251 List<Tunnel> existingTunnels = new ArrayList<Tunnel>();
252 OfOverlayNodeConfig ofConfig = getOfOverlayConfig(nodeIdString, dataBroker);
253 if (ofConfig != null) {
254 existingTunnels = ofConfig.getTunnel();
256 boolean tunnelsUpdated = false;
257 for (AbstractTunnelType tunnelType: tunnels) {
258 boolean tunnelFound = false;
259 for (Tunnel currentTun: existingTunnels) {
260 if (tunnelType.getTunnelType().equals(currentTun.getTunnelType())) {
262 TunnelBuilder tunnelBuilder = new TunnelBuilder(currentTun);
263 tunnelBuilder.setIp(ip);
264 tunnelBuilder.setPort(tunnelType.getPortNumber());
265 tunnelBuilder.setNodeConnectorId(nodeConnectorId);
266 tunnelList.add(tunnelBuilder.build());
268 tunnelsUpdated = true;
272 if (tunnelFound == false) {
273 TunnelBuilder tunnelBuilder = new TunnelBuilder();
274 tunnelBuilder.setIp(ip);
275 tunnelBuilder.setPort(tunnelType.getPortNumber());
276 tunnelBuilder.setNodeConnectorId(nodeConnectorId);
277 tunnelBuilder.setTunnelType(tunnelType.getTunnelType());
278 tunnelList.add(tunnelBuilder.build());
279 tunnelsUpdated = true;
282 if (tunnelsUpdated == true) {
283 for (Tunnel tunnel: tunnelList) {
284 addTunnelToOfOverlayAugmentation(tunnel, nodeIdString, dataBroker);