From: Ethan Jackson Date: Tue, 22 May 2012 10:47:36 +0000 (-0700) Subject: lib: New data structure - smap. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=79f1cbe9f86ddfb1b5d92b80d85e09cd44768d6c;p=openvswitch lib: New data structure - smap. A smap is a string to string hash map. It has a cleaner interface than shash's which were traditionally used for the same purpose. This patch implements the data structure, and changes netdev and its providers to use it. Signed-off-by: Ethan Jackson --- diff --git a/lib/automake.mk b/lib/automake.mk index 1d404c2c..6d3667cc 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -141,6 +141,8 @@ lib_libopenvswitch_a_SOURCES = \ lib/simap.h \ lib/signals.c \ lib/signals.h \ + lib/smap.c \ + lib/smap.h \ lib/socket-util.c \ lib/socket-util.h \ lib/sort.c \ diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 4d2f3ac0..61363c63 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -181,7 +181,7 @@ struct tc_ops { * * (This function is null for tc_ops_other, which cannot be installed. For * other TC classes it should always be nonnull.) */ - int (*tc_install)(struct netdev *netdev, const struct shash *details); + int (*tc_install)(struct netdev *netdev, const struct smap *details); /* Called when the netdev code determines (through a Netlink query) that * this TC class's qdisc is installed on 'netdev', but we didn't install @@ -221,7 +221,7 @@ struct tc_ops { * * This function may be null if 'tc' is not configurable. */ - int (*qdisc_get)(const struct netdev *netdev, struct shash *details); + int (*qdisc_get)(const struct netdev *netdev, struct smap *details); /* Reconfigures 'netdev->tc' according to 'details', performing any * required Netlink calls to complete the reconfiguration. @@ -232,7 +232,7 @@ struct tc_ops { * * This function may be null if 'tc' is not configurable. */ - int (*qdisc_set)(struct netdev *, const struct shash *details); + int (*qdisc_set)(struct netdev *, const struct smap *details); /* Retrieves details of 'queue' on 'netdev->tc' into 'details'. 'queue' is * one of the 'struct tc_queue's within 'netdev->tc->queues'. @@ -248,7 +248,7 @@ struct tc_ops { * This function may be null if 'tc' does not have queues ('n_queues' is * 0). */ int (*class_get)(const struct netdev *netdev, const struct tc_queue *queue, - struct shash *details); + struct smap *details); /* Configures or reconfigures 'queue_id' on 'netdev->tc' according to * 'details', perfoming any required Netlink calls to complete the @@ -262,7 +262,7 @@ struct tc_ops { * This function may be null if 'tc' does not have queues or its queues are * not configurable. */ int (*class_set)(struct netdev *, unsigned int queue_id, - const struct shash *details); + const struct smap *details); /* Deletes 'queue' from 'netdev->tc'. 'queue' is one of the 'struct * tc_queue's within 'netdev->tc->queues'. @@ -1845,7 +1845,7 @@ netdev_linux_get_qos_capabilities(const struct netdev *netdev OVS_UNUSED, static int netdev_linux_get_qos(const struct netdev *netdev, - const char **typep, struct shash *details) + const char **typep, struct smap *details) { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev)); @@ -1864,7 +1864,7 @@ netdev_linux_get_qos(const struct netdev *netdev, static int netdev_linux_set_qos(struct netdev *netdev, - const char *type, const struct shash *details) + const char *type, const struct smap *details) { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev)); @@ -1901,7 +1901,7 @@ netdev_linux_set_qos(struct netdev *netdev, static int netdev_linux_get_queue(const struct netdev *netdev, - unsigned int queue_id, struct shash *details) + unsigned int queue_id, struct smap *details) { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev)); @@ -1920,7 +1920,7 @@ netdev_linux_get_queue(const struct netdev *netdev, static int netdev_linux_set_queue(struct netdev *netdev, - unsigned int queue_id, const struct shash *details) + unsigned int queue_id, const struct smap *details) { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev)); @@ -2002,7 +2002,7 @@ netdev_linux_dump_queues(const struct netdev *netdev, struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev)); struct tc_queue *queue, *next_queue; - struct shash details; + struct smap details; int last_error; int error; @@ -2014,10 +2014,10 @@ netdev_linux_dump_queues(const struct netdev *netdev, } last_error = 0; - shash_init(&details); + smap_init(&details); HMAP_FOR_EACH_SAFE (queue, next_queue, hmap_node, &netdev_dev->tc->queues) { - shash_clear(&details); + smap_clear(&details); error = netdev_dev->tc->ops->class_get(netdev, queue, &details); if (!error) { @@ -2026,7 +2026,7 @@ netdev_linux_dump_queues(const struct netdev *netdev, last_error = error; } } - shash_destroy(&details); + smap_destroy(&details); return last_error; } @@ -2271,7 +2271,7 @@ netdev_linux_get_next_hop(const struct in_addr *host, struct in_addr *next_hop, } static int -netdev_linux_get_drv_info(const struct netdev *netdev, struct shash *sh) +netdev_linux_get_drv_info(const struct netdev *netdev, struct smap *smap) { int error; struct netdev_dev_linux *netdev_dev = @@ -2279,17 +2279,18 @@ netdev_linux_get_drv_info(const struct netdev *netdev, struct shash *sh) error = netdev_linux_get_drvinfo(netdev_dev); if (!error) { - shash_add(sh, "driver_name", xstrdup(netdev_dev->drvinfo.driver)); - shash_add(sh, "driver_version", xstrdup(netdev_dev->drvinfo.version)); - shash_add(sh, "firmware_version", xstrdup(netdev_dev->drvinfo.fw_version)); + smap_add(smap, "driver_name", netdev_dev->drvinfo.driver); + smap_add(smap, "driver_version", netdev_dev->drvinfo.version); + smap_add(smap, "firmware_version", netdev_dev->drvinfo.fw_version); } return error; } static int -netdev_internal_get_drv_info(const struct netdev *netdev OVS_UNUSED, struct shash *sh) +netdev_internal_get_drv_info(const struct netdev *netdev OVS_UNUSED, + struct smap *smap) { - shash_add(sh, "driver_name", xstrdup("openvswitch")); + smap_add(smap, "driver_name", "openvswitch"); return 0; } @@ -2651,11 +2652,11 @@ htb_parse_tcmsg__(struct ofpbuf *tcmsg, unsigned int *queue_id, static void htb_parse_qdisc_details__(struct netdev *netdev, - const struct shash *details, struct htb_class *hc) + const struct smap *details, struct htb_class *hc) { const char *max_rate_s; - max_rate_s = shash_find_data(details, "max-rate"); + max_rate_s = smap_get(details, "max-rate"); hc->max_rate = max_rate_s ? strtoull(max_rate_s, NULL, 10) / 8 : 0; if (!hc->max_rate) { enum netdev_features current; @@ -2670,13 +2671,13 @@ htb_parse_qdisc_details__(struct netdev *netdev, static int htb_parse_class_details__(struct netdev *netdev, - const struct shash *details, struct htb_class *hc) + const struct smap *details, struct htb_class *hc) { const struct htb *htb = htb_get__(netdev); - const char *min_rate_s = shash_find_data(details, "min-rate"); - const char *max_rate_s = shash_find_data(details, "max-rate"); - const char *burst_s = shash_find_data(details, "burst"); - const char *priority_s = shash_find_data(details, "priority"); + const char *min_rate_s = smap_get(details, "min-rate"); + const char *max_rate_s = smap_get(details, "max-rate"); + const char *burst_s = smap_get(details, "burst"); + const char *priority_s = smap_get(details, "priority"); int mtu, error; error = netdev_get_mtu(netdev, &mtu); @@ -2734,7 +2735,7 @@ htb_query_class__(const struct netdev *netdev, unsigned int handle, } static int -htb_tc_install(struct netdev *netdev, const struct shash *details) +htb_tc_install(struct netdev *netdev, const struct smap *details) { int error; @@ -2826,15 +2827,15 @@ htb_tc_destroy(struct tc *tc) } static int -htb_qdisc_get(const struct netdev *netdev, struct shash *details) +htb_qdisc_get(const struct netdev *netdev, struct smap *details) { const struct htb *htb = htb_get__(netdev); - shash_add(details, "max-rate", xasprintf("%llu", 8ULL * htb->max_rate)); + smap_add_format(details, "max-rate", "%llu", 8ULL * htb->max_rate); return 0; } static int -htb_qdisc_set(struct netdev *netdev, const struct shash *details) +htb_qdisc_set(struct netdev *netdev, const struct smap *details) { struct htb_class hc; int error; @@ -2850,24 +2851,24 @@ htb_qdisc_set(struct netdev *netdev, const struct shash *details) static int htb_class_get(const struct netdev *netdev OVS_UNUSED, - const struct tc_queue *queue, struct shash *details) + const struct tc_queue *queue, struct smap *details) { const struct htb_class *hc = htb_class_cast__(queue); - shash_add(details, "min-rate", xasprintf("%llu", 8ULL * hc->min_rate)); + smap_add_format(details, "min-rate", "%llu", 8ULL * hc->min_rate); if (hc->min_rate != hc->max_rate) { - shash_add(details, "max-rate", xasprintf("%llu", 8ULL * hc->max_rate)); + smap_add_format(details, "max-rate", "%llu", 8ULL * hc->max_rate); } - shash_add(details, "burst", xasprintf("%llu", 8ULL * hc->burst)); + smap_add_format(details, "burst", "%llu", 8ULL * hc->burst); if (hc->priority) { - shash_add(details, "priority", xasprintf("%u", hc->priority)); + smap_add_format(details, "priority", "%u", hc->priority); } return 0; } static int htb_class_set(struct netdev *netdev, unsigned int queue_id, - const struct shash *details) + const struct smap *details) { struct htb_class hc; int error; @@ -3127,13 +3128,13 @@ hfsc_query_class__(const struct netdev *netdev, unsigned int handle, } static void -hfsc_parse_qdisc_details__(struct netdev *netdev, const struct shash *details, +hfsc_parse_qdisc_details__(struct netdev *netdev, const struct smap *details, struct hfsc_class *class) { uint32_t max_rate; const char *max_rate_s; - max_rate_s = shash_find_data(details, "max-rate"); + max_rate_s = smap_get(details, "max-rate"); max_rate = max_rate_s ? strtoull(max_rate_s, NULL, 10) / 8 : 0; if (!max_rate) { @@ -3149,7 +3150,7 @@ hfsc_parse_qdisc_details__(struct netdev *netdev, const struct shash *details, static int hfsc_parse_class_details__(struct netdev *netdev, - const struct shash *details, + const struct smap *details, struct hfsc_class * class) { const struct hfsc *hfsc; @@ -3157,8 +3158,8 @@ hfsc_parse_class_details__(struct netdev *netdev, const char *min_rate_s, *max_rate_s; hfsc = hfsc_get__(netdev); - min_rate_s = shash_find_data(details, "min-rate"); - max_rate_s = shash_find_data(details, "max-rate"); + min_rate_s = smap_get(details, "min-rate"); + max_rate_s = smap_get(details, "max-rate"); min_rate = min_rate_s ? strtoull(min_rate_s, NULL, 10) / 8 : 0; min_rate = MAX(min_rate, 1); @@ -3259,7 +3260,7 @@ hfsc_setup_class__(struct netdev *netdev, unsigned int handle, } static int -hfsc_tc_install(struct netdev *netdev, const struct shash *details) +hfsc_tc_install(struct netdev *netdev, const struct smap *details) { int error; struct hfsc_class class; @@ -3327,16 +3328,16 @@ hfsc_tc_destroy(struct tc *tc) } static int -hfsc_qdisc_get(const struct netdev *netdev, struct shash *details) +hfsc_qdisc_get(const struct netdev *netdev, struct smap *details) { const struct hfsc *hfsc; hfsc = hfsc_get__(netdev); - shash_add(details, "max-rate", xasprintf("%llu", 8ULL * hfsc->max_rate)); + smap_add_format(details, "max-rate", "%llu", 8ULL * hfsc->max_rate); return 0; } static int -hfsc_qdisc_set(struct netdev *netdev, const struct shash *details) +hfsc_qdisc_set(struct netdev *netdev, const struct smap *details) { int error; struct hfsc_class class; @@ -3354,21 +3355,21 @@ hfsc_qdisc_set(struct netdev *netdev, const struct shash *details) static int hfsc_class_get(const struct netdev *netdev OVS_UNUSED, - const struct tc_queue *queue, struct shash *details) + const struct tc_queue *queue, struct smap *details) { const struct hfsc_class *hc; hc = hfsc_class_cast__(queue); - shash_add(details, "min-rate", xasprintf("%llu", 8ULL * hc->min_rate)); + smap_add_format(details, "min-rate", "%llu", 8ULL * hc->min_rate); if (hc->min_rate != hc->max_rate) { - shash_add(details, "max-rate", xasprintf("%llu", 8ULL * hc->max_rate)); + smap_add_format(details, "max-rate", "%llu", 8ULL * hc->max_rate); } return 0; } static int hfsc_class_set(struct netdev *netdev, unsigned int queue_id, - const struct shash *details) + const struct smap *details) { int error; struct hfsc_class class; @@ -3473,7 +3474,7 @@ default_install__(struct netdev *netdev) static int default_tc_install(struct netdev *netdev, - const struct shash *details OVS_UNUSED) + const struct smap *details OVS_UNUSED) { default_install__(netdev); return 0; diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index 080b76a6..5fb1bbf2 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -24,6 +24,7 @@ #include "netdev.h" #include "list.h" #include "shash.h" +#include "smap.h" #ifdef __cplusplus extern "C" { @@ -126,17 +127,17 @@ struct netdev_class { void (*destroy)(struct netdev_dev *netdev_dev); /* Fetches the device 'netdev_dev''s configuration, storing it in 'args'. - * The caller owns 'args' and pre-initializes it to an empty shash. + * The caller owns 'args' and pre-initializes it to an empty smap. * * If this netdev class does not have any configuration options, this may * be a null pointer. */ - int (*get_config)(struct netdev_dev *netdev_dev, struct shash *args); + int (*get_config)(struct netdev_dev *netdev_dev, struct smap *args); /* Changes the device 'netdev_dev''s configuration to 'args'. * * If this netdev class does not support configuration, this may be a null * pointer. */ - int (*set_config)(struct netdev_dev *netdev_dev, const struct shash *args); + int (*set_config)(struct netdev_dev *netdev_dev, const struct smap *args); /* Attempts to open a network device. On success, sets 'netdevp' * to the new network device. */ @@ -381,7 +382,7 @@ struct netdev_class { * * May be NULL if 'netdev' does not support QoS at all. */ int (*get_qos)(const struct netdev *netdev, - const char **typep, struct shash *details); + const char **typep, struct smap *details); /* Attempts to reconfigure QoS on 'netdev', changing the form of QoS to * 'type' with details of configuration from 'details'. @@ -401,7 +402,7 @@ struct netdev_class { * * May be NULL if 'netdev' does not support QoS at all. */ int (*set_qos)(struct netdev *netdev, - const char *type, const struct shash *details); + const char *type, const struct smap *details); /* Queries 'netdev' for information about the queue numbered 'queue_id'. * If successful, adds that information as string key-value pairs to @@ -420,7 +421,7 @@ struct netdev_class { * vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)). */ int (*get_queue)(const struct netdev *netdev, - unsigned int queue_id, struct shash *details); + unsigned int queue_id, struct smap *details); /* Configures the queue numbered 'queue_id' on 'netdev' with the key-value * string pairs in 'details'. The contents of 'details' should be @@ -440,7 +441,7 @@ struct netdev_class { * * May be NULL if 'netdev' does not support QoS at all. */ int (*set_queue)(struct netdev *netdev, - unsigned int queue_id, const struct shash *details); + unsigned int queue_id, const struct smap *details); /* Attempts to delete the queue numbered 'queue_id' from 'netdev'. * @@ -475,7 +476,7 @@ struct netdev_class { */ int (*dump_queues)(const struct netdev *netdev, void (*cb)(unsigned int queue_id, - const struct shash *details, + const struct smap *details, void *aux), void *aux); @@ -550,12 +551,11 @@ struct netdev_class { * representing netdev type specific information. For more information see * ovs-vswitchd.conf.db(5). * - * The data of 'sh' are heap allocated strings which the caller is - * responsible for deallocating. + * The caller is responsible for destroying 'smap' and its data. * * This function may be set to null if it would always return EOPNOTSUPP * anyhow. */ - int (*get_drv_info)(const struct netdev *netdev, struct shash *sh); + int (*get_drv_info)(const struct netdev *netdev, struct smap *smap); /* Looks up the ARP table entry for 'ip' on 'netdev' and stores the * corresponding MAC address in 'mac'. A return value of ENXIO, in diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index a9eb3eb1..7fe169e3 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -65,10 +65,10 @@ struct vport_class { enum ovs_vport_type type; struct netdev_class netdev_class; int (*parse_config)(const char *name, const char *type, - const struct shash *args, struct ofpbuf *options); + const struct smap *args, struct ofpbuf *options); int (*unparse_config)(const char *name, const char *type, const struct nlattr *options, size_t options_len, - struct shash *args); + struct smap *args); }; static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); @@ -223,7 +223,7 @@ netdev_vport_close(struct netdev *netdev_) } static int -netdev_vport_get_config(struct netdev_dev *dev_, struct shash *args) +netdev_vport_get_config(struct netdev_dev *dev_, struct smap *args) { const struct netdev_class *netdev_class = netdev_dev_get_class(dev_); const struct vport_class *vport_class = vport_class_cast(netdev_class); @@ -260,7 +260,7 @@ netdev_vport_get_config(struct netdev_dev *dev_, struct shash *args) } static int -netdev_vport_set_config(struct netdev_dev *dev_, const struct shash *args) +netdev_vport_set_config(struct netdev_dev *dev_, const struct smap *args) { const struct netdev_class *netdev_class = netdev_dev_get_class(dev_); const struct vport_class *vport_class = vport_class_cast(netdev_class); @@ -459,19 +459,18 @@ netdev_vport_set_stats(struct netdev *netdev, const struct netdev_stats *stats) } static int -netdev_vport_get_drv_info(const struct netdev *netdev, struct shash *sh) +netdev_vport_get_drv_info(const struct netdev *netdev, struct smap *smap) { const char *iface = netdev_vport_get_tnl_iface(netdev); if (iface) { struct netdev *egress_netdev; - shash_add(sh, "tunnel_egress_iface", xstrdup(iface)); + smap_add(smap, "tunnel_egress_iface", iface); if (!netdev_open(iface, "system", &egress_netdev)) { - shash_add(sh, "tunnel_egress_iface_carrier", - xstrdup(netdev_get_carrier(egress_netdev) - ? "up" : "down")); + smap_add(smap, "tunnel_egress_iface_carrier", + netdev_get_carrier(egress_netdev) ? "up" : "down"); netdev_close(egress_netdev); } } @@ -551,14 +550,14 @@ netdev_vport_poll_notify(const struct netdev *netdev) /* Code specific to individual vport types. */ static void -set_key(const struct shash *args, const char *name, uint16_t type, +set_key(const struct smap *args, const char *name, uint16_t type, struct ofpbuf *options) { const char *s; - s = shash_find_data(args, name); + s = smap_get(args, name); if (!s) { - s = shash_find_data(args, "key"); + s = smap_get(args, "key"); if (!s) { s = "0"; } @@ -573,11 +572,11 @@ set_key(const struct shash *args, const char *name, uint16_t type, static int parse_tunnel_config(const char *name, const char *type, - const struct shash *args, struct ofpbuf *options) + const struct smap *args, struct ofpbuf *options) { bool is_gre = false; bool is_ipsec = false; - struct shash_node *node; + struct smap_node *node; bool ipsec_mech_set = false; ovs_be32 daddr = htonl(0); ovs_be32 saddr = htonl(0); @@ -593,60 +592,60 @@ parse_tunnel_config(const char *name, const char *type, flags &= ~TNL_F_HDR_CACHE; } - SHASH_FOR_EACH (node, args) { - if (!strcmp(node->name, "remote_ip")) { + SMAP_FOR_EACH (node, args) { + if (!strcmp(node->key, "remote_ip")) { struct in_addr in_addr; - if (lookup_ip(node->data, &in_addr)) { + if (lookup_ip(node->value, &in_addr)) { VLOG_WARN("%s: bad %s 'remote_ip'", name, type); } else { daddr = in_addr.s_addr; } - } else if (!strcmp(node->name, "local_ip")) { + } else if (!strcmp(node->key, "local_ip")) { struct in_addr in_addr; - if (lookup_ip(node->data, &in_addr)) { + if (lookup_ip(node->value, &in_addr)) { VLOG_WARN("%s: bad %s 'local_ip'", name, type); } else { saddr = in_addr.s_addr; } - } else if (!strcmp(node->name, "tos")) { - if (!strcmp(node->data, "inherit")) { + } else if (!strcmp(node->key, "tos")) { + if (!strcmp(node->value, "inherit")) { flags |= TNL_F_TOS_INHERIT; } else { char *endptr; int tos; - tos = strtol(node->data, &endptr, 0); + tos = strtol(node->value, &endptr, 0); if (*endptr == '\0') { nl_msg_put_u8(options, OVS_TUNNEL_ATTR_TOS, tos); } } - } else if (!strcmp(node->name, "ttl")) { - if (!strcmp(node->data, "inherit")) { + } else if (!strcmp(node->key, "ttl")) { + if (!strcmp(node->value, "inherit")) { flags |= TNL_F_TTL_INHERIT; } else { - nl_msg_put_u8(options, OVS_TUNNEL_ATTR_TTL, atoi(node->data)); + nl_msg_put_u8(options, OVS_TUNNEL_ATTR_TTL, atoi(node->value)); } - } else if (!strcmp(node->name, "csum") && is_gre) { - if (!strcmp(node->data, "true")) { + } else if (!strcmp(node->key, "csum") && is_gre) { + if (!strcmp(node->value, "true")) { flags |= TNL_F_CSUM; } - } else if (!strcmp(node->name, "df_inherit")) { - if (!strcmp(node->data, "true")) { + } else if (!strcmp(node->key, "df_inherit")) { + if (!strcmp(node->value, "true")) { flags |= TNL_F_DF_INHERIT; } - } else if (!strcmp(node->name, "df_default")) { - if (!strcmp(node->data, "false")) { + } else if (!strcmp(node->key, "df_default")) { + if (!strcmp(node->value, "false")) { flags &= ~TNL_F_DF_DEFAULT; } - } else if (!strcmp(node->name, "pmtud")) { - if (!strcmp(node->data, "false")) { + } else if (!strcmp(node->key, "pmtud")) { + if (!strcmp(node->value, "false")) { flags &= ~TNL_F_PMTUD; } - } else if (!strcmp(node->name, "header_cache")) { - if (!strcmp(node->data, "false")) { + } else if (!strcmp(node->key, "header_cache")) { + if (!strcmp(node->value, "false")) { flags &= ~TNL_F_HDR_CACHE; } - } else if (!strcmp(node->name, "peer_cert") && is_ipsec) { - if (shash_find(args, "certificate")) { + } else if (!strcmp(node->key, "peer_cert") && is_ipsec) { + if (smap_get(args, "certificate")) { ipsec_mech_set = true; } else { const char *use_ssl_cert; @@ -657,7 +656,7 @@ parse_tunnel_config(const char *name, const char *type, * will like be removed when multiple SSL configurations * are supported by OVS. */ - use_ssl_cert = shash_find_data(args, "use_ssl_cert"); + use_ssl_cert = smap_get(args, "use_ssl_cert"); if (!use_ssl_cert || strcmp(use_ssl_cert, "true")) { VLOG_ERR("%s: 'peer_cert' requires 'certificate' argument", name); @@ -665,19 +664,19 @@ parse_tunnel_config(const char *name, const char *type, } ipsec_mech_set = true; } - } else if (!strcmp(node->name, "psk") && is_ipsec) { + } else if (!strcmp(node->key, "psk") && is_ipsec) { ipsec_mech_set = true; } else if (is_ipsec - && (!strcmp(node->name, "certificate") - || !strcmp(node->name, "private_key") - || !strcmp(node->name, "use_ssl_cert"))) { + && (!strcmp(node->key, "certificate") + || !strcmp(node->key, "private_key") + || !strcmp(node->key, "use_ssl_cert"))) { /* Ignore options not used by the netdev. */ - } else if (!strcmp(node->name, "key") || - !strcmp(node->name, "in_key") || - !strcmp(node->name, "out_key")) { + } else if (!strcmp(node->key, "key") || + !strcmp(node->key, "in_key") || + !strcmp(node->key, "out_key")) { /* Handled separately below. */ } else { - VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->name); + VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key); } } @@ -692,7 +691,7 @@ parse_tunnel_config(const char *name, const char *type, return EINVAL; } - if (shash_find(args, "peer_cert") && shash_find(args, "psk")) { + if (smap_get(args, "peer_cert") && smap_get(args, "psk")) { VLOG_ERR("%s: cannot define both 'peer_cert' and 'psk'", name); return EINVAL; } @@ -759,7 +758,7 @@ get_be64_or_zero(const struct nlattr *a) static int unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED, const struct nlattr *options, size_t options_len, - struct shash *args) + struct smap *args) { struct nlattr *a[OVS_TUNNEL_ATTR_MAX + 1]; ovs_be32 daddr; @@ -778,11 +777,11 @@ unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED, } daddr = nl_attr_get_be32(a[OVS_TUNNEL_ATTR_DST_IPV4]); - shash_add(args, "remote_ip", xasprintf(IP_FMT, IP_ARGS(&daddr))); + smap_add_format(args, "remote_ip", IP_FMT, IP_ARGS(&daddr)); if (a[OVS_TUNNEL_ATTR_SRC_IPV4]) { ovs_be32 saddr = nl_attr_get_be32(a[OVS_TUNNEL_ATTR_SRC_IPV4]); - shash_add(args, "local_ip", xasprintf(IP_FMT, IP_ARGS(&saddr))); + smap_add_format(args, "local_ip", IP_FMT, IP_ARGS(&saddr)); } if (!a[OVS_TUNNEL_ATTR_IN_KEY] && !a[OVS_TUNNEL_ATTR_OUT_KEY]) { @@ -792,18 +791,18 @@ unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED, uint64_t out_key = get_be64_or_zero(a[OVS_TUNNEL_ATTR_OUT_KEY]); if (in_key && in_key == out_key) { - shash_add(args, "key", xasprintf("%"PRIu64, in_key)); + smap_add_format(args, "key", "%"PRIu64, in_key); } else { if (!a[OVS_TUNNEL_ATTR_IN_KEY]) { smap_add(args, "in_key", "flow"); } else if (in_key) { - shash_add(args, "in_key", xasprintf("%"PRIu64, in_key)); + smap_add_format(args, "in_key", "%"PRIu64, in_key); } if (!a[OVS_TUNNEL_ATTR_OUT_KEY]) { smap_add(args, "out_key", "flow"); } else if (out_key) { - shash_add(args, "out_key", xasprintf("%"PRIu64, out_key)); + smap_add_format(args, "out_key", "%"PRIu64, out_key); } } } @@ -812,14 +811,14 @@ unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED, smap_add(args, "tos", "inherit"); } else if (a[OVS_TUNNEL_ATTR_TTL]) { int ttl = nl_attr_get_u8(a[OVS_TUNNEL_ATTR_TTL]); - shash_add(args, "tos", xasprintf("%d", ttl)); + smap_add_format(args, "tos", "%d", ttl); } if (flags & TNL_F_TOS_INHERIT) { smap_add(args, "tos", "inherit"); } else if (a[OVS_TUNNEL_ATTR_TOS]) { int tos = nl_attr_get_u8(a[OVS_TUNNEL_ATTR_TOS]); - shash_add(args, "tos", xasprintf("0x%x", tos)); + smap_add_format(args, "tos", "0x%x", tos); } if (flags & TNL_F_CSUM) { @@ -840,17 +839,17 @@ unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED, static int parse_patch_config(const char *name, const char *type OVS_UNUSED, - const struct shash *args, struct ofpbuf *options) + const struct smap *args, struct ofpbuf *options) { const char *peer; - peer = shash_find_data(args, "peer"); + peer = smap_get(args, "peer"); if (!peer) { VLOG_ERR("%s: patch type requires valid 'peer' argument", name); return EINVAL; } - if (shash_count(args) > 1) { + if (smap_count(args) > 1) { VLOG_ERR("%s: patch type takes only a 'peer' argument", name); return EINVAL; } @@ -873,7 +872,7 @@ parse_patch_config(const char *name, const char *type OVS_UNUSED, static int unparse_patch_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED, const struct nlattr *options, size_t options_len, - struct shash *args) + struct smap *args) { static const struct nl_policy ovs_patch_policy[] = { [OVS_PATCH_ATTR_PEER] = { .type = NL_A_STRING, diff --git a/lib/netdev.c b/lib/netdev.c index e4e7ab13..1b76785a 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -37,6 +37,7 @@ #include "packets.h" #include "poll-loop.h" #include "shash.h" +#include "smap.h" #include "sset.h" #include "svec.h" #include "vlog.h" @@ -243,15 +244,15 @@ netdev_open(const char *name, const char *type, struct netdev **netdevp) /* Reconfigures the device 'netdev' with 'args'. 'args' may be empty * or NULL if none are needed. */ int -netdev_set_config(struct netdev *netdev, const struct shash *args) +netdev_set_config(struct netdev *netdev, const struct smap *args) { struct netdev_dev *netdev_dev = netdev_get_dev(netdev); if (netdev_dev->netdev_class->set_config) { - struct shash no_args = SHASH_INITIALIZER(&no_args); + struct smap no_args = SMAP_INITIALIZER(&no_args); return netdev_dev->netdev_class->set_config(netdev_dev, args ? args : &no_args); - } else if (args && !shash_is_empty(args)) { + } else if (args && !smap_is_empty(args)) { VLOG_WARN("%s: arguments provided to device that is not configurable", netdev_get_name(netdev)); } @@ -260,23 +261,23 @@ netdev_set_config(struct netdev *netdev, const struct shash *args) } /* Returns the current configuration for 'netdev' in 'args'. The caller must - * have already initialized 'args' with shash_init(). Returns 0 on success, in + * have already initialized 'args' with smap_init(). Returns 0 on success, in * which case 'args' will be filled with 'netdev''s configuration. On failure * returns a positive errno value, in which case 'args' will be empty. * * The caller owns 'args' and its contents and must eventually free them with - * shash_destroy_free_data(). */ + * smap_destroy(). */ int -netdev_get_config(const struct netdev *netdev, struct shash *args) +netdev_get_config(const struct netdev *netdev, struct smap *args) { struct netdev_dev *netdev_dev = netdev_get_dev(netdev); int error; - shash_clear_free_data(args); + smap_clear(args); if (netdev_dev->netdev_class->get_config) { error = netdev_dev->netdev_class->get_config(netdev_dev, args); if (error) { - shash_clear_free_data(args); + smap_clear(args); } } else { error = 0; @@ -759,18 +760,18 @@ netdev_get_next_hop(const struct netdev *netdev, return error; } -/* Populates 'sh' with status information. +/* Populates 'smap' with status information. * - * Populates 'sh' with 'netdev' specific status information. This information - * may be used to populate the status column of the Interface table as defined - * in ovs-vswitchd.conf.db(5). */ + * Populates 'smap' with 'netdev' specific status information. This + * information may be used to populate the status column of the Interface table + * as defined in ovs-vswitchd.conf.db(5). */ int -netdev_get_drv_info(const struct netdev *netdev, struct shash *sh) +netdev_get_drv_info(const struct netdev *netdev, struct smap *smap) { struct netdev_dev *dev = netdev_get_dev(netdev); return (dev->netdev_class->get_drv_info - ? dev->netdev_class->get_drv_info(netdev, sh) + ? dev->netdev_class->get_drv_info(netdev, smap) : EOPNOTSUPP); } @@ -1065,10 +1066,9 @@ netdev_get_n_queues(const struct netdev *netdev, * * A '*typep' of "" indicates that QoS is currently disabled on 'netdev'. * - * The caller must initialize 'details' as an empty shash (e.g. with - * shash_init()) before calling this function. The caller must free 'details', - * including 'data' members, when it is no longer needed (e.g. with - * shash_destroy_free_data()). + * The caller must initialize 'details' as an empty smap (e.g. with + * smap_init()) before calling this function. The caller must free 'details' + * when it is no longer needed (e.g. with smap_destroy()). * * The caller must not modify or free '*typep'. * @@ -1078,7 +1078,7 @@ netdev_get_n_queues(const struct netdev *netdev, * vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)). */ int netdev_get_qos(const struct netdev *netdev, - const char **typep, struct shash *details) + const char **typep, struct smap *details) { const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class; int retval; @@ -1087,7 +1087,7 @@ netdev_get_qos(const struct netdev *netdev, retval = class->get_qos(netdev, typep, details); if (retval) { *typep = NULL; - shash_clear_free_data(details); + smap_clear(details); } return retval; } else { @@ -1117,7 +1117,7 @@ netdev_get_qos(const struct netdev *netdev, * details. */ int netdev_set_qos(struct netdev *netdev, - const char *type, const struct shash *details) + const char *type, const struct smap *details) { const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class; @@ -1127,7 +1127,7 @@ netdev_set_qos(struct netdev *netdev, if (class->set_qos) { if (!details) { - static struct shash empty = SHASH_INITIALIZER(&empty); + static struct smap empty = SMAP_INITIALIZER(&empty); details = ∅ } return class->set_qos(netdev, type, details); @@ -1147,12 +1147,12 @@ netdev_set_qos(struct netdev *netdev, * given 'type' in the "other_config" column in the "Queue" table in * vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)). * - * The caller must initialize 'details' (e.g. with shash_init()) before calling - * this function. The caller must free 'details', including 'data' members, - * when it is no longer needed (e.g. with shash_destroy_free_data()). */ + * The caller must initialize 'details' (e.g. with smap_init()) before calling + * this function. The caller must free 'details' when it is no longer needed + * (e.g. with smap_destroy()). */ int netdev_get_queue(const struct netdev *netdev, - unsigned int queue_id, struct shash *details) + unsigned int queue_id, struct smap *details) { const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class; int retval; @@ -1161,7 +1161,7 @@ netdev_get_queue(const struct netdev *netdev, ? class->get_queue(netdev, queue_id, details) : EOPNOTSUPP); if (retval) { - shash_clear_free_data(details); + smap_clear(details); } return retval; } @@ -1180,7 +1180,7 @@ netdev_get_queue(const struct netdev *netdev, * it. */ int netdev_set_queue(struct netdev *netdev, - unsigned int queue_id, const struct shash *details) + unsigned int queue_id, const struct smap *details) { const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class; return (class->set_queue diff --git a/lib/netdev.h b/lib/netdev.h index 4b86c21e..d2cc8b5d 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -35,7 +35,7 @@ extern "C" { struct ofpbuf; struct in_addr; struct in6_addr; -struct shash; +struct smap; struct sset; enum netdev_flags { @@ -93,8 +93,8 @@ bool netdev_is_open(const char *name); void netdev_parse_name(const char *netdev_name, char **name, char **type); /* Options. */ -int netdev_set_config(struct netdev *, const struct shash *args); -int netdev_get_config(const struct netdev *, struct shash *); +int netdev_set_config(struct netdev *, const struct smap *args); +int netdev_get_config(const struct netdev *, struct smap *); /* Basic properties. */ const char *netdev_get_name(const struct netdev *); @@ -159,7 +159,7 @@ int netdev_get_in6(const struct netdev *, struct in6_addr *); int netdev_add_router(struct netdev *, struct in_addr router); int netdev_get_next_hop(const struct netdev *, const struct in_addr *host, struct in_addr *next_hop, char **); -int netdev_get_drv_info(const struct netdev *, struct shash *sh); +int netdev_get_drv_info(const struct netdev *, struct smap *); int netdev_arp_lookup(const struct netdev *, ovs_be32 ip, uint8_t mac[6]); int netdev_get_flags(const struct netdev *, enum netdev_flags *); @@ -195,20 +195,20 @@ int netdev_get_n_queues(const struct netdev *, const char *type, unsigned int *n_queuesp); int netdev_get_qos(const struct netdev *, - const char **typep, struct shash *details); + const char **typep, struct smap *details); int netdev_set_qos(struct netdev *, - const char *type, const struct shash *details); + const char *type, const struct smap *details); int netdev_get_queue(const struct netdev *, - unsigned int queue_id, struct shash *details); + unsigned int queue_id, struct smap *details); int netdev_set_queue(struct netdev *, - unsigned int queue_id, const struct shash *details); + unsigned int queue_id, const struct smap *details); int netdev_delete_queue(struct netdev *, unsigned int queue_id); int netdev_get_queue_stats(const struct netdev *, unsigned int queue_id, struct netdev_queue_stats *); typedef void netdev_dump_queues_cb(unsigned int queue_id, - const struct shash *details, void *aux); + const struct smap *details, void *aux); int netdev_dump_queues(const struct netdev *, netdev_dump_queues_cb *, void *aux); diff --git a/lib/shash.c b/lib/shash.c index af917b33..74801763 100644 --- a/lib/shash.c +++ b/lib/shash.c @@ -313,58 +313,3 @@ shash_random_node(struct shash *sh) { return CONTAINER_OF(hmap_random_node(&sh->map), struct shash_node, node); } - -/* String-to-string maps (smaps). */ - -/* Frees 'smap', including its keys and string values. */ -void -smap_destroy(struct shash *smap) -{ - shash_destroy_free_data(smap); -} - -/* Returns true if string-to-string maps 'a' and 'b' contain the same keys and - * values, false otherwise. */ -bool -smap_equal(const struct shash *a, const struct shash *b) -{ - struct shash_node *a_node; - - if (shash_count(a) != shash_count(b)) { - return false; - } - - SHASH_FOR_EACH (a_node, a) { - uint32_t hash = a_node->node.hash; - size_t len = strlen(a_node->name); - struct shash_node *b_node = shash_find__(b, a_node->name, len, hash); - if (!b_node || strcmp(a_node->data, b_node->data)) { - return false; - } - } - - return true; -} - -/* Initializes 'dst' as a clone of 'src'. */ -void -smap_clone(struct shash *dst, const struct shash *src) -{ - struct shash_node *node; - - shash_init(dst); - SHASH_FOR_EACH (node, src) { - shash_add_nocopy__(dst, xstrdup(node->name), xstrdup(node->data), - node->node.hash); - } -} - -/* Adds 'key' with string 'value' to 'smap', making a copy of each. - * - * It is the caller's responsibility to avoid duplicate names, if that is - * desirable. */ -void -smap_add(struct shash *smap, const char *key, const char *value) -{ - shash_add(smap, key, xstrdup(value)); -} diff --git a/lib/shash.h b/lib/shash.h index decfcbc1..97d36bad 100644 --- a/lib/shash.h +++ b/lib/shash.h @@ -67,12 +67,6 @@ const struct shash_node **shash_sort(const struct shash *); bool shash_equal_keys(const struct shash *, const struct shash *); struct shash_node *shash_random_node(struct shash *); -/* Working with "smaps": shashes used as string-to-string maps. */ -void smap_destroy(struct shash *); -bool smap_equal(const struct shash *, const struct shash *); -void smap_clone(struct shash *, const struct shash *); -void smap_add(struct shash *, const char *key, const char *value); - #ifdef __cplusplus } #endif diff --git a/lib/smap.c b/lib/smap.c new file mode 100644 index 00000000..642804ee --- /dev/null +++ b/lib/smap.c @@ -0,0 +1,269 @@ +/* Copyright (c) 2012 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include +#include "smap.h" + +#include + +#include "hash.h" + +static struct smap_node *smap_add__(struct smap *, char *, void *, + size_t hash); +static struct smap_node *smap_find__(const struct smap *, const char *key, + size_t key_len, size_t hash); +static int compare_nodes_by_key(const void *, const void *); + +/* Public Functions. */ + +void +smap_init(struct smap *smap) +{ + hmap_init(&smap->map); +} + +void +smap_destroy(struct smap *smap) +{ + if (smap) { + smap_clear(smap); + hmap_destroy(&smap->map); + } +} + +/* Adds 'key' paired with 'value' to 'smap'. It is the caller's responsibility + * to avoid duplicate keys if desirable. */ +struct smap_node * +smap_add(struct smap *smap, const char *key, const char *value) +{ + size_t key_len = strlen(key); + return smap_add__(smap, xmemdup0(key, key_len), xstrdup(value), + hash_bytes(key, key_len, 0)); +} + +/* Attempts to add 'key' to 'smap' associated with 'value'. If 'key' already + * exists in 'smap', does nothing and returns false. Otherwise, performs the + * addition and returns true. */ +bool +smap_add_once(struct smap *smap, const char *key, const char *value) +{ + if (!smap_get(smap, key)) { + smap_add(smap, key, value); + return true; + } else { + return false; + } +} + +/* Adds 'key' paired with a value derived from 'format' (similar to printf). + * It is the caller's responsibility to avoid duplicate keys if desirable. */ +void +smap_add_format(struct smap *smap, const char *key, const char *format, ...) +{ + size_t key_len; + va_list args; + char *value; + + va_start(args, format); + value = xvasprintf(format, args); + va_end(args); + + key_len = strlen(key); + smap_add__(smap, xmemdup0(key, key_len), value, + hash_bytes(key, key_len, 0)); +} + +/* Searches for 'key' in 'smap'. If it does not already exists, adds it. + * Otherwise, changes its value to 'value'. */ +void +smap_replace(struct smap *smap, const char *key, const char *value) +{ + size_t key_len = strlen(key); + size_t hash = hash_bytes(key, key_len, 0); + + struct smap_node *node; + + node = smap_find__(smap, key, key_len, hash); + if (node) { + free(node->value); + node->value = xstrdup(value); + } else { + smap_add__(smap, xmemdup0(key, key_len), xstrdup(value), hash); + } +} + +/* If 'key' is in 'smap', removes it. Otherwise does nothing. */ +void +smap_remove(struct smap *smap, const char *key) +{ + struct smap_node *node = smap_get_node(smap, key); + + if (node) { + smap_remove_node(smap, node); + } +} + +/* Removes 'node' from 'smap'. */ +void +smap_remove_node(struct smap *smap, struct smap_node *node) +{ + hmap_remove(&smap->map, &node->node); + free(node->key); + free(node->value); + free(node); +} + +/* Removes all key-value pairs from 'smap'. */ +void +smap_clear(struct smap *smap) +{ + struct smap_node *node, *next; + + SMAP_FOR_EACH_SAFE (node, next, smap) { + smap_remove_node(smap, node); + } +} + +/* Returns the value associated with 'key' in 'smap', or NULL. */ +const char * +smap_get(const struct smap *smap, const char *key) +{ + struct smap_node *node = smap_get_node(smap, key); + return node ? node->value : NULL; +} + +/* Returns the node associated with 'key' in 'smap', or NULL. */ +struct smap_node * +smap_get_node(const struct smap *smap, const char *key) +{ + size_t key_len = strlen(key); + return smap_find__(smap, key, key_len, hash_bytes(key, key_len, 0)); +} + +/* Gets the value associated with 'key' in 'smap' and converts it to a boolean. + * If 'key' is not in 'smap', or its value is neither "true" nor "false", + * returns 'def'. */ +bool +smap_get_bool(const struct smap *smap, const char *key, bool def) +{ + const char *value = smap_get(smap, key); + + if (!value) { + return def; + } + + if (def) { + return strcasecmp("false", value) != 0; + } else { + return !strcasecmp("true", value); + } +} + +/* Gets the value associated with 'key' in 'smap' and converts it to an int + * using atoi(). If 'key' is not in 'smap', returns 'def'. */ +int +smap_get_int(const struct smap *smap, const char *key, int def) +{ + const char *value = smap_get(smap, key); + + return value ? atoi(value) : def; +} + +/* Returns true of there are no elements in 'smap'. */ +bool +smap_is_empty(const struct smap *smap) +{ + return hmap_is_empty(&smap->map); +} + +/* Returns the number of elements in 'smap'. */ +size_t +smap_count(const struct smap *smap) +{ + return hmap_count(&smap->map); +} + +/* Initializes 'dst' as a clone of 'src. */ +void +smap_clone(struct smap *dst, struct smap *src) +{ + struct smap_node *node; + + smap_init(dst); + SMAP_FOR_EACH (node, src) { + smap_add__(dst, xstrdup(node->key), xstrdup(node->value), + node->node.hash); + } +} + +/* Returns an array of nodes sorted on key or NULL if 'smap' is empty. The + * caller is responsible for freeing this array. */ +const struct smap_node ** +smap_sort(const struct smap *smap) +{ + if (smap_is_empty(smap)) { + return NULL; + } else { + const struct smap_node **nodes; + struct smap_node *node; + size_t i, n; + + n = smap_count(smap); + nodes = xmalloc(n * sizeof *nodes); + i = 0; + SMAP_FOR_EACH (node, smap) { + nodes[i++] = node; + } + assert(i == n); + + qsort(nodes, n, sizeof *nodes, compare_nodes_by_key); + + return nodes; + } +} + +/* Private Helpers. */ + +static struct smap_node * +smap_add__(struct smap *smap, char *key, void *value, size_t hash) +{ + struct smap_node *node = xmalloc(sizeof *node); + node->key = key; + node->value = value; + hmap_insert(&smap->map, &node->node, hash); + return node; +} + +static struct smap_node * +smap_find__(const struct smap *smap, const char *key, size_t key_len, + size_t hash) +{ + struct smap_node *node; + + HMAP_FOR_EACH_WITH_HASH (node, node, hash, &smap->map) { + if (!strncmp(node->key, key, key_len) && !node->key[key_len]) { + return node; + } + } + + return NULL; +} + +static int +compare_nodes_by_key(const void *a_, const void *b_) +{ + const struct smap_node *const *a = a_; + const struct smap_node *const *b = b_; + return strcmp((*a)->key, (*b)->key); +} diff --git a/lib/smap.h b/lib/smap.h new file mode 100644 index 00000000..993d0b24 --- /dev/null +++ b/lib/smap.h @@ -0,0 +1,63 @@ +/* Copyright (c) 2012 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#ifndef SMAP_H +#define SMAP_H 1 + +#include "hmap.h" + +/* A map from string to string. */ +struct smap { + struct hmap map; /* Contains "struct smap_node"s. */ +}; + +struct smap_node { + struct hmap_node node; /* In struct smap's 'map' hmap. */ + char *key; + char *value; +}; + +#define SMAP_INITIALIZER(SMAP) { HMAP_INITIALIZER(&(SMAP)->map) } + +#define SMAP_FOR_EACH(SMAP_NODE, SMAP) \ + HMAP_FOR_EACH (SMAP_NODE, node, &(SMAP)->map) + +#define SMAP_FOR_EACH_SAFE(SMAP_NODE, NEXT, SMAP) \ + HMAP_FOR_EACH_SAFE (SMAP_NODE, NEXT, node, &(SMAP)->map) + +void smap_init(struct smap *); +void smap_destroy(struct smap *); + +struct smap_node *smap_add(struct smap *, const char *, const char *); +bool smap_add_once(struct smap *, const char *, const char *); +void smap_add_format(struct smap *, const char *key, const char *, ...) + PRINTF_FORMAT(3, 4); +void smap_replace(struct smap *, const char *, const char *); + +void smap_remove(struct smap *, const char *); +void smap_remove_node(struct smap *smap, struct smap_node *); +void smap_clear(struct smap *); + +const char *smap_get(const struct smap *, const char *); +struct smap_node *smap_get_node(const struct smap *, const char *); +bool smap_get_bool(const struct smap *smap, const char *key, bool def); +int smap_get_int(const struct smap *smap, const char *key, int def); + +bool smap_is_empty(const struct smap *); +size_t smap_count(const struct smap *); + +void smap_clone(struct smap *dst, struct smap *src); +const struct smap_node **smap_sort(const struct smap *); + +#endif /* smap.h */ diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c index 6cb05b88..950e8f41 100644 --- a/utilities/ovs-dpctl.c +++ b/utilities/ovs-dpctl.c @@ -44,6 +44,7 @@ #include "packets.h" #include "shash.h" #include "simap.h" +#include "smap.h" #include "sset.h" #include "timeval.h" #include "util.h" @@ -246,7 +247,7 @@ do_add_if(int argc OVS_UNUSED, char *argv[]) const char *name, *type; char *save_ptr = NULL; struct netdev *netdev = NULL; - struct shash args; + struct smap args; char *option; int error; @@ -259,7 +260,7 @@ do_add_if(int argc OVS_UNUSED, char *argv[]) continue; } - shash_init(&args); + smap_init(&args); while ((option = strtok_r(NULL, ",", &save_ptr)) != NULL) { char *save_ptr_2 = NULL; char *key, *value; @@ -272,7 +273,7 @@ do_add_if(int argc OVS_UNUSED, char *argv[]) if (!strcmp(key, "type")) { type = value; - } else if (!shash_add_once(&args, key, value)) { + } else if (!smap_add_once(&args, key, value)) { ovs_error(0, "duplicate \"%s\" option", key); } } @@ -323,7 +324,7 @@ do_set_if(int argc, char *argv[]) char *save_ptr = NULL; char *type = NULL; const char *name; - struct shash args; + struct smap args; char *option; int error; @@ -350,7 +351,7 @@ do_set_if(int argc, char *argv[]) goto next; } - shash_init(&args); + smap_init(&args); error = netdev_get_config(netdev, &args); if (error) { ovs_error(error, "%s: failed to fetch configuration", name); @@ -375,9 +376,9 @@ do_set_if(int argc, char *argv[]) failure = true; } } else if (value[0] == '\0') { - free(shash_find_and_delete(&args, key)); + smap_remove(&args, key); } else { - free(shash_replace(&args, key, xstrdup(value))); + smap_replace(&args, key, value); } } @@ -500,26 +501,26 @@ show_dpif(struct dpif *dpif) error = netdev_open(dpif_port.name, dpif_port.type, &netdev); if (!error) { - struct shash config; + struct smap config; - shash_init(&config); + smap_init(&config); error = netdev_get_config(netdev, &config); if (!error) { - const struct shash_node **nodes; + const struct smap_node **nodes; size_t i; - nodes = shash_sort(&config); - for (i = 0; i < shash_count(&config); i++) { - const struct shash_node *node = nodes[i]; - printf("%c %s=%s", i ? ',' : ':', - node->name, (char *) node->data); + nodes = smap_sort(&config); + for (i = 0; i < smap_count(&config); i++) { + const struct smap_node *node = nodes[i]; + printf("%c %s=%s", i ? ',' : ':', node->key, + node->value); } free(nodes); } else { printf(", could not retrieve configuration (%s)", strerror(error)); } - shash_destroy_free_data(&config); + smap_destroy(&config); netdev_close(netdev); } else { diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c index bd472580..830132c3 100644 --- a/utilities/ovs-vsctl.c +++ b/utilities/ovs-vsctl.c @@ -3936,7 +3936,7 @@ do_vsctl(const char *args, struct vsctl_command *commands, size_t n_commands, table_destroy(c->table); free(c->table); - smap_destroy(&c->options); + shash_destroy_free_data(&c->options); } free(commands); diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index fe92d6fb..53454db4 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -41,6 +41,7 @@ #include "poll-loop.h" #include "sha1.h" #include "shash.h" +#include "smap.h" #include "socket-util.h" #include "stream.h" #include "stream-ssl.h" @@ -245,10 +246,10 @@ static void iface_refresh_cfm_stats(struct iface *); static void iface_refresh_stats(struct iface *); static void iface_refresh_status(struct iface *); static bool iface_is_synthetic(const struct iface *); -static void shash_from_ovs_idl_map(char **keys, char **values, size_t n, - struct shash *); -static void shash_to_ovs_idl_map(struct shash *, - char ***keys, char ***values, size_t *n); +static void smap_from_ovs_idl_map(char **keys, char **values, size_t n, + struct smap *); +static void smap_to_ovs_idl_map(struct smap *, + char ***keys, char ***values, size_t *n); /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.) * @@ -1150,15 +1151,15 @@ static int iface_set_netdev_config(const struct ovsrec_interface *iface_cfg, struct netdev *netdev) { - struct shash args; + struct smap args; int error; - shash_init(&args); - shash_from_ovs_idl_map(iface_cfg->key_options, - iface_cfg->value_options, - iface_cfg->n_options, &args); + smap_init(&args); + smap_from_ovs_idl_map(iface_cfg->key_options, + iface_cfg->value_options, + iface_cfg->n_options, &args); error = netdev_set_config(netdev, &args); - shash_destroy(&args); + smap_destroy(&args); if (error) { VLOG_WARN("could not configure network device %s (%s)", @@ -1650,7 +1651,7 @@ dpid_from_hash(const void *data, size_t n) static void iface_refresh_status(struct iface *iface) { - struct shash sh; + struct smap smap; enum netdev_features current; enum netdev_flags flags; @@ -1663,13 +1664,13 @@ iface_refresh_status(struct iface *iface) return; } - shash_init(&sh); + smap_init(&smap); - if (!netdev_get_drv_info(iface->netdev, &sh)) { + if (!netdev_get_drv_info(iface->netdev, &smap)) { size_t n; char **keys, **values; - shash_to_ovs_idl_map(&sh, &keys, &values, &n); + smap_to_ovs_idl_map(&smap, &keys, &values, &n); ovsrec_interface_set_status(iface->cfg, keys, values, n); free(keys); @@ -1678,7 +1679,7 @@ iface_refresh_status(struct iface *iface) ovsrec_interface_set_status(iface->cfg, NULL, NULL, 0); } - shash_destroy_free_data(&sh); + smap_destroy(&smap); error = netdev_get_flags(iface->netdev, &flags); if (!error) { @@ -2250,14 +2251,14 @@ struct qos_unixctl_show_cbdata { static void qos_unixctl_show_cb(unsigned int queue_id, - const struct shash *details, + const struct smap *details, void *aux) { struct qos_unixctl_show_cbdata *data = aux; struct ds *ds = data->ds; struct iface *iface = data->iface; struct netdev_queue_stats stats; - struct shash_node *node; + struct smap_node *node; int error; ds_put_cstr(ds, "\n"); @@ -2267,8 +2268,8 @@ qos_unixctl_show_cb(unsigned int queue_id, ds_put_cstr(ds, "Default:\n"); } - SHASH_FOR_EACH (node, details) { - ds_put_format(ds, "\t%s: %s\n", node->name, (char *)node->data); + SMAP_FOR_EACH (node, details) { + ds_put_format(ds, "\t%s: %s\n", node->key, node->value); } error = netdev_get_queue_stats(iface->netdev, queue_id, &stats); @@ -2295,10 +2296,10 @@ qos_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; - struct shash sh = SHASH_INITIALIZER(&sh); + struct smap smap = SMAP_INITIALIZER(&smap); struct iface *iface; const char *type; - struct shash_node *node; + struct smap_node *node; struct qos_unixctl_show_cbdata data; int error; @@ -2308,13 +2309,13 @@ qos_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, return; } - netdev_get_qos(iface->netdev, &type, &sh); + netdev_get_qos(iface->netdev, &type, &smap); if (*type != '\0') { ds_put_format(&ds, "QoS: %s %s\n", iface->name, type); - SHASH_FOR_EACH (node, &sh) { - ds_put_format(&ds, "%s: %s\n", node->name, (char *)node->data); + SMAP_FOR_EACH (node, &smap) { + ds_put_format(&ds, "%s: %s\n", node->key, node->value); } data.ds = &ds; @@ -2330,7 +2331,7 @@ qos_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, unixctl_command_reply_error(conn, ds_cstr(&ds)); } - shash_destroy_free_data(&sh); + smap_destroy(&smap); ds_destroy(&ds); } @@ -3273,46 +3274,42 @@ iface_clear_db_record(const struct ovsrec_interface *if_cfg) } } -/* Adds the 'n' key-value pairs in 'keys' in 'values' to 'shash'. - * - * The value strings in '*shash' are taken directly from values[], not copied, - * so the caller should not modify or free them. */ +/* Adds the 'n' key-value pairs in 'keys' in 'values' to 'shash'. */ static void -shash_from_ovs_idl_map(char **keys, char **values, size_t n, - struct shash *shash) +smap_from_ovs_idl_map(char **keys, char **values, size_t n, struct smap *smap) { size_t i; - shash_init(shash); + smap_init(smap); for (i = 0; i < n; i++) { - shash_add(shash, keys[i], values[i]); + smap_add(smap, keys[i], values[i]); } } /* Creates 'keys' and 'values' arrays from 'shash'. * * Sets 'keys' and 'values' to heap allocated arrays representing the key-value - * pairs in 'shash'. The caller takes ownership of 'keys' and 'values'. They + * pairs in 'smap'. The caller takes ownership of 'keys' and 'values'. They * are populated with with strings taken directly from 'shash' and thus have * the same ownership of the key-value pairs in shash. */ static void -shash_to_ovs_idl_map(struct shash *shash, - char ***keys, char ***values, size_t *n) +smap_to_ovs_idl_map(struct smap *smap, + char ***keys, char ***values, size_t *n) { size_t i, count; char **k, **v; - struct shash_node *sn; + struct smap_node *sn; - count = shash_count(shash); + count = smap_count(smap); k = xmalloc(count * sizeof *k); v = xmalloc(count * sizeof *v); i = 0; - SHASH_FOR_EACH(sn, shash) { - k[i] = sn->name; - v[i] = sn->data; + SMAP_FOR_EACH(sn, smap) { + k[i] = sn->key; + v[i] = sn->value; i++; } @@ -3337,7 +3334,7 @@ queue_ids_include(const struct ovsdb_datum *queues, int64_t target) static void iface_delete_queues(unsigned int queue_id, - const struct shash *details OVS_UNUSED, void *cbdata_) + const struct smap *details OVS_UNUSED, void *cbdata_) { struct iface_delete_queues_cbdata *cbdata = cbdata_; @@ -3357,15 +3354,15 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos) netdev_set_qos(iface->netdev, NULL, NULL); } else { struct iface_delete_queues_cbdata cbdata; - struct shash details; + struct smap details; bool queue_zero; size_t i; /* Configure top-level Qos for 'iface'. */ - shash_from_ovs_idl_map(qos->key_other_config, qos->value_other_config, - qos->n_other_config, &details); + smap_from_ovs_idl_map(qos->key_other_config, qos->value_other_config, + qos->n_other_config, &details); netdev_set_qos(iface->netdev, qos->type, &details); - shash_destroy(&details); + smap_destroy(&details); /* Deconfigure queues that were deleted. */ cbdata.netdev = iface->netdev; @@ -3392,16 +3389,16 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos) port_queue->dscp = queue->dscp[0]; } - shash_from_ovs_idl_map(queue->key_other_config, - queue->value_other_config, - queue->n_other_config, &details); + smap_from_ovs_idl_map(queue->key_other_config, + queue->value_other_config, + queue->n_other_config, &details); netdev_set_queue(iface->netdev, queue_id, &details); - shash_destroy(&details); + smap_destroy(&details); } if (!queue_zero) { - shash_init(&details); + smap_init(&details); netdev_set_queue(iface->netdev, 0, &details); - shash_destroy(&details); + smap_destroy(&details); } }