Installing NORMAL rules on all the default neutron bridges.
[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.List;
5 import java.util.Map;
6 import java.util.Set;
7
8 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
9 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
10 import org.opendaylight.controller.sal.action.ActionType;
11 import org.opendaylight.controller.sal.core.Node;
12 import org.opendaylight.controller.sal.utils.EtherTypes;
13 import org.opendaylight.controller.sal.utils.HexEncode;
14 import org.opendaylight.controller.sal.utils.ServiceHelper;
15 import org.opendaylight.controller.sal.utils.Status;
16 import org.opendaylight.controller.sal.utils.StatusCode;
17 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
18 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
19 import org.opendaylight.ovsdb.lib.notation.UUID;
20 import org.opendaylight.ovsdb.lib.table.Bridge;
21 import org.opendaylight.ovsdb.lib.table.Interface;
22 import org.opendaylight.ovsdb.lib.table.Port;
23 import org.opendaylight.ovsdb.lib.table.internal.Table;
24 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
25 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
26 import org.opendaylight.ovsdb.plugin.StatusWithUuid;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * OpenStack Neutron with the OpenVswitch data plan relies on a typical OVS bridge configurations that
32  * consists of br-int (Integration Bridge), br-tun (Tunnel bridge), br-ex (External bridge).
33  *
34  * In DevStack like setups, the br-tun is not automatically created on the controller nodes.
35  * Hence this class attempts to bring all the nodes to be elibible for OpenStack operations.
36  *
37  */
38 public class InternalNetworkManager {
39     static final Logger logger = LoggerFactory.getLogger(InternalNetworkManager.class);
40     private static final int LLDP_PRIORITY = 1000;
41     private static final int NORMAL_PRIORITY = 0;
42
43     private static InternalNetworkManager internalNetwork = new InternalNetworkManager();
44     private InternalNetworkManager() {
45     }
46
47     public static InternalNetworkManager getManager() {
48         return internalNetwork;
49     }
50
51     public String getInternalBridgeUUID (Node node, String bridgeName) {
52         try {
53             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
54             Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
55             if (bridgeTable == null) return null;
56             for (String key : bridgeTable.keySet()) {
57                 Bridge bridge = (Bridge)bridgeTable.get(key);
58                 if (bridge.getName().equals(bridgeName)) return key;
59             }
60         } catch (Exception e) {
61             logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
62         }
63         return null;
64     }
65
66     public boolean isInternalNetworkNeutronReady(Node node) {
67         if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getIntegrationBridgeName()) != null) {
68             return true;
69         } else {
70             return false;
71         }
72     }
73
74     public boolean isInternalNetworkOverlayReady(Node node) {
75         if (!this.isInternalNetworkNeutronReady(node)) {
76             return false;
77         }
78         if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName()) != null) {
79             return true;
80         } else {
81             return false;
82         }
83     }
84
85     /*
86      * Lets create these if not already present :
87      *
88        Bridge br-int
89             Port patch-tun
90                 Interface patch-tun
91                     type: patch
92                     options: {peer=patch-int}
93             Port br-int
94                 Interface br-int
95                     type: internal
96       Bridge br-tun
97             Port patch-int
98                 Interface patch-int
99                     type: patch
100                     options: {peer=patch-tun}
101             Port br-tun
102                 Interface br-tun
103                     type: internal
104      */
105     public void createInternalNetworkForOverlay(Node node) throws Exception {
106         String brTun = AdminConfigManager.getManager().getTunnelBridgeName();
107         String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
108         String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
109         String patchTun = AdminConfigManager.getManager().getPatchToTunnel();
110
111         Status status = this.addInternalBridge(node, brInt, patchTun, patchInt);
112         if (!status.isSuccess()) logger.debug("Integration Bridge Creation Status : "+status.toString());
113         status = this.addInternalBridge(node, brTun, patchInt, patchTun);
114         if (!status.isSuccess()) logger.debug("Tunnel Bridge Creation Status : "+status.toString());
115     }
116
117     /*
118      * Lets create these if not already present :
119      *
120        Bridge br-int
121             Port br-int
122                 Interface br-int
123                     type: internal
124      */
125     public void createInternalNetworkForNeutron(Node node) throws Exception {
126         String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
127
128         Status status = this.addInternalBridge(node, brInt, null, null);
129         if (!status.isSuccess()) logger.debug("Integration Bridge Creation Status : "+status.toString());
130     }
131
132     private Status addInternalBridge (Node node, String bridgeName, String localPathName, String remotePatchName) throws Exception {
133         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
134
135         String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
136         if (bridgeUUID == null) {
137             Bridge bridge = new Bridge();
138             bridge.setName(bridgeName);
139
140             StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, bridge);
141             if (!statusWithUuid.isSuccess()) return statusWithUuid;
142             bridgeUUID = statusWithUuid.getUuid().toString();
143             Port port = new Port();
144             port.setName(bridgeName);
145             ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
146         }
147
148         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
149         connectionService.setOFController(node, bridgeUUID);
150
151         if (localPathName != null && remotePatchName != null) {
152             return addPatchPort(node, bridgeUUID, localPathName, remotePatchName);
153         }
154         return new Status(StatusCode.SUCCESS);
155     }
156
157     private Status addPatchPort (Node node, String bridgeUUID, String portName, String patchName) throws Exception {
158         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
159
160         Port patchPort = new Port();
161         patchPort.setName(portName);
162         // Create patch port and interface
163         StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, patchPort);
164         if (!statusWithUuid.isSuccess()) return statusWithUuid;
165
166         String patchPortUUID = statusWithUuid.getUuid().toString();
167
168         String interfaceUUID = null;
169         int timeout = 6;
170         while ((interfaceUUID == null) && (timeout > 0)) {
171             patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), patchPortUUID);
172             OvsDBSet<UUID> interfaces = patchPort.getInterfaces();
173             if (interfaces == null || interfaces.size() == 0) {
174                 // Wait for the OVSDB update to sync up the Local cache.
175                 Thread.sleep(500);
176                 timeout--;
177                 continue;
178             }
179             interfaceUUID = interfaces.toArray()[0].toString();
180         }
181
182         if (interfaceUUID == null) {
183             return new Status(StatusCode.INTERNALERROR);
184         }
185
186         Interface tunInterface = new Interface();
187         tunInterface.setType("patch");
188         OvsDBMap<String, String> options = new OvsDBMap<String, String>();
189         options.put("peer", patchName);
190         tunInterface.setOptions(options);
191         return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, tunInterface);
192     }
193
194     private void initializeOFNormalFlowRules(Node node, String bridgeName) {
195         String brIntId = this.getInternalBridgeUUID(node, bridgeName);
196         if (brIntId == null) {
197             logger.error("Failed to initialize Flow Rules for {}", node);
198             return;
199         }
200         try {
201             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
202             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
203             Set<String> dpids = bridge.getDatapath_id();
204             if (dpids == null || dpids.size() ==  0) return;
205             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
206             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
207             IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
208                     IForwardingRulesManager.class, "default", this);
209             String flowName = ActionType.HW_PATH.toString();
210             FlowConfig flow = new FlowConfig();
211             flow.setName("NORMAL");
212             flow.setNode(ofNode);
213             flow.setPriority(NORMAL_PRIORITY+"");
214             flow.setInstallInHw(true);
215             List<String> normalAction = new ArrayList<String>();
216             normalAction.add(flowName);
217             flow.setActions(normalAction);
218             Status status = null;
219             if (frm.getStaticFlow(flowName, ofNode) == null) {
220                 status = frm.addStaticFlow(flow);
221                 logger.debug("Flow Programming Add Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
222             } else {
223                 status = frm.modifyStaticFlow(flow);
224                 logger.debug("Flow Programming Modify Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
225             }
226         } catch (Exception e) {
227             logger.error("Failed to initialize Flow Rules for {}", node, e);
228         }
229     }
230
231     private void initializeLLDPFlowRules(Node node, String bridgeName) {
232         String brIntId = this.getInternalBridgeUUID(node, bridgeName);
233         if (brIntId == null) {
234             logger.error("Failed to initialize Flow Rules for {}", node);
235             return;
236         }
237         try {
238             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
239             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
240             Set<String> dpids = bridge.getDatapath_id();
241             if (dpids == null || dpids.size() ==  0) return;
242             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
243             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
244             IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
245                     IForwardingRulesManager.class, "default", this);
246             String flowName = "PuntLLDP";
247             List<String> puntAction = new ArrayList<String>();
248             puntAction.add(ActionType.CONTROLLER.toString());
249
250             FlowConfig allowLLDP = new FlowConfig();
251             allowLLDP.setInstallInHw(true);
252             allowLLDP.setName(flowName);
253             allowLLDP.setPriority(LLDP_PRIORITY+"");
254             allowLLDP.setNode(ofNode);
255             allowLLDP.setInstallInHw(true);
256             allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue())
257                     .toUpperCase());
258             allowLLDP.setActions(puntAction);
259             Status status = null;
260             if (frm.getStaticFlow(flowName, ofNode) == null) {
261                 status = frm.addStaticFlow(allowLLDP);
262                 logger.debug("LLDP Flow Add Status {} for Flow {} on {} / {}", status, allowLLDP, ofNode, node);
263             } else {
264                 status = frm.modifyStaticFlow(allowLLDP);
265                 logger.debug("LLDP Flow Modify Status {} for Flow {} on {} / {}", status, allowLLDP, ofNode, node);
266             }
267         } catch (Exception e) {
268             logger.error("Failed to initialize Flow Rules for {}", node, e);
269         }
270     }
271
272     public void prepareInternalNetwork(Node node) {
273         try {
274             this.createInternalNetworkForOverlay(node);
275         } catch (Exception e) {
276             logger.error("Error creating internal network "+node.toString(), e);
277         }
278         //Install NORMAL flows on all the bridges to make sure that we dont end up punting traffic to the OF Controller
279         this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
280         this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getExternalBridgeName());
281         this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
282         this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
283         this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
284     }
285 }