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.Arrays;
77 import java.util.HashMap;
78 import java.util.HashSet;
79 import java.util.Iterator;
80 import java.util.List;
83 import java.util.concurrent.ConcurrentMap;
84 import java.util.concurrent.ExecutionException;
85 import java.util.concurrent.atomic.AtomicReference;
86 import java.util.stream.Collectors;
89 * An representation of an ovsdb client.
91 public class DefaultOvsdbClient
92 implements OvsdbProviderService, OvsdbClientService {
94 private final Logger log = LoggerFactory
95 .getLogger(DefaultOvsdbClient.class);
97 private Channel channel;
99 private OvsdbAgent agent;
100 private boolean connected;
101 private OvsdbNodeId nodeId;
102 private Callback monitorCallBack;
104 private OvsdbStore ovsdbStore = new OvsdbStore();
106 private final Map<String, String> requestMethod = Maps.newHashMap();
107 private final Map<String, SettableFuture<? extends Object>> requestResult = Maps
110 private final Map<String, DatabaseSchema> schema = Maps.newHashMap();
111 private final Set<OvsdbTunnel> ovsdbTunnels = new HashSet<OvsdbTunnel>();
114 * Creates an OvsdbClient.
116 * @param nodeId ovsdb node id
118 public DefaultOvsdbClient(OvsdbNodeId nodeId) {
119 this.nodeId = nodeId;
123 public OvsdbNodeId nodeId() {
128 public void setAgent(OvsdbAgent agent) {
129 if (this.agent == null) {
135 public void setChannel(Channel channel) {
136 this.channel = channel;
140 public void setConnection(boolean connected) {
141 this.connected = connected;
145 public boolean isConnected() {
146 return this.connected;
150 public void nodeAdded() {
151 this.agent.addConnectedNode(nodeId, this);
155 public void nodeRemoved() {
156 this.agent.removeConnectedNode(nodeId);
157 channel.disconnect();
161 * Gets the ovsdb table store.
163 * @param dbName the ovsdb database name
164 * @return ovsTableStore, empty if table store is find
166 private OvsdbTableStore getTableStore(String dbName) {
167 if (ovsdbStore == null) {
170 return ovsdbStore.getOvsdbTableStore(dbName);
174 * Gets the ovsdb row store.
176 * @param dbName the ovsdb database name
177 * @param tableName the ovsdb table name
178 * @return ovsRowStore, empty if row store is find
180 private OvsdbRowStore getRowStore(String dbName, String tableName) {
181 OvsdbTableStore tableStore = getTableStore(dbName);
182 if (tableStore == null) {
185 return tableStore.getRows(tableName);
189 * Gets the ovsdb row.
191 * @param dbName the ovsdb database name
192 * @param tableName the ovsdb table name
193 * @param uuid the key of the row
194 * @return row, empty if row is find
197 public Row getRow(String dbName, String tableName, String uuid) {
198 OvsdbTableStore tableStore = getTableStore(dbName);
199 if (tableStore == null) {
202 OvsdbRowStore rowStore = tableStore.getRows(tableName);
203 if (rowStore == null) {
206 return rowStore.getRow(uuid);
210 public void removeRow(String dbName, String tableName, String uuid) {
211 OvsdbTableStore tableStore = getTableStore(dbName);
212 if (tableStore == null) {
215 OvsdbRowStore rowStore = tableStore.getRows(tableName);
216 if (rowStore == null) {
219 rowStore.deleteRow(uuid);
223 public void updateOvsdbStore(String dbName, String tableName, String uuid,
225 OvsdbTableStore tableStore = ovsdbStore.getOvsdbTableStore(dbName);
226 if (tableStore == null) {
227 tableStore = new OvsdbTableStore();
229 OvsdbRowStore rowStore = tableStore.getRows(tableName);
230 if (rowStore == null) {
231 rowStore = new OvsdbRowStore();
233 rowStore.insertRow(uuid, row);
234 tableStore.createOrUpdateTable(tableName, rowStore);
235 ovsdbStore.createOrUpdateOvsdbStore(dbName, tableStore);
239 public String getPortUuid(String portName, String bridgeUuid) {
240 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
242 Row bridgeRow = getRow(OvsdbConstant.DATABASENAME,
243 OvsdbConstant.BRIDGE, bridgeUuid);
245 Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, bridgeRow,
247 if (bridge != null) {
248 OvsdbSet setPorts = (OvsdbSet) bridge.getPortsColumn().data();
249 @SuppressWarnings("unchecked")
250 Set<UUID> ports = setPorts.set();
251 if (ports == null || ports.size() == 0) {
252 log.warn("The port uuid is null");
256 for (UUID uuid : ports) {
257 Row portRow = getRow(OvsdbConstant.DATABASENAME,
258 OvsdbConstant.PORT, uuid.value());
259 Port port = (Port) TableGenerator.getTable(dbSchema, portRow,
261 if (port != null && portName.equalsIgnoreCase(port.getName())) {
271 public String getInterfaceUuid(String portUuid, String portName) {
272 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
274 Row portRow = getRow(OvsdbConstant.DATABASENAME, OvsdbConstant.PORT,
276 Port port = (Port) TableGenerator.getTable(dbSchema, portRow,
280 OvsdbSet setInterfaces = (OvsdbSet) port.getInterfacesColumn().data();
281 @SuppressWarnings("unchecked")
282 Set<UUID> interfaces = setInterfaces.set();
284 if (interfaces == null || interfaces.size() == 0) {
285 log.warn("The interface uuid is null");
289 for (UUID uuid : interfaces) {
290 Row intfRow = getRow(OvsdbConstant.DATABASENAME,
291 OvsdbConstant.INTERFACE, uuid.value());
292 Interface intf = (Interface) TableGenerator
293 .getTable(dbSchema, intfRow, OvsdbTable.INTERFACE);
294 if (intf != null && portName.equalsIgnoreCase(intf.getName())) {
305 public String getBridgeUuid(String bridgeName) {
306 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
308 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
309 OvsdbConstant.BRIDGE);
310 if (rowStore == null) {
311 log.debug("The bridge uuid is null");
315 ConcurrentMap<String, Row> bridgeTableRows = rowStore.getRowStore();
316 if (bridgeTableRows == null) {
317 log.debug("The bridge uuid is null");
321 for (String uuid : bridgeTableRows.keySet()) {
322 Bridge bridge = (Bridge) TableGenerator
323 .getTable(dbSchema, bridgeTableRows.get(uuid),
326 if (bridge.getName().equals(bridgeName)) {
335 public String getControllerUuid(String controllerName,
336 String controllerTarget) {
337 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
338 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
339 OvsdbConstant.CONTROLLER);
340 if (rowStore == null) {
341 log.debug("The controller uuid is null");
345 ConcurrentMap<String, Row> controllerTableRows = rowStore.getRowStore();
346 if (controllerTableRows != null) {
347 for (String uuid : controllerTableRows.keySet()) {
349 Controller controller = (Controller) TableGenerator
350 .getTable(dbSchema, controllerTableRows.get(uuid),
351 OvsdbTable.CONTROLLER);
352 String target = (String) controller.getTargetColumn().data();
353 if (target.equalsIgnoreCase(controllerTarget)) {
363 public String getOvsUuid(String dbName) {
364 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
365 OvsdbConstant.DATABASENAME);
366 if (rowStore == null) {
367 log.debug("The bridge uuid is null");
370 ConcurrentMap<String, Row> ovsTableRows = rowStore.getRowStore();
371 if (ovsTableRows != null) {
372 for (String uuid : ovsTableRows.keySet()) {
373 Row row = ovsTableRows.get(uuid);
374 String tableName = row.tableName();
375 if (tableName.equals(dbName)) {
384 public void createPort(String bridgeName, String portName) {
385 String bridgeUuid = getBridgeUuid(bridgeName);
386 if (bridgeUuid == null) {
387 log.error("Can't find bridge {} in {}", bridgeName,
388 nodeId.getIpAddress());
392 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
393 String portUuid = getPortUuid(portName, bridgeUuid);
395 Port port = (Port) TableGenerator
396 .createTable(dbSchema, OvsdbTable.PORT);
398 port.setName(portName);
399 if (portUuid == null) {
400 insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
401 "ports", bridgeUuid, port.getRow());
403 updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
410 public void dropPort(String bridgeName, String portName) {
411 String bridgeUuid = getBridgeUuid(bridgeName);
412 if (bridgeUuid == null) {
413 log.error("Could not find Bridge {} in {}", bridgeName, nodeId);
417 String portUuid = getPortUuid(portName, bridgeUuid);
418 if (portUuid != null) {
419 log.info("Port {} delete", portName);
420 deleteConfig(OvsdbConstant.PORT, "_uuid", portUuid,
421 OvsdbConstant.BRIDGE, "ports");
426 public void createBridge(String bridgeName) {
427 log.debug("create bridge {}", bridgeName);
429 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
430 if (dbSchema == null) {
431 log.warn("The schema is null");
435 Bridge bridge = (Bridge) TableGenerator.createTable(dbSchema,
437 if (bridge == null) {
438 log.debug("Can not create bridge");
442 Set<String> failModes = new HashSet<>();
443 failModes.add("secure");
444 bridge.setFailMode(failModes);
446 Set<String> protocols = new HashSet<>();
447 protocols.add(OvsdbConstant.OPENFLOW13);
448 bridge.setProtocols(protocols);
450 String ovsUuid = getOvsUuid(OvsdbConstant.DATABASENAME);
451 if (ovsUuid == null) {
452 log.warn("The Open_vSwitch is null");
456 String bridgeUuid = getBridgeUuid(bridgeName);
457 if (bridgeUuid == null) {
458 log.debug("Create a new bridge");
460 bridge.setName(bridgeName);
461 bridgeUuid = insertConfig(OvsdbConstant.BRIDGE, "_uuid",
462 OvsdbConstant.DATABASENAME, "bridges",
463 ovsUuid, bridge.getRow());
465 if (bridgeUuid != null) {
466 Port port = (Port) TableGenerator.createTable(dbSchema,
469 log.debug("the port is not null");
470 port.setName(bridgeName);
472 insertConfig(OvsdbConstant.PORT, "_uuid", "Bridge", "ports", bridgeUuid,
478 log.info("Update a bridge");
479 updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid, bridge.getRow());
482 setControllerAuto(bridgeUuid);
483 log.info("Create bridge success");
487 public boolean createBridge(String bridgeName, String dpid, List<ControllerInfo> controllers) {
489 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
490 String ovsUuid = getOvsUuid(OvsdbConstant.DATABASENAME);
492 if (dbSchema == null || ovsUuid == null) {
493 log.warn("Couldn't find database Open_vSwitch");
497 String bridgeUuid = getBridgeUuid(bridgeName);
498 if (bridgeUuid != null) {
499 log.warn("Bridge {} is already exist", bridgeName);
500 // remove existing one and re-create?
504 Bridge bridge = (Bridge) TableGenerator.createTable(dbSchema, OvsdbTable.BRIDGE);
505 bridge.setName(bridgeName);
507 Set<String> failMode = new HashSet<>(Arrays.asList("secure"));
508 bridge.setFailMode(failMode);
510 Set<String> protocols = new HashSet<>(Arrays.asList(OvsdbConstant.OPENFLOW13));
511 bridge.setProtocols(protocols);
513 Map<String, String> options = new HashMap<>();
514 options.put("datapath-id", dpid);
515 bridge.setOtherConfig(options);
517 bridgeUuid = insertConfig(OvsdbConstant.BRIDGE, "_uuid",
518 OvsdbConstant.DATABASENAME, "bridges",
519 ovsUuid, bridge.getRow());
521 if (bridgeUuid != null) {
522 createPort(bridgeName, bridgeName);
524 log.warn("Failed to create bridge {} on {}", bridgeName, nodeId.toString());
528 setControllersWithUUID(UUID.uuid(bridgeUuid), controllers);
533 * Sets the bridge's controller automatically.
535 * The connection is a TCP connection to the local ONOS instance's IP
536 * and the default OpenFlow port.
538 * @param bridgeUuid bridge uuid
540 private void setControllerAuto(String bridgeUuid) {
541 IpAddress ipAddress = IpAddress.valueOf(((InetSocketAddress) channel.localAddress()).getAddress());
542 ControllerInfo controllerInfo = new ControllerInfo(ipAddress, OvsdbConstant.OFPORT, "tcp");
543 log.debug("Automatically setting controller for bridge {} to {}",
544 bridgeUuid, controllerInfo.target());
545 setControllersWithUUID(UUID.uuid(bridgeUuid), ImmutableList.of(controllerInfo));
549 public void setControllersWithUUID(UUID bridgeUuid, List<ControllerInfo> controllers) {
551 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
552 if (dbSchema == null) {
553 log.debug("There is no schema");
556 List<Controller> oldControllers = getControllers(bridgeUuid);
557 if (oldControllers == null) {
558 log.warn("There are no controllers");
562 Set<UUID> newControllerUuids = new HashSet<>();
564 Set<ControllerInfo> newControllers = new HashSet<>(controllers);
565 List<Controller> removeControllers = new ArrayList<>();
566 oldControllers.forEach(controller -> {
567 ControllerInfo controllerInfo = new ControllerInfo((String) controller.getTargetColumn().data());
568 if (newControllers.contains(controllerInfo)) {
569 newControllers.remove(controllerInfo);
570 newControllerUuids.add(controller.getRow().uuid());
572 removeControllers.add(controller);
575 OvsdbRowStore controllerRowStore = getRowStore(OvsdbConstant.DATABASENAME,
576 OvsdbConstant.CONTROLLER);
577 if (controllerRowStore == null) {
578 log.debug("There is no controller table");
582 removeControllers.forEach(c -> deleteConfig(OvsdbConstant.CONTROLLER, "_uuid", c.getRow().uuid().value(),
583 OvsdbConstant.BRIDGE, "controller"));
585 newControllers.stream().map(c -> {
586 Controller controller = (Controller) TableGenerator
587 .createTable(dbSchema, OvsdbTable.CONTROLLER);
588 controller.setTarget(c.target());
591 String uuid = insertConfig(OvsdbConstant.CONTROLLER, "_uuid",
592 OvsdbConstant.BRIDGE, "controller", bridgeUuid.value(),
594 newControllerUuids.add(UUID.uuid(uuid));
598 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
599 OvsdbConstant.BRIDGE);
600 if (rowStore == null) {
601 log.debug("There is no bridge table");
605 Row bridgeRow = rowStore.getRow(bridgeUuid.value());
606 Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
607 bridge.setController(OvsdbSet.ovsdbSet(newControllerUuids));
608 updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid.value(), bridge.getRow());
612 public void setControllersWithDeviceId(DeviceId deviceId, List<ControllerInfo> controllers) {
613 setControllersWithUUID(getBridgeUUID(deviceId), controllers);
617 public void dropBridge(String bridgeName) {
618 String bridgeUUID = getBridgeUuid(bridgeName);
619 if (bridgeUUID == null) {
620 log.warn("Could not find bridge in node", nodeId.getIpAddress());
623 deleteConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUUID,
624 OvsdbConstant.DATABASENAME, "bridges");
628 public void createTunnel(IpAddress srcIp, IpAddress dstIp) {
629 String bridgeUuid = getBridgeUuid(OvsdbConstant.INTEGRATION_BRIDGE);
630 if (bridgeUuid == null) {
631 log.warn("Could not find bridge {} and Could not create tunnel. ",
632 OvsdbConstant.INTEGRATION_BRIDGE);
636 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
637 String portName = getTunnelName(OvsdbConstant.TYPEVXLAN, dstIp);
638 String portUuid = getPortUuid(portName, bridgeUuid);
640 Port port = (Port) TableGenerator
641 .createTable(dbSchema, OvsdbTable.PORT);
643 port.setName(portName);
646 if (portUuid == null) {
647 portUuid = insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
648 "ports", bridgeUuid, port.getRow());
650 updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
653 // When a tunnel is created, A row is inserted into port table and
654 // interface table of the ovsdb node.
655 // and the following step is to get the interface uuid from local store
656 // in controller node.
657 // but it need spend some time synchronising data between node and
659 // so loop to judge if interfaceUUid is null is necessary.
660 String interfaceUuid = null;
661 for (int i = 0; i < 10; i++) {
662 interfaceUuid = getInterfaceUuid(portUuid, portName);
663 if (interfaceUuid == null) {
666 } catch (InterruptedException e) {
667 log.warn("Interrupted while waiting to get interfaceUuid");
668 Thread.currentThread().interrupt();
675 if (interfaceUuid != null) {
677 Interface tunInterface = (Interface) TableGenerator
678 .createTable(dbSchema, OvsdbTable.INTERFACE);
680 if (tunInterface != null) {
682 tunInterface.setType(OvsdbConstant.TYPEVXLAN);
683 Map<String, String> options = Maps.newHashMap();
684 options.put("key", "flow");
685 options.put("local_ip", srcIp.toString());
686 options.put("remote_ip", dstIp.toString());
687 tunInterface.setOptions(options);
688 updateConfig(OvsdbConstant.INTERFACE, "_uuid", interfaceUuid,
689 tunInterface.getRow());
690 log.info("Tunnel added success", tunInterface);
699 public boolean createTunnel(String bridgeName, String portName, String tunnelType, Map<String, String> options) {
701 String bridgeUuid = getBridgeUuid(bridgeName);
702 if (bridgeUuid == null) {
703 log.warn("Couldn't find bridge {} in {}", bridgeName, nodeId.getIpAddress());
707 if (getPortUuid(portName, bridgeUuid) != null) {
708 log.warn("Port {} already exists", portName);
709 // remove existing one and re-create?
713 ArrayList<Operation> operations = Lists.newArrayList();
714 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
716 // insert a new port to the port table
717 Port port = (Port) TableGenerator.createTable(dbSchema, OvsdbTable.PORT);
718 port.setName(portName);
719 Insert portInsert = new Insert(dbSchema.getTableSchema("Port"), "Port", port.getRow());
720 portInsert.getRow().put("interfaces", UUID.uuid("Interface"));
721 operations.add(portInsert);
723 // update the bridge table
724 Condition condition = ConditionUtil.equals("_uuid", UUID.uuid(bridgeUuid));
725 Mutation mutation = MutationUtil.insert("ports", UUID.uuid("Port"));
726 List<Condition> conditions = new ArrayList<>(Arrays.asList(condition));
727 List<Mutation> mutations = new ArrayList<>(Arrays.asList(mutation));
728 operations.add(new Mutate(dbSchema.getTableSchema("Bridge"), conditions, mutations));
730 // insert a tunnel interface
731 Interface intf = (Interface) TableGenerator.createTable(dbSchema, OvsdbTable.INTERFACE);
732 intf.setName(portName);
733 intf.setType(tunnelType);
734 intf.setOptions(options);
735 Insert intfInsert = new Insert(dbSchema.getTableSchema("Interface"), "Interface", intf.getRow());
736 operations.add(intfInsert);
738 transactConfig(OvsdbConstant.DATABASENAME, operations);
743 public void dropTunnel(IpAddress srcIp, IpAddress dstIp) {
744 String bridgeName = OvsdbConstant.INTEGRATION_BRIDGE;
745 String portName = getTunnelName(OvsdbConstant.TYPEVXLAN, dstIp);
746 String bridgeUuid = getBridgeUuid(OvsdbConstant.INTEGRATION_BRIDGE);
747 if (bridgeUuid == null) {
748 log.warn("Could not find bridge {} in {}", bridgeName,
749 nodeId.getIpAddress());
753 String portUUID = getPortUuid(portName, bridgeUuid);
754 if (portUUID != null) {
755 log.info("Delete tunnel");
756 deleteConfig(OvsdbConstant.PORT, "_uuid", portUUID,
757 OvsdbConstant.BRIDGE, "ports");
764 * Delete transact config.
766 * @param childTableName child table name
767 * @param childColumnName child column name
768 * @param childUuid child row uuid
769 * @param parentTableName parent table name
770 * @param parentColumnName parent column
772 private void deleteConfig(String childTableName, String childColumnName,
773 String childUuid, String parentTableName,
774 String parentColumnName) {
775 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
776 TableSchema childTableSchema = dbSchema.getTableSchema(childTableName);
778 ArrayList<Operation> operations = Lists.newArrayList();
779 if (parentTableName != null && parentColumnName != null) {
780 TableSchema parentTableSchema = dbSchema
781 .getTableSchema(parentTableName);
782 ColumnSchema parentColumnSchema = parentTableSchema
783 .getColumnSchema(parentColumnName);
784 List<Mutation> mutations = Lists.newArrayList();
785 Mutation mutation = MutationUtil.delete(parentColumnSchema.name(),
786 UUID.uuid(childUuid));
787 mutations.add(mutation);
788 List<Condition> conditions = Lists.newArrayList();
789 Condition condition = ConditionUtil.includes(parentColumnName,
790 UUID.uuid(childUuid));
791 conditions.add(condition);
792 Mutate op = new Mutate(parentTableSchema, conditions, mutations);
796 List<Condition> conditions = Lists.newArrayList();
797 Condition condition = ConditionUtil.equals(childColumnName, UUID.uuid(childUuid));
798 conditions.add(condition);
799 Delete del = new Delete(childTableSchema, conditions);
801 transactConfig(OvsdbConstant.DATABASENAME, operations);
807 * Update transact config.
809 * @param tableName table name
810 * @param columnName column name
812 * @param row the config data
814 private void updateConfig(String tableName, String columnName, String uuid,
816 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
817 TableSchema tableSchema = dbSchema.getTableSchema(tableName);
819 List<Condition> conditions = Lists.newArrayList();
820 Condition condition = ConditionUtil.equals(columnName, UUID.uuid(uuid));
821 conditions.add(condition);
823 Update update = new Update(tableSchema, row, conditions);
825 ArrayList<Operation> operations = Lists.newArrayList();
826 operations.add(update);
828 transactConfig(OvsdbConstant.DATABASENAME, operations);
832 * Insert transact config.
834 * @param childTableName child table name
835 * @param childColumnName child column name
836 * @param parentTableName parent table name
837 * @param parentColumnName parent column
838 * @param parentUuid parent uuid
839 * @param row the config data
840 * @return uuid, empty if no uuid is find
842 private String insertConfig(String childTableName, String childColumnName,
843 String parentTableName, String parentColumnName,
844 String parentUuid, Row row) {
845 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
846 TableSchema tableSchema = dbSchema.getTableSchema(childTableName);
848 String namedUuid = childTableName;
849 Insert insert = new Insert(tableSchema, namedUuid, row);
851 ArrayList<Operation> operations = Lists.newArrayList();
852 operations.add(insert);
854 if (parentTableName != null && parentColumnName != null) {
855 TableSchema parentTableSchema = dbSchema
856 .getTableSchema(parentTableName);
857 ColumnSchema parentColumnSchema = parentTableSchema
858 .getColumnSchema(parentColumnName);
860 List<Mutation> mutations = Lists.newArrayList();
861 Mutation mutation = MutationUtil.insert(parentColumnSchema.name(),
862 UUID.uuid(namedUuid));
863 mutations.add(mutation);
865 List<Condition> conditions = Lists.newArrayList();
866 Condition condition = ConditionUtil.equals("_uuid",
867 UUID.uuid(parentUuid));
868 conditions.add(condition);
870 Mutate op = new Mutate(parentTableSchema, conditions, mutations);
873 if (childTableName.equalsIgnoreCase(OvsdbConstant.PORT)) {
874 log.info("Handle port insert");
875 Insert intfInsert = handlePortInsertTable(OvsdbConstant.INTERFACE,
878 if (intfInsert != null) {
879 operations.add(intfInsert);
882 Insert ins = (Insert) operations.get(0);
883 ins.getRow().put("interfaces",
884 UUID.uuid(OvsdbConstant.INTERFACE));
887 List<OperationResult> results;
889 results = transactConfig(OvsdbConstant.DATABASENAME, operations)
892 return results.get(0).getUuid().value();
893 } catch (InterruptedException e) {
894 log.warn("Interrupted while waiting to get result");
895 Thread.currentThread().interrupt();
896 } catch (ExecutionException e) {
897 log.error("Exception thrown while to get result");
904 * Handles port insert.
906 * @param tableName ovsdb table interface
907 * @param portRow row of port
908 * @return insert, empty if null
910 private Insert handlePortInsertTable(String tableName, Row portRow) {
911 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
913 TableSchema portTableSchema = dbSchema
914 .getTableSchema(OvsdbConstant.PORT);
915 ColumnSchema portColumnSchema = portTableSchema.getColumnSchema("name");
917 String portName = (String) portRow.getColumn(portColumnSchema.name()).data();
919 Interface inf = (Interface) TableGenerator
920 .createTable(dbSchema, OvsdbTable.INTERFACE);
922 inf.setName(portName);
924 TableSchema intfTableSchema = dbSchema
925 .getTableSchema(OvsdbConstant.INTERFACE);
926 Insert insert = new Insert(intfTableSchema, OvsdbConstant.INTERFACE,
935 * @param dstIp the remote ip address
936 * @return tunnel name
938 private String getTunnelName(String tunnelType, IpAddress dstIp) {
939 return tunnelType + "-" + dstIp.toString();
943 public ListenableFuture<DatabaseSchema> getOvsdbSchema(String dbName) {
944 if (dbName == null) {
947 DatabaseSchema databaseSchema = schema.get(dbName);
948 if (databaseSchema == null) {
949 List<String> dbNames = new ArrayList<String>();
951 Function<JsonNode, DatabaseSchema> rowFunction = new Function<JsonNode, DatabaseSchema>() {
953 public DatabaseSchema apply(JsonNode input) {
954 log.info("Get ovsdb database schema {}", dbName);
955 DatabaseSchema dbSchema = FromJsonUtil
956 .jsonNodeToDbSchema(dbName, input);
957 if (dbSchema == null) {
958 log.debug("Get ovsdb database schema error");
961 schema.put(dbName, dbSchema);
967 ListenableFuture<JsonNode> input = getSchema(dbNames);
969 return Futures.transform(input, rowFunction);
973 return Futures.immediateFuture(databaseSchema);
978 public ListenableFuture<TableUpdates> monitorTables(String dbName, String id) {
979 if (dbName == null) {
982 DatabaseSchema dbSchema = schema.get(dbName);
983 if (dbSchema != null) {
984 Function<JsonNode, TableUpdates> rowFunction = new Function<JsonNode, TableUpdates>() {
986 public TableUpdates apply(JsonNode input) {
987 log.info("Get table updates");
988 TableUpdates updates = FromJsonUtil
989 .jsonNodeToTableUpdates(input, dbSchema);
990 if (updates == null) {
991 log.debug("Get table updates error");
997 return Futures.transform(monitor(dbSchema, id), rowFunction);
1003 public ListenableFuture<List<OperationResult>> transactConfig(String dbName,
1004 List<Operation> operations) {
1005 if (dbName == null) {
1008 DatabaseSchema dbSchema = schema.get(dbName);
1009 if (dbSchema != null) {
1010 Function<List<JsonNode>, List<OperationResult>> rowFunction = (input -> {
1011 log.info("Get ovsdb operation result");
1012 List<OperationResult> result = FromJsonUtil
1013 .jsonNodeToOperationResult(input, operations);
1015 if (result == null) {
1016 log.debug("The operation result is null");
1021 return Futures.transform(transact(dbSchema, operations),
1028 public ListenableFuture<JsonNode> getSchema(List<String> dbnames) {
1029 String id = java.util.UUID.randomUUID().toString();
1030 String getSchemaString = JsonRpcWriterUtil.getSchemaStr(id, dbnames);
1032 SettableFuture<JsonNode> sf = SettableFuture.create();
1033 requestResult.put(id, sf);
1034 requestMethod.put(id, "getSchema");
1036 channel.writeAndFlush(getSchemaString);
1042 public ListenableFuture<List<String>> echo() {
1043 String id = java.util.UUID.randomUUID().toString();
1044 String echoString = JsonRpcWriterUtil.echoStr(id);
1046 SettableFuture<List<String>> sf = SettableFuture.create();
1047 requestResult.put(id, sf);
1048 requestMethod.put(id, "echo");
1050 channel.writeAndFlush(echoString);
1056 public ListenableFuture<JsonNode> monitor(DatabaseSchema dbSchema,
1058 String id = java.util.UUID.randomUUID().toString();
1059 String monitorString = JsonRpcWriterUtil.monitorStr(id, monitorId,
1062 SettableFuture<JsonNode> sf = SettableFuture.create();
1063 requestResult.put(id, sf);
1064 requestMethod.put(id, "monitor");
1066 channel.writeAndFlush(monitorString);
1072 public ListenableFuture<List<String>> listDbs() {
1073 String id = java.util.UUID.randomUUID().toString();
1074 String listDbsString = JsonRpcWriterUtil.listDbsStr(id);
1076 SettableFuture<List<String>> sf = SettableFuture.create();
1077 requestResult.put(id, sf);
1078 requestMethod.put(id, "listDbs");
1080 channel.writeAndFlush(listDbsString);
1086 public ListenableFuture<List<JsonNode>> transact(DatabaseSchema dbSchema,
1087 List<Operation> operations) {
1088 String id = java.util.UUID.randomUUID().toString();
1089 String transactString = JsonRpcWriterUtil.transactStr(id, dbSchema,
1092 SettableFuture<List<JsonNode>> sf = SettableFuture.create();
1093 requestResult.put(id, sf);
1094 requestMethod.put(id, "transact");
1096 channel.writeAndFlush(transactString);
1101 @SuppressWarnings({"rawtypes", "unchecked"})
1103 public void processResult(JsonNode response) {
1104 log.debug("Handle result");
1105 String requestId = response.get("id").asText();
1106 SettableFuture sf = requestResult.get(requestId);
1108 log.debug("No such future to process");
1111 String methodName = requestMethod.get(requestId);
1114 result = FromJsonUtil.jsonResultParser(response, methodName);
1121 public void processRequest(JsonNode requestJson) {
1122 log.debug("Handle request");
1123 if (requestJson.get("method").asText().equalsIgnoreCase("echo")) {
1124 log.debug("handle echo request");
1126 String replyString = FromJsonUtil.getEchoRequestStr(requestJson);
1127 channel.writeAndFlush(replyString);
1132 .jsonCallbackRequestParser(requestJson, monitorCallBack);
1138 public void setCallback(Callback monitorCallback) {
1139 this.monitorCallBack = monitorCallback;
1143 public Set<OvsdbTunnel> getTunnels() {
1144 return ovsdbTunnels;
1148 public Set<OvsdbBridge> getBridges() {
1149 Set<OvsdbBridge> ovsdbBridges = new HashSet<OvsdbBridge>();
1150 OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1151 if (tableStore == null) {
1154 OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.BRIDGE);
1155 if (rowStore == null) {
1158 ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1159 for (String uuid : rows.keySet()) {
1160 Row row = getRow(OvsdbConstant.DATABASENAME, OvsdbConstant.BRIDGE,
1162 OvsdbBridge ovsdbBridge = getOvsdbBridge(row);
1163 if (ovsdbBridge != null) {
1164 ovsdbBridges.add(ovsdbBridge);
1167 return ovsdbBridges;
1171 public Set<ControllerInfo> getControllers(DeviceId openflowDeviceId) {
1172 UUID bridgeUuid = getBridgeUUID(openflowDeviceId);
1173 if (bridgeUuid == null) {
1174 log.warn("bad bridge Uuid");
1177 List<Controller> controllers = getControllers(bridgeUuid);
1178 if (controllers == null) {
1179 log.warn("bad list of controllers");
1182 return controllers.stream().
1183 map(controller -> new ControllerInfo(
1184 (String) controller.getTargetColumn()
1185 .data())).collect(Collectors.toSet());
1188 private List<Controller> getControllers(UUID bridgeUuid) {
1189 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
1190 if (dbSchema == null) {
1193 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
1194 OvsdbConstant.BRIDGE);
1195 if (rowStore == null) {
1196 log.debug("There is no bridge table");
1200 Row bridgeRow = rowStore.getRow(bridgeUuid.value());
1201 Bridge bridge = (Bridge) TableGenerator.
1202 getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
1205 log.warn("type of controller column", bridge.getControllerColumn()
1206 .data().getClass());
1207 Set<UUID> controllerUuids = (Set<UUID>) ((OvsdbSet) bridge
1208 .getControllerColumn().data()).set();
1209 // Set<String> controllerUuidStrings = (Set<String>) bridge.getControllerColumn().data();
1211 OvsdbRowStore controllerRowStore = getRowStore(OvsdbConstant.DATABASENAME,
1212 OvsdbConstant.CONTROLLER);
1213 if (controllerRowStore == null) {
1214 log.debug("There is no controller table");
1218 List<Controller> ovsdbControllers = new ArrayList<>();
1219 ConcurrentMap<String, Row> controllerTableRows = controllerRowStore.getRowStore();
1220 controllerTableRows.forEach((key, row) -> {
1221 if (!controllerUuids.contains(UUID.uuid(key))) {
1224 Controller controller = (Controller) TableGenerator
1225 .getTable(dbSchema, row, OvsdbTable.CONTROLLER);
1226 ovsdbControllers.add(controller);
1228 return ovsdbControllers;
1232 private UUID getBridgeUUID(DeviceId openflowDeviceId) {
1233 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
1234 if (dbSchema == null) {
1237 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
1238 OvsdbConstant.BRIDGE);
1239 if (rowStore == null) {
1240 log.debug("There is no bridge table");
1244 ConcurrentMap<String, Row> bridgeTableRows = rowStore.getRowStore();
1245 final AtomicReference<UUID> uuid = new AtomicReference<>();
1246 for (Map.Entry<String, Row> entry : bridgeTableRows.entrySet()) {
1247 Bridge b = (Bridge) TableGenerator.getTable(dbSchema,
1250 if (matchesDpid(b, openflowDeviceId)) {
1251 uuid.set(UUID.uuid(entry.getKey()));
1255 if (uuid.get() == null) {
1256 log.debug("There is no bridge for {}", openflowDeviceId);
1262 private static boolean matchesDpid(Bridge b, DeviceId deviceId) {
1263 String ofDpid = deviceId.toString().replace("of:", "");
1264 Set ofDeviceIds = ((OvsdbSet) b.getDatapathIdColumn().data()).set();
1266 return ofDeviceIds.contains(ofDpid);
1270 public Set<OvsdbPort> getPorts() {
1271 Set<OvsdbPort> ovsdbPorts = new HashSet<OvsdbPort>();
1272 OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1273 if (tableStore == null) {
1276 OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.INTERFACE);
1277 if (rowStore == null) {
1280 ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1281 for (String uuid : rows.keySet()) {
1282 Row row = getRow(OvsdbConstant.DATABASENAME,
1283 OvsdbConstant.INTERFACE, uuid);
1284 OvsdbPort ovsdbPort = getOvsdbPort(row);
1285 if (ovsdbPort != null) {
1286 ovsdbPorts.add(ovsdbPort);
1293 public DatabaseSchema getDatabaseSchema(String dbName) {
1294 return schema.get(dbName);
1298 private OvsdbPort getOvsdbPort(Row row) {
1299 DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1300 Interface intf = (Interface) TableGenerator
1301 .getTable(dbSchema, row, OvsdbTable.INTERFACE);
1305 long ofPort = getOfPort(intf);
1306 String portName = intf.getName();
1307 if ((ofPort < 0) || (portName == null)) {
1311 OvsdbPort ovsdbPort = new OvsdbPort(new OvsdbPortNumber(ofPort),
1312 new OvsdbPortName(portName));
1316 ////Gets ovsdb bridge.
1317 private OvsdbBridge getOvsdbBridge(Row row) {
1318 DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1319 Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, row,
1321 if (bridge == null) {
1325 OvsdbSet datapathIdSet = (OvsdbSet) bridge.getDatapathIdColumn().data();
1326 @SuppressWarnings("unchecked")
1327 Set<String> datapathIds = datapathIdSet.set();
1328 if (datapathIds == null || datapathIds.size() == 0) {
1331 String datapathId = (String) datapathIds.toArray()[0];
1332 String bridgeName = bridge.getName();
1333 if ((datapathId == null) || (bridgeName == null)) {
1337 OvsdbBridge ovsdbBridge = new OvsdbBridge(new OvsdbBridgeName(bridgeName),
1338 new OvsdbDatapathId(datapathId));
1342 //Gets ofPort in the interface.
1343 private long getOfPort(Interface intf) {
1344 OvsdbSet ofPortSet = (OvsdbSet) intf.getOpenFlowPortColumn().data();
1345 @SuppressWarnings("unchecked")
1346 Set<Integer> ofPorts = ofPortSet.set();
1347 while (ofPorts == null || ofPorts.size() <= 0) {
1348 log.debug("The ofport is null in {}", intf.getName());
1351 // return (long) ofPorts.toArray()[0];
1352 Iterator<Integer> it = ofPorts.iterator();
1353 return Long.parseLong(it.next().toString());
1357 public Set<OvsdbPort> getLocalPorts(Iterable<String> ifaceids) {
1358 Set<OvsdbPort> ovsdbPorts = new HashSet<OvsdbPort>();
1359 OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1360 if (tableStore == null) {
1363 OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.INTERFACE);
1364 if (rowStore == null) {
1367 ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1368 for (String uuid : rows.keySet()) {
1369 Row row = getRow(OvsdbConstant.DATABASENAME,
1370 OvsdbConstant.INTERFACE, uuid);
1371 DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1372 Interface intf = (Interface) TableGenerator
1373 .getTable(dbSchema, row, OvsdbTable.INTERFACE);
1374 if (intf == null || getIfaceid(intf) == null) {
1377 String portName = intf.getName();
1378 Set<String> ifaceidSet = Sets.newHashSet(ifaceids);
1379 if (portName.startsWith("vxlan")
1380 || !ifaceidSet.contains(getIfaceid(intf))) {
1383 long ofPort = getOfPort(intf);
1384 if ((ofPort < 0) || (portName == null)) {
1388 OvsdbPort ovsdbPort = new OvsdbPort(new OvsdbPortNumber(ofPort),
1389 new OvsdbPortName(portName));
1390 if (ovsdbPort != null) {
1391 ovsdbPorts.add(ovsdbPort);
1397 private String getIfaceid(Interface intf) {
1398 OvsdbMap ovsdbMap = (OvsdbMap) intf.getExternalIdsColumn().data();
1399 @SuppressWarnings("unchecked")
1400 Map<String, String> externalIds = ovsdbMap.map();
1401 if (externalIds.isEmpty()) {
1402 log.warn("The external_ids is null");
1405 String ifaceid = externalIds
1406 .get(OvsdbConstant.EXTERNAL_ID_INTERFACE_ID);
1407 if (ifaceid == null) {
1408 log.warn("The ifaceid is null");
1415 public void disconnect() {
1416 channel.disconnect();
1417 this.agent.removeConnectedNode(nodeId);