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 <azhou@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
}
}
+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,
dpif_netdev_register_upcall_cb,
dpif_netdev_enable_upcall,
dpif_netdev_disable_upcall,
+ dpif_netdev_get_datapath_version,
};
static void
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,
NULL, /* register_upcall_cb */
NULL, /* enable_upcall */
NULL, /* disable_upcall */
+ dpif_netlink_get_datapath_version, /* get_datapath_version */
};
static int
/* 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;
}
}
+/*
+ * 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
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
/* 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. */
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);
}
* 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;
}
return error;
}
\f
+/* 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)
group_dealloc, /* group_dealloc */
group_modify, /* group_modify */
group_get_stats, /* group_get_stats */
+ get_datapath_version, /* get_datapath_version */
};
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;
controller : []
datapath_id : []
datapath_type : ""
+datapath_version : ""
external_ids : {}
fail_mode : []
flood_vlans : []
controller : []
datapath_id : []
datapath_type : ""
+datapath_version : ""
external_ids : {}
fail_mode : []
flood_vlans : []
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);
ovs_strerror(error));
shash_destroy(&br->wanted_ports);
bridge_destroy(br);
+ } else {
+ /* Trigger storing datapath version. */
+ seq_change(connectivity_seq_get());
}
}
}
#undef IFACE_STATS
}
+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)
{
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;
{"name": "Open_vSwitch",
- "version": "7.10.1",
- "cksum": "2340049037 21461",
+ "version": "7.11.1",
+ "cksum": "1038213587 21518",
"tables": {
"Open_vSwitch": {
"columns": {
"mutable": false},
"datapath_type": {
"type": "string"},
+ "datapath_version": {
+ "type": "string"},
"datapath_id": {
"type": {"key": "string", "min": 0, "max": 1},
"ephemeral": true},
column="other-config" key="datapath-id"/> instead.)
</column>
+ <column name="datapath_version">
+ <p>
+ Reports the version number of the Open vSwitch datapath in use.
+ This allows management software to detect and report discrepancies
+ between Open vSwitch userspace and datapath versions. (The <ref
+ column="ovs_version" table="Open_vSwitch"/> column in the <ref
+ table="Open_vSwitch"/> reports the Open vSwitch userspace version.)
+ The version reported depends on the datapath in use:
+ </p>
+
+ <ul>
+ <li>
+ When the kernel module included in the Open vSwitch source tree is
+ used, this column reports the Open vSwitch version from which the
+ module was taken.
+ </li>
+
+ <li>
+ When the kernel module that is part of the upstream Linux kernel is
+ used, this column reports <code><unknown></code>.
+ </li>
+
+ <li>
+ When the datapath is built into the <code>ovs-vswitchd</code>
+ binary, this column reports <code><built-in></code>. A
+ built-in datapath is by definition the same version as the rest of
+ the Open VSwitch userspace.
+ </li>
+
+ <li>
+ Other datapaths (such as the Hyper-V kernel datapath) currently
+ report <code><unknown></code>.
+ </li>
+ </ul>
+
+ <p>
+ A version discrepancy between <code>ovs-vswitchd</code> and the
+ datapath in use is not normally cause for alarm. The Open vSwitch
+ kernel datapaths for Linux and Hyper-V, in particular, are designed
+ for maximum inter-version compatibility: any userspace version works
+ with with any kernel version. Some reasons do exist to insist on
+ particular user/kernel pairings. First, newer kernel versions add
+ new features, that can only be used by new-enough userspace, e.g.
+ VXLAN tunneling requires certain minimal userspace and kernel
+ versions. Second, as an extension to the first reason, some newer
+ kernel versions add new features for enhancing performance that only
+ new-enough userspace versions can take advantage of.
+ </p>
+ </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.