OVS userspace are backward compatible with older Linux kernel modules.
However, not having the most up-to-date datapath kernel modules can
some times lead to user confusion. Storing the datapath version in
OVSDB allows management software to check and optionally provide
notifications to users.

Signed-off-by: Andy Zhou <az...@nicira.com>

----
v1->v2:  Get version string from dpif_class.
V2->V3:  Fix missspelling of 'datapath' in comments
V3->v4:  Fix vswitch.xml description to referece Open vSwitch instead
         of OpenFlow
V4->V5:  Add handlinf for possible empty kernel module version file.
         Update OVSDB with empty string when datapath version cannot
         be determined.
V5->v6:  Store "<unknown>" when datapath version can not be determined.
         Store "<built-in>" when datapath is linked into the user space.
---
 lib/dpif-netdev.c          |  7 +++++++
 lib/dpif-netlink.c         | 31 +++++++++++++++++++++++++++++++
 lib/dpif-provider.h        |  4 ++++
 lib/dpif.c                 | 16 ++++++++++++++++
 lib/dpif.h                 |  1 +
 ofproto/ofproto-dpif.c     | 17 +++++++++++++++++
 ofproto/ofproto-provider.h | 13 +++++++++++++
 tests/ovs-vsctl.at         |  2 ++
 vswitchd/bridge.c          | 18 ++++++++++++++++++
 vswitchd/vswitch.ovsschema |  6 ++++--
 vswitchd/vswitch.xml       |  7 +++++++
 11 files changed, 120 insertions(+), 2 deletions(-)

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 2009206..dfb831c 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2520,6 +2520,12 @@ dp_netdev_reset_pmd_threads(struct dp_netdev *dp)
     }
 }
 
+static char *
+dpif_netdev_get_datapath_version(void)
+{
+     return xstrdup("<built-in>");
+}
+
 static void
 dp_netdev_flow_used(struct dp_netdev_flow *netdev_flow,
                     int cnt, int size,
@@ -3100,6 +3106,7 @@ const struct dpif_class dpif_netdev_class = {
     dpif_netdev_register_upcall_cb,
     dpif_netdev_enable_upcall,
     dpif_netdev_disable_upcall,
+    dpif_netdev_get_datapath_version,
 };
 
 static void
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index 67c2814..f5a4a6c 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -1903,6 +1903,36 @@ dpif_netlink_recv_purge(struct dpif *dpif_)
     fat_rwlock_unlock(&dpif->upcall_lock);
 }
 
+static char *
+dpif_netlink_get_datapath_version(void)
+{
+    char *version_str = NULL;
+
+#ifdef __linux__
+
+#define MAX_VERSION_STR_SIZE 80
+#define LINUX_DATAPATH_VERSION_FILE  "/sys/module/openvswitch/version"
+    FILE *f;
+
+    f = fopen(LINUX_DATAPATH_VERSION_FILE, "r");
+    if (f) {
+        char *newline;
+        char version[MAX_VERSION_STR_SIZE];
+
+        if (fgets(version, MAX_VERSION_STR_SIZE, f)) {
+            newline = strchr(version, '\n');
+            if (newline) {
+                *newline = '\0';
+            }
+            version_str = xstrdup(version);
+        }
+        fclose(f);
+    }
+#endif
+
+    return version_str;
+}
+
 const struct dpif_class dpif_netlink_class = {
     "system",
     dpif_netlink_enumerate,
@@ -1940,6 +1970,7 @@ const struct dpif_class dpif_netlink_class = {
     NULL,                       /* register_upcall_cb */
     NULL,                       /* enable_upcall */
     NULL,                       /* disable_upcall */
+    dpif_netlink_get_datapath_version, /* get_datapath_version */
 };
 
 static int
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 65cf505..0f2de0a 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -363,6 +363,10 @@ struct dpif_class {
 
     /* Disables upcalls if 'dpif' directly executes upcall functions. */
     void (*disable_upcall)(struct dpif *);
+
+    /* Get datapath version. Caller is responsible for freeing the string
+     * returned.  */
+    char *(*get_datapath_version)(void);
 };
 
 extern const struct dpif_class dpif_netlink_class;
diff --git a/lib/dpif.c b/lib/dpif.c
index 64e6a0e..73f747e 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1379,6 +1379,22 @@ dpif_recv_wait(struct dpif *dpif, uint32_t handler_id)
     }
 }
 
