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