f7e60d33f5b712f6135c76e125746982aee0f2cd
[groupbasedpolicy.git] / neutron-ovsdb / src / main / java / org / opendaylight / groupbasedpolicy / neutron / ovsdb / util / InventoryHelper.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.groupbasedpolicy.neutron.ovsdb.util;
9
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;
14
15 import java.util.ArrayList;
16 import java.util.List;
17
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.inventory.rev130819.NodeConnectorId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import com.google.common.base.Optional;
45
46 public class InventoryHelper {
47     private static final Logger LOG = LoggerFactory.getLogger(InventoryHelper.class);
48     private static final String HEX = "0x";
49
50     /**
51      * Convert an OpenFlow Datapath ID to a Long
52      *
53      * @param dpid The OpenFlow Datapath ID
54      * @return The Long representation of the DPID
55      */
56     public static Long getLongFromDpid(String dpid) {
57         String[] addressInBytes = dpid.split(":");
58         Long address =
59                 (Long.decode(HEX + addressInBytes[2]) << 40) |
60                 (Long.decode(HEX + addressInBytes[3]) << 32) |
61                 (Long.decode(HEX + addressInBytes[4]) << 24) |
62                 (Long.decode(HEX + addressInBytes[5]) << 16) |
63                 (Long.decode(HEX + addressInBytes[6]) << 8 ) |
64                 (Long.decode(HEX + addressInBytes[7]));
65         return address;
66     }
67
68     private static final Long MAX_OF_PORT=65534L;
69     /**
70      * Construct a String that can be used to create a
71      * {@link NodeId}.
72      * The String is constructed by getting the Datapath ID from the OVSDB bridge
73      * augmentation, converting that to a Long, and prepending it with the
74      * "openflow:" prefix.
75      *
76      * @param ovsdbBridge The OVSDB bridge augmentation
77      * @return String representation of the Inventory NodeId, null if it fails
78      */
79     public static String getInventoryNodeIdString(OvsdbBridgeAugmentation ovsdbBridge,
80             InstanceIdentifier<OvsdbTerminationPointAugmentation> ovsdbTpIid, DataBroker dataBroker) {
81         DatapathId dpid = ovsdbBridge.getDatapathId();
82         if (dpid == null) {
83             OvsdbBridgeAugmentation bridgeData = getOvsdbBridgeFromTerminationPoint(ovsdbTpIid, dataBroker);
84             dpid = bridgeData.getDatapathId();
85             if (dpid == null) {
86                 LOG.error("No Data Path ID for OVSDB Bridge {}", ovsdbBridge);
87                 return null;
88             }
89         }
90         Long macLong = getLongFromDpid(ovsdbBridge.getDatapathId().getValue());
91         String nodeIdString = "openflow:" + String.valueOf(macLong);
92         if(StringUtils.countMatches(nodeIdString, ":") != 1) {
93             LOG.error("{} is not correct format for NodeId.",nodeIdString);
94             return null;
95         }
96         return nodeIdString;
97     }
98
99     /**
100      * Construct a string that can be used to create a
101      * {@link org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId}.
102      * The String is constructed by first getting the inventory Node ID string, and then
103      * adding the port number obtained by the OVSDB augmentation.
104      *
105      * @param inventoryNodeId The string representation of the Inventory NodeId
106      * @param ovsdbTp The {@link OvsdbTerminationPointAugmentation}
107      * @return String representation of the Inventory NodeConnectorId, null if it fails
108      */
109     public static String getInventoryNodeConnectorIdString(String inventoryNodeId,
110                        OvsdbTerminationPointAugmentation ovsdbTp,
111                        InstanceIdentifier<OvsdbTerminationPointAugmentation> tpIid,
112                        DataBroker dataBroker) {
113         Long ofport = null;
114         if (ovsdbTp.getOfport() != null && ovsdbTp.getOfport()>MAX_OF_PORT) {
115             LOG.debug("Invalid OpenFlow port {} for {}",ovsdbTp.getOfport(), ovsdbTp);
116             return null;
117         }
118         if (ovsdbTp.getOfport() == null) {
119             OvsdbTerminationPointAugmentation readOvsdbTp =
120                     getOvsdbTerminationPoint(tpIid, dataBroker);
121             if (readOvsdbTp == null
122                     || readOvsdbTp.getOfport() == null
123                     || readOvsdbTp.getOfport() >MAX_OF_PORT) {
124                 LOG.debug("Couldn't get OpenFlow port for {}",ovsdbTp);
125                 return null;
126             }
127             ofport = readOvsdbTp.getOfport();
128         } else {
129             ofport = ovsdbTp.getOfport();
130         }
131         String nodeConnectorIdString = inventoryNodeId + ":" + String.valueOf(ofport);
132
133         if(StringUtils.countMatches(nodeConnectorIdString, ":") != 2) {
134             LOG.error("{} is not correct format for NodeConnectorId.",nodeConnectorIdString);
135             return null;
136         }
137         return nodeConnectorIdString;
138     }
139
140     /**
141      * Read the {@link OfOverlayNodeConfig} augmentation from the
142      * Inventory Node, and verify that the tunnel types we need
143      * are present
144      *
145      * @return true if tunnel types are present, false otherwise
146      */
147     public static boolean checkOfOverlayConfig(String nodeIdString,
148                        List<AbstractTunnelType> requiredTunnelTypes, DataBroker dataBroker) {
149         OfOverlayNodeConfig config = getOfOverlayConfig(nodeIdString, dataBroker);
150         if (config == null || config.getTunnel() == null) {
151             LOG.debug("No OfOverlay config for {}",nodeIdString);
152             return false;
153         }
154
155         /*
156          * See if the OfOverlayNodeConfig has the
157          * tunnel type information.
158          */
159         for (AbstractTunnelType tunnelType: requiredTunnelTypes) {
160             boolean tunnelPresent = false;
161             for (Tunnel tunnel: config.getTunnel()) {
162                 if (tunnelType.getTunnelType().equals(tunnel.getTunnelType())) {
163                     tunnelPresent = true;
164                     break;
165                 }
166             }
167             if (tunnelPresent == false) {
168                 return false;
169             }
170         }
171         return true;
172     }
173
174     public static void addOfOverlayExternalPort(String nodeIdString, NodeConnectorId ncId, DataBroker dataBroker) {
175         InstanceIdentifier<ExternalInterfaces> nodeExternalInterfacesIid = InstanceIdentifier.builder(
176                 Nodes.class)
177             .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
178             .augmentation(OfOverlayNodeConfig.class)
179             .child(ExternalInterfaces.class,new ExternalInterfacesKey(ncId))
180             .build();
181
182         ExternalInterfaces externalInterfaces = new ExternalInterfacesBuilder()
183                                                 .setKey(new ExternalInterfacesKey(ncId))
184                                                 .setNodeConnectorId(ncId)
185                                                 .build();
186         WriteTransaction transaction = dataBroker.newReadWriteTransaction();
187         transaction.put(LogicalDatastoreType.CONFIGURATION, nodeExternalInterfacesIid, externalInterfaces, true);
188         submitToDs(transaction);
189         LOG.trace("Added external interface node connector {} to node {}", ncId.getValue(),nodeIdString);
190     }
191
192     public static OfOverlayNodeConfig getOfOverlayConfig(String nodeIdString, DataBroker dataBroker) {
193         InstanceIdentifier<OfOverlayNodeConfig> ofOverlayNodeIid = InstanceIdentifier.builder(
194                 Nodes.class)
195             .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
196             .augmentation(OfOverlayNodeConfig.class)
197             .build();
198
199         ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();
200         Optional<OfOverlayNodeConfig> overlayConfig = readFromDs(LogicalDatastoreType.OPERATIONAL, ofOverlayNodeIid, transaction );
201         if (overlayConfig.isPresent()) {
202             return overlayConfig.get();
203         }
204         return null;
205     }
206
207     private static void addOfOverlayAugmentation(OfOverlayNodeConfig config, String nodeIdString, DataBroker dataBroker) {
208         InstanceIdentifier<OfOverlayNodeConfig> ofOverlayNodeIid = InstanceIdentifier.builder(
209                 Nodes.class)
210             .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
211             .augmentation(OfOverlayNodeConfig.class)
212             .build();
213
214         WriteTransaction transaction = dataBroker.newReadWriteTransaction();
215         transaction.put(LogicalDatastoreType.CONFIGURATION, ofOverlayNodeIid, config, true);
216         submitToDs(transaction);
217     }
218
219     /**
220      * Update the {@link OfOverlayConfig} of an Inventory Node
221      * using the new tunnel state.
222      *
223      * @param nodeIdString
224      * @param tunnels
225      * @param dataBroker
226      */
227     public static void updateOfOverlayConfig(IpAddress ip, String nodeIdString,
228             String nodeConnectorIdString, List<AbstractTunnelType> tunnels, DataBroker dataBroker) {
229
230         if ((ip == null) || (nodeIdString == null)
231                 || (nodeConnectorIdString == null)) {
232             LOG.debug("Can't update OfOverlay: requisite information not present");
233             return;
234         }
235         NodeConnectorId nodeConnectorId = new NodeConnectorId(nodeConnectorIdString);
236         List<Tunnel> tunnelList = new ArrayList<Tunnel>();
237         List<Tunnel> existingTunnels = new ArrayList<Tunnel>();
238         OfOverlayNodeConfig ofConfig = getOfOverlayConfig(nodeIdString, dataBroker);
239         if (ofConfig != null) {
240             existingTunnels = ofConfig.getTunnel();
241         }
242         boolean tunnelsUpdated = false;
243         for (AbstractTunnelType tunnelType: tunnels) {
244             boolean tunnelFound = false;
245             for (Tunnel currentTun: existingTunnels) {
246                 if (tunnelType.getTunnelType().equals(currentTun.getTunnelType())) {
247                     // tunnel update
248                     TunnelBuilder tunnelBuilder = new TunnelBuilder(currentTun);
249                     tunnelBuilder.setIp(ip);
250                     tunnelBuilder.setPort(tunnelType.getPortNumber());
251                     tunnelBuilder.setNodeConnectorId(nodeConnectorId);
252                     tunnelList.add(tunnelBuilder.build());
253                     tunnelFound = true;
254                     tunnelsUpdated = true;
255                 }
256             }
257             // new tunnel
258             if (tunnelFound == false) {
259                 TunnelBuilder tunnelBuilder = new TunnelBuilder();
260                 tunnelBuilder.setIp(ip);
261                 tunnelBuilder.setPort(tunnelType.getPortNumber());
262                 tunnelBuilder.setNodeConnectorId(nodeConnectorId);
263                 tunnelBuilder.setTunnelType(tunnelType.getTunnelType());
264                 tunnelList.add(tunnelBuilder.build());
265                 tunnelsUpdated = true;
266             }
267         }
268         if (tunnelsUpdated == true) {
269             OfOverlayNodeConfigBuilder ofOverlayBuilder = null;
270             if (ofConfig == null) {
271                 ofOverlayBuilder = new OfOverlayNodeConfigBuilder();
272             } else {
273                 ofOverlayBuilder = new OfOverlayNodeConfigBuilder(ofConfig);
274             }
275             ofOverlayBuilder.setTunnel(tunnelList);
276             addOfOverlayAugmentation(ofOverlayBuilder.build(), nodeIdString, dataBroker);
277         }
278     }
279 }