2 * Copyright 2015 Open Networking Laboratory
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org.onosproject.ovsdb.controller.driver;
18 import com.fasterxml.jackson.databind.JsonNode;
19 import com.google.common.base.Function;
20 import com.google.common.collect.ImmutableList;
21 import com.google.common.collect.Lists;
22 import com.google.common.collect.Maps;
23 import com.google.common.collect.Sets;
24 import com.google.common.util.concurrent.Futures;
25 import com.google.common.util.concurrent.ListenableFuture;
26 import com.google.common.util.concurrent.SettableFuture;
27 import io.netty.channel.Channel;
28 import org.onlab.packet.IpAddress;
29 import org.onosproject.net.DeviceId;
30 import org.onosproject.net.behaviour.ControllerInfo;
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;
74 import java.net.InetSocketAddress;
75 import java.util.ArrayList;
76 import java.util.HashSet;
77 import java.util.Iterator;
78 import java.util.List;
81 import java.util.concurrent.ConcurrentMap;
82 import java.util.concurrent.ExecutionException;
83 import java.util.concurrent.atomic.AtomicReference;
84 import java.util.stream.Collectors;
87 * An representation of an ovsdb client.
89 public class DefaultOvsdbClient
90 implements OvsdbProviderService, OvsdbClientService {
92 private final Logger log = LoggerFactory
93 .getLogger(DefaultOvsdbClient.class);
95 private Channel channel;
97 private OvsdbAgent agent;
98 private boolean connected;
99 private OvsdbNodeId nodeId;
100 private Callback monitorCallBack;
102 private OvsdbStore ovsdbStore = new OvsdbStore();
104 private final Map<String, String> requestMethod = Maps.newHashMap();
105 private final Map<String, SettableFuture<? extends Object>> requestResult = Maps
108 private final Map<String, DatabaseSchema> schema = Maps.newHashMap();
109 private final Set<OvsdbTunnel> ovsdbTunnels = new HashSet<OvsdbTunnel>();
112 * Creates an OvsdbClient.
114 * @param nodeId ovsdb node id
116 public DefaultOvsdbClient(OvsdbNodeId nodeId) {
117 this.nodeId = nodeId;
121 public OvsdbNodeId nodeId() {
126 public void setAgent(OvsdbAgent agent) {
127 if (this.agent == null) {
133 public void setChannel(Channel channel) {
134 this.channel = channel;
138 public void setConnection(boolean connected) {
139 this.connected = connected;
143 public boolean isConnected() {
144 return this.connected;
148 public void nodeAdded() {
149 this.agent.addConnectedNode(nodeId, this);
153 public void nodeRemoved() {
154 this.agent.removeConnectedNode(nodeId);
155 channel.disconnect();
159 * Gets the ovsdb table store.
161 * @param dbName the ovsdb database name
162 * @return ovsTableStore, empty if table store is find
164 private OvsdbTableStore getTableStore(String dbName) {
165 if (ovsdbStore == null) {
168 return ovsdbStore.getOvsdbTableStore(dbName);
172 * Gets the ovsdb row store.
174 * @param dbName the ovsdb database name
175 * @param tableName the ovsdb table name
176 * @return ovsRowStore, empty if row store is find
178 private OvsdbRowStore getRowStore(String dbName, String tableName) {
179 OvsdbTableStore tableStore = getTableStore(dbName);
180 if (tableStore == null) {
183 return tableStore.getRows(tableName);
187 * Gets the ovsdb row.
189 * @param dbName the ovsdb database name
190 * @param tableName the ovsdb table name
191 * @param uuid the key of the row
192 * @return row, empty if row is find
195 public Row getRow(String dbName, String tableName, String uuid) {
196 OvsdbTableStore tableStore = getTableStore(dbName);
197 if (tableStore == null) {
200 OvsdbRowStore rowStore = tableStore.getRows(tableName);
201 if (rowStore == null) {
204 return rowStore.getRow(uuid);
208 public void removeRow(String dbName, String tableName, String uuid) {
209 OvsdbTableStore tableStore = getTableStore(dbName);
210 if (tableStore == null) {
213 OvsdbRowStore rowStore = tableStore.getRows(tableName);
214 if (rowStore == null) {
217 rowStore.deleteRow(uuid);
221 public void updateOvsdbStore(String dbName, String tableName, String uuid,
223 OvsdbTableStore tableStore = ovsdbStore.getOvsdbTableStore(dbName);
224 if (tableStore == null) {
225 tableStore = new OvsdbTableStore();
227 OvsdbRowStore rowStore = tableStore.getRows(tableName);
228 if (rowStore == null) {
229 rowStore = new OvsdbRowStore();
231 rowStore.insertRow(uuid, row);
232 tableStore.createOrUpdateTable(tableName, rowStore);
233 ovsdbStore.createOrUpdateOvsdbStore(dbName, tableStore);
237 public String getPortUuid(String portName, String bridgeUuid) {
238 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
240 Row bridgeRow = getRow(OvsdbConstant.DATABASENAME,
241 OvsdbConstant.BRIDGE, bridgeUuid);
243 Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, bridgeRow,
245 if (bridge != null) {
246 OvsdbSet setPorts = (OvsdbSet) bridge.getPortsColumn().data();
247 @SuppressWarnings("unchecked")
248 Set<UUID> ports = setPorts.set();
249 if (ports == null || ports.size() == 0) {
250 log.warn("The port uuid is null");
254 for (UUID uuid : ports) {
255 Row portRow = getRow(OvsdbConstant.DATABASENAME,
256 OvsdbConstant.PORT, uuid.value());
257 Port port = (Port) TableGenerator.getTable(dbSchema, portRow,
259 if (port != null && portName.equalsIgnoreCase(port.getName())) {
269 public String getInterfaceUuid(String portUuid, String portName) {
270 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
272 Row portRow = getRow(OvsdbConstant.DATABASENAME, OvsdbConstant.PORT,
274 Port port = (Port) TableGenerator.getTable(dbSchema, portRow,
278 OvsdbSet setInterfaces = (OvsdbSet) port.getInterfacesColumn().data();
279 @SuppressWarnings("unchecked")
280 Set<UUID> interfaces = setInterfaces.set();
282 if (interfaces == null || interfaces.size() == 0) {
283 log.warn("The interface uuid is null");
287 for (UUID uuid : interfaces) {
288 Row intfRow = getRow(OvsdbConstant.DATABASENAME,
289 OvsdbConstant.INTERFACE, uuid.value());
290 Interface intf = (Interface) TableGenerator
291 .getTable(dbSchema, intfRow, OvsdbTable.INTERFACE);
292 if (intf != null && portName.equalsIgnoreCase(intf.getName())) {
303 public String getBridgeUuid(String bridgeName) {
304 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
306 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
307 OvsdbConstant.BRIDGE);
308 if (rowStore == null) {
309 log.debug("The bridge uuid is null");
313 ConcurrentMap<String, Row> bridgeTableRows = rowStore.getRowStore();
314 if (bridgeTableRows == null) {
315 log.debug("The bridge uuid is null");
319 for (String uuid : bridgeTableRows.keySet()) {
320 Bridge bridge = (Bridge) TableGenerator
321 .getTable(dbSchema, bridgeTableRows.get(uuid),
324 if (bridge.getName().equals(bridgeName)) {
333 public String getControllerUuid(String controllerName,
334 String controllerTarget) {
335 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
336 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
337 OvsdbConstant.CONTROLLER);
338 if (rowStore == null) {
339 log.debug("The controller uuid is null");
343 ConcurrentMap<String, Row> controllerTableRows = rowStore.getRowStore();
344 if (controllerTableRows != null) {
345 for (String uuid : controllerTableRows.keySet()) {
347 Controller controller = (Controller) TableGenerator
348 .getTable(dbSchema, controllerTableRows.get(uuid),
349 OvsdbTable.CONTROLLER);
350 String target = (String) controller.getTargetColumn().data();
351 if (target.equalsIgnoreCase(controllerTarget)) {
361 public String getOvsUuid(String dbName) {
362 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
363 OvsdbConstant.DATABASENAME);
364 if (rowStore == null) {
365 log.debug("The bridge uuid is null");
368 ConcurrentMap<String, Row> ovsTableRows = rowStore.getRowStore();
369 if (ovsTableRows != null) {
370 for (String uuid : ovsTableRows.keySet()) {
371 Row row = ovsTableRows.get(uuid);
372 String tableName = row.tableName();
373 if (tableName.equals(dbName)) {
382 public void createPort(String bridgeName, String portName) {
383 String bridgeUuid = getBridgeUuid(bridgeName);
384 if (bridgeUuid == null) {
385 log.error("Can't find bridge {} in {}", bridgeName,
386 nodeId.getIpAddress());
390 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
391 String portUuid = getPortUuid(portName, bridgeUuid);
393 Port port = (Port) TableGenerator
394 .createTable(dbSchema, OvsdbTable.PORT);
396 port.setName(portName);
397 if (portUuid == null) {
398 insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
399 "ports", bridgeUuid, port.getRow());
401 updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
408 public void dropPort(String bridgeName, String portName) {
409 String bridgeUuid = getBridgeUuid(bridgeName);
410 if (bridgeUuid == null) {
411 log.error("Could not find Bridge {} in {}", bridgeName, nodeId);
415 String portUuid = getPortUuid(portName, bridgeUuid);
416 if (portUuid != null) {
417 log.info("Port {} delete", portName);
418 deleteConfig(OvsdbConstant.PORT, "_uuid", portUuid,
419 OvsdbConstant.BRIDGE, "ports");
424 public void createBridge(String bridgeName) {
425 log.debug("create bridge {}", bridgeName);
427 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
428 if (dbSchema == null) {
429 log.warn("The schema is null");
433 Bridge bridge = (Bridge) TableGenerator.createTable(dbSchema,
435 if (bridge == null) {
436 log.debug("Can not create bridge");
440 Set<String> failModes = new HashSet<>();
441 failModes.add("secure");
442 bridge.setFailMode(failModes);
444 Set<String> protocols = new HashSet<>();
445 protocols.add(OvsdbConstant.OPENFLOW13);
446 bridge.setProtocols(protocols);
448 String ovsUuid = getOvsUuid(OvsdbConstant.DATABASENAME);
449 if (ovsUuid == null) {
450 log.warn("The Open_vSwitch is null");
454 String bridgeUuid = getBridgeUuid(bridgeName);
455 if (bridgeUuid == null) {
456 log.debug("Create a new bridge");
458 bridge.setName(bridgeName);
459 bridgeUuid = insertConfig(OvsdbConstant.BRIDGE, "_uuid",
460 OvsdbConstant.DATABASENAME, "bridges",
461 ovsUuid, bridge.getRow());
463 if (bridgeUuid != null) {
464 Port port = (Port) TableGenerator.createTable(dbSchema,
467 log.debug("the port is not null");
468 port.setName(bridgeName);
470 insertConfig(OvsdbConstant.PORT, "_uuid", "Bridge", "ports", bridgeUuid,
476 log.info("Update a bridge");
477 updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid, bridge.getRow());
480 setControllerAuto(bridgeUuid);
481 log.info("Create bridge success");
485 * Sets the bridge's controller automatically.
487 * The connection is a TCP connection to the local ONOS instance's IP
488 * and the default OpenFlow port.
490 * @param bridgeUuid bridge uuid
492 private void setControllerAuto(String bridgeUuid) {
493 IpAddress ipAddress = IpAddress.valueOf(((InetSocketAddress) channel.localAddress()).getAddress());
494 ControllerInfo controllerInfo = new ControllerInfo(ipAddress, OvsdbConstant.OFPORT, "tcp");
495 log.debug("Automatically setting controller for bridge {} to {}",
496 bridgeUuid, controllerInfo.target());
497 setControllersWithUUID(UUID.uuid(bridgeUuid), ImmutableList.of(controllerInfo));
501 public void setControllersWithUUID(UUID bridgeUuid, List<ControllerInfo> controllers) {
503 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
504 if (dbSchema == null) {
505 log.debug("There is no schema");
508 List<Controller> oldControllers = getControllers(bridgeUuid);
509 if (oldControllers == null) {
510 log.warn("There are no controllers");
514 Set<UUID> newControllerUuids = new HashSet<>();
516 Set<ControllerInfo> newControllers = new HashSet<>(controllers);
517 List<Controller> removeControllers = new ArrayList<>();
518 oldControllers.forEach(controller -> {
519 ControllerInfo controllerInfo = new ControllerInfo((String) controller.getTargetColumn().data());
520 if (newControllers.contains(controllerInfo)) {
521 newControllers.remove(controllerInfo);
522 newControllerUuids.add(controller.getRow().uuid());
524 removeControllers.add(controller);
527 OvsdbRowStore controllerRowStore = getRowStore(OvsdbConstant.DATABASENAME,
528 OvsdbConstant.CONTROLLER);
529 if (controllerRowStore == null) {
530 log.debug("There is no controller table");
534 removeControllers.forEach(c -> deleteConfig(OvsdbConstant.CONTROLLER, "_uuid", c.getRow().uuid().value(),
535 OvsdbConstant.BRIDGE, "controller"));
537 newControllers.stream().map(c -> {
538 Controller controller = (Controller) TableGenerator
539 .createTable(dbSchema, OvsdbTable.CONTROLLER);
540 controller.setTarget(c.target());
543 String uuid = insertConfig(OvsdbConstant.CONTROLLER, "_uuid",
544 OvsdbConstant.BRIDGE, "controller", bridgeUuid.value(),
546 newControllerUuids.add(UUID.uuid(uuid));
550 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
551 OvsdbConstant.BRIDGE);
552 if (rowStore == null) {
553 log.debug("There is no bridge table");
557 Row bridgeRow = rowStore.getRow(bridgeUuid.value());
558 Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
559 bridge.setController(OvsdbSet.ovsdbSet(newControllerUuids));
560 updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid.value(), bridge.getRow());
564 public void setControllersWithDeviceId(DeviceId deviceId, List<ControllerInfo> controllers) {
565 setControllersWithUUID(getBridgeUUID(deviceId), controllers);
569 public void dropBridge(String bridgeName) {
570 String bridgeUUID = getBridgeUuid(bridgeName);
571 if (bridgeUUID == null) {
572 log.warn("Could not find bridge in node", nodeId.getIpAddress());
575 deleteConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUUID,
576 OvsdbConstant.DATABASENAME, "bridges");
580 public void createTunnel(IpAddress srcIp, IpAddress dstIp) {
581 String bridgeUuid = getBridgeUuid(OvsdbConstant.INTEGRATION_BRIDGE);
582 if (bridgeUuid == null) {
583 log.warn("Could not find bridge {} and Could not create tunnel. ",
584 OvsdbConstant.INTEGRATION_BRIDGE);
588 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
589 String portName = getTunnelName(OvsdbConstant.TYPEVXLAN, dstIp);
590 String portUuid = getPortUuid(portName, bridgeUuid);
592 Port port = (Port) TableGenerator
593 .createTable(dbSchema, OvsdbTable.PORT);
595 port.setName(portName);
598 if (portUuid == null) {
599 portUuid = insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
600 "ports", bridgeUuid, port.getRow());
602 updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
605 // When a tunnel is created, A row is inserted into port table and
606 // interface table of the ovsdb node.
607 // and the following step is to get the interface uuid from local store
608 // in controller node.
609 // but it need spend some time synchronising data between node and
611 // so loop to judge if interfaceUUid is null is necessary.
612 String interfaceUuid = null;
613 for (int i = 0; i < 10; i++) {
614 interfaceUuid = getInterfaceUuid(portUuid, portName);
615 if (interfaceUuid == null) {
618 } catch (InterruptedException e) {
619 log.warn("Interrupted while waiting to get interfaceUuid");
620 Thread.currentThread().interrupt();
627 if (interfaceUuid != null) {
629 Interface tunInterface = (Interface) TableGenerator
630 .createTable(dbSchema, OvsdbTable.INTERFACE);
632 if (tunInterface != null) {
634 tunInterface.setType(OvsdbConstant.TYPEVXLAN);
635 Map<String, String> options = Maps.newHashMap();
636 options.put("key", "flow");
637 options.put("local_ip", srcIp.toString());
638 options.put("remote_ip", dstIp.toString());
639 tunInterface.setOptions(options);
640 updateConfig(OvsdbConstant.INTERFACE, "_uuid", interfaceUuid,
641 tunInterface.getRow());
642 log.info("Tunnel added success", tunInterface);
651 public void dropTunnel(IpAddress srcIp, IpAddress dstIp) {
652 String bridgeName = OvsdbConstant.INTEGRATION_BRIDGE;
653 String portName = getTunnelName(OvsdbConstant.TYPEVXLAN, dstIp);
654 String bridgeUuid = getBridgeUuid(OvsdbConstant.INTEGRATION_BRIDGE);
655 if (bridgeUuid == null) {
656 log.warn("Could not find bridge {} in {}", bridgeName,
657 nodeId.getIpAddress());
661 String portUUID = getPortUuid(portName, bridgeUuid);
662 if (portUUID != null) {
663 log.info("Delete tunnel");
664 deleteConfig(OvsdbConstant.PORT, "_uuid", portUUID,
665 OvsdbConstant.BRIDGE, "ports");
672 * Delete transact config.
674 * @param childTableName child table name
675 * @param childColumnName child column name
676 * @param childUuid child row uuid
677 * @param parentTableName parent table name
678 * @param parentColumnName parent column
680 private void deleteConfig(String childTableName, String childColumnName,
681 String childUuid, String parentTableName,
682 String parentColumnName) {
683 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
684 TableSchema childTableSchema = dbSchema.getTableSchema(childTableName);
686 ArrayList<Operation> operations = Lists.newArrayList();
687 if (parentTableName != null && parentColumnName != null) {
688 TableSchema parentTableSchema = dbSchema
689 .getTableSchema(parentTableName);
690 ColumnSchema parentColumnSchema = parentTableSchema
691 .getColumnSchema(parentColumnName);
692 List<Mutation> mutations = Lists.newArrayList();
693 Mutation mutation = MutationUtil.delete(parentColumnSchema.name(),
694 UUID.uuid(childUuid));
695 mutations.add(mutation);
696 List<Condition> conditions = Lists.newArrayList();
697 Condition condition = ConditionUtil.includes(parentColumnName,
698 UUID.uuid(childUuid));
699 conditions.add(condition);
700 Mutate op = new Mutate(parentTableSchema, conditions, mutations);
704 List<Condition> conditions = Lists.newArrayList();
705 Condition condition = ConditionUtil.equals(childColumnName, UUID.uuid(childUuid));
706 conditions.add(condition);
707 Delete del = new Delete(childTableSchema, conditions);
709 transactConfig(OvsdbConstant.DATABASENAME, operations);
715 * Update transact config.
717 * @param tableName table name
718 * @param columnName column name
720 * @param row the config data
722 private void updateConfig(String tableName, String columnName, String uuid,
724 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
725 TableSchema tableSchema = dbSchema.getTableSchema(tableName);
727 List<Condition> conditions = Lists.newArrayList();
728 Condition condition = ConditionUtil.equals(columnName, UUID.uuid(uuid));
729 conditions.add(condition);
731 Update update = new Update(tableSchema, row, conditions);
733 ArrayList<Operation> operations = Lists.newArrayList();
734 operations.add(update);
736 transactConfig(OvsdbConstant.DATABASENAME, operations);
740 * Insert transact config.
742 * @param childTableName child table name
743 * @param childColumnName child column name
744 * @param parentTableName parent table name
745 * @param parentColumnName parent column
746 * @param parentUuid parent uuid
747 * @param row the config data
748 * @return uuid, empty if no uuid is find
750 private String insertConfig(String childTableName, String childColumnName,
751 String parentTableName, String parentColumnName,
752 String parentUuid, Row row) {
753 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
754 TableSchema tableSchema = dbSchema.getTableSchema(childTableName);
756 String namedUuid = childTableName;
757 Insert insert = new Insert(tableSchema, namedUuid, row);
759 ArrayList<Operation> operations = Lists.newArrayList();
760 operations.add(insert);
762 if (parentTableName != null && parentColumnName != null) {
763 TableSchema parentTableSchema = dbSchema
764 .getTableSchema(parentTableName);
765 ColumnSchema parentColumnSchema = parentTableSchema
766 .getColumnSchema(parentColumnName);
768 List<Mutation> mutations = Lists.newArrayList();
769 Mutation mutation = MutationUtil.insert(parentColumnSchema.name(),
770 UUID.uuid(namedUuid));
771 mutations.add(mutation);
773 List<Condition> conditions = Lists.newArrayList();
774 Condition condition = ConditionUtil.equals("_uuid",
775 UUID.uuid(parentUuid));
776 conditions.add(condition);
778 Mutate op = new Mutate(parentTableSchema, conditions, mutations);
781 if (childTableName.equalsIgnoreCase(OvsdbConstant.PORT)) {
782 log.info("Handle port insert");
783 Insert intfInsert = handlePortInsertTable(OvsdbConstant.INTERFACE,
786 if (intfInsert != null) {
787 operations.add(intfInsert);
790 Insert ins = (Insert) operations.get(0);
791 ins.getRow().put("interfaces",
792 UUID.uuid(OvsdbConstant.INTERFACE));
795 List<OperationResult> results;
797 results = transactConfig(OvsdbConstant.DATABASENAME, operations)
800 return results.get(0).getUuid().value();
801 } catch (InterruptedException e) {
802 log.warn("Interrupted while waiting to get result");
803 Thread.currentThread().interrupt();
804 } catch (ExecutionException e) {
805 log.error("Exception thrown while to get result");
812 * Handles port insert.
814 * @param tableName ovsdb table interface
815 * @param portRow row of port
816 * @return insert, empty if null
818 private Insert handlePortInsertTable(String tableName, Row portRow) {
819 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
821 TableSchema portTableSchema = dbSchema
822 .getTableSchema(OvsdbConstant.PORT);
823 ColumnSchema portColumnSchema = portTableSchema.getColumnSchema("name");
825 String portName = (String) portRow.getColumn(portColumnSchema.name()).data();
827 Interface inf = (Interface) TableGenerator
828 .createTable(dbSchema, OvsdbTable.INTERFACE);
830 inf.setName(portName);
832 TableSchema intfTableSchema = dbSchema
833 .getTableSchema(OvsdbConstant.INTERFACE);
834 Insert insert = new Insert(intfTableSchema, OvsdbConstant.INTERFACE,
843 * @param dstIp the remote ip address
844 * @return tunnel name
846 private String getTunnelName(String tunnelType, IpAddress dstIp) {
847 return tunnelType + "-" + dstIp.toString();
851 public ListenableFuture<DatabaseSchema> getOvsdbSchema(String dbName) {
852 if (dbName == null) {
855 DatabaseSchema databaseSchema = schema.get(dbName);
856 if (databaseSchema == null) {
857 List<String> dbNames = new ArrayList<String>();
859 Function<JsonNode, DatabaseSchema> rowFunction = new Function<JsonNode, DatabaseSchema>() {
861 public DatabaseSchema apply(JsonNode input) {
862 log.info("Get ovsdb database schema {}", dbName);
863 DatabaseSchema dbSchema = FromJsonUtil
864 .jsonNodeToDbSchema(dbName, input);
865 if (dbSchema == null) {
866 log.debug("Get ovsdb database schema error");
869 schema.put(dbName, dbSchema);
875 ListenableFuture<JsonNode> input = getSchema(dbNames);
877 return Futures.transform(input, rowFunction);
881 return Futures.immediateFuture(databaseSchema);
886 public ListenableFuture<TableUpdates> monitorTables(String dbName, String id) {
887 if (dbName == null) {
890 DatabaseSchema dbSchema = schema.get(dbName);
891 if (dbSchema != null) {
892 Function<JsonNode, TableUpdates> rowFunction = new Function<JsonNode, TableUpdates>() {
894 public TableUpdates apply(JsonNode input) {
895 log.info("Get table updates");
896 TableUpdates updates = FromJsonUtil
897 .jsonNodeToTableUpdates(input, dbSchema);
898 if (updates == null) {
899 log.debug("Get table updates error");
905 return Futures.transform(monitor(dbSchema, id), rowFunction);
911 public ListenableFuture<List<OperationResult>> transactConfig(String dbName,
912 List<Operation> operations) {
913 if (dbName == null) {
916 DatabaseSchema dbSchema = schema.get(dbName);
917 if (dbSchema != null) {
918 Function<List<JsonNode>, List<OperationResult>> rowFunction = (input -> {
919 log.info("Get ovsdb operation result");
920 List<OperationResult> result = FromJsonUtil
921 .jsonNodeToOperationResult(input, operations);
923 if (result == null) {
924 log.debug("The operation result is null");
929 return Futures.transform(transact(dbSchema, operations),
936 public ListenableFuture<JsonNode> getSchema(List<String> dbnames) {
937 String id = java.util.UUID.randomUUID().toString();
938 String getSchemaString = JsonRpcWriterUtil.getSchemaStr(id, dbnames);
940 SettableFuture<JsonNode> sf = SettableFuture.create();
941 requestResult.put(id, sf);
942 requestMethod.put(id, "getSchema");
944 channel.writeAndFlush(getSchemaString);
950 public ListenableFuture<List<String>> echo() {
951 String id = java.util.UUID.randomUUID().toString();
952 String echoString = JsonRpcWriterUtil.echoStr(id);
954 SettableFuture<List<String>> sf = SettableFuture.create();
955 requestResult.put(id, sf);
956 requestMethod.put(id, "echo");
958 channel.writeAndFlush(echoString);
964 public ListenableFuture<JsonNode> monitor(DatabaseSchema dbSchema,
966 String id = java.util.UUID.randomUUID().toString();
967 String monitorString = JsonRpcWriterUtil.monitorStr(id, monitorId,
970 SettableFuture<JsonNode> sf = SettableFuture.create();
971 requestResult.put(id, sf);
972 requestMethod.put(id, "monitor");
974 channel.writeAndFlush(monitorString);
980 public ListenableFuture<List<String>> listDbs() {
981 String id = java.util.UUID.randomUUID().toString();
982 String listDbsString = JsonRpcWriterUtil.listDbsStr(id);
984 SettableFuture<List<String>> sf = SettableFuture.create();
985 requestResult.put(id, sf);
986 requestMethod.put(id, "listDbs");
988 channel.writeAndFlush(listDbsString);
994 public ListenableFuture<List<JsonNode>> transact(DatabaseSchema dbSchema,
995 List<Operation> operations) {
996 String id = java.util.UUID.randomUUID().toString();
997 String transactString = JsonRpcWriterUtil.transactStr(id, dbSchema,
1000 SettableFuture<List<JsonNode>> sf = SettableFuture.create();
1001 requestResult.put(id, sf);
1002 requestMethod.put(id, "transact");
1004 channel.writeAndFlush(transactString);
1009 @SuppressWarnings({"rawtypes", "unchecked"})
1011 public void processResult(JsonNode response) {
1012 log.debug("Handle result");
1013 String requestId = response.get("id").asText();
1014 SettableFuture sf = requestResult.get(requestId);
1016 log.debug("No such future to process");
1019 String methodName = requestMethod.get(requestId);
1022 result = FromJsonUtil.jsonResultParser(response, methodName);
1029 public void processRequest(JsonNode requestJson) {
1030 log.debug("Handle request");
1031 if (requestJson.get("method").asText().equalsIgnoreCase("echo")) {
1032 log.debug("handle echo request");
1034 String replyString = FromJsonUtil.getEchoRequestStr(requestJson);
1035 channel.writeAndFlush(replyString);
1040 .jsonCallbackRequestParser(requestJson, monitorCallBack);
1046 public void setCallback(Callback monitorCallback) {
1047 this.monitorCallBack = monitorCallback;
1051 public Set<OvsdbTunnel> getTunnels() {
1052 return ovsdbTunnels;
1056 public Set<OvsdbBridge> getBridges() {
1057 Set<OvsdbBridge> ovsdbBridges = new HashSet<OvsdbBridge>();
1058 OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1059 if (tableStore == null) {
1062 OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.BRIDGE);
1063 if (rowStore == null) {
1066 ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1067 for (String uuid : rows.keySet()) {
1068 Row row = getRow(OvsdbConstant.DATABASENAME, OvsdbConstant.BRIDGE,
1070 OvsdbBridge ovsdbBridge = getOvsdbBridge(row);
1071 if (ovsdbBridge != null) {
1072 ovsdbBridges.add(ovsdbBridge);
1075 return ovsdbBridges;
1079 public Set<ControllerInfo> getControllers(DeviceId openflowDeviceId) {
1080 UUID bridgeUuid = getBridgeUUID(openflowDeviceId);
1081 if (bridgeUuid == null) {
1082 log.warn("bad bridge Uuid");
1085 List<Controller> controllers = getControllers(bridgeUuid);
1086 if (controllers == null) {
1087 log.warn("bad list of controllers");
1090 return controllers.stream().
1091 map(controller -> new ControllerInfo(
1092 (String) controller.getTargetColumn()
1093 .data())).collect(Collectors.toSet());
1096 private List<Controller> getControllers(UUID bridgeUuid) {
1097 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
1098 if (dbSchema == null) {
1101 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
1102 OvsdbConstant.BRIDGE);
1103 if (rowStore == null) {
1104 log.debug("There is no bridge table");
1108 Row bridgeRow = rowStore.getRow(bridgeUuid.value());
1109 Bridge bridge = (Bridge) TableGenerator.
1110 getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
1113 log.warn("type of controller column", bridge.getControllerColumn()
1114 .data().getClass());
1115 Set<UUID> controllerUuids = (Set<UUID>) ((OvsdbSet) bridge
1116 .getControllerColumn().data()).set();
1117 // Set<String> controllerUuidStrings = (Set<String>) bridge.getControllerColumn().data();
1119 OvsdbRowStore controllerRowStore = getRowStore(OvsdbConstant.DATABASENAME,
1120 OvsdbConstant.CONTROLLER);
1121 if (controllerRowStore == null) {
1122 log.debug("There is no controller table");
1126 List<Controller> ovsdbControllers = new ArrayList<>();
1127 ConcurrentMap<String, Row> controllerTableRows = controllerRowStore.getRowStore();
1128 controllerTableRows.forEach((key, row) -> {
1129 if (!controllerUuids.contains(UUID.uuid(key))) {
1132 Controller controller = (Controller) TableGenerator
1133 .getTable(dbSchema, row, OvsdbTable.CONTROLLER);
1134 ovsdbControllers.add(controller);
1136 return ovsdbControllers;
1140 private UUID getBridgeUUID(DeviceId openflowDeviceId) {
1141 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
1142 if (dbSchema == null) {
1145 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
1146 OvsdbConstant.BRIDGE);
1147 if (rowStore == null) {
1148 log.debug("There is no bridge table");
1152 ConcurrentMap<String, Row> bridgeTableRows = rowStore.getRowStore();
1153 final AtomicReference<UUID> uuid = new AtomicReference<>();
1154 for (Map.Entry<String, Row> entry : bridgeTableRows.entrySet()) {
1155 Bridge b = (Bridge) TableGenerator.getTable(dbSchema,
1158 if (matchesDpid(b, openflowDeviceId)) {
1159 uuid.set(UUID.uuid(entry.getKey()));
1163 if (uuid.get() == null) {
1164 log.debug("There is no bridge for {}", openflowDeviceId);
1170 private static boolean matchesDpid(Bridge b, DeviceId deviceId) {
1171 String ofDpid = deviceId.toString().replace("of:", "");
1172 Set ofDeviceIds = ((OvsdbSet) b.getDatapathIdColumn().data()).set();
1174 return ofDeviceIds.contains(ofDpid);
1178 public Set<OvsdbPort> getPorts() {
1179 Set<OvsdbPort> ovsdbPorts = new HashSet<OvsdbPort>();
1180 OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1181 if (tableStore == null) {
1184 OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.INTERFACE);
1185 if (rowStore == null) {
1188 ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1189 for (String uuid : rows.keySet()) {
1190 Row row = getRow(OvsdbConstant.DATABASENAME,
1191 OvsdbConstant.INTERFACE, uuid);
1192 OvsdbPort ovsdbPort = getOvsdbPort(row);
1193 if (ovsdbPort != null) {
1194 ovsdbPorts.add(ovsdbPort);
1201 public DatabaseSchema getDatabaseSchema(String dbName) {
1202 return schema.get(dbName);
1206 private OvsdbPort getOvsdbPort(Row row) {
1207 DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1208 Interface intf = (Interface) TableGenerator
1209 .getTable(dbSchema, row, OvsdbTable.INTERFACE);
1213 long ofPort = getOfPort(intf);
1214 String portName = intf.getName();
1215 if ((ofPort < 0) || (portName == null)) {
1219 OvsdbPort ovsdbPort = new OvsdbPort(new OvsdbPortNumber(ofPort),
1220 new OvsdbPortName(portName));
1224 ////Gets ovsdb bridge.
1225 private OvsdbBridge getOvsdbBridge(Row row) {
1226 DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1227 Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, row,
1229 if (bridge == null) {
1233 OvsdbSet datapathIdSet = (OvsdbSet) bridge.getDatapathIdColumn().data();
1234 @SuppressWarnings("unchecked")
1235 Set<String> datapathIds = datapathIdSet.set();
1236 if (datapathIds == null || datapathIds.size() == 0) {
1239 String datapathId = (String) datapathIds.toArray()[0];
1240 String bridgeName = bridge.getName();
1241 if ((datapathId == null) || (bridgeName == null)) {
1245 OvsdbBridge ovsdbBridge = new OvsdbBridge(new OvsdbBridgeName(bridgeName),
1246 new OvsdbDatapathId(datapathId));
1250 //Gets ofPort in the interface.
1251 private long getOfPort(Interface intf) {
1252 OvsdbSet ofPortSet = (OvsdbSet) intf.getOpenFlowPortColumn().data();
1253 @SuppressWarnings("unchecked")
1254 Set<Integer> ofPorts = ofPortSet.set();
1255 while (ofPorts == null || ofPorts.size() <= 0) {
1256 log.debug("The ofport is null in {}", intf.getName());
1259 // return (long) ofPorts.toArray()[0];
1260 Iterator<Integer> it = ofPorts.iterator();
1261 return Long.parseLong(it.next().toString());
1265 public Set<OvsdbPort> getLocalPorts(Iterable<String> ifaceids) {
1266 Set<OvsdbPort> ovsdbPorts = new HashSet<OvsdbPort>();
1267 OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1268 if (tableStore == null) {
1271 OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.INTERFACE);
1272 if (rowStore == null) {
1275 ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1276 for (String uuid : rows.keySet()) {
1277 Row row = getRow(OvsdbConstant.DATABASENAME,
1278 OvsdbConstant.INTERFACE, uuid);
1279 DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1280 Interface intf = (Interface) TableGenerator
1281 .getTable(dbSchema, row, OvsdbTable.INTERFACE);
1282 if (intf == null || getIfaceid(intf) == null) {
1285 String portName = intf.getName();
1286 Set<String> ifaceidSet = Sets.newHashSet(ifaceids);
1287 if (portName.startsWith("vxlan")
1288 || !ifaceidSet.contains(getIfaceid(intf))) {
1291 long ofPort = getOfPort(intf);
1292 if ((ofPort < 0) || (portName == null)) {
1296 OvsdbPort ovsdbPort = new OvsdbPort(new OvsdbPortNumber(ofPort),
1297 new OvsdbPortName(portName));
1298 if (ovsdbPort != null) {
1299 ovsdbPorts.add(ovsdbPort);
1305 private String getIfaceid(Interface intf) {
1306 OvsdbMap ovsdbMap = (OvsdbMap) intf.getExternalIdsColumn().data();
1307 @SuppressWarnings("unchecked")
1308 Map<String, String> externalIds = ovsdbMap.map();
1309 if (externalIds.isEmpty()) {
1310 log.warn("The external_ids is null");
1313 String ifaceid = externalIds
1314 .get(OvsdbConstant.EXTERNAL_ID_INTERFACE_ID);
1315 if (ifaceid == null) {
1316 log.warn("The ifaceid is null");
1323 public void disconnect() {
1324 channel.disconnect();
1325 this.agent.removeConnectedNode(nodeId);