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, "<built-in>" + will be stored, in liue of the actual version. If datapath version + cannot be determined, "<unknown>" 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