ebb439
From 561f1c3ee471e3b3212111abeb8239122eb8efd4 Mon Sep 17 00:00:00 2001
ebb439
From: Numan Siddique <numans@ovn.org>
ebb439
Date: Sun, 22 Nov 2020 18:47:25 +0530
ebb439
Subject: [PATCH 02/16] controller: Allow pinctrl thread to handle packet-ins
ebb439
 when version mismatch with northd.
ebb439
ebb439
The commit 1dd27ea7aea4 added the support to pin ovn-controller to a
ebb439
specific version of ovn-northd.  This patch did not handle the
ebb439
scenario the packet-in scenario when ovn-controller is started and it
ebb439
detects version mismatch with ovn-northd.  In this case, pinctrl
ebb439
thread is not configured with the proper integration bridge name,
ebb439
because of which it cannot handle any packet-ins.
ebb439
ebb439
This patch addresses this scenario.  This is required so that any
ebb439
existing VMs do not loose DHCP address during renewal.
ebb439
ebb439
Fixes: 1dd27ea7aea4("Provide the option to pin ovn-controller and ovn-northd to a specific version")
ebb439
Acked-by: Flavio Fernandes <flavio@flaviof.com>
ebb439
Tested-by: Flavio Fernandes <flavio@flaviof.com>
ebb439
Signed-off-by: Numan Siddique <numans@ovn.org>
ebb439
---
ebb439
 controller/ovn-controller.c | 27 ++++++++++++-----
ebb439
 controller/pinctrl.c        | 34 ++++++++++++++-------
ebb439
 controller/pinctrl.h        |  2 +-
ebb439
 tests/ovn.at                | 59 ++++++++++++++++++++++++++++++++++++-
ebb439
 4 files changed, 102 insertions(+), 20 deletions(-)
ebb439
ebb439
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
ebb439
index faae787f3..3b41cc390 100644
ebb439
--- a/controller/ovn-controller.c
ebb439
+++ b/controller/ovn-controller.c
ebb439
@@ -2552,25 +2552,29 @@ main(int argc, char *argv[])
ebb439
 
ebb439
         engine_set_context(&eng_ctx);
ebb439
 
ebb439
-        if (ovsdb_idl_has_ever_connected(ovnsb_idl_loop.idl) &&
ebb439
+        bool northd_version_match =
ebb439
             check_northd_version(ovs_idl_loop.idl, ovnsb_idl_loop.idl,
ebb439
-                                 ovn_version)) {
ebb439
+                                 ovn_version);
ebb439
+
ebb439
+        const struct ovsrec_bridge_table *bridge_table =
ebb439
+            ovsrec_bridge_table_get(ovs_idl_loop.idl);
ebb439
+        const struct ovsrec_open_vswitch_table *ovs_table =
ebb439
+            ovsrec_open_vswitch_table_get(ovs_idl_loop.idl);
ebb439
+        const struct ovsrec_bridge *br_int =
ebb439
+            process_br_int(ovs_idl_txn, bridge_table, ovs_table);
ebb439
+
ebb439
+        if (ovsdb_idl_has_ever_connected(ovnsb_idl_loop.idl) &&
ebb439
+            northd_version_match) {
ebb439
             /* Contains the transport zones that this Chassis belongs to */
ebb439
             struct sset transport_zones = SSET_INITIALIZER(&transport_zones);
ebb439
             sset_from_delimited_string(&transport_zones,
ebb439
                 get_transport_zones(ovsrec_open_vswitch_table_get(
ebb439
                                     ovs_idl_loop.idl)), ",");
ebb439
 
ebb439
-            const struct ovsrec_bridge_table *bridge_table =
ebb439
-                ovsrec_bridge_table_get(ovs_idl_loop.idl);
ebb439
-            const struct ovsrec_open_vswitch_table *ovs_table =
ebb439
-                ovsrec_open_vswitch_table_get(ovs_idl_loop.idl);
ebb439
             const struct sbrec_chassis_table *chassis_table =
ebb439
                 sbrec_chassis_table_get(ovnsb_idl_loop.idl);
ebb439
             const struct sbrec_chassis_private_table *chassis_pvt_table =
ebb439
                 sbrec_chassis_private_table_get(ovnsb_idl_loop.idl);
ebb439
-            const struct ovsrec_bridge *br_int =
ebb439
-                process_br_int(ovs_idl_txn, bridge_table, ovs_table);
ebb439
             const char *chassis_id = get_ovs_chassis_id(ovs_table);
ebb439
             const struct sbrec_chassis *chassis = NULL;
ebb439
             const struct sbrec_chassis_private *chassis_private = NULL;
ebb439
@@ -2751,6 +2755,13 @@ main(int argc, char *argv[])
ebb439
             }
