In my previous post, I briefly introduced the OVSDB Management Protocol in the process of talking about hardware VTEPs. In this post, I will focus on specific OVSDB Server features. And to do that, I will (mis)use it outside of SDN.
Huh??? But OVSDB == SDN!
Actually, no. OVSDB can exist independent of Open vSwitch. In fact, what’s actually happening under the covers is that Open vSwitch connects to OVSDB and monitors certain tables in the Open_vSwitch database for updates. When OVS receives update notifications from OVSDB, the former then gets to work creating and manipulating bridges, ports, etc.
Alright, so OVSDB is a Management Protocol!
Actually, no. OVSDB does not do anything to the host system. All it does is receive messages relating to data it has and responds accordingly. If anything needs to be done on the host system, that will be the job of external clients connecting to and monitoring tables inside OVSDB.
So…OVSDB is just a database engine?
Bingo! And here are its features:
- Native JSON RPC v1 support. In fact, this is the only way you can talk to it;
- Persistent plain TCP socket connections. No HTTP overhead. You can optionally wrap your connections with SSL/TLS for super secret message sending;
- Journaled in-memory datastore;
- Atomic transactions;
- Relational data with automatic garbage collection of orphaned rows;
- And more!
Hands-on Part 1: Using OVSDB as a To Do List database
I hope I got you intrigued about OVSDB’s features. Let’s dive deeper by creating our own database using the ovsdb-client CLI tool. The first database we will create is a To Do List database. But before everything else, let’s reload ovs-lab to a known good state.
Once reloading is done, let’s ssh to each of the servers on different
terminals via vagrant ssh server1
, vagrant ssh internet
, and
vagrant ssh server2
. Next, inside of server1
, let’s login as root
and ensure that Open vSwitch and OVSDB are not running:
Next, we’ll create a new database using a schema definition file that
I’ve included in the lesson03 directory named todo.ovsschema
:
Let’s take a moment to read the schema definition we just loaded. I’ll focus on the part of the schema definition that talks about the tables.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{
"name": "todo",
"version": "1.0.0",
"tables": {
"List": {
"columns": {
"name": {
"type": "string"
},
"items": {
"type": {
"key": {
"type": "uuid",
"refTable": "Item"
},
"min": 0,
"max": "unlimited"
}
}
},
"isRoot": true,
"indexes": [
[
"name"
]
]
},
"Item": {
"columns": {
"status": {
"type": "string"
},
"description": {
"type": "string"
}
}
}
}
}
In lines 2 and 23 are the names of our two tables, List and Item. The List table has two columns: name, and items. The name column is easy to read: it’s just a string datatype. The items column, on the other hand, is more involved, but it basically is a set of references to the UUID column of the Item table and it can have 0 or more references.
Yes, you read that right. In traditional database schemas, the child table references the parent table. In OVSDB, it’s the other way around and this primarily (probably exclusively) has something to do with its automatic garbage collection feature. Let me explain by pointing out the “isRoot” key in the schema (line 18). When a table’s isRoot key is set to true, that means that its records will never be garbage collected. However, if the isRoot key is false or not defined, then any record in that table that is not referenced by any other records in other tables will be automatically garbage collected. This feature is very crucial for environments like networking where communication between devices (e.g. OVS and controller) must be as efficient as possible.
We’ll see that in action shortly. First, let’s continue by starting OVSDB and loading our newly created database:
Let’s check that our database was loaded properly:
If that command didn’t print todo
then you probably missed a step.
Go back and review the steps. If you have it working properly, let’s
proceed by having OVSDB listening for connections on port 6640.
SIDENOTE: The
p
inptcp
means passive. You can alternatively make OVSDB accept only SSL/TLS-based connections by usingpssl
. Seeman ovsdb-server
for more info on that.
Alright, we’ve now set up our To Do List database. If at any point after
this you need to reset the state of the database, just execute
/vagrant/shared/lesson03/reset_todo_db.sh
while logged in as root
in server1
:
Let’s log in to server2
and monitor the List table in server1
for
changes:
That command should not return anything since it’s just waiting for
the OVSDB server in server1
to send update notifications. So let’s
login to internet
and add a row on the List table:
In the above command, we used the ovsdb-client
CLI tool to execute a
transaction against the OVSDB server in server1
. The last argument of
the command specifies the parameters of that transaction. In the first element
of that array, we say that we are performing the transaction against
our todo
database. The second element is our one and only operation
which happens to be an insert on the List table with a row named
List1
. After the transaction has completed, OVSDB responds with the
UUID of our newly created row.
Shifting back to our server2
terminal, we can see that OVSDB sent us
an update notification:
Neat! Now let’s try creating Item rows. Ctrl-C
in server2
and issue
the command below to start monitoring the Item
table.
Head back to internet
and execute the following command:
Shift back to server2
and you will see…nothing. Why??? Remember our
.ovsschema
file above? We specified that the Item table is not a root
table. Therefore, any row we create there that’s not referenced by a List
row is automatically garbage collected. In the above command, as soon as
OVSDB created the row, it was immediately deleted so OVSDB didn’t bother
sending an update notification to server2
. We can double check by running
the select method against the Item table back in internet
:
Cool. Garbage collection works. Now let’s try and create an Item that
won’t be garbage collected. Head back to internet
and execute the
following transaction against server1
:
There’s a lot more going on above so let’s pretty-fy the last argument:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[
"todo",
{
"op": "insert",
"table": "Item",
"row": {
"description": "Sample Item1",
"status": "new"
},
"uuid-name": "newitem"
},
{
"op": "insert",
"table": "List",
"row": {
"name": "List2",
"items": [
"set",
[
["named-uuid", "newitem"]
]
]
}
}
]
- In line 2, we can see that this transaction is still for the
todo
database - Lines 3 to 11 is our first operation and it inserts a new row in the Item table
- Line 10 is something new and is useful if you want to reference the UUID of new Item in a subsequent operation within the same transaction. You’ll see this being used in the next operation.
- Lines 12 to 24 is our second operation and it inserts a new row in the List table. To reference the item we created in the previous operation, we make use of its uuid-name.
NOTE: The uuid-name is temporary and is only valid within the transaction. If you ever want to reference the row after the transaction has completed, you can A) capture the UUID provided in OVSDB’s response or B) run a select against the table and capture the UUID from that response.
Head back to server2
to see the following update:
Let’s add one more Item to List2:
Let’s look at the transaction parameters more closely:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[
"todo",
{
"op": "insert",
"table": "Item",
"row": {
"description": "Sample Item2",
"status": "new"
},
"uuid-name": "anotheritem"
},
{
"op": "mutate",
"table": "List",
"where": [
["name", "==", "List2"]
],
"mutations": [
[
"items",
"insert",
[
"set",
[
["named-uuid", "anotheritem"]
]
]
]
]
}
]
- As with the previous transaction, this one operates on the
todo
database. - Lines 3 to 10 is just another insert operation on the Item table. Notice that we gave it a uuid-name of anotheritem.
- Lines 12 to 30 is a mutate operation on the List table, specifically on our List2 row. This operation is useful for manipulating columns of type set or map where we want to add or remove references to other tables. In this case, we are inserting the newly created Item’s UUID.
Let’s check how our todo database looks like by using the dump command
You should have two Item rows and two List rows with List2 referencing both Item rows.
Hands-on Part 2: Using OVSDB as a Chat database
Here’s something a little bit more fun. I’ve created two python scripts that use OVSDB as a chat room. It’s a very limited implementation in that one script can only send a message and the other can only receive them but it should be enough to further showcase some of OVSDB’s features.
Go to server1
and execute the following:
You’ve just reset OVSDB and made it load a different database called chat
.
Start tailing its logs. The reset script above set the loglevel to debug
so that you can see the messages passing between OVSDB and its clients.
Now go to internet
and execute the receiver script:
You should see OVSDB sends pings regularly and the receiver responding with a pong. This is OVSDB’s inactivity probe sequence and is its way of checking if the remote client is still connected. If our receiver did not reply back in time, OVSDB promptly closes the socket.
Next, let’s go to server2
and run the sender script:
Type a message and hit ENTER to see your message pop up on the receiver terminal. Also check the OVSDB logs to see your message being received and passed on to the receiver.
Feel free to poke around the code to understand how the scripts talk to OVSDB! If you want to learn some more about the various other methods that you can call against it, please consult IETF RFC 7047
Hands-on Part 3: Open vStamps Database
Finally, we can’t end this post without referencing this tweet:
@colinmcnamara @virtualswede @scott_lowe @mcowger OVSDB is a database. You can use it to configure a switch or track your stamp collection.
— Ben Pfaff (@Ben_Pfaff) April 8, 2014
So let’s track our stamp collection! First, do the following:
You’ve just reset OVSDB in server1
and turned it into a pre-seeded stamp
collection database! Look at the script for more information. When you’re
done with that, let’s prepare to turn server1
into a web server by doing
the following:
Then, let’s execute our web app:
In your local machine, browse on over to the above IP and port. Enjoy!
Parting Thoughts
OVSDB is a very interesting and versatile tool with potential applications independent of Open_vSwitch. In fact, in my previous post, we’ve seen that we can even use it as a front for hardware VTEPs. In this post, we’ve seen that it can even be applied to other things outside of SDN. Now, while I can’t vouch for its efficacy outside of SDN (since I have not really done any performance tests on it outside of SDN), I hope this post did its job of showing what you can do with the tool.
Also, this post talks about just a small fraction of what OVSDB can do. To learn more about the other methods available, please see IETF RFC 7047.
That’s it for now. Feel free to ask questions below!