OF Flow programming on br-int (NORMAL) and bidirectional br-tun (based on tenant...
[netvirt.git] / neutron / src / main / java / org / opendaylight / ovsdb / neutron / InternalNetworkManager.java
1 package org.opendaylight.ovsdb.neutron;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Set;
8
9 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
10 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
11 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
12 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
13 import org.opendaylight.controller.sal.action.ActionType;
14 import org.opendaylight.controller.sal.core.Node;
15 import org.opendaylight.controller.sal.utils.HexEncode;
16 import org.opendaylight.controller.sal.utils.ServiceHelper;
17 import org.opendaylight.controller.sal.utils.Status;
18 import org.opendaylight.controller.sal.utils.StatusCode;
19 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
20 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
21 import org.opendaylight.ovsdb.lib.notation.UUID;
22 import org.opendaylight.ovsdb.lib.table.Bridge;
23 import org.opendaylight.ovsdb.lib.table.Interface;
24 import org.opendaylight.ovsdb.lib.table.Port;
25 import org.opendaylight.ovsdb.lib.table.internal.Table;
26 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
27 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 /**
32  * OpenStack Neutron with the OpenVswitch data plan relies on a typical OVS bridge configurations that
33  * consists of br-int (Integration Bridge), br-tun (Tunnel bridge), br-ex (External bridge).
34  *
35  * In DevStack like setups, the br-tun is not automatically created on the controller nodes.
36  * Hence this class attempts to bring all the nodes to be elibible for OpenStack operations.
37  *
38  */
39 public class InternalNetworkManager {
40     static final Logger logger = LoggerFactory.getLogger(InternalNetworkManager.class);
41
42     private static InternalNetworkManager internalNetwork = new InternalNetworkManager();
43     private InternalNetworkManager() {
44     }
45
46     public static InternalNetworkManager getManager() {
47         return internalNetwork;
48     }
49
50     public String getInternalBridgeUUID (Node node, String bridgeName) {
51         try {
52             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
53             Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
54             if (bridgeTable == null) return null;
55             for (String key : bridgeTable.keySet()) {
56                 Bridge bridge = (Bridge)bridgeTable.get(key);
57                 if (bridge.getName().equals(bridgeName)) return key;
58             }
59         } catch (Exception e) {
60             logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
61         }
62         return null;
63     }
64
65     public boolean isInternalNetworkNeutronReady(Node node) throws Exception {
66         if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getIntegrationBridgeName()) != null) {
67             return true;
68         } else {
69             return false;
70         }
71     }
72
73     public boolean isInternalNetworkOverlayReady(Node node) throws Exception {
74         if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName()) != null) {
75             return true;
76         } else {
77             return false;
78         }
79     }
80
81     public Status createInternalNetworkForOverlay(Node node) throws Exception {
82         if (!isInternalNetworkNeutronReady(node)) {
83             logger.error("Integration Bridge is not available in Node {}", node);
84             return new Status(StatusCode.NOTACCEPTABLE, "Integration Bridge is not avaialble in Node " + node);
85         }
86         if (isInternalNetworkOverlayReady(node)) {
87             logger.error("Network Overlay Bridge is already present in Node {}", node);
88             return new Status(StatusCode.NOTACCEPTABLE, "Network Overlay Bridge is already present in Node " + node);
89         }
90
91         /*
92          * Lets create this :
93          *
94          * Bridge br-tun
95                 Port patch-int
96                     Interface patch-int
97                         type: patch
98                         options: {peer=patch-tun}
99                 Port br-tun
100                     Interface br-tun
101                         type: internal
102          */
103
104         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
105         Bridge brTun = new Bridge();
106         brTun.setName(AdminConfigManager.getManager().getTunnelBridgeName());
107         // Create br-tun bridge
108         Status status = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, brTun);
109         if (!status.isSuccess()) return status;
110         String bridgeUUID = status.getDescription();
111         // Set OF Controller
112         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
113         connectionService.setOFController(node, bridgeUUID);
114
115         Port port = new Port();
116         port.setName(brTun.getName());
117         status = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
118
119         String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
120         String patchTun = AdminConfigManager.getManager().getPatchToTunnel();
121
122         status = addPatchPort(node, bridgeUUID, patchInt, patchTun);
123         if (!status.isSuccess()) return status;
124
125         // Create the corresponding patch-tun port in br-int
126         Map<String, Table<?>> bridges = ovsdbTable.getRows(node, Bridge.NAME.getName());
127         for (String brIntUUID : bridges.keySet()) {
128             Bridge brInt = (Bridge) bridges.get(brIntUUID);
129             if (brInt.getName().equalsIgnoreCase(AdminConfigManager.getManager().getIntegrationBridgeName())) {
130                 return addPatchPort(node, brIntUUID, patchTun, patchInt);
131             }
132         }
133
134         return status;
135     }
136
137     private Status addPatchPort (Node node, String bridgeUUID, String portName, String patchName) throws Exception {
138         Status status = null;
139         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
140
141         Port patchPort = new Port();
142         patchPort.setName(portName);
143         // Create patch-int port and interface
144         status = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, patchPort);
145         if (!status.isSuccess()) return status;
146
147         String patchPortUUID = status.getDescription();
148
149         String interfaceUUID = null;
150         int timeout = 6;
151         while ((interfaceUUID == null) && (timeout > 0)) {
152             patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), patchPortUUID);
153             OvsDBSet<UUID> interfaces = patchPort.getInterfaces();
154             if (interfaces == null || interfaces.size() == 0) {
155                 // Wait for the OVSDB update to sync up the Local cache.
156                 Thread.sleep(500);
157                 timeout--;
158                 continue;
159             }
160             interfaceUUID = interfaces.toArray()[0].toString();
161         }
162
163         if (interfaceUUID == null) {
164             return new Status(StatusCode.INTERNALERROR);
165         }
166
167         Interface tunInterface = new Interface();
168         tunInterface.setType("patch");
169         OvsDBMap<String, String> options = new OvsDBMap<String, String>();
170         options.put("peer", patchName);
171         tunInterface.setOptions(options);
172         status = ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, tunInterface);
173
174         return status;
175     }
176
177     private void prepareInternalNetwork (NeutronNetwork network, Node node) {
178         // vlan, vxlan, and gre
179         if (network.getProviderNetworkType().equalsIgnoreCase("gre") ||
180                 network.getProviderNetworkType().equalsIgnoreCase("vxlan") ||
181                 network.getProviderNetworkType().equalsIgnoreCase("vlan")) {
182
183             try {
184                 if (!this.isInternalNetworkOverlayReady(node)) {
185                     this.createInternalNetworkForOverlay(node);
186                 }
187             } catch (Exception e) {
188                 e.printStackTrace();
189             }
190         } else {
191             try {
192                 if (!this.isInternalNetworkNeutronReady(node)) {
193                     // TODO : FILL IN
194                     // this.createInternalNetworkForNeutron(node);
195                 }
196             } catch (Exception e) {
197                 e.printStackTrace();
198             }
199         }
200
201         this.initializeFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
202     }
203
204     private void initializeFlowRules(Node node, String bridgeName) {
205         String brIntId = this.getInternalBridgeUUID(node, bridgeName);
206         if (brIntId == null) {
207             logger.error("Failed to initialize Flow Rules for {}", node);
208             return;
209         }
210         try {
211             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
212             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
213             Set<String> dpids = bridge.getDatapath_id();
214             if (dpids == null || dpids.size() ==  0) return;
215             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
216             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
217             IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
218                     IForwardingRulesManager.class, "default", this);
219             FlowConfig flow = new FlowConfig();
220             flow.setName("IntegrationBridgeNormal");
221             flow.setNode(ofNode);
222             flow.setPriority("1");
223             List<String> normalAction = new ArrayList<String>();
224             normalAction.add(ActionType.HW_PATH.toString());
225             flow.setActions(normalAction);
226             Status status = frm.addStaticFlow(flow);
227             logger.debug("Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
228         } catch (Exception e) {
229             logger.error("Failed to initialize Flow Rules for {}", node, e);
230         }
231     }
232
233     public void prepareInternalNetwork(NeutronNetwork network) {
234         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
235         List<Node> nodes = connectionService.getNodes();
236         for (Node node : nodes) {
237             prepareInternalNetwork(network, node);
238         }
239     }
240
241     public void prepareInternalNetwork(Node node) {
242         INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
243         List <NeutronNetwork> networks = neutronNetworkService.getAllNetworks();
244         for (NeutronNetwork network : networks) {
245             prepareInternalNetwork(network, node);
246         }
247     }
248
249     public static List safe( List other ) {
250         return other == null ? Collections.EMPTY_LIST : other;
251     }
252 }