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;
28 import io.netty.channel.Channel;
30 import org.onlab.packet.IpAddress;
31 import org.onosproject.net.DeviceId;
32 import org.onosproject.net.behaviour.ControllerInfo;
33 import org.onosproject.ovsdb.controller.OvsdbBridge;
34 import org.onosproject.ovsdb.controller.OvsdbBridgeName;
35 import org.onosproject.ovsdb.controller.OvsdbClientService;
36 import org.onosproject.ovsdb.controller.OvsdbConstant;
37 import org.onosproject.ovsdb.controller.OvsdbDatapathId;
38 import org.onosproject.ovsdb.controller.OvsdbNodeId;
39 import org.onosproject.ovsdb.controller.OvsdbPort;
40 import org.onosproject.ovsdb.controller.OvsdbPortName;
41 import org.onosproject.ovsdb.controller.OvsdbPortNumber;
42 import org.onosproject.ovsdb.controller.OvsdbRowStore;
43 import org.onosproject.ovsdb.controller.OvsdbStore;
44 import org.onosproject.ovsdb.controller.OvsdbTableStore;
45 import org.onosproject.ovsdb.controller.OvsdbTunnel;
46 import org.onosproject.ovsdb.rfc.exception.BridgeCreateException;
47 import org.onosproject.ovsdb.rfc.jsonrpc.Callback;
48 import org.onosproject.ovsdb.rfc.message.OperationResult;
49 import org.onosproject.ovsdb.rfc.message.TableUpdates;
50 import org.onosproject.ovsdb.rfc.notation.Condition;
51 import org.onosproject.ovsdb.rfc.notation.Mutation;
52 import org.onosproject.ovsdb.rfc.notation.OvsdbMap;
53 import org.onosproject.ovsdb.rfc.notation.OvsdbSet;
54 import org.onosproject.ovsdb.rfc.notation.Row;
55 import org.onosproject.ovsdb.rfc.notation.UUID;
56 import org.onosproject.ovsdb.rfc.operations.Delete;
57 import org.onosproject.ovsdb.rfc.operations.Insert;
58 import org.onosproject.ovsdb.rfc.operations.Mutate;
59 import org.onosproject.ovsdb.rfc.operations.Operation;
60 import org.onosproject.ovsdb.rfc.operations.Update;
61 import org.onosproject.ovsdb.rfc.schema.ColumnSchema;
62 import org.onosproject.ovsdb.rfc.schema.DatabaseSchema;
63 import org.onosproject.ovsdb.rfc.schema.TableSchema;
64 import org.onosproject.ovsdb.rfc.table.Bridge;
65 import org.onosproject.ovsdb.rfc.table.Controller;
66 import org.onosproject.ovsdb.rfc.table.Interface;
67 import org.onosproject.ovsdb.rfc.table.OvsdbTable;
68 import org.onosproject.ovsdb.rfc.table.Port;
69 import org.onosproject.ovsdb.rfc.table.TableGenerator;
70 import org.onosproject.ovsdb.rfc.utils.ConditionUtil;
71 import org.onosproject.ovsdb.rfc.utils.FromJsonUtil;
72 import org.onosproject.ovsdb.rfc.utils.JsonRpcWriterUtil;
73 import org.onosproject.ovsdb.rfc.utils.MutationUtil;
74 import org.slf4j.Logger;
75 import org.slf4j.LoggerFactory;
77 import java.net.InetSocketAddress;
78 import java.util.ArrayList;
79 import java.util.Arrays;
80 import java.util.HashMap;
81 import java.util.HashSet;
82 import java.util.Iterator;
83 import java.util.List;
86 import java.util.concurrent.ConcurrentMap;
87 import java.util.concurrent.ExecutionException;
88 import java.util.concurrent.atomic.AtomicReference;
89 import java.util.stream.Collectors;
92 * An representation of an ovsdb client.
94 public class DefaultOvsdbClient
95 implements OvsdbProviderService, OvsdbClientService {
97 private final Logger log = LoggerFactory
98 .getLogger(DefaultOvsdbClient.class);
100 private Channel channel;
102 private OvsdbAgent agent;
103 private boolean connected;
104 private OvsdbNodeId nodeId;
105 private Callback monitorCallBack;
107 private OvsdbStore ovsdbStore = new OvsdbStore();
109 private final Map<String, String> requestMethod = Maps.newHashMap();
110 private final Map<String, SettableFuture<? extends Object>> requestResult = Maps
113 private final Map<String, DatabaseSchema> schema = Maps.newHashMap();
114 private final Set<OvsdbTunnel> ovsdbTunnels = new HashSet<OvsdbTunnel>();
117 * Creates an OvsdbClient.
119 * @param nodeId ovsdb node id
121 public DefaultOvsdbClient(OvsdbNodeId nodeId) {
122 this.nodeId = nodeId;
126 public OvsdbNodeId nodeId() {
131 public void setAgent(OvsdbAgent agent) {
132 if (this.agent == null) {
138 public void setChannel(Channel channel) {
139 this.channel = channel;
143 public void setConnection(boolean connected) {
144 this.connected = connected;
148 public boolean isConnected() {
149 return this.connected;
153 public void nodeAdded() {
154 this.agent.addConnectedNode(nodeId, this);
158 public void nodeRemoved() {
159 this.agent.removeConnectedNode(nodeId);
160 channel.disconnect();
164 * Gets the ovsdb table store.
166 * @param dbName the ovsdb database name
167 * @return ovsTableStore, empty if table store is find
169 private OvsdbTableStore getTableStore(String dbName) {
170 if (ovsdbStore == null) {
173 return ovsdbStore.getOvsdbTableStore(dbName);
177 * Gets the ovsdb row store.
179 * @param dbName the ovsdb database name
180 * @param tableName the ovsdb table name
181 * @return ovsRowStore, empty store if no rows exist in the table
183 private OvsdbRowStore getRowStore(String dbName, String tableName) {
184 OvsdbTableStore tableStore = getTableStore(dbName);
185 if (tableStore == null) {
189 OvsdbRowStore rowStore = tableStore.getRows(tableName);
190 if (rowStore == null) {
191 rowStore = new OvsdbRowStore();
197 * Gets the ovsdb row.
199 * @param dbName the ovsdb database name
200 * @param tableName the ovsdb table name
201 * @param uuid the key of the row
202 * @return row, empty if row is find
205 public Row getRow(String dbName, String tableName, String uuid) {
206 OvsdbTableStore tableStore = getTableStore(dbName);
207 if (tableStore == null) {
210 OvsdbRowStore rowStore = tableStore.getRows(tableName);
211 if (rowStore == null) {
214 return rowStore.getRow(uuid);
218 public void removeRow(String dbName, String tableName, String uuid) {
219 OvsdbTableStore tableStore = getTableStore(dbName);
220 if (tableStore == null) {
223 OvsdbRowStore rowStore = tableStore.getRows(tableName);
224 if (rowStore == null) {
227 rowStore.deleteRow(uuid);
231 public void updateOvsdbStore(String dbName, String tableName, String uuid,
233 OvsdbTableStore tableStore = ovsdbStore.getOvsdbTableStore(dbName);
234 if (tableStore == null) {
235 tableStore = new OvsdbTableStore();
237 OvsdbRowStore rowStore = tableStore.getRows(tableName);
238 if (rowStore == null) {
239 rowStore = new OvsdbRowStore();
241 rowStore.insertRow(uuid, row);
242 tableStore.createOrUpdateTable(tableName, rowStore);
243 ovsdbStore.createOrUpdateOvsdbStore(dbName, tableStore);
247 public String getPortUuid(String portName, String bridgeUuid) {
248 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
250 Row bridgeRow = getRow(OvsdbConstant.DATABASENAME,
251 OvsdbConstant.BRIDGE, bridgeUuid);
253 Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, bridgeRow,
255 if (bridge != null) {
256 OvsdbSet setPorts = (OvsdbSet) bridge.getPortsColumn().data();
257 @SuppressWarnings("unchecked")
258 Set<UUID> ports = setPorts.set();
259 if (ports == null || ports.size() == 0) {
260 log.warn("The port uuid is null");
264 for (UUID uuid : ports) {
265 Row portRow = getRow(OvsdbConstant.DATABASENAME,
266 OvsdbConstant.PORT, uuid.value());
267 Port port = (Port) TableGenerator.getTable(dbSchema, portRow,
269 if (port != null && portName.equalsIgnoreCase(port.getName())) {
279 public String getInterfaceUuid(String portUuid, String portName) {
280 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
282 Row portRow = getRow(OvsdbConstant.DATABASENAME, OvsdbConstant.PORT,
284 Port port = (Port) TableGenerator.getTable(dbSchema, portRow,
288 OvsdbSet setInterfaces = (OvsdbSet) port.getInterfacesColumn().data();
289 @SuppressWarnings("unchecked")
290 Set<UUID> interfaces = setInterfaces.set();
292 if (interfaces == null || interfaces.size() == 0) {
293 log.warn("The interface uuid is null");
297 for (UUID uuid : interfaces) {
298 Row intfRow = getRow(OvsdbConstant.DATABASENAME,
299 OvsdbConstant.INTERFACE, uuid.value());
300 Interface intf = (Interface) TableGenerator
301 .getTable(dbSchema, intfRow, OvsdbTable.INTERFACE);
302 if (intf != null && portName.equalsIgnoreCase(intf.getName())) {
313 public String getBridgeUuid(String bridgeName) {
314 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
316 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
317 OvsdbConstant.BRIDGE);
318 if (rowStore == null) {
319 log.debug("The bridge uuid is null");
323 ConcurrentMap<String, Row> bridgeTableRows = rowStore.getRowStore();
324 if (bridgeTableRows == null) {
325 log.debug("The bridge uuid is null");
329 for (String uuid : bridgeTableRows.keySet()) {
330 Bridge bridge = (Bridge) TableGenerator
331 .getTable(dbSchema, bridgeTableRows.get(uuid),
334 if (bridge.getName().equals(bridgeName)) {
343 public String getControllerUuid(String controllerName,
344 String controllerTarget) {
345 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
346 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
347 OvsdbConstant.CONTROLLER);
348 if (rowStore == null) {
349 log.debug("The controller uuid is null");
353 ConcurrentMap<String, Row> controllerTableRows = rowStore.getRowStore();
354 if (controllerTableRows != null) {
355 for (String uuid : controllerTableRows.keySet()) {
357 Controller controller = (Controller) TableGenerator
358 .getTable(dbSchema, controllerTableRows.get(uuid),
359 OvsdbTable.CONTROLLER);
360 String target = (String) controller.getTargetColumn().data();
361 if (target.equalsIgnoreCase(controllerTarget)) {
371 public String getOvsUuid(String dbName) {
372 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
373 OvsdbConstant.DATABASENAME);
374 if (rowStore == null) {
375 log.debug("The bridge uuid is null");
378 ConcurrentMap<String, Row> ovsTableRows = rowStore.getRowStore();
379 if (ovsTableRows != null) {
380 for (String uuid : ovsTableRows.keySet()) {
381 Row row = ovsTableRows.get(uuid);
382 String tableName = row.tableName();
383 if (tableName.equals(dbName)) {
392 public void createPort(String bridgeName, String portName) {
393 String bridgeUuid = getBridgeUuid(bridgeName);
394 if (bridgeUuid == null) {
395 log.error("Can't find bridge {} in {}", bridgeName,
396 nodeId.getIpAddress());
400 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
401 String portUuid = getPortUuid(portName, bridgeUuid);
403 Port port = (Port) TableGenerator
404 .createTable(dbSchema, OvsdbTable.PORT);
406 port.setName(portName);
407 if (portUuid == null) {
408 insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
409 "ports", bridgeUuid, port.getRow());
411 updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
418 public void dropPort(String bridgeName, String portName) {
419 String bridgeUuid = getBridgeUuid(bridgeName);
420 if (bridgeUuid == null) {
421 log.error("Could not find Bridge {} in {}", bridgeName, nodeId);
425 String portUuid = getPortUuid(portName, bridgeUuid);
426 if (portUuid != null) {
427 log.info("Port {} delete", portName);
428 deleteConfig(OvsdbConstant.PORT, "_uuid", portUuid,
429 OvsdbConstant.BRIDGE, "ports");
434 public void createBridge(String bridgeName) {
435 log.debug("create bridge {}", bridgeName);
437 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
438 if (dbSchema == null) {
439 log.warn("The schema is null");
443 Bridge bridge = (Bridge) TableGenerator.createTable(dbSchema,
445 if (bridge == null) {
446 log.debug("Can not create bridge");
450 Set<String> failModes = new HashSet<>();
451 failModes.add("secure");
452 bridge.setFailMode(failModes);
454 Set<String> protocols = new HashSet<>();
455 protocols.add(OvsdbConstant.OPENFLOW13);
456 bridge.setProtocols(protocols);
458 String ovsUuid = getOvsUuid(OvsdbConstant.DATABASENAME);
459 if (ovsUuid == null) {
460 log.warn("The Open_vSwitch is null");
464 String bridgeUuid = getBridgeUuid(bridgeName);
465 if (bridgeUuid == null) {
466 log.debug("Create a new bridge");
468 bridge.setName(bridgeName);
469 bridgeUuid = insertConfig(OvsdbConstant.BRIDGE, "_uuid",
470 OvsdbConstant.DATABASENAME, "bridges",
471 ovsUuid, bridge.getRow());
473 if (bridgeUuid != null) {
474 Port port = (Port) TableGenerator.createTable(dbSchema,
477 log.debug("the port is not null");
478 port.setName(bridgeName);
480 insertConfig(OvsdbConstant.PORT, "_uuid", "Bridge", "ports", bridgeUuid,
484 String message = BridgeCreateException.createMessage(ovsUuid);
485 throw new BridgeCreateException(message);
489 log.info("Update a bridge");
490 updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid, bridge.getRow());
493 setControllerAuto(bridgeUuid);
494 log.info("Create bridge success");
498 public void createBridge(String bridgeName, String dpid, String exPortName) {
499 log.debug("create bridge {}", bridgeName);
501 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
502 if (dbSchema == null) {
503 log.warn("The schema is null");
507 Bridge bridge = (Bridge) TableGenerator.createTable(dbSchema,
509 if (bridge == null) {
510 log.debug("Can not create bridge");
514 Set<String> failModes = new HashSet<>();
515 failModes.add("secure");
516 bridge.setFailMode(failModes);
518 Set<String> protocols = new HashSet<>();
519 protocols.add(OvsdbConstant.OPENFLOW13);
520 bridge.setProtocols(protocols);
522 String ovsUuid = getOvsUuid(OvsdbConstant.DATABASENAME);
523 if (ovsUuid == null) {
524 log.warn("The Open_vSwitch is null");
528 String bridgeUuid = getBridgeUuid(bridgeName);
529 if (bridgeUuid == null) {
530 log.debug("Create a new bridge");
532 bridge.setName(bridgeName);
534 Map<String, String> options = new HashMap<>();
535 options.put("datapath-id", dpid);
536 bridge.setOtherConfig(options);
538 bridgeUuid = insertConfig(OvsdbConstant.BRIDGE, "_uuid",
539 OvsdbConstant.DATABASENAME, "bridges",
540 ovsUuid, bridge.getRow());
542 if (bridgeUuid != null) {
543 Port port = (Port) TableGenerator.createTable(dbSchema,
546 log.debug("the port is not null");
547 port.setName(bridgeName);
549 insertConfig(OvsdbConstant.PORT, "_uuid", "Bridge", "ports", bridgeUuid,
553 String message = BridgeCreateException.createMessage(ovsUuid);
554 throw new BridgeCreateException(message);
558 log.info("Update a bridge");
559 updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid, bridge.getRow());
561 // Create external port
562 if (exPortName != null) {
563 createPort(bridgeName, exPortName);
566 setControllerAuto(bridgeUuid);
567 log.info("Create bridge success");
571 public boolean createBridge(String bridgeName, String dpid, List<ControllerInfo> controllers) {
573 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
574 String ovsUuid = getOvsUuid(OvsdbConstant.DATABASENAME);
576 if (dbSchema == null || ovsUuid == null) {
577 log.warn("Couldn't find database Open_vSwitch");
581 String bridgeUuid = getBridgeUuid(bridgeName);
582 if (bridgeUuid != null) {
583 log.warn("Bridge {} is already exist", bridgeName);
584 // remove existing one and re-create?
588 Bridge bridge = (Bridge) TableGenerator.createTable(dbSchema, OvsdbTable.BRIDGE);
589 bridge.setName(bridgeName);
591 Set<String> failMode = new HashSet<>(Arrays.asList("secure"));
592 bridge.setFailMode(failMode);
594 Set<String> protocols = new HashSet<>(Arrays.asList(OvsdbConstant.OPENFLOW13));
595 bridge.setProtocols(protocols);
597 Map<String, String> options = new HashMap<>();
598 options.put("datapath-id", dpid);
599 bridge.setOtherConfig(options);
601 bridgeUuid = insertConfig(OvsdbConstant.BRIDGE, "_uuid",
602 OvsdbConstant.DATABASENAME, "bridges",
603 ovsUuid, bridge.getRow());
605 if (bridgeUuid != null) {
606 createPort(bridgeName, bridgeName);
608 log.warn("Failed to create bridge {} on {}", bridgeName, nodeId.toString());
612 setControllersWithUUID(UUID.uuid(bridgeUuid), controllers);
617 * Sets the bridge's controller automatically.
619 * The connection is a TCP connection to the local ONOS instance's IP
620 * and the default OpenFlow port.
622 * @param bridgeUuid bridge uuid
624 private void setControllerAuto(String bridgeUuid) {
625 IpAddress ipAddress = IpAddress.valueOf(((InetSocketAddress) channel.localAddress()).getAddress());
626 ControllerInfo controllerInfo = new ControllerInfo(ipAddress, OvsdbConstant.OFPORT, "tcp");
627 log.debug("Automatically setting controller for bridge {} to {}",
628 bridgeUuid, controllerInfo.target());
629 setControllersWithUUID(UUID.uuid(bridgeUuid), ImmutableList.of(controllerInfo));
633 public void setControllersWithUUID(UUID bridgeUuid, List<ControllerInfo> controllers) {
635 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
636 if (dbSchema == null) {
637 log.debug("There is no schema");
640 List<Controller> oldControllers = getControllers(bridgeUuid);
641 if (oldControllers == null) {
642 log.warn("There are no controllers");
646 Set<UUID> newControllerUuids = new HashSet<>();
648 Set<ControllerInfo> newControllers = new HashSet<>(controllers);
649 List<Controller> removeControllers = new ArrayList<>();
650 oldControllers.forEach(controller -> {
651 ControllerInfo controllerInfo = new ControllerInfo((String) controller.getTargetColumn().data());
652 if (newControllers.contains(controllerInfo)) {
653 newControllers.remove(controllerInfo);
654 newControllerUuids.add(controller.getRow().uuid());
656 removeControllers.add(controller);
659 OvsdbRowStore controllerRowStore = getRowStore(OvsdbConstant.DATABASENAME,
660 OvsdbConstant.CONTROLLER);
661 if (controllerRowStore == null) {
662 log.debug("There is no controller table");
666 removeControllers.forEach(c -> deleteConfig(OvsdbConstant.CONTROLLER, "_uuid", c.getRow().uuid().value(),
667 OvsdbConstant.BRIDGE, "controller"));
669 newControllers.stream().map(c -> {
670 Controller controller = (Controller) TableGenerator
671 .createTable(dbSchema, OvsdbTable.CONTROLLER);
672 controller.setTarget(c.target());
675 String uuid = insertConfig(OvsdbConstant.CONTROLLER, "_uuid",
676 OvsdbConstant.BRIDGE, "controller", bridgeUuid.value(),
678 newControllerUuids.add(UUID.uuid(uuid));
682 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
683 OvsdbConstant.BRIDGE);
684 if (rowStore == null) {
685 log.debug("There is no bridge table");
689 Row bridgeRow = rowStore.getRow(bridgeUuid.value());
690 Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
691 bridge.setController(OvsdbSet.ovsdbSet(newControllerUuids));
692 updateConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUuid.value(), bridge.getRow());
696 public void setControllersWithDeviceId(DeviceId deviceId, List<ControllerInfo> controllers) {
697 setControllersWithUUID(getBridgeUUID(deviceId), controllers);
701 public void dropBridge(String bridgeName) {
702 String bridgeUUID = getBridgeUuid(bridgeName);
703 if (bridgeUUID == null) {
704 log.warn("Could not find bridge in node", nodeId.getIpAddress());
707 deleteConfig(OvsdbConstant.BRIDGE, "_uuid", bridgeUUID,
708 OvsdbConstant.DATABASENAME, "bridges");
712 public void createTunnel(IpAddress srcIp, IpAddress dstIp) {
713 String bridgeUuid = getBridgeUuid(OvsdbConstant.INTEGRATION_BRIDGE);
714 if (bridgeUuid == null) {
715 log.warn("Could not find bridge {} and Could not create tunnel. ",
716 OvsdbConstant.INTEGRATION_BRIDGE);
720 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
721 String portName = getTunnelName(OvsdbConstant.TYPEVXLAN, dstIp);
722 String portUuid = getPortUuid(portName, bridgeUuid);
724 Port port = (Port) TableGenerator
725 .createTable(dbSchema, OvsdbTable.PORT);
727 port.setName(portName);
730 if (portUuid == null) {
731 portUuid = insertConfig(OvsdbConstant.PORT, "_uuid", OvsdbConstant.BRIDGE,
732 "ports", bridgeUuid, port.getRow());
734 updateConfig(OvsdbConstant.PORT, "_uuid", portUuid, port.getRow());
737 // When a tunnel is created, A row is inserted into port table and
738 // interface table of the ovsdb node.
739 // and the following step is to get the interface uuid from local store
740 // in controller node.
741 // but it need spend some time synchronising data between node and
743 // so loop to judge if interfaceUUid is null is necessary.
744 String interfaceUuid = null;
745 for (int i = 0; i < 10; i++) {
746 interfaceUuid = getInterfaceUuid(portUuid, portName);
747 if (interfaceUuid == null) {
750 } catch (InterruptedException e) {
751 log.warn("Interrupted while waiting to get interfaceUuid");
752 Thread.currentThread().interrupt();
759 if (interfaceUuid != null) {
761 Interface tunInterface = (Interface) TableGenerator
762 .createTable(dbSchema, OvsdbTable.INTERFACE);
764 if (tunInterface != null) {
766 tunInterface.setType(OvsdbConstant.TYPEVXLAN);
767 Map<String, String> options = Maps.newHashMap();
768 options.put("key", "flow");
769 options.put("local_ip", srcIp.toString());
770 options.put("remote_ip", dstIp.toString());
771 tunInterface.setOptions(options);
772 updateConfig(OvsdbConstant.INTERFACE, "_uuid", interfaceUuid,
773 tunInterface.getRow());
774 log.info("Tunnel added success", tunInterface);
783 public boolean createTunnel(String bridgeName, String portName, String tunnelType, Map<String, String> options) {
785 String bridgeUuid = getBridgeUuid(bridgeName);
786 if (bridgeUuid == null) {
787 log.warn("Couldn't find bridge {} in {}", bridgeName, nodeId.getIpAddress());
791 if (getPortUuid(portName, bridgeUuid) != null) {
792 log.warn("Port {} already exists", portName);
793 // remove existing one and re-create?
797 ArrayList<Operation> operations = Lists.newArrayList();
798 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
800 // insert a new port to the port table
801 Port port = (Port) TableGenerator.createTable(dbSchema, OvsdbTable.PORT);
802 port.setName(portName);
803 Insert portInsert = new Insert(dbSchema.getTableSchema("Port"), "Port", port.getRow());
804 portInsert.getRow().put("interfaces", UUID.uuid("Interface"));
805 operations.add(portInsert);
807 // update the bridge table
808 Condition condition = ConditionUtil.equals("_uuid", UUID.uuid(bridgeUuid));
809 Mutation mutation = MutationUtil.insert("ports", UUID.uuid("Port"));
810 List<Condition> conditions = new ArrayList<>(Arrays.asList(condition));
811 List<Mutation> mutations = new ArrayList<>(Arrays.asList(mutation));
812 operations.add(new Mutate(dbSchema.getTableSchema("Bridge"), conditions, mutations));
814 // insert a tunnel interface
815 Interface intf = (Interface) TableGenerator.createTable(dbSchema, OvsdbTable.INTERFACE);
816 intf.setName(portName);
817 intf.setType(tunnelType);
818 intf.setOptions(options);
819 Insert intfInsert = new Insert(dbSchema.getTableSchema("Interface"), "Interface", intf.getRow());
820 operations.add(intfInsert);
822 transactConfig(OvsdbConstant.DATABASENAME, operations);
827 public void dropTunnel(IpAddress srcIp, IpAddress dstIp) {
828 String bridgeName = OvsdbConstant.INTEGRATION_BRIDGE;
829 String portName = getTunnelName(OvsdbConstant.TYPEVXLAN, dstIp);
830 String bridgeUuid = getBridgeUuid(OvsdbConstant.INTEGRATION_BRIDGE);
831 if (bridgeUuid == null) {
832 log.warn("Could not find bridge {} in {}", bridgeName,
833 nodeId.getIpAddress());
837 String portUUID = getPortUuid(portName, bridgeUuid);
838 if (portUUID != null) {
839 log.info("Delete tunnel");
840 deleteConfig(OvsdbConstant.PORT, "_uuid", portUUID,
841 OvsdbConstant.BRIDGE, "ports");
848 * Delete transact config.
850 * @param childTableName child table name
851 * @param childColumnName child column name
852 * @param childUuid child row uuid
853 * @param parentTableName parent table name
854 * @param parentColumnName parent column
856 private void deleteConfig(String childTableName, String childColumnName,
857 String childUuid, String parentTableName,
858 String parentColumnName) {
859 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
860 TableSchema childTableSchema = dbSchema.getTableSchema(childTableName);
862 ArrayList<Operation> operations = Lists.newArrayList();
863 if (parentTableName != null && parentColumnName != null) {
864 TableSchema parentTableSchema = dbSchema
865 .getTableSchema(parentTableName);
866 ColumnSchema parentColumnSchema = parentTableSchema
867 .getColumnSchema(parentColumnName);
868 List<Mutation> mutations = Lists.newArrayList();
869 Mutation mutation = MutationUtil.delete(parentColumnSchema.name(),
870 UUID.uuid(childUuid));
871 mutations.add(mutation);
872 List<Condition> conditions = Lists.newArrayList();
873 Condition condition = ConditionUtil.includes(parentColumnName,
874 UUID.uuid(childUuid));
875 conditions.add(condition);
876 Mutate op = new Mutate(parentTableSchema, conditions, mutations);
880 List<Condition> conditions = Lists.newArrayList();
881 Condition condition = ConditionUtil.equals(childColumnName, UUID.uuid(childUuid));
882 conditions.add(condition);
883 Delete del = new Delete(childTableSchema, conditions);
885 transactConfig(OvsdbConstant.DATABASENAME, operations);
891 * Update transact config.
893 * @param tableName table name
894 * @param columnName column name
896 * @param row the config data
898 private void updateConfig(String tableName, String columnName, String uuid,
900 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
901 TableSchema tableSchema = dbSchema.getTableSchema(tableName);
903 List<Condition> conditions = Lists.newArrayList();
904 Condition condition = ConditionUtil.equals(columnName, UUID.uuid(uuid));
905 conditions.add(condition);
907 Update update = new Update(tableSchema, row, conditions);
909 ArrayList<Operation> operations = Lists.newArrayList();
910 operations.add(update);
912 transactConfig(OvsdbConstant.DATABASENAME, operations);
916 * Insert transact config.
918 * @param childTableName child table name
919 * @param childColumnName child column name
920 * @param parentTableName parent table name
921 * @param parentColumnName parent column
922 * @param parentUuid parent uuid
923 * @param row the config data
924 * @return uuid, empty if no uuid is find
926 private String insertConfig(String childTableName, String childColumnName,
927 String parentTableName, String parentColumnName,
928 String parentUuid, Row row) {
929 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
930 TableSchema tableSchema = dbSchema.getTableSchema(childTableName);
932 String namedUuid = childTableName;
933 Insert insert = new Insert(tableSchema, namedUuid, row);
935 ArrayList<Operation> operations = Lists.newArrayList();
936 operations.add(insert);
938 if (parentTableName != null && parentColumnName != null) {
939 TableSchema parentTableSchema = dbSchema
940 .getTableSchema(parentTableName);
941 ColumnSchema parentColumnSchema = parentTableSchema
942 .getColumnSchema(parentColumnName);
944 List<Mutation> mutations = Lists.newArrayList();
945 Mutation mutation = MutationUtil.insert(parentColumnSchema.name(),
946 UUID.uuid(namedUuid));
947 mutations.add(mutation);
949 List<Condition> conditions = Lists.newArrayList();
950 Condition condition = ConditionUtil.equals("_uuid",
951 UUID.uuid(parentUuid));
952 conditions.add(condition);
954 Mutate op = new Mutate(parentTableSchema, conditions, mutations);
957 if (childTableName.equalsIgnoreCase(OvsdbConstant.PORT)) {
958 log.info("Handle port insert");
959 Insert intfInsert = handlePortInsertTable(OvsdbConstant.INTERFACE,
962 if (intfInsert != null) {
963 operations.add(intfInsert);
966 Insert ins = (Insert) operations.get(0);
967 ins.getRow().put("interfaces",
968 UUID.uuid(OvsdbConstant.INTERFACE));
971 List<OperationResult> results;
973 results = transactConfig(OvsdbConstant.DATABASENAME, operations)
976 return results.get(0).getUuid().value();
977 } catch (InterruptedException e) {
978 log.warn("Interrupted while waiting to get result");
979 Thread.currentThread().interrupt();
980 } catch (ExecutionException e) {
981 log.error("Exception thrown while to get result");
988 * Handles port insert.
990 * @param tableName ovsdb table interface
991 * @param portRow row of port
992 * @return insert, empty if null
994 private Insert handlePortInsertTable(String tableName, Row portRow) {
995 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
997 TableSchema portTableSchema = dbSchema
998 .getTableSchema(OvsdbConstant.PORT);
999 ColumnSchema portColumnSchema = portTableSchema.getColumnSchema("name");
1001 String portName = (String) portRow.getColumn(portColumnSchema.name()).data();
1003 Interface inf = (Interface) TableGenerator
1004 .createTable(dbSchema, OvsdbTable.INTERFACE);
1006 inf.setName(portName);
1008 TableSchema intfTableSchema = dbSchema
1009 .getTableSchema(OvsdbConstant.INTERFACE);
1010 Insert insert = new Insert(intfTableSchema, OvsdbConstant.INTERFACE,
1019 * @param dstIp the remote ip address
1020 * @return tunnel name
1022 private String getTunnelName(String tunnelType, IpAddress dstIp) {
1023 return tunnelType + "-" + dstIp.toString();
1027 public ListenableFuture<DatabaseSchema> getOvsdbSchema(String dbName) {
1028 if (dbName == null) {
1031 DatabaseSchema databaseSchema = schema.get(dbName);
1032 if (databaseSchema == null) {
1033 List<String> dbNames = new ArrayList<String>();
1034 dbNames.add(dbName);
1035 Function<JsonNode, DatabaseSchema> rowFunction = new Function<JsonNode, DatabaseSchema>() {
1037 public DatabaseSchema apply(JsonNode input) {
1038 log.info("Get ovsdb database schema {}", dbName);
1039 DatabaseSchema dbSchema = FromJsonUtil
1040 .jsonNodeToDbSchema(dbName, input);
1041 if (dbSchema == null) {
1042 log.debug("Get ovsdb database schema error");
1045 schema.put(dbName, dbSchema);
1051 ListenableFuture<JsonNode> input = getSchema(dbNames);
1052 if (input != null) {
1053 return Futures.transform(input, rowFunction);
1057 return Futures.immediateFuture(databaseSchema);
1062 public ListenableFuture<TableUpdates> monitorTables(String dbName, String id) {
1063 if (dbName == null) {
1066 DatabaseSchema dbSchema = schema.get(dbName);
1067 if (dbSchema != null) {
1068 Function<JsonNode, TableUpdates> rowFunction = new Function<JsonNode, TableUpdates>() {
1070 public TableUpdates apply(JsonNode input) {
1071 log.info("Get table updates");
1072 TableUpdates updates = FromJsonUtil
1073 .jsonNodeToTableUpdates(input, dbSchema);
1074 if (updates == null) {
1075 log.debug("Get table updates error");
1081 return Futures.transform(monitor(dbSchema, id), rowFunction);
1087 public ListenableFuture<List<OperationResult>> transactConfig(String dbName,
1088 List<Operation> operations) {
1089 if (dbName == null) {
1092 DatabaseSchema dbSchema = schema.get(dbName);
1093 if (dbSchema != null) {
1094 Function<List<JsonNode>, List<OperationResult>> rowFunction = (input -> {
1095 log.info("Get ovsdb operation result");
1096 List<OperationResult> result = FromJsonUtil
1097 .jsonNodeToOperationResult(input, operations);
1099 if (result == null) {
1100 log.debug("The operation result is null");
1105 return Futures.transform(transact(dbSchema, operations),
1112 public ListenableFuture<JsonNode> getSchema(List<String> dbnames) {
1113 String id = java.util.UUID.randomUUID().toString();
1114 String getSchemaString = JsonRpcWriterUtil.getSchemaStr(id, dbnames);
1116 SettableFuture<JsonNode> sf = SettableFuture.create();
1117 requestResult.put(id, sf);
1118 requestMethod.put(id, "getSchema");
1120 channel.writeAndFlush(getSchemaString);
1126 public ListenableFuture<List<String>> echo() {
1127 String id = java.util.UUID.randomUUID().toString();
1128 String echoString = JsonRpcWriterUtil.echoStr(id);
1130 SettableFuture<List<String>> sf = SettableFuture.create();
1131 requestResult.put(id, sf);
1132 requestMethod.put(id, "echo");
1134 channel.writeAndFlush(echoString);
1140 public ListenableFuture<JsonNode> monitor(DatabaseSchema dbSchema,
1142 String id = java.util.UUID.randomUUID().toString();
1143 String monitorString = JsonRpcWriterUtil.monitorStr(id, monitorId,
1146 SettableFuture<JsonNode> sf = SettableFuture.create();
1147 requestResult.put(id, sf);
1148 requestMethod.put(id, "monitor");
1150 channel.writeAndFlush(monitorString);
1156 public ListenableFuture<List<String>> listDbs() {
1157 String id = java.util.UUID.randomUUID().toString();
1158 String listDbsString = JsonRpcWriterUtil.listDbsStr(id);
1160 SettableFuture<List<String>> sf = SettableFuture.create();
1161 requestResult.put(id, sf);
1162 requestMethod.put(id, "listDbs");
1164 channel.writeAndFlush(listDbsString);
1170 public ListenableFuture<List<JsonNode>> transact(DatabaseSchema dbSchema,
1171 List<Operation> operations) {
1172 String id = java.util.UUID.randomUUID().toString();
1173 String transactString = JsonRpcWriterUtil.transactStr(id, dbSchema,
1176 SettableFuture<List<JsonNode>> sf = SettableFuture.create();
1177 requestResult.put(id, sf);
1178 requestMethod.put(id, "transact");
1180 channel.writeAndFlush(transactString);
1185 @SuppressWarnings({"rawtypes", "unchecked"})
1187 public void processResult(JsonNode response) {
1188 log.debug("Handle result");
1189 String requestId = response.get("id").asText();
1190 SettableFuture sf = requestResult.get(requestId);
1192 log.debug("No such future to process");
1195 String methodName = requestMethod.get(requestId);
1198 result = FromJsonUtil.jsonResultParser(response, methodName);
1205 public void processRequest(JsonNode requestJson) {
1206 log.debug("Handle request");
1207 if (requestJson.get("method").asText().equalsIgnoreCase("echo")) {
1208 log.debug("handle echo request");
1210 String replyString = FromJsonUtil.getEchoRequestStr(requestJson);
1211 channel.writeAndFlush(replyString);
1216 .jsonCallbackRequestParser(requestJson, monitorCallBack);
1222 public void setCallback(Callback monitorCallback) {
1223 this.monitorCallBack = monitorCallback;
1227 public Set<OvsdbTunnel> getTunnels() {
1228 return ovsdbTunnels;
1232 public Set<OvsdbBridge> getBridges() {
1233 Set<OvsdbBridge> ovsdbBridges = new HashSet<OvsdbBridge>();
1234 OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1235 if (tableStore == null) {
1238 OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.BRIDGE);
1239 if (rowStore == null) {
1242 ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1243 for (String uuid : rows.keySet()) {
1244 Row row = getRow(OvsdbConstant.DATABASENAME, OvsdbConstant.BRIDGE,
1246 OvsdbBridge ovsdbBridge = getOvsdbBridge(row);
1247 if (ovsdbBridge != null) {
1248 ovsdbBridges.add(ovsdbBridge);
1251 return ovsdbBridges;
1255 public Set<ControllerInfo> getControllers(DeviceId openflowDeviceId) {
1256 UUID bridgeUuid = getBridgeUUID(openflowDeviceId);
1257 if (bridgeUuid == null) {
1258 log.warn("bad bridge Uuid");
1261 List<Controller> controllers = getControllers(bridgeUuid);
1262 if (controllers == null) {
1263 log.warn("bad list of controllers");
1266 return controllers.stream().
1267 map(controller -> new ControllerInfo(
1268 (String) controller.getTargetColumn()
1269 .data())).collect(Collectors.toSet());
1272 private List<Controller> getControllers(UUID bridgeUuid) {
1273 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
1274 if (dbSchema == null) {
1277 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
1278 OvsdbConstant.BRIDGE);
1279 if (rowStore == null) {
1280 log.debug("There is no bridge table");
1284 Row bridgeRow = rowStore.getRow(bridgeUuid.value());
1285 Bridge bridge = (Bridge) TableGenerator.
1286 getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
1289 log.warn("type of controller column", bridge.getControllerColumn()
1290 .data().getClass());
1291 Set<UUID> controllerUuids = (Set<UUID>) ((OvsdbSet) bridge
1292 .getControllerColumn().data()).set();
1293 // Set<String> controllerUuidStrings = (Set<String>) bridge.getControllerColumn().data();
1295 OvsdbRowStore controllerRowStore = getRowStore(OvsdbConstant.DATABASENAME,
1296 OvsdbConstant.CONTROLLER);
1297 if (controllerRowStore == null) {
1298 log.debug("There is no controller table");
1302 List<Controller> ovsdbControllers = new ArrayList<>();
1303 ConcurrentMap<String, Row> controllerTableRows = controllerRowStore.getRowStore();
1304 controllerTableRows.forEach((key, row) -> {
1305 if (!controllerUuids.contains(UUID.uuid(key))) {
1308 Controller controller = (Controller) TableGenerator
1309 .getTable(dbSchema, row, OvsdbTable.CONTROLLER);
1310 ovsdbControllers.add(controller);
1312 return ovsdbControllers;
1316 private UUID getBridgeUUID(DeviceId openflowDeviceId) {
1317 DatabaseSchema dbSchema = schema.get(OvsdbConstant.DATABASENAME);
1318 if (dbSchema == null) {
1321 OvsdbRowStore rowStore = getRowStore(OvsdbConstant.DATABASENAME,
1322 OvsdbConstant.BRIDGE);
1323 if (rowStore == null) {
1324 log.debug("There is no bridge table");
1328 ConcurrentMap<String, Row> bridgeTableRows = rowStore.getRowStore();
1329 final AtomicReference<UUID> uuid = new AtomicReference<>();
1330 for (Map.Entry<String, Row> entry : bridgeTableRows.entrySet()) {
1331 Bridge b = (Bridge) TableGenerator.getTable(dbSchema,
1334 if (matchesDpid(b, openflowDeviceId)) {
1335 uuid.set(UUID.uuid(entry.getKey()));
1339 if (uuid.get() == null) {
1340 log.debug("There is no bridge for {}", openflowDeviceId);
1346 private static boolean matchesDpid(Bridge b, DeviceId deviceId) {
1347 String ofDpid = deviceId.toString().replace("of:", "");
1348 Set ofDeviceIds = ((OvsdbSet) b.getDatapathIdColumn().data()).set();
1350 return ofDeviceIds.contains(ofDpid);
1354 public Set<OvsdbPort> getPorts() {
1355 Set<OvsdbPort> ovsdbPorts = new HashSet<OvsdbPort>();
1356 OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1357 if (tableStore == null) {
1360 OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.INTERFACE);
1361 if (rowStore == null) {
1364 ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1365 for (String uuid : rows.keySet()) {
1366 Row row = getRow(OvsdbConstant.DATABASENAME,
1367 OvsdbConstant.INTERFACE, uuid);
1368 OvsdbPort ovsdbPort = getOvsdbPort(row);
1369 if (ovsdbPort != null) {
1370 ovsdbPorts.add(ovsdbPort);
1377 public DatabaseSchema getDatabaseSchema(String dbName) {
1378 return schema.get(dbName);
1382 private OvsdbPort getOvsdbPort(Row row) {
1383 DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1384 Interface intf = (Interface) TableGenerator
1385 .getTable(dbSchema, row, OvsdbTable.INTERFACE);
1389 long ofPort = getOfPort(intf);
1390 String portName = intf.getName();
1391 if ((ofPort < 0) || (portName == null)) {
1395 OvsdbPort ovsdbPort = new OvsdbPort(new OvsdbPortNumber(ofPort),
1396 new OvsdbPortName(portName));
1400 ////Gets ovsdb bridge.
1401 private OvsdbBridge getOvsdbBridge(Row row) {
1402 DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1403 Bridge bridge = (Bridge) TableGenerator.getTable(dbSchema, row,
1405 if (bridge == null) {
1409 OvsdbSet datapathIdSet = (OvsdbSet) bridge.getDatapathIdColumn().data();
1410 @SuppressWarnings("unchecked")
1411 Set<String> datapathIds = datapathIdSet.set();
1412 if (datapathIds == null || datapathIds.size() == 0) {
1415 String datapathId = (String) datapathIds.toArray()[0];
1416 String bridgeName = bridge.getName();
1417 if ((datapathId == null) || (bridgeName == null)) {
1421 OvsdbBridge ovsdbBridge = new OvsdbBridge(new OvsdbBridgeName(bridgeName),
1422 new OvsdbDatapathId(datapathId));
1426 //Gets ofPort in the interface.
1427 private long getOfPort(Interface intf) {
1428 OvsdbSet ofPortSet = (OvsdbSet) intf.getOpenFlowPortColumn().data();
1429 @SuppressWarnings("unchecked")
1430 Set<Integer> ofPorts = ofPortSet.set();
1431 while (ofPorts == null || ofPorts.size() <= 0) {
1432 log.debug("The ofport is null in {}", intf.getName());
1435 // return (long) ofPorts.toArray()[0];
1436 Iterator<Integer> it = ofPorts.iterator();
1437 return Long.parseLong(it.next().toString());
1441 public Set<OvsdbPort> getLocalPorts(Iterable<String> ifaceids) {
1442 Set<OvsdbPort> ovsdbPorts = new HashSet<OvsdbPort>();
1443 OvsdbTableStore tableStore = getTableStore(OvsdbConstant.DATABASENAME);
1444 if (tableStore == null) {
1447 OvsdbRowStore rowStore = tableStore.getRows(OvsdbConstant.INTERFACE);
1448 if (rowStore == null) {
1451 ConcurrentMap<String, Row> rows = rowStore.getRowStore();
1452 for (String uuid : rows.keySet()) {
1453 Row row = getRow(OvsdbConstant.DATABASENAME,
1454 OvsdbConstant.INTERFACE, uuid);
1455 DatabaseSchema dbSchema = getDatabaseSchema(OvsdbConstant.DATABASENAME);
1456 Interface intf = (Interface) TableGenerator
1457 .getTable(dbSchema, row, OvsdbTable.INTERFACE);
1458 if (intf == null || getIfaceid(intf) == null) {
1461 String portName = intf.getName();
1462 Set<String> ifaceidSet = Sets.newHashSet(ifaceids);
1463 if (portName.startsWith("vxlan")
1464 || !ifaceidSet.contains(getIfaceid(intf))) {
1467 long ofPort = getOfPort(intf);
1468 if ((ofPort < 0) || (portName == null)) {
1472 OvsdbPort ovsdbPort = new OvsdbPort(new OvsdbPortNumber(ofPort),
1473 new OvsdbPortName(portName));
1474 if (ovsdbPort != null) {
1475 ovsdbPorts.add(ovsdbPort);
1481 private String getIfaceid(Interface intf) {
1482 OvsdbMap ovsdbMap = (OvsdbMap) intf.getExternalIdsColumn().data();
1483 @SuppressWarnings("unchecked")
1484 Map<String, String> externalIds = ovsdbMap.map();
1485 if (externalIds.isEmpty()) {
1486 log.warn("The external_ids is null");
1489 String ifaceid = externalIds
1490 .get(OvsdbConstant.EXTERNAL_ID_INTERFACE_ID);
1491 if (ifaceid == null) {
1492 log.warn("The ifaceid is null");
1499 public void disconnect() {
1500 channel.disconnect();
1501 this.agent.removeConnectedNode(nodeId);