0c64cc0e9ade54d383bbf6e91834044ea37e0f71
[onosfw.git] /
1 /*
2  * Copyright 2015 Open Networking Laboratory
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.onosproject.ovsdb.controller.driver;
17
18 import io.netty.channel.Channel;
19
20 import java.net.InetSocketAddress;
21 import java.util.ArrayList;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.concurrent.ConcurrentMap;
28 import java.util.concurrent.ExecutionException;
29
30 import org.onlab.packet.IpAddress;
31 import org.onosproject.ovsdb.controller.OvsdbBridge;
32 import org.onosproject.ovsdb.controller.OvsdbBridgeName;
33 import org.onosproject.ovsdb.controller.OvsdbClientService;
34 import org.onosproject.ovsdb.controller.OvsdbConstant;
35 import org.onosproject.ovsdb.controller.OvsdbDatapathId;
36 import org.onosproject.ovsdb.controller.OvsdbNodeId;
37 import org.onosproject.ovsdb.controller.OvsdbPort;
38 import org.onosproject.ovsdb.controller.OvsdbPortName;
39 import org.onosproject.ovsdb.controller.OvsdbPortNumber;
40 import org.onosproject.ovsdb.controller.OvsdbRowStore;
41 import org.onosproject.ovsdb.controller.OvsdbStore;
42 import org.onosproject.ovsdb.controller.OvsdbTableStore;
43 import org.onosproject.ovsdb.controller.OvsdbTunnel;
44 import org.onosproject.ovsdb.rfc.jsonrpc.Callback;
45 import org.onosproject.ovsdb.rfc.message.OperationResult;
46 import org.onosproject.ovsdb.rfc.message.TableUpdates;
47 import org.onosproject.ovsdb.rfc.notation.Condition;
48 import org.onosproject.ovsdb.rfc.notation.Mutation;
49 import org.onosproject.ovsdb.rfc.notation.OvsdbMap;
50 import org.onosproject.ovsdb.rfc.notation.OvsdbSet;
51 import org.onosproject.ovsdb.rfc.notation.Row;
52 import org.onosproject.ovsdb.rfc.notation.UUID;
53 import org.onosproject.ovsdb.rfc.operations.Delete;
54 import org.onosproject.ovsdb.rfc.operations.Insert;
55 import org.onosproject.ovsdb.rfc.operations.Mutate;
56 import org.onosproject.ovsdb.rfc.operations.Operation;
57 import org.onosproject.ovsdb.rfc.operations.Update;
58 import org.onosproject.ovsdb.rfc.schema.ColumnSchema;
59 import org.onosproject.ovsdb.rfc.schema.DatabaseSchema;
60 import org.onosproject.ovsdb.rfc.schema.TableSchema;
61 import org.onosproject.ovsdb.rfc.table.Bridge;
62 import org.onosproject.ovsdb.rfc.table.Controller;
63 import org.onosproject.ovsdb.rfc.table.Interface;
64 import org.onosproject.ovsdb.rfc.table.OvsdbTable;
65 import org.onosproject.ovsdb.rfc.table.Port;
66 import org.onosproject.ovsdb.rfc.table.TableGenerator;
67 import org.onosproject.ovsdb.rfc.utils.ConditionUtil;
68 import org.onosproject.ovsdb.rfc.utils.FromJsonUtil;
69 import org.onosproject.ovsdb.rfc.utils.JsonRpcWriterUtil;
70 import org.onosproject.ovsdb.rfc.utils.MutationUtil;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 import com.fasterxml.jackson.databind.JsonNode;
75 import com.google.common.base.Function;
76 import com.google.common.collect.Lists;
77 import com.google.common.collect.Maps;
78 import com.google.common.collect.Sets;
79 import com.google.common.util.concurrent.Futures;
80 import com.google.common.util.concurrent.ListenableFuture;
81 import com.google.common.util.concurrent.SettableFuture;
82
83 /**
84  * An representation of an ovsdb client.
85  */
86 public class DefaultOvsdbClient
87         implements OvsdbProviderService, OvsdbClientService {
88
89     private final Logger log = LoggerFactory
90             .getLogger(DefaultOvsdbClient.class);
91
92     private Channel channel;
93
94     private OvsdbAgent agent;
95     private boolean connected;
96     private OvsdbNodeId nodeId;
97     private Callback monitorCallBack;
98
99     private OvsdbStore ovsdbStore = new OvsdbStore();
100
101     private final Map<String, String> requestMethod = Maps.newHashMap();
102     private final Map<String, SettableFuture<? extends Object>> requestResult = Maps
103             .newHashMap();
104
105     private final Map<String, DatabaseSchema> schema = Maps.newHashMap();
106     private final Set<OvsdbTunnel> ovsdbTunnels = new HashSet<OvsdbTunnel>();
107
108     /**
109      * Creates an OvsdbClient.
110      *
111      * @param nodeId ovsdb node id
112      */
113     public DefaultOvsdbClient(OvsdbNodeId nodeId) {
114         this.nodeId = nodeId;
115     }
116
117     @Override
118     public OvsdbNodeId nodeId() {
119         return nodeId;
120     }
121
122     @Override
123     public void setAgent(OvsdbAgent agent) {
124         if (this.agent == null) {
125             this.agent = agent;
126         }
127     }
128
129     @Override
130     public void setChannel(Channel channel) {
131         this.channel = channel;
132     }
133
134     @Override
135     public void setConnection(boolean connected) {
136         this.connected = connected;
137     }
138
139     @Override
140     public boolean isConnected() {
141         return this.connected;
142     }
143
144     @Override
145     public void nodeAdded() {
146         this.agent.addConnectedNode(nodeId, this);
147     }
148
149     @Override
150     public void nodeRemoved() {
151         this.agent.removeConnectedNode(nodeId);
152         channel.disconnect();
153     }
154
155     /**
156      * Gets the ovsdb table store.
157      *
158      * @param dbName the ovsdb database name
159      * @return ovsTableStore, empty if table store is find
160      */
161     private OvsdbTableStore getTableStore(String dbName) {
162         if (ovsdbStore == null) {
163             return null;
164         }
165         return ovsdbStore.getOvsdbTableStore(dbName);
166     }
167
168     /**
169      * Gets the ovsdb row store.
170      *
171      * @param dbName the ovsdb database name
172      * @param tableName the ovsdb table name
173      *
174      * @return ovsRowStore, empty if row store is find
175      */
176     private OvsdbRowStore getRowStore(String dbName, String tableName) {
177         OvsdbTableStore tableStore = getTableStore(dbName);
178         if (tableStore == null) {
179             return null;
180         }
181         return tableStore.getRows(tableName);
182     }
183
184     /**
185      * Gets the ovsdb row.
186      *
187      * @param dbName the ovsdb database name
188      * @param tableName the ovsdb table name
189      * @param uuid the key of the row
190      * @return row, empty if row is find
191      */
192     @Override
193     public Row getRow(String dbName, String tableName, String uuid) {
194         OvsdbTableStore tableStore = getTableStore(dbName);
195         if (tableStore == null) {
196             return null;
197         }
198         OvsdbRowStore rowStore = tableStore.getRows(tableName);
199         if (rowStore == null) {
200             return null;
201         }
202         return rowStore.getRow(uuid);
203     }
204
205     @Override
206     public void removeRow(String dbName, String tableName, String uuid) {
207         OvsdbTableStore tableStore = getTableStore(dbName);
208         if (tableStore == null) {
209             return;
210         }
211         OvsdbRowStore rowStore = tableStore.getRows(tableName);
212         if (rowStore == null) {
213             return;
214         }
215         rowStore.deleteRow(uuid);
216     }
217
218     @Override
219     public void updateOvsdbStore(String dbName, String tableName, String uuid,
220                                  Row row) {
221         OvsdbTableStore tableStore = ovsdbStore.getOvsdbTableStore(dbName);
222         if (tableStore == null) {
223             tableStore = new OvsdbTableStore();
224         }
225         OvsdbRowStore rowStore = tableStore.getRows(tableName);
226         if (rowStore == null) {
227             rowStore = new OvsdbRowStore();
228         }
229         rowStore.insertRow(uuid, row);
230         tableStore.createOrUpdateTable(tableName, rowStore);
231         ovsdbStore.createOrUpdateOvsdbStore(dbName, tableStore);
232     }
233
234     @Override
235     public String getPortUuid(String portName, String bridgeUuid) {
236         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
237
238         Row bridgeRow = getRow(OvsdbConstant.DATABASENAME,
239                                OvsdbConstant.BRIDGE, bridgeUuid);
240
241         Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, bridgeRow,
242                                                          OvsdbTable.BRIDGE);
243         if (bridge != null) {
244             OvsdbSet setPorts = (OvsdbSet) bridge.getPortsColumn().data();
245             @SuppressWarnings("unchecked")
246             Set<UUID> ports = setPorts.set();
247             if (ports == null || ports.size() == 0) {
248                 log.warn("The port uuid is null");
249                 return null;
250             }
251
252             for (UUID uuid : ports) {
253                 Row portRow = getRow(OvsdbConstant.DATABASENAME,
254                                      OvsdbConstant.PORT, uuid.value());
255                 Port port = (Port) TableGenerator.getTable(dbSchema, portRow,
256                                                            OvsdbTable.PORT);
257                 if (port != null && portName.equalsIgnoreCase(port.getName())) {
258                     return uuid.value();
259                 }
260             }
261
262         }
263         return null;
264     }
265
266     @Override
267     public String getInterfaceUuid(String portUuid, String portName) {
268         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
269
270         Row portRow = getRow(OvsdbConstant.DATABASENAME, OvsdbConstant.PORT,
271                              portUuid);
272         Port port = (Port) TableGenerator.getTable(dbSchema, portRow,
273                                                    OvsdbTable.PORT);
274
275         if (port != null) {
276             OvsdbSet setInterfaces = (OvsdbSet) port.getInterfacesColumn().data();
277             @SuppressWarnings("unchecked")
278             Set<UUID> interfaces = setInterfaces.set();
279
280             if (interfaces == null || interfaces.size() == 0) {
281                 log.warn("The interface uuid is null");
282                 return null;
283             }
284
285             for (UUID uuid : interfaces) {
286                 Row intfRow = getRow(OvsdbConstant.DATABASENAME,
287                                      OvsdbConstant.INTERFACE, uuid.value());
288                 Interface intf = (Interface) TableGenerator
289                         .getTable(dbSchema, intfRow, OvsdbTable.INTERFACE);
290                 if (intf != null && portName.equalsIgnoreCase(intf.getName())) {
291                     return uuid.value();
292                 }
293             }
294
295         }
296
297         return null;
298     }
299
300     @Override
301     public String getBridgeUuid(String bridgeName) {
302         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
303
304         OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
305                                              OvsdbConstant.BRIDGE);
306         if (rowStore == null) {
307             log.debug("The bridge uuid is null");
308             return null;
309         }
310
311         ConcurrentMap<String, Row> bridgeTableRows = rowStore.getRowStore();
312         if (bridgeTableRows == null) {
313             log.debug("The bridge uuid is null");
314             return null;
315         }
316
317         for (String uuid : bridgeTableRows.keySet()) {
318             Bridge bridge = (Bridge) TableGenerator
319                     .getTable(dbSchema, bridgeTableRows.get(uuid),
320                               OvsdbTable.BRIDGE);
321
322             if (bridge.getName().equals(bridgeName)) {
323                 return uuid;
324             }
325
326         }
327         return null;
328     }
329
330     @Override
331     public String getControllerUuid(String controllerName,
332                                     String controllerTarget) {
333         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
334         OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
335                                              OvsdbConstant.CONTROLLER);
336         if (rowStore == null) {
337             log.debug("The controller uuid is null");
338             return null;
339         }
340
341         ConcurrentMap<String, Row> controllerTableRows = rowStore.getRowStore();
342         if (controllerTableRows != null) {
343             for (String uuid : controllerTableRows.keySet()) {
344
345                 Controller controller = (Controller) TableGenerator
346                         .getTable(dbSchema, controllerTableRows.get(uuid),
347                                   OvsdbTable.CONTROLLER);
348                 String target = (String) controller.getTargetColumn().data();
349                 if (target.equalsIgnoreCase(controllerTarget)) {
350                     return uuid;
351                 }
352
353             }
354         }
355         return null;
356     }
357
358     @Override
359     public String getOvsUuid(String dbName) {
360         OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
361                                              OvsdbConstant.DATABASENAME);
362         if (rowStore == null) {
363             log.debug("The bridge uuid is null");
364             return null;
365         }
366         ConcurrentMap<String, Row> ovsTableRows = rowStore.getRowStore();
367         if (ovsTableRows != null) {
368             for (String uuid : ovsTableRows.keySet()) {
369                 Row row = ovsTableRows.get(uuid);
370                 String tableName = row.tableName();
371                 if (tableName.equals(dbName)) {
372                     return uuid;
373                 }
374             }
375         }
376         return null;
377     }
378
379     @Override
380     public void createPort(String bridgeName, String portName) {
381         String bridgeUuid = getBridgeUuid(bridgeName);
382         if (bridgeUuid == null) {
383             log.error("Can't find bridge {} in {}", bridgeName,
384                       nodeId.getIpAddress());
385             return;
386         }
387
388         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
389         String portUuid = getPortUuid(portName, bridgeUuid);
390
391         Port port = (Port) TableGenerator
392                 .createTable(dbSchema, OvsdbTable.PORT);
393
394         port.setName(portName);
395         if (portUuid == null) {
396             insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
397                       "ports", bridgeUuid, port.getRow());
398         } else {
399             updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
400         }
401
402         return;
403     }
404
405     @Override
406     public void dropPort(String bridgeName, String portName) {
407         String bridgeUuid = getBridgeUuid(bridgeName);
408         if (bridgeUuid == null) {
409             log.error("Could not find Bridge {} in {}", bridgeName, nodeId);
410             return;
411         }
412
413         String portUuid = getPortUuid(portName, bridgeUuid);
414         if (portUuid != null) {
415             log.info("Port {} delete", portName);
416             deleteConfig(OvsdbConstant.PORT, "_uuid", portUuid,
417                       OvsdbConstant.BRIDGE, "ports");
418         }
419     }
420
421     @Override
422     public void createBridge(String bridgeName) {
423         log.debug("create bridge {}", bridgeName);
424
425         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
426         if (dbSchema == null) {
427             log.warn("The schema is null");
428             return;
429         }
430
431         Bridge bridge = (Bridge) TableGenerator.createTable(dbSchema,
432                                                             OvsdbTable.BRIDGE);
433         if (bridge == null) {
434             log.debug("Can not create bridge");
435             return;
436         }
437
438         Set<String> failModes = new HashSet<>();
439         failModes.add("secure");
440         bridge.setFailMode(failModes);
441
442         Set<String> protocols = new HashSet<>();
443         protocols.add(OvsdbConstant.OPENFLOW13);
444         bridge.setProtocols(protocols);
445
446         String ovsUuid = getOvsUuid(OvsdbConstant.DATABASENAME);
447         if (ovsUuid == null) {
448             log.warn("The Open_vSwitch is null");
449             return;
450         }
451
452         String bridgeUuid = getBridgeUuid(bridgeName);
453         if (bridgeUuid == null) {
454             log.debug("Create a new bridge");
455
456             bridge.setName(bridgeName);
457             bridgeUuid = insertConfig(OvsdbConstant.BRIDGE, "_uuid",
458                                    OvsdbConstant.DATABASENAME, "bridges",
459                                    ovsUuid, bridge.getRow());
460
461             if (bridgeUuid != null) {
462                 Port port = (Port) TableGenerator.createTable(dbSchema,
463                                                               OvsdbTable.PORT);
464                 if (port != null) {
465                     log.debug("the port is not null");
466                     port.setName(bridgeName);
467
468                     insertConfig(OvsdbConstant.PORT, "_uuid", "Bridge", "ports", bridgeUuid,
469                               port.getRow());
470                 }
471             }
472
473         } else {
474             log.info("Update a bridge");
475             updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid, bridge.getRow());
476         }
477
478         setController(bridgeUuid);
479         log.info("Create bridge success");
480     }
481
482     /**
483      * Sets the Controller.
484      *
485      * @param bridgeUuid bridge uuid
486      */
487     private void setController(String bridgeUuid) {
488         String controllerUuid = null;
489         String iPAddress = IpAddress.valueOf(((InetSocketAddress) channel
490                                                      .localAddress())
491                                                      .getAddress()
492                                                      .getHostAddress())
493                 .toString();
494
495         String target = "tcp:" + iPAddress + ":" + OvsdbConstant.OFPORT;
496         log.debug("controller IP {}: port {}", iPAddress, OvsdbConstant.OFPORT);
497
498         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
499         Controller controller = (Controller) TableGenerator
500                 .createTable(dbSchema, OvsdbTable.CONTROLLER);
501
502         if (controller != null) {
503             controller.setTarget(target);
504             controllerUuid = getControllerUuid(OvsdbConstant.CONTROLLER, target);
505             if (controllerUuid == null) {
506
507                 insertConfig(OvsdbConstant.CONTROLLER, "_uuid",
508                           OvsdbConstant.BRIDGE, "controller", bridgeUuid,
509                           controller.getRow());
510
511             } else {
512
513                 Bridge bridge = (Bridge) TableGenerator
514                         .createTable(dbSchema, OvsdbTable.BRIDGE);
515                 Set<UUID> controllerUuids = new HashSet<>();
516                 controllerUuids.add(UUID.uuid(controllerUuid));
517                 bridge.setController(controllerUuids);
518                 updateConfig(OvsdbConstant.CONTROLLER, "_uuid", bridgeUuid, bridge.getRow());
519
520             }
521         }
522
523     }
524
525     @Override
526     public void dropBridge(String bridgeName) {
527         String bridgeUUID = getBridgeUuid(bridgeName);
528         if (bridgeUUID == null) {
529             log.warn("Could not find bridge in node", nodeId.getIpAddress());
530             return;
531         }
532         deleteConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUUID,
533                   OvsdbConstant.DATABASENAME, "bridges");
534     }
535
536     @Override
537     public void createTunnel(IpAddress srcIp, IpAddress dstIp) {
538         String bridgeUuid = getBridgeUuid(OvsdbConstant.INTEGRATION_BRIDGE);
539         if (bridgeUuid == null) {
540             log.warn("Could not find bridge {} and Could not create tunnel. ",
541                      OvsdbConstant.INTEGRATION_BRIDGE);
542             return;
543         }
544
545         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
546         String portName = getTunnelName(OvsdbConstant.TYPEVXLAN, dstIp);
547         String portUuid = getPortUuid(portName, bridgeUuid);
548
549         Port port = (Port) TableGenerator
550                 .createTable(dbSchema, OvsdbTable.PORT);
551         if (port != null) {
552             port.setName(portName);
553         }
554
555         if (portUuid == null) {
556             portUuid = insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
557                       "ports", bridgeUuid, port.getRow());
558         } else {
559             updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
560         }
561
562         // When a tunnel is created, A row is inserted into port table and
563         // interface table of the ovsdb node.
564         // and the following step is to get the interface uuid from local store
565         // in controller node.
566         // but it need spend some time synchronising data between node and
567         // controller.
568         // so loop to judge if interfaceUUid is null is necessary.
569         String interfaceUuid = null;
570         for (int i = 0; i < 10; i++) {
571             interfaceUuid = getInterfaceUuid(portUuid, portName);
572             if (interfaceUuid == null) {
573                 try {
574                     Thread.sleep(500);
575                 } catch (InterruptedException e) {
576                     log.warn("Interrupted while waiting to get interfaceUuid");
577                     Thread.currentThread().interrupt();
578                 }
579             } else {
580                 break;
581             }
582         }
583
584         if (interfaceUuid != null) {
585
586             Interface tunInterface = (Interface) TableGenerator
587                     .createTable(dbSchema, OvsdbTable.INTERFACE);
588
589             if (tunInterface != null) {
590
591                 tunInterface.setType(OvsdbConstant.TYPEVXLAN);
592                 Map<String, String> options = Maps.newHashMap();
593                 options.put("key", "flow");
594                 options.put("local_ip", srcIp.toString());
595                 options.put("remote_ip", dstIp.toString());
596                 tunInterface.setOptions(options);
597                 updateConfig(OvsdbConstant.INTERFACE, "_uuid", interfaceUuid,
598                           tunInterface.getRow());
599                 log.info("Tunnel added success", tunInterface);
600
601             }
602         }
603
604         return;
605     }
606
607     @Override
608     public void dropTunnel(IpAddress srcIp, IpAddress dstIp) {
609         String bridgeName = OvsdbConstant.INTEGRATION_BRIDGE;
610         String portName = getTunnelName(OvsdbConstant.TYPEVXLAN, dstIp);
611         String bridgeUuid = getBridgeUuid(OvsdbConstant.INTEGRATION_BRIDGE);
612         if (bridgeUuid == null) {
613             log.warn("Could not find bridge {} in {}", bridgeName,
614                      nodeId.getIpAddress());
615             return;
616         }
617
618         String portUUID = getPortUuid(portName, bridgeUuid);
619         if (portUUID != null) {
620             log.info("Delete tunnel");
621             deleteConfig(OvsdbConstant.PORT, "_uuid", portUUID,
622                       OvsdbConstant.BRIDGE, "ports");
623         }
624
625         return;
626     }
627
628     /**
629      * Delete transact config.
630      *
631      * @param childTableName child table name
632      * @param childColumnName child column name
633      * @param childUuid child row uuid
634      * @param parentTableName parent table name
635      * @param parentColumnName parent column
636      *
637      */
638     private void deleteConfig(String childTableName, String childColumnName,
639                            String childUuid, String parentTableName,
640                            String parentColumnName) {
641         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
642         TableSchema childTableSchema = dbSchema.getTableSchema(childTableName);
643
644         ArrayList<Operation> operations = Lists.newArrayList();
645         if (parentTableName != null && parentColumnName != null) {
646             TableSchema parentTableSchema = dbSchema
647                     .getTableSchema(parentTableName);
648             ColumnSchema parentColumnSchema = parentTableSchema
649                     .getColumnSchema(parentColumnName);
650             List<Mutation> mutations = Lists.newArrayList();
651             Mutation mutation = MutationUtil.delete(parentColumnSchema.name(),
652                                                     UUID.uuid(childUuid));
653             mutations.add(mutation);
654             List<Condition> conditions = Lists.newArrayList();
655             Condition condition = ConditionUtil.includes(parentColumnName,
656                                                          UUID.uuid(childUuid));
657             conditions.add(condition);
658             Mutate op = new Mutate(parentTableSchema, conditions, mutations);
659             operations.add(op);
660         }
661
662         List<Condition> conditions = Lists.newArrayList();
663         Condition condition = ConditionUtil.equals(childColumnName, UUID.uuid(childUuid));
664         conditions.add(condition);
665         Delete del = new Delete(childTableSchema, conditions);
666         operations.add(del);
667         transactConfig(OvsdbConstant.DATABASENAME, operations);
668
669         return;
670     }
671
672     /**
673      * Update transact config.
674      *
675      * @param tableName table name
676      * @param columnName column name
677      * @param uuid uuid
678      * @param row the config data
679      *
680      */
681     private void updateConfig(String tableName, String columnName, String uuid,
682                            Row row) {
683         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
684         TableSchema tableSchema = dbSchema.getTableSchema(tableName);
685
686         List<Condition> conditions = Lists.newArrayList();
687         Condition condition = ConditionUtil.equals(columnName, UUID.uuid(uuid));
688         conditions.add(condition);
689
690         Update update = new Update(tableSchema, row, conditions);
691
692         ArrayList<Operation> operations = Lists.newArrayList();
693         operations.add(update);
694
695         transactConfig(OvsdbConstant.DATABASENAME, operations);
696     }
697
698     /**
699      * Insert transact config.
700      *
701      * @param childTableName child table name
702      * @param childColumnName child column name
703      * @param parentTableName parent table name
704      * @param parentColumnName parent column
705      * @param parentUuid parent uuid
706      * @param row the config data
707      *
708      * @return uuid, empty if no uuid is find
709      */
710     private String insertConfig(String childTableName, String childColumnName,
711                              String parentTableName, String parentColumnName,
712                              String parentUuid, Row row) {
713         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
714         TableSchema tableSchema = dbSchema.getTableSchema(childTableName);
715
716         String namedUuid = childTableName;
717         Insert insert = new Insert(tableSchema, namedUuid, row);
718
719         ArrayList<Operation> operations = Lists.newArrayList();
720         operations.add(insert);
721
722         if (parentTableName != null && parentColumnName != null) {
723             TableSchema parentTableSchema = dbSchema
724                     .getTableSchema(parentTableName);
725             ColumnSchema parentColumnSchema = parentTableSchema
726                     .getColumnSchema(parentColumnName);
727
728             List<Mutation> mutations = Lists.newArrayList();
729             Mutation mutation = MutationUtil.insert(parentColumnSchema.name(),
730                                                     UUID.uuid(namedUuid));
731             mutations.add(mutation);
732
733             List<Condition> conditions = Lists.newArrayList();
734             Condition condition = ConditionUtil.equals("_uuid",
735                                                        UUID.uuid(parentUuid));
736             conditions.add(condition);
737
738             Mutate op = new Mutate(parentTableSchema, conditions, mutations);
739             operations.add(op);
740         }
741         if (childTableName.equalsIgnoreCase(OvsdbConstant.PORT)) {
742             log.info("Handle port insert");
743             Insert intfInsert = handlePortInsertTable(OvsdbConstant.INTERFACE,
744                                                     row);
745
746             if (intfInsert != null) {
747                 operations.add(intfInsert);
748             }
749
750             Insert ins = (Insert) operations.get(0);
751             ins.getRow().put("interfaces",
752                              UUID.uuid(OvsdbConstant.INTERFACE));
753         }
754
755         List<OperationResult> results;
756         try {
757             results = transactConfig(OvsdbConstant.DATABASENAME, operations)
758                     .get();
759
760             return results.get(0).getUuid().value();
761         } catch (InterruptedException e) {
762             log.warn("Interrupted while waiting to get result");
763             Thread.currentThread().interrupt();
764         } catch (ExecutionException e) {
765             log.error("Exception thrown while to get result");
766         }
767
768         return null;
769     }
770
771     /**
772      * Handles port insert.
773      *
774      * @param tableName ovsdb table interface
775      * @param portRow row of port
776      *
777      * @return insert, empty if null
778      */
779     private Insert handlePortInsertTable(String tableName, Row portRow) {
780         DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
781
782         TableSchema portTableSchema = dbSchema
783                 .getTableSchema(OvsdbConstant.PORT);
784         ColumnSchema portColumnSchema = portTableSchema.getColumnSchema("name");
785
786         String portName = (String) portRow.getColumn(portColumnSchema.name()).data();
787
788         Interface inf = (Interface) TableGenerator
789                 .createTable(dbSchema, OvsdbTable.INTERFACE);
790
791         inf.setName(portName);
792
793         TableSchema intfTableSchema = dbSchema
794                 .getTableSchema(OvsdbConstant.INTERFACE);
795         Insert insert = new Insert(intfTableSchema, OvsdbConstant.INTERFACE,
796                                    inf.getRow());
797         return insert;
798     }
799
800     /**
801      * Gets tunnel name.
802      *
803      * @param tunnelType
804      * @param dstIp the remote ip address
805      *
806      * @return tunnel name
807      */
808     private String getTunnelName(String tunnelType, IpAddress dstIp) {
809         return tunnelType + "-" + dstIp.toString();
810     }
811
812     @Override
813     public ListenableFuture<DatabaseSchema> getOvsdbSchema(String dbName) {
814         if (dbName == null) {
815             return null;
816         }
817         DatabaseSchema databaseSchema = schema.get(dbName);
818         if (databaseSchema == null) {
819             List<String> dbNames = new ArrayList<String>();
820             dbNames.add(dbName);
821             Function<JsonNode, DatabaseSchema> rowFunction = new Function<JsonNode, DatabaseSchema>() {
822                 @Override
823                 public DatabaseSchema apply(JsonNode input) {
824                     log.info("Get ovsdb database schema", dbName);
825                     DatabaseSchema dbSchema = FromJsonUtil
826                             .jsonNodeToDbSchema(dbName, input);
827                     if (dbSchema == null) {
828                         log.debug("Get ovsdb database schema error");
829                         return null;
830                     }
831                     schema.put(dbName, dbSchema);
832
833                     return dbSchema;
834                 }
835             };
836
837             ListenableFuture<JsonNode> input = getSchema(dbNames);
838             if (input != null) {
839                 return Futures.transform(input, rowFunction);
840             }
841             return null;
842         } else {
843             return Futures.immediateFuture(databaseSchema);
844         }
845     }
846
847     @Override
848     public ListenableFuture<TableUpdates> monitorTables(String dbName, String id) {
849         if (dbName == null) {
850             return null;
851         }
852         DatabaseSchema dbSchema = schema.get(dbName);
853         if (dbSchema != null) {
854             Function<JsonNode, TableUpdates> rowFunction = new Function<JsonNode, TableUpdates>() {
855                 @Override
856                 public TableUpdates apply(JsonNode input) {
857                     log.info("Get table updates");
858                     TableUpdates updates = FromJsonUtil
859                             .jsonNodeToTableUpdates(input, dbSchema);
860                     if (updates == null) {
861                         log.debug("Get table updates error");
862                         return null;
863                     }
864                     return updates;
865                 }
866             };
867             return Futures.transform(monitor(dbSchema, id), rowFunction);
868         }
869         return null;
870     }
871
872     @Override
873     public ListenableFuture<List<OperationResult>> transactConfig(String dbName,
874                                                                   List<Operation> operations) {
875         if (dbName == null) {
876             return null;
877         }
878         DatabaseSchema dbSchema = schema.get(dbName);
879         if (dbSchema != null) {
880             Function<List<JsonNode>, List<OperationResult>> rowFunction =
881                     new Function<List<JsonNode>, List<OperationResult>>() {
882                 @Override
883                 public List<OperationResult> apply(List<JsonNode> input) {
884                     log.info("Get ovsdb operation result");
885                     List<OperationResult> result = FromJsonUtil
886                             .jsonNodeToOperationResult(input, operations);
887
888                     if (result == null) {
889                         log.debug("The operation result is null");
890                         return null;
891                     }
892                     return result;
893                 }
894             };
895             return Futures.transform(transact(dbSchema, operations),
896                                      rowFunction);
897         }
898         return null;
899     }
900
901     @Override
902     public ListenableFuture<JsonNode> getSchema(List<String> dbnames) {
903         String id = java.util.UUID.randomUUID().toString();
904         String getSchemaString = JsonRpcWriterUtil.getSchemaStr(id, dbnames);
905
906         SettableFuture<JsonNode> sf = SettableFuture.create();
907         requestResult.put(id, sf);
908         requestMethod.put(id, "getSchema");
909
910         channel.writeAndFlush(getSchemaString);
911         return sf;
912
913     }
914
915     @Override
916     public ListenableFuture<List<String>> echo() {
917         String id = java.util.UUID.randomUUID().toString();
918         String echoString = JsonRpcWriterUtil.echoStr(id);
919
920         SettableFuture<List<String>> sf = SettableFuture.create();
921         requestResult.put(id, sf);
922         requestMethod.put(id, "echo");
923
924         channel.writeAndFlush(echoString);
925         return sf;
926
927     }
928
929     @Override
930     public ListenableFuture<JsonNode> monitor(DatabaseSchema dbSchema,
931                                               String monitorId) {
932         String id = java.util.UUID.randomUUID().toString();
933         String monitorString = JsonRpcWriterUtil.monitorStr(id, monitorId,
934                                                             dbSchema);
935
936         SettableFuture<JsonNode> sf = SettableFuture.create();
937         requestResult.put(id, sf);
938         requestMethod.put(id, "monitor");
939
940         channel.writeAndFlush(monitorString);
941         return sf;
942
943     }
944
945     @Override
946     public ListenableFuture<List<String>> listDbs() {
947         String id = java.util.UUID.randomUUID().toString();
948         String listDbsString = JsonRpcWriterUtil.listDbsStr(id);
949
950         SettableFuture<List<String>> sf = SettableFuture.create();
951         requestResult.put(id, sf);
952         requestMethod.put(id, "listDbs");
953
954         channel.writeAndFlush(listDbsString);
955         return sf;
956
957     }
958
959     @Override
960     public ListenableFuture<List<JsonNode>> transact(DatabaseSchema dbSchema,
961                                                      List<Operation> operations) {
962         String id = java.util.UUID.randomUUID().toString();
963         String transactString = JsonRpcWriterUtil.transactStr(id, dbSchema,
964                                                               operations);
965
966         SettableFuture<List<JsonNode>> sf = SettableFuture.create();
967         requestResult.put(id, sf);
968         requestMethod.put(id, "transact");
969
970         channel.writeAndFlush(transactString);
971         return sf;
972
973     }
974
975     @SuppressWarnings({ "rawtypes", "unchecked" })
976     @Override
977     public void processResult(JsonNode response) {
978         log.debug("Handle result");
979         String requestId = response.get("id").asText();
980         SettableFuture sf = requestResult.get(requestId);
981         if (sf == null) {
982             log.debug("No such future to process");
983             return;
984         }
985         String methodName = requestMethod.get(requestId);
986
987         Object result;
988         result = FromJsonUtil.jsonResultParser(response, methodName);
989
990         sf.set(result);
991         return;
992     }
993
994     @Override
995     public void processRequest(JsonNode requestJson) {
996         log.debug("Handle request");
997         if (requestJson.get("method").asText().equalsIgnoreCase("echo")) {
998             log.debug("handle echo request");
999
1000             String replyString = FromJsonUtil.getEchoRequestStr(requestJson);
1001             channel.writeAndFlush(replyString);
1002
1003             return;
1004         } else {
1005             FromJsonUtil
1006                     .jsonCallbackRequestParser(requestJson, monitorCallBack);
1007             return;
1008         }
1009     }
1010
1011     @Override
1012     public void setCallback(Callback monitorCallback) {
1013         this.monitorCallBack = monitorCallback;
1014     }
1015
1016     @Override
1017     public Set<OvsdbTunnel> getTunnels() {
1018         return ovsdbTunnels;
1019     }
1020
1021     @Override
1022     public Set<OvsdbBridge> getBridges() {
1023         Set<OvsdbBridge> ovsdbBridges = new HashSet<OvsdbBridge>();
1024         OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1025         if (tableStore == null) {
1026             return null;
1027         }
1028         OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.BRIDGE);
1029         if (rowStore == null) {
1030             return null;
1031         }
1032         ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1033         for (String uuid : rows.keySet()) {
1034             Row row = getRow(OvsdbConstant.DATABASENAME, OvsdbConstant.BRIDGE,
1035                              uuid);
1036             OvsdbBridge ovsdbBridge = getOvsdbBridge(row);
1037             if (ovsdbBridge != null) {
1038                 ovsdbBridges.add(ovsdbBridge);
1039             }
1040         }
1041         return ovsdbBridges;
1042     }
1043
1044     @Override
1045     public Set<OvsdbPort> getPorts() {
1046         Set<OvsdbPort> ovsdbPorts = new HashSet<OvsdbPort>();
1047         OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1048         if (tableStore == null) {
1049             return null;
1050         }
1051         OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.INTERFACE);
1052         if (rowStore == null) {
1053             return null;
1054         }
1055         ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1056         for (String uuid : rows.keySet()) {
1057             Row row = getRow(OvsdbConstant.DATABASENAME,
1058                              OvsdbConstant.INTERFACE, uuid);
1059             OvsdbPort ovsdbPort = getOvsdbPort(row);
1060             if (ovsdbPort != null) {
1061                 ovsdbPorts.add(ovsdbPort);
1062             }
1063         }
1064         return ovsdbPorts;
1065     }
1066
1067     @Override
1068     public DatabaseSchema getDatabaseSchema(String dbName) {
1069         return schema.get(dbName);
1070     }
1071
1072     //Gets ovsdb port.
1073     private OvsdbPort getOvsdbPort(Row row) {
1074         DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1075         Interface intf = (Interface) TableGenerator
1076                 .getTable(dbSchema, row, OvsdbTable.INTERFACE);
1077         if (intf == null) {
1078             return null;
1079         }
1080         long ofPort = getOfPort(intf);
1081         String portName = intf.getName();
1082         if ((ofPort < 0) || (portName == null)) {
1083             return null;
1084         }
1085
1086         OvsdbPort ovsdbPort = new OvsdbPort(new OvsdbPortNumber(ofPort),
1087                                             new OvsdbPortName(portName));
1088         return ovsdbPort;
1089     }
1090
1091     ////Gets ovsdb bridge.
1092     private OvsdbBridge getOvsdbBridge(Row row) {
1093         DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1094         Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, row,
1095                                                          OvsdbTable.BRIDGE);
1096         if (bridge == null) {
1097             return null;
1098         }
1099
1100         OvsdbSet datapathIdSet = (OvsdbSet) bridge.getDatapathIdColumn().data();
1101         @SuppressWarnings("unchecked")
1102         Set<String> datapathIds = datapathIdSet.set();
1103         if (datapathIds == null || datapathIds.size() == 0) {
1104             return null;
1105         }
1106         String datapathId = (String) datapathIds.toArray()[0];
1107         String bridgeName = bridge.getName();
1108         if ((datapathId == null) || (bridgeName == null)) {
1109             return null;
1110         }
1111
1112         OvsdbBridge ovsdbBridge = new OvsdbBridge(new OvsdbBridgeName(bridgeName),
1113                                                   new OvsdbDatapathId(datapathId));
1114         return ovsdbBridge;
1115     }
1116
1117     //Gets ofPort in the interface.
1118     private long getOfPort(Interface intf) {
1119         OvsdbSet ofPortSet = (OvsdbSet) intf.getOpenFlowPortColumn().data();
1120         @SuppressWarnings("unchecked")
1121         Set<Integer> ofPorts = ofPortSet.set();
1122         while (ofPorts == null || ofPorts.size() <= 0) {
1123             log.debug("The ofport is null in {}", intf.getName());
1124             return -1;
1125         }
1126         // return (long) ofPorts.toArray()[0];
1127         Iterator<Integer> it = ofPorts.iterator();
1128         return Long.parseLong(it.next().toString());
1129     }
1130
1131     @Override
1132     public Set<OvsdbPort> getLocalPorts(Iterable<String> ifaceids) {
1133         Set<OvsdbPort> ovsdbPorts = new HashSet<OvsdbPort>();
1134         OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1135         if (tableStore == null) {
1136             return null;
1137         }
1138         OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.INTERFACE);
1139         if (rowStore == null) {
1140             return null;
1141         }
1142         ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1143         for (String uuid : rows.keySet()) {
1144             Row row = getRow(OvsdbConstant.DATABASENAME,
1145                              OvsdbConstant.INTERFACE, uuid);
1146             DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1147             Interface intf = (Interface) TableGenerator
1148                     .getTable(dbSchema, row, OvsdbTable.INTERFACE);
1149             if (intf == null || getIfaceid(intf) == null) {
1150                 continue;
1151             }
1152             String portName = intf.getName();
1153             Set<String> ifaceidSet = Sets.newHashSet(ifaceids);
1154             if (portName.startsWith("vxlan")
1155                     || !ifaceidSet.contains(getIfaceid(intf))) {
1156                 continue;
1157             }
1158             long ofPort = getOfPort(intf);
1159             if ((ofPort < 0) || (portName == null)) {
1160                 continue;
1161             }
1162
1163             OvsdbPort ovsdbPort = new OvsdbPort(new OvsdbPortNumber(ofPort),
1164                                                 new OvsdbPortName(portName));
1165             if (ovsdbPort != null) {
1166                 ovsdbPorts.add(ovsdbPort);
1167             }
1168         }
1169         return ovsdbPorts;
1170     }
1171
1172     private String getIfaceid(Interface intf) {
1173         OvsdbMap ovsdbMap = (OvsdbMap) intf.getExternalIdsColumn().data();
1174         @SuppressWarnings("unchecked")
1175         Map<String, String> externalIds = ovsdbMap.map();
1176         if (externalIds.isEmpty()) {
1177             log.warn("The external_ids is null");
1178             return null;
1179         }
1180         String ifaceid = externalIds
1181                 .get(OvsdbConstant.EXTERNAL_ID_INTERFACE_ID);
1182         if (ifaceid == null) {
1183             log.warn("The ifaceid is null");
1184             return null;
1185         }
1186         return ifaceid;
1187     }
1188 }