ebb439
         }
ebb439
 
ebb439
+        if (!northd_version_match && br_int) {
ebb439
+            /* Set the integration bridge name to pinctrl so that the pinctrl
ebb439
+             * thread can handle any packet-ins when we are not processing
ebb439
+             * any DB updates due to version mismatch. */
ebb439
+            pinctrl_set_br_int_name(br_int->name);
ebb439
+        }
ebb439
+
ebb439
         unixctl_server_run(unixctl);
ebb439
 
ebb439
         unixctl_server_wait(unixctl);
ebb439
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
ebb439
index dd9fff959..728fb3063 100644
ebb439
--- a/controller/pinctrl.c
ebb439
+++ b/controller/pinctrl.c
ebb439
@@ -3113,6 +3113,29 @@ pinctrl_handler(void *arg_)
ebb439
     return NULL;
ebb439
 }
ebb439
 
ebb439
+static void
ebb439
+pinctrl_set_br_int_name_(char *br_int_name)
ebb439
+{
ebb439
+    if (br_int_name && (!pinctrl.br_int_name || strcmp(pinctrl.br_int_name,
ebb439
+                                                       br_int_name))) {
ebb439
+        if (pinctrl.br_int_name) {
ebb439
+            free(pinctrl.br_int_name);
ebb439
+        }
ebb439
+        pinctrl.br_int_name = xstrdup(br_int_name);
ebb439
+        /* Notify pinctrl_handler that integration bridge is
ebb439
+         * set/changed. */
ebb439
+        notify_pinctrl_handler();
ebb439
+    }
ebb439
+}
ebb439
+
ebb439
+void
ebb439
+pinctrl_set_br_int_name(char *br_int_name)
ebb439
+{
ebb439
+    ovs_mutex_lock(&pinctrl_mutex);
ebb439
+    pinctrl_set_br_int_name_(br_int_name);
ebb439
+    ovs_mutex_unlock(&pinctrl_mutex);
ebb439
+}
ebb439
+
ebb439
 /* Called by ovn-controller. */
ebb439
 void
ebb439
 pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
ebb439
@@ -3132,16 +3155,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
ebb439
             const struct sset *active_tunnels)
ebb439
 {
ebb439
     ovs_mutex_lock(&pinctrl_mutex);
ebb439
-    if (br_int && (!pinctrl.br_int_name || strcmp(pinctrl.br_int_name,
ebb439
-                                                  br_int->name))) {
ebb439
-        if (pinctrl.br_int_name) {
ebb439
-            free(pinctrl.br_int_name);
ebb439
-        }
ebb439
-        pinctrl.br_int_name = xstrdup(br_int->name);
ebb439
-        /* Notify pinctrl_handler that integration bridge is
ebb439
-         * set/changed. */
ebb439
-        notify_pinctrl_handler();
ebb439
-    }
ebb439
+    pinctrl_set_br_int_name_(br_int->name);
ebb439
     run_put_mac_bindings(ovnsb_idl_txn, sbrec_datapath_binding_by_key,
ebb439
                          sbrec_port_binding_by_key,
ebb439
                          sbrec_mac_binding_by_lport_ip);
ebb439
diff --git a/controller/pinctrl.h b/controller/pinctrl.h
ebb439
index 8fa4baae9..4b101ec92 100644
ebb439
--- a/controller/pinctrl.h
ebb439
+++ b/controller/pinctrl.h
ebb439
@@ -49,5 +49,5 @@ void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
ebb439
                  const struct sset *active_tunnels);
