summaryrefslogtreecommitdiff
path: root/tests/ovsdb-monitor.at
diff options
context:
space:
mode:
authorHan Zhou <hzhou8@ebay.com>2019-02-11 18:19:21 -0800
committerBen Pfaff <blp@ovn.org>2019-02-14 11:28:14 -0800
commite0f42d4a6548dc596ace9f33f633267ac36bf5a3 (patch)
treef05910b3076a8869945eb17c4934d745819d01ee /tests/ovsdb-monitor.at
parent5b5aa2d8a54c006b6c5239d04b7a751ca5ff5d44 (diff)
downloadopenvswitch-e0f42d4a6548dc596ace9f33f633267ac36bf5a3.tar.gz
monitor: Fix crash when monitor condition adds new columns.
The OVSDB conditional monitor implementation allows many clients to share same copy of monitored data if the clients are sharing same tables and columns being monitored, while they can have different monitor conditions. In monitor conditions they can have different columns which can be different from the columns being monitored. So the struct ovsdb_monitor_table maintains the union of the all the columns being used in any conditions. The problem of the current implementation is that for each change set generated, it doesn't maintain any metadata for the number of columns for the data that has already populated in it. Instead, it always rely on the n_columns field of the struct ovsdb_monitor_table to manipulate the data. However, the n_columns in struct ovsdb_monitor_table can increase (e.g. when a client changes its condition which involves more columns). So it can result in that the existing rows in a change set with N columns being later processed as if it had more than N columns, typically, when the row is freed. This causes the ovsdb-server crashing (see an example of the backtrace). The patch fixes the problem by maintaining n_columns for each change set, and added a test case which fails without the fix. (gdb) bt at lib/ovsdb-data.c:1031 out>, mt=<optimized out>) at ovsdb/monitor.c:320 mt=0x1e7b940) at ovsdb/monitor.c:333 out>, transaction=<optimized out>) at ovsdb/monitor.c:527 initial=<optimized out>, cond_updated=cond_updated@entry=false, unflushed_=unflushed_@entry=0x20dae70, condition=<optimized out>, version=<optimized out>) at ovsdb/monitor.c:1156 (m=m@entry=0x20dae40, initial=initial@entry=false) at ovsdb/jsonrpc-server.c:1655 at ovsdb/jsonrpc-server.c:1729 ovsdb/jsonrpc-server.c:551 ovsdb/jsonrpc-server.c:586 ovsdb/jsonrpc-server.c:401 exiting=0x7ffdb947f76f, run_process=0x0, remotes=0x7ffdb947f7c0, unixctl=0x1e7a560, all_dbs=0x7ffdb947f800, jsonrpc=<optimized out>, config=0x7ffdb947f820) at ovsdb/ovsdb-server.c:209 Signed-off-by: Han Zhou <hzhou8@ebay.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'tests/ovsdb-monitor.at')
-rw-r--r--tests/ovsdb-monitor.at68
1 files changed, 68 insertions, 0 deletions
diff --git a/tests/ovsdb-monitor.at b/tests/ovsdb-monitor.at
index dca7cadc1..f6e21d087 100644
--- a/tests/ovsdb-monitor.at
+++ b/tests/ovsdb-monitor.at
@@ -589,3 +589,71 @@ row,action,name,number,_version
[[[["name","==","one"]]]],
[[[false]]],
[[[true]]]])
+
+
+AT_SETUP(monitor-cond-change with many sessions pending)
+AT_KEYWORDS([ovsdb server monitor monitor-cond negative])
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+
+AT_CAPTURE_FILE([ovsdb-server-log])
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket --log-file="`pwd`"/ovsdb-server-log db >/dev/null 2>&1])
+on_exit 'kill `cat ovsdb-server.pid`'
+for txn in m4_foreach([txn], [[[["ordinals",
+ {"op": "insert",
+ "table": "ordinals",
+ "row": {"number": 0, "name": "zero"}},
+ {"op": "insert",
+ "table": "ordinals",
+ "row": {"number": 1, "name": "one"}},
+ {"op": "insert",
+ "table": "ordinals",
+ "row": {"number": 2, "name": "two"}}]]]], ['txn' ]); do
+ AT_CHECK([ovsdb-client transact unix:socket "$txn"], [0], [ignore], [ignore])
+done
+
+# 1001 clients monitoring column "name" and with condition for "name" only.
+# The clients are created in a way that the 991th client will request condition
+# change, so that the chance is high that the condition change will be handled
+# before some pending changes are freed.
+
+cond='[[["name","==","ten"]]]'
+for i in `seq 1 990`; do
+ AT_CHECK([ovsdb-client -vjsonrpc --pidfile=ovsdb-client$i.pid --detach --no-chdir -d json monitor-cond --format=csv unix:socket ordinals $cond ordinals ["name"]], [0], [ignore], [ignore])
+done
+
+AT_CHECK([ovsdb-client -vjsonrpc --pidfile --detach --no-chdir -d json monitor-cond --format=csv unix:socket ordinals $cond ordinals ["name"] > output],
+ [0], [ignore], [ignore])
+
+for i in `seq 991 1000`; do
+ AT_CHECK([ovsdb-client -vjsonrpc --pidfile=ovsdb-client$i.pid --detach --no-chdir -d json monitor-cond --format=csv unix:socket ordinals $cond ordinals ["name"]], [0], [ignore], [ignore])
+done
+
+for txn in m4_foreach([txn], [[[["ordinals",
+ {"op": "insert",
+ "table": "ordinals",
+ "row": {"number": 10, "name": "ten"}}]]]], ['txn' ]); do
+ AT_CHECK([ovsdb-client transact unix:socket "$txn"], [0],
+ [ignore], [ignore], [kill `cat server-pid client-pid`])
+done
+
+# Change the condition so that a new column "number" is added to monitor table.
+cond='[[["number","==",1]]]'
+AT_CHECK([ovs-appctl -t ovsdb-client ovsdb-client/cond_change ordinals $cond], [0], [ignore], [ignore])
+
+# Give some time for the server to flush and free pending changes
+# (to crash, when n_columns is not handled properly)
+sleep 1
+
+AT_CHECK([ovsdb-client transact unix:socket '[["ordinals"]]'], [0],
+ [ignore], [ignore])
+AT_CHECK([ovs-appctl -t ovsdb-server -e exit], [0], [ignore], [ignore])
+OVS_WAIT_UNTIL([test ! -e ovsdb-server.pid && test ! -e ovsdb-client.pid])
+AT_CHECK([$PYTHON $srcdir/ovsdb-monitor-sort.py < output | uuidfilt], [0], [[row,action,name
+<0>,insert,"""ten"""
+
+row,action,name
+<0>,delete,
+<1>,insert,"""one"""
+]], [ignore])
+AT_CLEANUP