2cbca5eb969c9f35b213fda62824f8dc1785bd9e
[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.neutron.ovsdb.util.DataStore.getLongFromDpid;
11 import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.DataStore.readFromDs;
12 import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.DataStore.submitToDs;
13 import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getOvsdbBridge;
14 import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getOvsdbTerminationPoint;
15
16 import java.util.ArrayList;
17 import java.util.List;
18
19 import org.apache.commons.lang3.StringUtils;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
22 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.groupbasedpolicy.neutron.ovsdb.AbstractTunnelType;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfig;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfigBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.Tunnel;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.TunnelBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import com.google.common.base.Optional;
43
44 public class InventoryHelper {
45     private static final Logger LOG = LoggerFactory.getLogger(InventoryHelper.class);
46
47     private static final Long MAX_OF_PORT=65534L;
48     /**
49      * Construct a String that can be used to create a
50      * {@link NodeId}.
51      * The String is constructed by getting the Datapath ID from the OVSDB bridge
52      * augmentation, converting that to a Long, and prepending it with the
53      * "openflow:" prefix.
54      *
55      * @param ovsdbBridge The OVSDB bridge augmentation
56      * @return String representation of the Inventory NodeId, null if it fails
57      */
58     public static String getInventoryNodeIdString(OvsdbBridgeAugmentation ovsdbBridge,
59             InstanceIdentifier<OvsdbTerminationPointAugmentation> ovsdbTpIid, DataBroker dataBroker) {
60         DatapathId dpid = ovsdbBridge.getDatapathId();
61         if (dpid == null) {
62             OvsdbBridgeAugmentation bridgeData = getOvsdbBridge(ovsdbTpIid, dataBroker);
63             dpid = bridgeData.getDatapathId();
64             if (dpid == null) {
65                 LOG.error("No Data Path ID for OVSDB Bridge {}", ovsdbBridge);
66                 return null;
67             }
68         }
69         Long macLong = getLongFromDpid(ovsdbBridge.getDatapathId().getValue());
70         String nodeIdString = "openflow:" + String.valueOf(macLong);
71         if(StringUtils.countMatches(nodeIdString, ":") != 1) {
72             LOG.error("{} is not correct format for NodeId.",nodeIdString);
73             return null;
74         }
75         return nodeIdString;
76     }
77
78     /**
79      * Construct a string that can be used to create a
80      * {@link org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId}.
81      * The String is constructed by first getting the inventory Node ID string, and then
82      * adding the port number obtained by the OVSDB augmentation.
83      *
84      * @param inventoryNodeId The string representation of the Inventory NodeId
85      * @param ovsdbTp The {@link OvsdbTerminationPointAugmentation}
86      * @return String representation of the Inventory NodeConnectorId, null if it fails
87      */
88     public static String getInventoryNodeConnectorIdString(String inventoryNodeId,
89                        OvsdbTerminationPointAugmentation ovsdbTp,
90                        InstanceIdentifier<OvsdbTerminationPointAugmentation> tpIid,
91                        DataBroker dataBroker) {
92         Long ofport = null;
93         if (ovsdbTp.getOfport() != null && ovsdbTp.getOfport()>MAX_OF_PORT) {
94             LOG.debug("Invalid OpenFlow port {} for {}",ovsdbTp.getOfport(), ovsdbTp);
95             return null;
96         }
97         if (ovsdbTp.getOfport() == null) {
98             OvsdbTerminationPointAugmentation readOvsdbTp =
99                     getOvsdbTerminationPoint(tpIid, dataBroker);
100             if (readOvsdbTp == null
101                     || readOvsdbTp.getOfport() == null
102                     || readOvsdbTp.getOfport() >MAX_OF_PORT) {
103                 LOG.debug("Couldn't get OpenFlow port for {}",ovsdbTp);
104                 return null;
105             }
106             ofport = readOvsdbTp.getOfport();
107         } else {
108             ofport = ovsdbTp.getOfport();
109         }
110         String nodeConnectorIdString = inventoryNodeId + ":" + String.valueOf(ofport);
111
112         if(StringUtils.countMatches(nodeConnectorIdString, ":") != 2) {
113             LOG.error("{} is not correct format for NodeConnectorId.",nodeConnectorIdString);
114             return null;
115         }
116         return nodeConnectorIdString;
117     }
118
119     /**
120      * Read the {@link OfOverlayNodeConfig} augmentation from the
121      * Inventory Node, and verify that the tunnel types we need
122      * are present
123      *
124      * @return true if tunnel types are present, false otherwise
125      */
126     public static boolean checkOfOverlayConfig(String nodeIdString,
127                        List<AbstractTunnelType> requiredTunnelTypes, DataBroker dataBroker) {
128         OfOverlayNodeConfig config = getOfOverlayConfig(nodeIdString, dataBroker);
129         if (config == null || config.getTunnel() == null) {
130             LOG.debug("No OfOverlay config for {}",nodeIdString);
131             return false;
132         }
133
134         /*
135          * See if the OfOverlayNodeConfig has the
136          * tunnel type information.
137          */
138         for (AbstractTunnelType tunnelType: requiredTunnelTypes) {
139             boolean tunnelPresent = false;
140             for (Tunnel tunnel: config.getTunnel()) {
141                 if (tunnelType.getTunnelType().equals(tunnel.getTunnelType())) {
142                     tunnelPresent = true;
143                     break;
144                 }
145             }
146             if (tunnelPresent == false) {
147                 return false;
148             }
149         }
150         return true;
151     }
152
153     public static OfOverlayNodeConfig getOfOverlayConfig(String nodeIdString, DataBroker dataBroker) {
154         InstanceIdentifier<OfOverlayNodeConfig> ofOverlayNodeIid = InstanceIdentifier.builder(
155                 Nodes.class)
156             .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
157             .augmentation(OfOverlayNodeConfig.class)
158             .build();
159
160         ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();
161         Optional<OfOverlayNodeConfig> overlayConfig = readFromDs(LogicalDatastoreType.OPERATIONAL, ofOverlayNodeIid, transaction );
162         if (overlayConfig.isPresent()) {
163             return overlayConfig.get();
164         }
165         return null;
166     }
167
168     private static void addOfOverlayAugmentation(OfOverlayNodeConfig config, String nodeIdString, DataBroker dataBroker) {
169         InstanceIdentifier<OfOverlayNodeConfig> ofOverlayNodeIid = InstanceIdentifier.builder(
170                 Nodes.class)
171             .child(Node.class, new NodeKey(new NodeId(nodeIdString)))
172             .augmentation(OfOverlayNodeConfig.class)
173             .build();
174
175         WriteTransaction transaction = dataBroker.newReadWriteTransaction();
176         transaction.put(LogicalDatastoreType.CONFIGURATION, ofOverlayNodeIid, config, true);
177         submitToDs(transaction);
178     }
179
180     /**
181      * Update the {@link OfOverlayConfig} of an Inventory Node
182      * using the new tunnel state.
183      *
184      * @param nodeIdString
185      * @param tunnels
186      * @param dataBroker
187      */
188     public static void updateOfOverlayConfig(IpAddress ip, String nodeIdString,
189             String nodeConnectorIdString, List<AbstractTunnelType> tunnels, DataBroker dataBroker) {
190
191         if ((ip == null) || (nodeIdString == null)
192                 || (nodeConnectorIdString == null)) {
193             LOG.debug("Can't update OfOverlay: requisite information not present");
194             return;
195         }
196         NodeConnectorId nodeConnectorId = new NodeConnectorId(nodeConnectorIdString);
197         List<Tunnel> tunnelList = new ArrayList<Tunnel>();
198         List<Tunnel> existingTunnels = new ArrayList<Tunnel>();
199         OfOverlayNodeConfig ofConfig = getOfOverlayConfig(nodeIdString, dataBroker);
200         if (ofConfig != null) {
201             existingTunnels = ofConfig.getTunnel();
202         }
203         boolean tunnelsUpdated = false;
204         for (AbstractTunnelType tunnelType: tunnels) {
205             boolean tunnelFound = false;
206             for (Tunnel currentTun: existingTunnels) {
207                 if (tunnelType.getTunnelType().equals(currentTun.getTunnelType())) {
208                     // tunnel update
209                     TunnelBuilder tunnelBuilder = new TunnelBuilder(currentTun);
210                     tunnelBuilder.setIp(ip);
211                     tunnelBuilder.setPort(tunnelType.getPortNumber());
212                     tunnelBuilder.setNodeConnectorId(nodeConnectorId);
213                     tunnelList.add(tunnelBuilder.build());
214                     tunnelFound = true;
215                     tunnelsUpdated = true;
216                 }
217             }
218             // new tunnel
219             if (tunnelFound == false) {
220                 TunnelBuilder tunnelBuilder = new TunnelBuilder();
221                 tunnelBuilder.setIp(ip);
222                 tunnelBuilder.setPort(tunnelType.getPortNumber());
223                 tunnelBuilder.setNodeConnectorId(nodeConnectorId);
224                 tunnelBuilder.setTunnelType(tunnelType.getTunnelType());
225                 tunnelList.add(tunnelBuilder.build());
226                 tunnelsUpdated = true;
227             }
228         }
229         if (tunnelsUpdated == true) {
230             OfOverlayNodeConfigBuilder ofOverlayBuilder = null;
231             if (ofConfig == null) {
232                 ofOverlayBuilder = new OfOverlayNodeConfigBuilder();
233             } else {
234                 ofOverlayBuilder = new OfOverlayNodeConfigBuilder(ofConfig);
235             }
236             ofOverlayBuilder.setTunnel(tunnelList);
237             addOfOverlayAugmentation(ofOverlayBuilder.build(), nodeIdString, dataBroker);
238         }
239     }
240 }