ebb439
 void pinctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn);
ebb439
 void pinctrl_destroy(void);
ebb439
-
ebb439
+void pinctrl_set_br_int_name(char *br_int_name);
ebb439
 #endif /* controller/pinctrl.h */
ebb439
diff --git a/tests/ovn.at b/tests/ovn.at
ebb439
index f771b7563..f56f8a696 100644
ebb439
--- a/tests/ovn.at
ebb439
+++ b/tests/ovn.at
ebb439
@@ -6093,7 +6093,64 @@ AT_CHECK([cat 1.packets | cut -c -48], [0], [expout])
ebb439
 cat 1.expected | cut -c 53- > expout
ebb439
 AT_CHECK([cat 1.packets | cut -c 53-], [0], [expout])
ebb439
 
ebb439
-OVN_CLEANUP([hv1])
ebb439
+# Test that ovn-controller pinctrl thread handles dhcp requests when it
ebb439
+# connects to a wrong version of ovn-northd at startup.
ebb439
+
ebb439
+# Stop ovn-northd so that we can modify the northd_version.
ebb439
+as northd
ebb439
+OVS_APP_EXIT_AND_WAIT([ovn-northd])
ebb439
+
ebb439
+as northd-backup
ebb439
+OVS_APP_EXIT_AND_WAIT([ovn-northd])
ebb439
+
ebb439
+northd_version=$(ovn-sbctl get SB_Global . options:northd_internal_version | sed s/\"//g)
ebb439
+echo "northd version = $northd_version"
ebb439
+
ebb439
+check ovn-sbctl set SB_Global . options:northd_internal_version=foo
ebb439
+
ebb439
+echo
ebb439
+echo "__file__:__line__: Stop ovn-controller."
ebb439
+as hv1
ebb439
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
ebb439
+
ebb439
+echo
ebb439
+echo "__file__:__line__: Pin ovn-controller to ovn-northd version."
ebb439
+
ebb439
+as hv1
ebb439
+check ovs-vsctl set open . external_ids:ovn-match-northd-version=true
ebb439
+
ebb439
+# Start ovn-controller
ebb439
+as hv1
ebb439
+start_daemon ovn-controller
ebb439
+
ebb439
+OVS_WAIT_UNTIL(
ebb439
+    [test 1 = $(grep -c "controller version - $northd_version mismatch with northd version - foo" hv1/ovn-controller.log)
ebb439
+])
ebb439
+
ebb439
+reset_pcap_file hv1-vif1 hv1/vif1
ebb439
+reset_pcap_file hv1-vif2 hv1/vif2
ebb439
+rm -f 1.expected
ebb439
+rm -f 2.expected
ebb439
+
ebb439
+# ----------------------------------------------------------------------
ebb439
+
ebb439
+offer_ip=`ip_to_hex 10 0 0 4`
ebb439
+server_ip=`ip_to_hex 10 0 0 1`
ebb439
+ciaddr=`ip_to_hex 0 0 0 0`
ebb439
+request_ip=0
ebb439
+boofile=4308626f6f7466696c65
ebb439
+expected_dhcp_opts=${boofile}330400000e100104ffffff0003040a00000136040a000001
ebb439
+test_dhcp 20 1 f00000000001 01 0 $ciaddr $offer_ip $request_ip 1 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
ebb439
+compare_dhcp_packets 1
ebb439
+
ebb439
+as hv1
ebb439
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
ebb439
+
ebb439
+as ovn-sb
ebb439
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
ebb439
+
ebb439
+as ovn-nb
ebb439
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
ebb439
 
ebb439
 AT_CLEANUP
ebb439
 
ebb439
-- 
ebb439
2.28.0
ebb439