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 store if no rows exist in the table
180 private OvsdbRowStore getRowStore(String dbName, String tableName) {
181 OvsdbTableStore tableStore = getTableStore(dbName);
182 if (tableStore == null) {
186 OvsdbRowStore rowStore = tableStore.getRows(tableName);
187 if (rowStore == null) {
188 rowStore = new OvsdbRowStore();
194 * Gets the ovsdb row.
196 * @param dbName the ovsdb database name
197 * @param tableName the ovsdb table name
198 * @param uuid the key of the row
199 * @return row, empty if row is find
202 public Row getRow(String dbName, String tableName, String uuid) {
203 OvsdbTableStore tableStore = getTableStore(dbName);
204 if (tableStore == null) {
207 OvsdbRowStore rowStore = tableStore.getRows(tableName);
208 if (rowStore == null) {
211 return rowStore.getRow(uuid);
215 public void removeRow(String dbName, String tableName, String uuid) {
216 OvsdbTableStore tableStore = getTableStore(dbName);
217 if (tableStore == null) {
220 OvsdbRowStore rowStore = tableStore.getRows(tableName);
221 if (rowStore == null) {
224 rowStore.deleteRow(uuid);
228 public void updateOvsdbStore(String dbName, String tableName, String uuid,
230 OvsdbTableStore tableStore = ovsdbStore.getOvsdbTableStore(dbName);
231 if (tableStore == null) {
232 tableStore = new OvsdbTableStore();
234 OvsdbRowStore rowStore = tableStore.getRows(tableName);
235 if (rowStore == null) {
236 rowStore = new OvsdbRowStore();
238 rowStore.insertRow(uuid, row);
239 tableStore.createOrUpdateTable(tableName, rowStore);
240 ovsdbStore.createOrUpdateOvsdbStore(dbName, tableStore);
244 public String getPortUuid(String portName, String bridgeUuid) {
245 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
247 Row bridgeRow = getRow(OvsdbConstant.DATABASENAME,
248 OvsdbConstant.BRIDGE, bridgeUuid);
250 Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, bridgeRow,
252 if (bridge != null) {
253 OvsdbSet setPorts = (OvsdbSet) bridge.getPortsColumn().data();
254 @SuppressWarnings("unchecked")
255 Set<UUID> ports = setPorts.set();
256 if (ports == null || ports.size() == 0) {
257 log.warn("The port uuid is null");
261 for (UUID uuid : ports) {
262 Row portRow = getRow(OvsdbConstant.DATABASENAME,
263 OvsdbConstant.PORT, uuid.value());
264 Port port = (Port) TableGenerator.getTable(dbSchema, portRow,
266 if (port != null && portName.equalsIgnoreCase(port.getName())) {
276 public String getInterfaceUuid(String portUuid, String portName) {
277 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
279 Row portRow = getRow(OvsdbConstant.DATABASENAME, OvsdbConstant.PORT,
281 Port port = (Port) TableGenerator.getTable(dbSchema, portRow,
285 OvsdbSet setInterfaces = (OvsdbSet) port.getInterfacesColumn().data();
286 @SuppressWarnings("unchecked")
287 Set<UUID> interfaces = setInterfaces.set();
289 if (interfaces == null || interfaces.size() == 0) {
290 log.warn("The interface uuid is null");
294 for (UUID uuid : interfaces) {
295 Row intfRow = getRow(OvsdbConstant.DATABASENAME,
296 OvsdbConstant.INTERFACE, uuid.value());
297 Interface intf = (Interface) TableGenerator
298 .getTable(dbSchema, intfRow, OvsdbTable.INTERFACE);
299 if (intf != null && portName.equalsIgnoreCase(intf.getName())) {
310 public String getBridgeUuid(String bridgeName) {
311 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
313 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
314 OvsdbConstant.BRIDGE);
315 if (rowStore == null) {
316 log.debug("The bridge uuid is null");
320 ConcurrentMap<String, Row> bridgeTableRows = rowStore.getRowStore();
321 if (bridgeTableRows == null) {
322 log.debug("The bridge uuid is null");
326 for (String uuid : bridgeTableRows.keySet()) {
327 Bridge bridge = (Bridge) TableGenerator
328 .getTable(dbSchema, bridgeTableRows.get(uuid),
331 if (bridge.getName().equals(bridgeName)) {
340 public String getControllerUuid(String controllerName,
341 String controllerTarget) {
342 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
343 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
344 OvsdbConstant.CONTROLLER);
345 if (rowStore == null) {
346 log.debug("The controller uuid is null");
350 ConcurrentMap<String, Row> controllerTableRows = rowStore.getRowStore();
351 if (controllerTableRows != null) {
352 for (String uuid : controllerTableRows.keySet()) {
354 Controller controller = (Controller) TableGenerator
355 .getTable(dbSchema, controllerTableRows.get(uuid),
356 OvsdbTable.CONTROLLER);
357 String target = (String) controller.getTargetColumn().data();
358 if (target.equalsIgnoreCase(controllerTarget)) {
368 public String getOvsUuid(String dbName) {
369 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
370 OvsdbConstant.DATABASENAME);
371 if (rowStore == null) {
372 log.debug("The bridge uuid is null");
375 ConcurrentMap<String, Row> ovsTableRows = rowStore.getRowStore();
376 if (ovsTableRows != null) {
377 for (String uuid : ovsTableRows.keySet()) {
378 Row row = ovsTableRows.get(uuid);
379 String tableName = row.tableName();
380 if (tableName.equals(dbName)) {
389 public void createPort(String bridgeName, String portName) {
390 String bridgeUuid = getBridgeUuid(bridgeName);
391 if (bridgeUuid == null) {
392 log.error("Can't find bridge {} in {}", bridgeName,
393 nodeId.getIpAddress());
397 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
398 String portUuid = getPortUuid(portName, bridgeUuid);
400 Port port = (Port) TableGenerator
401 .createTable(dbSchema, OvsdbTable.PORT);
403 port.setName(portName);
404 if (portUuid == null) {
405 insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
406 "ports", bridgeUuid, port.getRow());
408 updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
415 public void dropPort(String bridgeName, String portName) {
416 String bridgeUuid = getBridgeUuid(bridgeName);
417 if (bridgeUuid == null) {
418 log.error("Could not find Bridge {} in {}", bridgeName, nodeId);
422 String portUuid = getPortUuid(portName, bridgeUuid);
423 if (portUuid != null) {
424 log.info("Port {} delete", portName);
425 deleteConfig(OvsdbConstant.PORT, "_uuid", portUuid,
426 OvsdbConstant.BRIDGE, "ports");
431 public void createBridge(String bridgeName) {
432 log.debug("create bridge {}", bridgeName);
434 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
435 if (dbSchema == null) {
436 log.warn("The schema is null");
440 Bridge bridge = (Bridge) TableGenerator.createTable(dbSchema,
442 if (bridge == null) {
443 log.debug("Can not create bridge");
447 Set<String> failModes = new HashSet<>();
448 failModes.add("secure");
449 bridge.setFailMode(failModes);
451 Set<String> protocols = new HashSet<>();
452 protocols.add(OvsdbConstant.OPENFLOW13);
453 bridge.setProtocols(protocols);
455 String ovsUuid = getOvsUuid(OvsdbConstant.DATABASENAME);
456 if (ovsUuid == null) {
457 log.warn("The Open_vSwitch is null");
461 String bridgeUuid = getBridgeUuid(bridgeName);
462 if (bridgeUuid == null) {
463 log.debug("Create a new bridge");
465 bridge.setName(bridgeName);
466 bridgeUuid = insertConfig(OvsdbConstant.BRIDGE, "_uuid",
467 OvsdbConstant.DATABASENAME, "bridges",
468 ovsUuid, bridge.getRow());
470 if (bridgeUuid != null) {
471 Port port = (Port) TableGenerator.createTable(dbSchema,
474 log.debug("the port is not null");
475 port.setName(bridgeName);
477 insertConfig(OvsdbConstant.PORT, "_uuid", "Bridge", "ports", bridgeUuid,
483 log.info("Update a bridge");
484 updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid, bridge.getRow());
487 setControllerAuto(bridgeUuid);
488 log.info("Create bridge success");
492 public boolean createBridge(String bridgeName, String dpid, List<ControllerInfo> controllers) {
494 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
495 String ovsUuid = getOvsUuid(OvsdbConstant.DATABASENAME);
497 if (dbSchema == null || ovsUuid == null) {
498 log.warn("Couldn't find database Open_vSwitch");
502 String bridgeUuid = getBridgeUuid(bridgeName);
503 if (bridgeUuid != null) {
504 log.warn("Bridge {} is already exist", bridgeName);
505 // remove existing one and re-create?
509 Bridge bridge = (Bridge) TableGenerator.createTable(dbSchema, OvsdbTable.BRIDGE);
510 bridge.setName(bridgeName);
512 Set<String> failMode = new HashSet<>(Arrays.asList("secure"));
513 bridge.setFailMode(failMode);
515 Set<String> protocols = new HashSet<>(Arrays.asList(OvsdbConstant.OPENFLOW13));
516 bridge.setProtocols(protocols);
518 Map<String, String> options = new HashMap<>();
519 options.put("datapath-id", dpid);
520 bridge.setOtherConfig(options);
522 bridgeUuid = insertConfig(OvsdbConstant.BRIDGE, "_uuid",
523 OvsdbConstant.DATABASENAME, "bridges",
524 ovsUuid, bridge.getRow());
526 if (bridgeUuid != null) {
527 createPort(bridgeName, bridgeName);
529 log.warn("Failed to create bridge {} on {}", bridgeName, nodeId.toString());
533 setControllersWithUUID(UUID.uuid(bridgeUuid), controllers);
538 * Sets the bridge's controller automatically.
540 * The connection is a TCP connection to the local ONOS instance's IP
541 * and the default OpenFlow port.
543 * @param bridgeUuid bridge uuid
545 private void setControllerAuto(String bridgeUuid) {
546 IpAddress ipAddress = IpAddress.valueOf(((InetSocketAddress) channel.localAddress()).getAddress());
547 ControllerInfo controllerInfo = new ControllerInfo(ipAddress, OvsdbConstant.OFPORT, "tcp");
548 log.debug("Automatically setting controller for bridge {} to {}",
549 bridgeUuid, controllerInfo.target());
550 setControllersWithUUID(UUID.uuid(bridgeUuid), ImmutableList.of(controllerInfo));
554 public void setControllersWithUUID(UUID bridgeUuid, List<ControllerInfo> controllers) {
556 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
557 if (dbSchema == null) {
558 log.debug("There is no schema");
561 List<Controller> oldControllers = getControllers(bridgeUuid);
562 if (oldControllers == null) {
563 log.warn("There are no controllers");
567 Set<UUID> newControllerUuids = new HashSet<>();
569 Set<ControllerInfo> newControllers = new HashSet<>(controllers);
570 List<Controller> removeControllers = new ArrayList<>();
571 oldControllers.forEach(controller -> {
572 ControllerInfo controllerInfo = new ControllerInfo((String) controller.getTargetColumn().data());
573 if (newControllers.contains(controllerInfo)) {
574 newControllers.remove(controllerInfo);
575 newControllerUuids.add(controller.getRow().uuid());
577 removeControllers.add(controller);
580 OvsdbRowStore controllerRowStore = getRowStore(OvsdbConstant.DATABASENAME,
581 OvsdbConstant.CONTROLLER);
582 if (controllerRowStore == null) {
583 log.debug("There is no controller table");
587 removeControllers.forEach(c -> deleteConfig(OvsdbConstant.CONTROLLER, "_uuid", c.getRow().uuid().value(),
588 OvsdbConstant.BRIDGE, "controller"));
590 newControllers.stream().map(c -> {
591 Controller controller = (Controller) TableGenerator
592 .createTable(dbSchema, OvsdbTable.CONTROLLER);
593 controller.setTarget(c.target());
596 String uuid = insertConfig(OvsdbConstant.CONTROLLER, "_uuid",
597 OvsdbConstant.BRIDGE, "controller", bridgeUuid.value(),
599 newControllerUuids.add(UUID.uuid(uuid));
603 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
604 OvsdbConstant.BRIDGE);
605 if (rowStore == null) {
606 log.debug("There is no bridge table");
610 Row bridgeRow = rowStore.getRow(bridgeUuid.value());
611 Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
612 bridge.setController(OvsdbSet.ovsdbSet(newControllerUuids));
613 updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid.value(), bridge.getRow());
617 public void setControllersWithDeviceId(DeviceId deviceId, List<ControllerInfo> controllers) {
618 setControllersWithUUID(getBridgeUUID(deviceId), controllers);
622 public void dropBridge(String bridgeName) {
623 String bridgeUUID = getBridgeUuid(bridgeName);
624 if (bridgeUUID == null) {
625 log.warn("Could not find bridge in node", nodeId.getIpAddress());
628 deleteConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUUID,
629 OvsdbConstant.DATABASENAME, "bridges");
633 public void createTunnel(IpAddress srcIp, IpAddress dstIp) {
634 String bridgeUuid = getBridgeUuid(OvsdbConstant.INTEGRATION_BRIDGE);
635 if (bridgeUuid == null) {
636 log.warn("Could not find bridge {} and Could not create tunnel. ",
637 OvsdbConstant.INTEGRATION_BRIDGE);
641 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
642 String portName = getTunnelName(OvsdbConstant.TYPEVXLAN, dstIp);
643 String portUuid = getPortUuid(portName, bridgeUuid);
645 Port port = (Port) TableGenerator
646 .createTable(dbSchema, OvsdbTable.PORT);
648 port.setName(portName);
651 if (portUuid == null) {
652 portUuid = insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
653 "ports", bridgeUuid, port.getRow());
655 updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
658 // When a tunnel is created, A row is inserted into port table and
659 // interface table of the ovsdb node.
660 // and the following step is to get the interface uuid from local store
661 // in controller node.
662 // but it need spend some time synchronising data between node and
664 // so loop to judge if interfaceUUid is null is necessary.
665 String interfaceUuid = null;
666 for (int i = 0; i < 10; i++) {
667 interfaceUuid = getInterfaceUuid(portUuid, portName);
668 if (interfaceUuid == null) {
671 } catch (InterruptedException e) {
672 log.warn("Interrupted while waiting to get interfaceUuid");
673 Thread.currentThread().interrupt();
680 if (interfaceUuid != null) {
682 Interface tunInterface = (Interface) TableGenerator
683 .createTable(dbSchema, OvsdbTable.INTERFACE);
685 if (tunInterface != null) {
687 tunInterface.setType(OvsdbConstant.TYPEVXLAN);
688 Map<String, String> options = Maps.newHashMap();
689 options.put("key", "flow");
690 options.put("local_ip", srcIp.toString());
691 options.put("remote_ip", dstIp.toString());
692 tunInterface.setOptions(options);
693 updateConfig(OvsdbConstant.INTERFACE, "_uuid", interfaceUuid,
694 tunInterface.getRow());
695 log.info("Tunnel added success", tunInterface);
704 public boolean createTunnel(String bridgeName, String portName, String tunnelType, Map<String, String> options) {
706 String bridgeUuid = getBridgeUuid(bridgeName);
707 if (bridgeUuid == null) {
708 log.warn("Couldn't find bridge {} in {}", bridgeName, nodeId.getIpAddress());
712 if (getPortUuid(portName, bridgeUuid) != null) {
713 log.warn("Port {} already exists", portName);
714 // remove existing one and re-create?
718 ArrayList<Operation> operations = Lists.newArrayList();
719 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
721 // insert a new port to the port table
722 Port port = (Port) TableGenerator.createTable(dbSchema, OvsdbTable.PORT);
723 port.setName(portName);
724 Insert portInsert = new Insert(dbSchema.getTableSchema("Port"), "Port", port.getRow());
725 portInsert.getRow().put("interfaces", UUID.uuid("Interface"));
726 operations.add(portInsert);
728 // update the bridge table
729 Condition condition = ConditionUtil.equals("_uuid", UUID.uuid(bridgeUuid));
730 Mutation mutation = MutationUtil.insert("ports", UUID.uuid("Port"));
731 List<Condition> conditions = new ArrayList<>(Arrays.asList(condition));
732 List<Mutation> mutations = new ArrayList<>(Arrays.asList(mutation));
733 operations.add(new Mutate(dbSchema.getTableSchema("Bridge"), conditions, mutations));
735 // insert a tunnel interface
736 Interface intf = (Interface) TableGenerator.createTable(dbSchema, OvsdbTable.INTERFACE);
737 intf.setName(portName);
738 intf.setType(tunnelType);
739 intf.setOptions(options);
740 Insert intfInsert = new Insert(dbSchema.getTableSchema("Interface"), "Interface", intf.getRow());
741 operations.add(intfInsert);
743 transactConfig(OvsdbConstant.DATABASENAME, operations);
748 public void dropTunnel(IpAddress srcIp, IpAddress dstIp) {
749 String bridgeName = OvsdbConstant.INTEGRATION_BRIDGE;
750 String portName = getTunnelName(OvsdbConstant.TYPEVXLAN, dstIp);
751 String bridgeUuid = getBridgeUuid(OvsdbConstant.INTEGRATION_BRIDGE);
752 if (bridgeUuid == null) {
753 log.warn("Could not find bridge {} in {}", bridgeName,
754 nodeId.getIpAddress());
758 String portUUID = getPortUuid(portName, bridgeUuid);
759 if (portUUID != null) {
760 log.info("Delete tunnel");
761 deleteConfig(OvsdbConstant.PORT, "_uuid", portUUID,
762 OvsdbConstant.BRIDGE, "ports");
769 * Delete transact config.
771 * @param childTableName child table name
772 * @param childColumnName child column name
773 * @param childUuid child row uuid
774 * @param parentTableName parent table name
775 * @param parentColumnName parent column
777 private void deleteConfig(String childTableName, String childColumnName,
778 String childUuid, String parentTableName,
779 String parentColumnName) {
780 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
781 TableSchema childTableSchema = dbSchema.getTableSchema(childTableName);
783 ArrayList<Operation> operations = Lists.newArrayList();
784 if (parentTableName != null && parentColumnName != null) {
785 TableSchema parentTableSchema = dbSchema
786 .getTableSchema(parentTableName);
787 ColumnSchema parentColumnSchema = parentTableSchema
788 .getColumnSchema(parentColumnName);
789 List<Mutation> mutations = Lists.newArrayList();
790 Mutation mutation = MutationUtil.delete(parentColumnSchema.name(),
791 UUID.uuid(childUuid));
792 mutations.add(mutation);
793 List<Condition> conditions = Lists.newArrayList();
794 Condition condition = ConditionUtil.includes(parentColumnName,
795 UUID.uuid(childUuid));
796 conditions.add(condition);
797 Mutate op = new Mutate(parentTableSchema, conditions, mutations);
801 List<Condition> conditions = Lists.newArrayList();
802 Condition condition = ConditionUtil.equals(childColumnName, UUID.uuid(childUuid));
803 conditions.add(condition);
804 Delete del = new Delete(childTableSchema, conditions);
806 transactConfig(OvsdbConstant.DATABASENAME, operations);
812 * Update transact config.
814 * @param tableName table name
815 * @param columnName column name
817 * @param row the config data
819 private void updateConfig(String tableName, String columnName, String uuid,
821 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
822 TableSchema tableSchema = dbSchema.getTableSchema(tableName);
824 List<Condition> conditions = Lists.newArrayList();
825 Condition condition = ConditionUtil.equals(columnName, UUID.uuid(uuid));
826 conditions.add(condition);
828 Update update = new Update(tableSchema, row, conditions);
830 ArrayList<Operation> operations = Lists.newArrayList();
831 operations.add(update);
833 transactConfig(OvsdbConstant.DATABASENAME, operations);
837 * Insert transact config.
839 * @param childTableName child table name
840 * @param childColumnName child column name
841 * @param parentTableName parent table name
842 * @param parentColumnName parent column
843 * @param parentUuid parent uuid
844 * @param row the config data
845 * @return uuid, empty if no uuid is find
847 private String insertConfig(String childTableName, String childColumnName,
848 String parentTableName, String parentColumnName,
849 String parentUuid, Row row) {
850 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
851 TableSchema tableSchema = dbSchema.getTableSchema(childTableName);
853 String namedUuid = childTableName;
854 Insert insert = new Insert(tableSchema, namedUuid, row);
856 ArrayList<Operation> operations = Lists.newArrayList();
857 operations.add(insert);
859 if (parentTableName != null && parentColumnName != null) {
860 TableSchema parentTableSchema = dbSchema
861 .getTableSchema(parentTableName);
862 ColumnSchema parentColumnSchema = parentTableSchema
863 .getColumnSchema(parentColumnName);
865 List<Mutation> mutations = Lists.newArrayList();
866 Mutation mutation = MutationUtil.insert(parentColumnSchema.name(),
867 UUID.uuid(namedUuid));
868 mutations.add(mutation);
870 List<Condition> conditions = Lists.newArrayList();
871 Condition condition = ConditionUtil.equals("_uuid",
872 UUID.uuid(parentUuid));
873 conditions.add(condition);
875 Mutate op = new Mutate(parentTableSchema, conditions, mutations);
878 if (childTableName.equalsIgnoreCase(OvsdbConstant.PORT)) {
879 log.info("Handle port insert");
880 Insert intfInsert = handlePortInsertTable(OvsdbConstant.INTERFACE,
883 if (intfInsert != null) {
884 operations.add(intfInsert);
887 Insert ins = (Insert) operations.get(0);
888 ins.getRow().put("interfaces",
889 UUID.uuid(OvsdbConstant.INTERFACE));
892 List<OperationResult> results;
894 results = transactConfig(OvsdbConstant.DATABASENAME, operations)
897 return results.get(0).getUuid().value();
898 } catch (InterruptedException e) {
899 log.warn("Interrupted while waiting to get result");
900 Thread.currentThread().interrupt();
901 } catch (ExecutionException e) {
902 log.error("Exception thrown while to get result");
909 * Handles port insert.
911 * @param tableName ovsdb table interface
912 * @param portRow row of port
913 * @return insert, empty if null
915 private Insert handlePortInsertTable(String tableName, Row portRow) {
916 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
918 TableSchema portTableSchema = dbSchema
919 .getTableSchema(OvsdbConstant.PORT);
920 ColumnSchema portColumnSchema = portTableSchema.getColumnSchema("name");
922 String portName = (String) portRow.getColumn(portColumnSchema.name()).data();
924 Interface inf = (Interface) TableGenerator
925 .createTable(dbSchema, OvsdbTable.INTERFACE);
927 inf.setName(portName);
929 TableSchema intfTableSchema = dbSchema
930 .getTableSchema(OvsdbConstant.INTERFACE);
931 Insert insert = new Insert(intfTableSchema, OvsdbConstant.INTERFACE,
940 * @param dstIp the remote ip address
941 * @return tunnel name
943 private String getTunnelName(String tunnelType, IpAddress dstIp) {
944 return tunnelType + "-" + dstIp.toString();
948 public ListenableFuture<DatabaseSchema> getOvsdbSchema(String dbName) {
949 if (dbName == null) {
952 DatabaseSchema databaseSchema = schema.get(dbName);
953 if (databaseSchema == null) {
954 List<String> dbNames = new ArrayList<String>();
956 Function<JsonNode, DatabaseSchema> rowFunction = new Function<JsonNode, DatabaseSchema>() {
958 public DatabaseSchema apply(JsonNode input) {
959 log.info("Get ovsdb database schema {}", dbName);
960 DatabaseSchema dbSchema = FromJsonUtil
961 .jsonNodeToDbSchema(dbName, input);
962 if (dbSchema == null) {
963 log.debug("Get ovsdb database schema error");
966 schema.put(dbName, dbSchema);
972 ListenableFuture<JsonNode> input = getSchema(dbNames);
974 return Futures.transform(input, rowFunction);
978 return Futures.immediateFuture(databaseSchema);
983 public ListenableFuture<TableUpdates> monitorTables(String dbName, String id) {
984 if (dbName == null) {
987 DatabaseSchema dbSchema = schema.get(dbName);
988 if (dbSchema != null) {
989 Function<JsonNode, TableUpdates> rowFunction = new Function<JsonNode, TableUpdates>() {
991 public TableUpdates apply(JsonNode input) {
992 log.info("Get table updates");
993 TableUpdates updates = FromJsonUtil
994 .jsonNodeToTableUpdates(input, dbSchema);
995 if (updates == null) {
996 log.debug("Get table updates error");
1002 return Futures.transform(monitor(dbSchema, id), rowFunction);
1008 public ListenableFuture<List<OperationResult>> transactConfig(String dbName,
1009 List<Operation> operations) {
1010 if (dbName == null) {
1013 DatabaseSchema dbSchema = schema.get(dbName);
1014 if (dbSchema != null) {
1015 Function<List<JsonNode>, List<OperationResult>> rowFunction = (input -> {
1016 log.info("Get ovsdb operation result");
1017 List<OperationResult> result = FromJsonUtil
1018 .jsonNodeToOperationResult(input, operations);
1020 if (result == null) {
1021 log.debug("The operation result is null");
1026 return Futures.transform(transact(dbSchema, operations),
1033 public ListenableFuture<JsonNode> getSchema(List<String> dbnames) {
1034 String id = java.util.UUID.randomUUID().toString();
1035 String getSchemaString = JsonRpcWriterUtil.getSchemaStr(id, dbnames);
1037 SettableFuture<JsonNode> sf = SettableFuture.create();
1038 requestResult.put(id, sf);
1039 requestMethod.put(id, "getSchema");
1041 channel.writeAndFlush(getSchemaString);
1047 public ListenableFuture<List<String>> echo() {
1048 String id = java.util.UUID.randomUUID().toString();
1049 String echoString = JsonRpcWriterUtil.echoStr(id);
1051 SettableFuture<List<String>> sf = SettableFuture.create();
1052 requestResult.put(id, sf);
1053 requestMethod.put(id, "echo");
1055 channel.writeAndFlush(echoString);
1061 public ListenableFuture<JsonNode> monitor(DatabaseSchema dbSchema,
1063 String id = java.util.UUID.randomUUID().toString();
1064 String monitorString = JsonRpcWriterUtil.monitorStr(id, monitorId,
1067 SettableFuture<JsonNode> sf = SettableFuture.create();
1068 requestResult.put(id, sf);
1069 requestMethod.put(id, "monitor");
1071 channel.writeAndFlush(monitorString);
1077 public ListenableFuture<List<String>> listDbs() {
1078 String id = java.util.UUID.randomUUID().toString();
1079 String listDbsString = JsonRpcWriterUtil.listDbsStr(id);
1081 SettableFuture<List<String>> sf = SettableFuture.create();
1082 requestResult.put(id, sf);
1083 requestMethod.put(id, "listDbs");
1085 channel.writeAndFlush(listDbsString);
1091 public ListenableFuture<List<JsonNode>> transact(DatabaseSchema dbSchema,
1092 List<Operation> operations) {
1093 String id = java.util.UUID.randomUUID().toString();
1094 String transactString = JsonRpcWriterUtil.transactStr(id, dbSchema,
1097 SettableFuture<List<JsonNode>> sf = SettableFuture.create();
1098 requestResult.put(id, sf);
1099 requestMethod.put(id, "transact");
1101 channel.writeAndFlush(transactString);
1106 @SuppressWarnings({"rawtypes", "unchecked"})
1108 public void processResult(JsonNode response) {
1109 log.debug("Handle result");
1110 String requestId = response.get("id").asText();
1111 SettableFuture sf = requestResult.get(requestId);
1113 log.debug("No such future to process");
1116 String methodName = requestMethod.get(requestId);
1119 result = FromJsonUtil.jsonResultParser(response, methodName);
1126 public void processRequest(JsonNode requestJson) {
1127 log.debug("Handle request");
1128 if (requestJson.get("method").asText().equalsIgnoreCase("echo")) {
1129 log.debug("handle echo request");
1131 String replyString = FromJsonUtil.getEchoRequestStr(requestJson);
1132 channel.writeAndFlush(replyString);
1137 .jsonCallbackRequestParser(requestJson, monitorCallBack);
1143 public void setCallback(Callback monitorCallback) {
1144 this.monitorCallBack = monitorCallback;
1148 public Set<OvsdbTunnel> getTunnels() {
1149 return ovsdbTunnels;
1153 public Set<OvsdbBridge> getBridges() {
1154 Set<OvsdbBridge> ovsdbBridges = new HashSet<OvsdbBridge>();
1155 OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1156 if (tableStore == null) {
1159 OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.BRIDGE);
1160 if (rowStore == null) {
1163 ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1164 for (String uuid : rows.keySet()) {
1165 Row row = getRow(OvsdbConstant.DATABASENAME, OvsdbConstant.BRIDGE,
1167 OvsdbBridge ovsdbBridge = getOvsdbBridge(row);
1168 if (ovsdbBridge != null) {
1169 ovsdbBridges.add(ovsdbBridge);
1172 return ovsdbBridges;
1176 public Set<ControllerInfo> getControllers(DeviceId openflowDeviceId) {
1177 UUID bridgeUuid = getBridgeUUID(openflowDeviceId);
1178 if (bridgeUuid == null) {
1179 log.warn("bad bridge Uuid");
1182 List<Controller> controllers = getControllers(bridgeUuid);
1183 if (controllers == null) {
1184 log.warn("bad list of controllers");
1187 return controllers.stream().
1188 map(controller -> new ControllerInfo(
1189 (String) controller.getTargetColumn()
1190 .data())).collect(Collectors.toSet());
1193 private List<Controller> getControllers(UUID bridgeUuid) {
1194 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
1195 if (dbSchema == null) {
1198 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
1199 OvsdbConstant.BRIDGE);
1200 if (rowStore == null) {
1201 log.debug("There is no bridge table");
1205 Row bridgeRow = rowStore.getRow(bridgeUuid.value());
1206 Bridge bridge = (Bridge) TableGenerator.
1207 getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
1210 log.warn("type of controller column", bridge.getControllerColumn()
1211 .data().getClass());
1212 Set<UUID> controllerUuids = (Set<UUID>) ((OvsdbSet) bridge
1213 .getControllerColumn().data()).set();
1214 // Set<String> controllerUuidStrings = (Set<String>) bridge.getControllerColumn().data();
1216 OvsdbRowStore controllerRowStore = getRowStore(OvsdbConstant.DATABASENAME,
1217 OvsdbConstant.CONTROLLER);
1218 if (controllerRowStore == null) {
1219 log.debug("There is no controller table");
1223 List<Controller> ovsdbControllers = new ArrayList<>();
1224 ConcurrentMap<String, Row> controllerTableRows = controllerRowStore.getRowStore();
1225 controllerTableRows.forEach((key, row) -> {
1226 if (!controllerUuids.contains(UUID.uuid(key))) {
1229 Controller controller = (Controller) TableGenerator
1230 .getTable(dbSchema, row, OvsdbTable.CONTROLLER);
1231 ovsdbControllers.add(controller);
1233 return ovsdbControllers;
1237 private UUID getBridgeUUID(DeviceId openflowDeviceId) {
1238 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
1239 if (dbSchema == null) {
1242 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
1243 OvsdbConstant.BRIDGE);
1244 if (rowStore == null) {
1245 log.debug("There is no bridge table");
1249 ConcurrentMap<String, Row> bridgeTableRows = rowStore.getRowStore();
1250 final AtomicReference<UUID> uuid = new AtomicReference<>();
1251 for (Map.Entry<String, Row> entry : bridgeTableRows.entrySet()) {
1252 Bridge b = (Bridge) TableGenerator.getTable(dbSchema,
1255 if (matchesDpid(b, openflowDeviceId)) {
1256 uuid.set(UUID.uuid(entry.getKey()));
1260 if (uuid.get() == null) {
1261 log.debug("There is no bridge for {}", openflowDeviceId);
1267 private static boolean matchesDpid(Bridge b, DeviceId deviceId) {
1268 String ofDpid = deviceId.toString().replace("of:", "");
1269 Set ofDeviceIds = ((OvsdbSet) b.getDatapathIdColumn().data()).set();
1271 return ofDeviceIds.contains(ofDpid);
1275 public Set<OvsdbPort> getPorts() {
1276 Set<OvsdbPort> ovsdbPorts = new HashSet<OvsdbPort>();
1277 OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1278 if (tableStore == null) {
1281 OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.INTERFACE);
1282 if (rowStore == null) {
1285 ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1286 for (String uuid : rows.keySet()) {
1287 Row row = getRow(OvsdbConstant.DATABASENAME,
1288 OvsdbConstant.INTERFACE, uuid);
1289 OvsdbPort ovsdbPort = getOvsdbPort(row);
1290 if (ovsdbPort != null) {
1291 ovsdbPorts.add(ovsdbPort);
1298 public DatabaseSchema getDatabaseSchema(String dbName) {
1299 return schema.get(dbName);
1303 private OvsdbPort getOvsdbPort(Row row) {
1304 DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1305 Interface intf = (Interface) TableGenerator
1306 .getTable(dbSchema, row, OvsdbTable.INTERFACE);
1310 long ofPort = getOfPort(intf);
1311 String portName = intf.getName();
1312 if ((ofPort < 0) || (portName == null)) {
1316 OvsdbPort ovsdbPort = new OvsdbPort(new OvsdbPortNumber(ofPort),
1317 new OvsdbPortName(portName));
1321 ////Gets ovsdb bridge.
1322 private OvsdbBridge getOvsdbBridge(Row row) {
1323 DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1324 Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, row,
1326 if (bridge == null) {
1330 OvsdbSet datapathIdSet = (OvsdbSet) bridge.getDatapathIdColumn().data();
1331 @SuppressWarnings("unchecked")
1332 Set<String> datapathIds = datapathIdSet.set();
1333 if (datapathIds == null || datapathIds.size() == 0) {
1336 String datapathId = (String) datapathIds.toArray()[0];
1337 String bridgeName = bridge.getName();
1338 if ((datapathId == null) || (bridgeName == null)) {
1342 OvsdbBridge ovsdbBridge = new OvsdbBridge(new OvsdbBridgeName(bridgeName),
1343 new OvsdbDatapathId(datapathId));
1347 //Gets ofPort in the interface.
1348 private long getOfPort(Interface intf) {
1349 OvsdbSet ofPortSet = (OvsdbSet) intf.getOpenFlowPortColumn().data();
1350 @SuppressWarnings("unchecked")
1351 Set<Integer> ofPorts = ofPortSet.set();
1352 while (ofPorts == null || ofPorts.size() <= 0) {
1353 log.debug("The ofport is null in {}", intf.getName());
1356 // return (long) ofPorts.toArray()[0];
1357 Iterator<Integer> it = ofPorts.iterator();
1358 return Long.parseLong(it.next().toString());
1362 public Set<OvsdbPort> getLocalPorts(Iterable<String> ifaceids) {
1363 Set<OvsdbPort> ovsdbPorts = new HashSet<OvsdbPort>();
1364 OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1365 if (tableStore == null) {
1368 OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.INTERFACE);
1369 if (rowStore == null) {
1372 ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1373 for (String uuid : rows.keySet()) {
1374 Row row = getRow(OvsdbConstant.DATABASENAME,
1375 OvsdbConstant.INTERFACE, uuid);
1376 DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1377 Interface intf = (Interface) TableGenerator
1378 .getTable(dbSchema, row, OvsdbTable.INTERFACE);
1379 if (intf == null || getIfaceid(intf) == null) {
1382 String portName = intf.getName();
1383 Set<String> ifaceidSet = Sets.newHashSet(ifaceids);
1384 if (portName.startsWith("vxlan")
1385 || !ifaceidSet.contains(getIfaceid(intf))) {
1388 long ofPort = getOfPort(intf);
1389 if ((ofPort < 0) || (portName == null)) {
1393 OvsdbPort ovsdbPort = new OvsdbPort(new OvsdbPortNumber(ofPort),
1394 new OvsdbPortName(portName));
1395 if (ovsdbPort != null) {
1396 ovsdbPorts.add(ovsdbPort);
1402 private String getIfaceid(Interface intf) {
1403 OvsdbMap ovsdbMap = (OvsdbMap) intf.getExternalIdsColumn().data();
1404 @SuppressWarnings("unchecked")
1405 Map<String, String> externalIds = ovsdbMap.map();
1406 if (externalIds.isEmpty()) {
1407 log.warn("The external_ids is null");
1410 String ifaceid = externalIds
1411 .get(OvsdbConstant.EXTERNAL_ID_INTERFACE_ID);
1412 if (ifaceid == null) {
1413 log.warn("The ifaceid is null");
1420 public void disconnect() {
1421 channel.disconnect();
1422 this.agent.removeConnectedNode(nodeId);