+/*
+ * Return the datapath version. Caller is responsible for freeing
+ * the string.
+ */
+char *
+dpif_get_dp_version(const struct dpif *dpif)
+{
+    char *version = NULL;
+
+    if (dpif->dpif_class->get_datapath_version) {
+        version = dpif->dpif_class->get_datapath_version();
+    }
+
+    return version;
+}
+
 /* Obtains the NetFlow engine type and engine ID for 'dpif' into '*engine_type'
  * and '*engine_id', respectively. */
 void
diff --git a/lib/dpif.h b/lib/dpif.h
index f88fa78..2bab4d0 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -790,6 +790,7 @@ void dpif_get_netflow_ids(const struct dpif *,
 int dpif_queue_to_priority(const struct dpif *, uint32_t queue_id,
                            uint32_t *priority);
 
+char *dpif_get_dp_version(const struct dpif *);
 #ifdef  __cplusplus
 }
 #endif
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index d965d38..bceec7c 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -280,6 +280,9 @@ struct dpif_backer {
     /* Maximum number of MPLS label stack entries that the datapath supports
      * in a match */
     size_t max_mpls_depth;
+
+    /* Version string of the datapath stored in OVSDB. */
+    char *dp_version_string;
 };
 
 /* All existing ofproto_backer instances, indexed by ofproto->up.type. */
@@ -837,6 +840,7 @@ close_dpif_backer(struct dpif_backer *backer)
     shash_find_and_delete(&all_dpif_backers, backer->type);
     recirc_id_pool_destroy(backer->rid_pool);
     free(backer->type);
+    free(backer->dp_version_string);
     dpif_close(backer->dpif);
     free(backer);
 }
@@ -965,6 +969,7 @@ open_dpif_backer(const char *type, struct dpif_backer 
**backerp)
      * as the kernel module checks that the 'pid' in userspace action
      * is non-zero. */
     backer->variable_length_userdata = check_variable_length_userdata(backer);
+    backer->dp_version_string = dpif_get_dp_version(backer->dpif);
 
     return error;
 }
@@ -4084,6 +4089,17 @@ ofproto_dpif_send_packet(const struct ofport_dpif 
*ofport, struct ofpbuf *packet
     return error;
 }
 
+/* Return the version string of the datapath that backs up
+ * this 'ofproto'.
+ */
+static const char *
+get_datapath_version(const struct ofproto *ofproto_)
+{
+    struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+
+    return ofproto->backer->dp_version_string;
+}
+
 static bool
 set_frag_handling(struct ofproto *ofproto_,
                   enum ofp_config_flags frag_handling)
@@ -5452,4 +5468,5 @@ const struct ofproto_class ofproto_dpif_class = {
     group_dealloc,              /* group_dealloc */
     group_modify,               /* group_modify */
     group_get_stats,            /* group_get_stats */
+    get_datapath_version,       /* get_datapath_version */
 };
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 158f86e..e6f9ff1 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -1659,6 +1659,19 @@ struct ofproto_class {
 
     enum ofperr (*group_get_stats)(const struct ofgroup *,
                                    struct ofputil_group_stats *);
+
+/* ## --------------------- ## */
+/* ## Datapath information  ## */
+/* ## --------------------- ## */
+    /* Retrieve the version string of the datapath. The version
+     * string can be NULL if it can not be determined.
+     *
+     * The version retuned is read only. The caller should not
+     * free it.
+     *
+     * This function should be NULL if an implementation does not support it.
+     */
+    const char *(*get_datapath_version)(const struct ofproto *);
 };
 
 extern const struct ofproto_class ofproto_dpif_class;
diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at
index 2f83566..d02f993 100644
--- a/tests/ovs-vsctl.at
+++ b/tests/ovs-vsctl.at
@@ -648,6 +648,7 @@ _uuid               : <0>
 controller          : []
 datapath_id         : []
 datapath_type       : ""
+datapath_version    : ""
 external_ids        : {}
 fail_mode           : []
 flood_vlans         : []
@@ -1146,6 +1147,7 @@ _uuid               : <1>
 controller          : []
 datapath_id         : []
 datapath_type       : ""
+datapath_version    : ""
 external_ids        : {}
 fail_mode           : []
 flood_vlans         : []
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 5f6000e..33d8d6a 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -381,6 +381,7 @@ bridge_init(const char *remote)
     ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_system_version);
 
     ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_datapath_id);
+    ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_datapath_version);
     ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_status);
     ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_rstp_status);
     ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_stp_enable);
@@ -595,6 +596,9 @@ bridge_reconfigure(const struct ovsrec_open_vswitch 
*ovs_cfg)
                          ovs_strerror(error));
                 shash_destroy(&br->wanted_ports);
                 bridge_destroy(br);
+            } else {
+                /* Trigger storing datapath version. */
+                seq_change(connectivity_seq_get());
             }
         }
     }
@@ -2320,6 +2324,19 @@ iface_refresh_stats(struct iface *iface)
 }
 
 static void
+br_refresh_datapath_info(struct bridge *br)
+{
+    const char *version;
+
+    version = (br->ofproto && br->ofproto->ofproto_class->get_datapath_version
+               ? br->ofproto->ofproto_class->get_datapath_version(br->ofproto)
+               : NULL);
+
+    ovsrec_bridge_set_datapath_version(br->cfg,
+                                       version ? version : "<unknown>");
+}
+
+static void
 br_refresh_stp_status(struct bridge *br)
 {
     struct smap smap = SMAP_INITIALIZER(&smap);
@@ -2695,6 +2712,7 @@ run_status_update(void)
 
                 br_refresh_stp_status(br);
                 br_refresh_rstp_status(br);
+                br_refresh_datapath_info(br);
                 HMAP_FOR_EACH (port, hmap_node, &br->ports) {
                     struct iface *iface;
 
diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
index 1817766..196c33c 100644
--- a/vswitchd/vswitch.ovsschema
+++ b/vswitchd/vswitch.ovsschema
@@ -1,6 +1,6 @@
 {"name": "Open_vSwitch",
- "version": "7.10.1",
- "cksum": "2340049037 21461",
+ "version": "7.11.1",
+ "cksum": "1038213587 21518",
  "tables": {
    "Open_vSwitch": {
      "columns": {
@@ -49,6 +49,8 @@
          "mutable": false},
        "datapath_type": {
          "type": "string"},
+       "datapath_version": {
+         "type": "string"},
        "datapath_id": {
          "type": {"key": "string", "min": 0, "max": 1},
          "ephemeral": true},
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index d90f221..a0623d0 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -582,6 +582,13 @@
         column="other-config" key="datapath-id"/> instead.)
       </column>
 
+      <column name="datapath_version">
+        Reports the Open vSwitch datapath version in use.  If the bridge
+        uses a datapath that is  linked into ovsvswitchd, "&lt;built-in&gt;"
+        will be stored, in liue of the actual version. If datapath version
+        cannot be determined, "&lt;unknown&gt;" will be stored.
+      </column>
+
       <column name="other_config" key="datapath-id">
         Exactly 16 hex digits to set the OpenFlow datapath ID to a specific
         value.  May not be all-zero.
-- 
1.9.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to