X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fnetdev-linux.c;h=412a92debf0d0758ffcdb2fe0e7fa70c1ee0e7d3;hb=543a550837f40e39c9f6f110e927b4c230c2d77c;hp=5be51c8dc4a641521ba1bb231584bc133eaa08a6;hpb=44445cac40bec2b2f12e8baf7bbb7fcf32fcbb42;p=openvswitch diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 5be51c8d..412a92de 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks. + * Copyright (c) 2009, 2010, 2011, 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. @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -78,7 +77,8 @@ COVERAGE_DEFINE(netdev_arp_lookup); COVERAGE_DEFINE(netdev_get_ifindex); COVERAGE_DEFINE(netdev_get_hwaddr); COVERAGE_DEFINE(netdev_set_hwaddr); -COVERAGE_DEFINE(netdev_ethtool); +COVERAGE_DEFINE(netdev_get_ethtool); +COVERAGE_DEFINE(netdev_set_ethtool); /* These were introduced in Linux 2.6.14, so they might be missing if we have @@ -117,6 +117,7 @@ enum { VALID_POLICING = 1 << 5, VALID_VPORT_STAT_ERROR = 1 << 6, VALID_DRVINFO = 1 << 7, + VALID_FEATURES = 1 << 8, }; struct tap_state { @@ -181,7 +182,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 +222,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 +233,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 +249,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 +263,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'. @@ -378,6 +379,14 @@ struct netdev_dev_linux { 0 or an errno value. */ int netdev_mtu_error; /* Cached error code from SIOCGIFMTU or SIOCSIFMTU. */ int ether_addr_error; /* Cached error code from set/get etheraddr. */ + int netdev_policing_error; /* Cached error code from set policing. */ + int get_features_error; /* Cached error code from ETHTOOL_GSET. */ + int get_ifindex_error; /* Cached error code from SIOCGIFINDEX. */ + + enum netdev_features current; /* Cached from ETHTOOL_GSET. */ + enum netdev_features advertised; /* Cached from ETHTOOL_GSET. */ + enum netdev_features supported; /* Cached from ETHTOOL_GSET. */ + enum netdev_features peer; /* Cached from ETHTOOL_GSET. */ struct ethtool_drvinfo drvinfo; /* Cached from ETHTOOL_GDRVINFO. */ struct tc *tc; @@ -498,6 +507,7 @@ netdev_linux_get_drvinfo(struct netdev_dev_linux *netdev_dev) return 0; } + COVERAGE_INC(netdev_get_ethtool); memset(&netdev_dev->drvinfo, 0, sizeof netdev_dev->drvinfo); error = netdev_linux_do_ethtool(netdev_dev->netdev_dev.name, (struct ethtool_cmd *)&netdev_dev->drvinfo, @@ -535,6 +545,7 @@ netdev_dev_linux_update(struct netdev_dev_linux *dev, /* Keep drv-info */ netdev_dev_linux_changed(dev, change->ifi_flags, VALID_DRVINFO); + /* Update netdev from rtnl-change msg. */ if (change->mtu) { dev->mtu = change->mtu; dev->cache_valid |= VALID_MTU; @@ -547,6 +558,10 @@ netdev_dev_linux_update(struct netdev_dev_linux *dev, dev->ether_addr_error = 0; } + dev->ifindex = change->ifi_index; + dev->cache_valid |= VALID_IFINDEX; + dev->get_ifindex_error = 0; + } else { netdev_dev_linux_changed(dev, change->ifi_flags, 0); } @@ -940,7 +955,7 @@ netdev_linux_send(struct netdev *netdev_, const void *data, size_t size) sll.sll_family = AF_PACKET; sll.sll_ifindex = ifindex; - iov.iov_base = (void *) data; + iov.iov_base = CONST_CAST(void *, data); iov.iov_len = size; msg.msg_name = &sll; @@ -1190,6 +1205,7 @@ netdev_linux_get_miimon(const char *name, bool *miimon) VLOG_DBG_RL(&rl, "%s: failed to query MII, falling back to ethtool", name); + COVERAGE_INC(netdev_get_ethtool); memset(&ecmd, 0, sizeof ecmd); error = netdev_linux_do_ethtool(name, &ecmd, ETHTOOL_GLINK, "ETHTOOL_GLINK"); @@ -1472,140 +1488,164 @@ netdev_internal_get_stats(const struct netdev *netdev_, return netdev_dev->vport_stats_error; } -/* Stores the features supported by 'netdev' into each of '*current', - * '*advertised', '*supported', and '*peer' that are non-null. Each value is a - * bitmap of NETDEV_* bits. Returns 0 if successful, otherwise a positive - * errno value. */ -static int -netdev_linux_get_features(const struct netdev *netdev, - enum netdev_features *current, - enum netdev_features *advertised, - enum netdev_features *supported, - enum netdev_features *peer) +static void +netdev_linux_read_features(struct netdev_dev_linux *netdev_dev) { struct ethtool_cmd ecmd; uint32_t speed; int error; + if (netdev_dev->cache_valid & VALID_FEATURES) { + return; + } + + COVERAGE_INC(netdev_get_ethtool); memset(&ecmd, 0, sizeof ecmd); - error = netdev_linux_do_ethtool(netdev_get_name(netdev), &ecmd, + error = netdev_linux_do_ethtool(netdev_dev->netdev_dev.name, &ecmd, ETHTOOL_GSET, "ETHTOOL_GSET"); if (error) { - return error; + goto out; } /* Supported features. */ - *supported = 0; + netdev_dev->supported = 0; if (ecmd.supported & SUPPORTED_10baseT_Half) { - *supported |= NETDEV_F_10MB_HD; + netdev_dev->supported |= NETDEV_F_10MB_HD; } if (ecmd.supported & SUPPORTED_10baseT_Full) { - *supported |= NETDEV_F_10MB_FD; + netdev_dev->supported |= NETDEV_F_10MB_FD; } if (ecmd.supported & SUPPORTED_100baseT_Half) { - *supported |= NETDEV_F_100MB_HD; + netdev_dev->supported |= NETDEV_F_100MB_HD; } if (ecmd.supported & SUPPORTED_100baseT_Full) { - *supported |= NETDEV_F_100MB_FD; + netdev_dev->supported |= NETDEV_F_100MB_FD; } if (ecmd.supported & SUPPORTED_1000baseT_Half) { - *supported |= NETDEV_F_1GB_HD; + netdev_dev->supported |= NETDEV_F_1GB_HD; } if (ecmd.supported & SUPPORTED_1000baseT_Full) { - *supported |= NETDEV_F_1GB_FD; + netdev_dev->supported |= NETDEV_F_1GB_FD; } if (ecmd.supported & SUPPORTED_10000baseT_Full) { - *supported |= NETDEV_F_10GB_FD; + netdev_dev->supported |= NETDEV_F_10GB_FD; } if (ecmd.supported & SUPPORTED_TP) { - *supported |= NETDEV_F_COPPER; + netdev_dev->supported |= NETDEV_F_COPPER; } if (ecmd.supported & SUPPORTED_FIBRE) { - *supported |= NETDEV_F_FIBER; + netdev_dev->supported |= NETDEV_F_FIBER; } if (ecmd.supported & SUPPORTED_Autoneg) { - *supported |= NETDEV_F_AUTONEG; + netdev_dev->supported |= NETDEV_F_AUTONEG; } if (ecmd.supported & SUPPORTED_Pause) { - *supported |= NETDEV_F_PAUSE; + netdev_dev->supported |= NETDEV_F_PAUSE; } if (ecmd.supported & SUPPORTED_Asym_Pause) { - *supported |= NETDEV_F_PAUSE_ASYM; + netdev_dev->supported |= NETDEV_F_PAUSE_ASYM; } /* Advertised features. */ - *advertised = 0; + netdev_dev->advertised = 0; if (ecmd.advertising & ADVERTISED_10baseT_Half) { - *advertised |= NETDEV_F_10MB_HD; + netdev_dev->advertised |= NETDEV_F_10MB_HD; } if (ecmd.advertising & ADVERTISED_10baseT_Full) { - *advertised |= NETDEV_F_10MB_FD; + netdev_dev->advertised |= NETDEV_F_10MB_FD; } if (ecmd.advertising & ADVERTISED_100baseT_Half) { - *advertised |= NETDEV_F_100MB_HD; + netdev_dev->advertised |= NETDEV_F_100MB_HD; } if (ecmd.advertising & ADVERTISED_100baseT_Full) { - *advertised |= NETDEV_F_100MB_FD; + netdev_dev->advertised |= NETDEV_F_100MB_FD; } if (ecmd.advertising & ADVERTISED_1000baseT_Half) { - *advertised |= NETDEV_F_1GB_HD; + netdev_dev->advertised |= NETDEV_F_1GB_HD; } if (ecmd.advertising & ADVERTISED_1000baseT_Full) { - *advertised |= NETDEV_F_1GB_FD; + netdev_dev->advertised |= NETDEV_F_1GB_FD; } if (ecmd.advertising & ADVERTISED_10000baseT_Full) { - *advertised |= NETDEV_F_10GB_FD; + netdev_dev->advertised |= NETDEV_F_10GB_FD; } if (ecmd.advertising & ADVERTISED_TP) { - *advertised |= NETDEV_F_COPPER; + netdev_dev->advertised |= NETDEV_F_COPPER; } if (ecmd.advertising & ADVERTISED_FIBRE) { - *advertised |= NETDEV_F_FIBER; + netdev_dev->advertised |= NETDEV_F_FIBER; } if (ecmd.advertising & ADVERTISED_Autoneg) { - *advertised |= NETDEV_F_AUTONEG; + netdev_dev->advertised |= NETDEV_F_AUTONEG; } if (ecmd.advertising & ADVERTISED_Pause) { - *advertised |= NETDEV_F_PAUSE; + netdev_dev->advertised |= NETDEV_F_PAUSE; } if (ecmd.advertising & ADVERTISED_Asym_Pause) { - *advertised |= NETDEV_F_PAUSE_ASYM; + netdev_dev->advertised |= NETDEV_F_PAUSE_ASYM; } /* Current settings. */ speed = ecmd.speed; if (speed == SPEED_10) { - *current = ecmd.duplex ? NETDEV_F_10MB_FD : NETDEV_F_10MB_HD; + netdev_dev->current = ecmd.duplex ? NETDEV_F_10MB_FD : NETDEV_F_10MB_HD; } else if (speed == SPEED_100) { - *current = ecmd.duplex ? NETDEV_F_100MB_FD : NETDEV_F_100MB_HD; + netdev_dev->current = ecmd.duplex ? NETDEV_F_100MB_FD : NETDEV_F_100MB_HD; } else if (speed == SPEED_1000) { - *current = ecmd.duplex ? NETDEV_F_1GB_FD : NETDEV_F_1GB_HD; + netdev_dev->current = ecmd.duplex ? NETDEV_F_1GB_FD : NETDEV_F_1GB_HD; } else if (speed == SPEED_10000) { - *current = NETDEV_F_10GB_FD; + netdev_dev->current = NETDEV_F_10GB_FD; } else if (speed == 40000) { - *current = NETDEV_F_40GB_FD; + netdev_dev->current = NETDEV_F_40GB_FD; } else if (speed == 100000) { - *current = NETDEV_F_100GB_FD; + netdev_dev->current = NETDEV_F_100GB_FD; } else if (speed == 1000000) { - *current = NETDEV_F_1TB_FD; + netdev_dev->current = NETDEV_F_1TB_FD; } else { - *current = 0; + netdev_dev->current = 0; } if (ecmd.port == PORT_TP) { - *current |= NETDEV_F_COPPER; + netdev_dev->current |= NETDEV_F_COPPER; } else if (ecmd.port == PORT_FIBRE) { - *current |= NETDEV_F_FIBER; + netdev_dev->current |= NETDEV_F_FIBER; } if (ecmd.autoneg) { - *current |= NETDEV_F_AUTONEG; + netdev_dev->current |= NETDEV_F_AUTONEG; } /* Peer advertisements. */ - *peer = 0; /* XXX */ + netdev_dev->peer = 0; /* XXX */ - return 0; +out: + netdev_dev->cache_valid |= VALID_FEATURES; + netdev_dev->get_features_error = error; +} + +/* Stores the features supported by 'netdev' into each of '*current', + * '*advertised', '*supported', and '*peer' that are non-null. Each value is a + * bitmap of NETDEV_* bits. Returns 0 if successful, otherwise a positive + * errno value. */ +static int +netdev_linux_get_features(const struct netdev *netdev_, + enum netdev_features *current, + enum netdev_features *advertised, + enum netdev_features *supported, + enum netdev_features *peer) +{ + struct netdev_dev_linux *netdev_dev = + netdev_dev_linux_cast(netdev_get_dev(netdev_)); + + netdev_linux_read_features(netdev_dev); + + if (!netdev_dev->get_features_error) { + *current = netdev_dev->current; + *advertised = netdev_dev->advertised; + *supported = netdev_dev->supported; + *peer = netdev_dev->peer; + } + return netdev_dev->get_features_error; } /* Set the features advertised by 'netdev' to 'advertise'. */ @@ -1616,6 +1656,7 @@ netdev_linux_set_advertisements(struct netdev *netdev, struct ethtool_cmd ecmd; int error; + COVERAGE_INC(netdev_get_ethtool); memset(&ecmd, 0, sizeof ecmd); error = netdev_linux_do_ethtool(netdev_get_name(netdev), &ecmd, ETHTOOL_GSET, "ETHTOOL_GSET"); @@ -1660,6 +1701,7 @@ netdev_linux_set_advertisements(struct netdev *netdev, if (advertise & NETDEV_F_PAUSE_ASYM) { ecmd.advertising |= ADVERTISED_Asym_Pause; } + COVERAGE_INC(netdev_set_ethtool); return netdev_linux_do_ethtool(netdev_get_name(netdev), &ecmd, ETHTOOL_SSET, "ETHTOOL_SSET"); } @@ -1680,11 +1722,17 @@ netdev_linux_set_policing(struct netdev *netdev, : !kbits_burst ? 1000 /* Default to 1000 kbits if 0. */ : kbits_burst); /* Stick with user-specified value. */ - if (netdev_dev->cache_valid & VALID_POLICING - && netdev_dev->kbits_rate == kbits_rate - && netdev_dev->kbits_burst == kbits_burst) { - /* Assume that settings haven't changed since we last set them. */ - return 0; + if (netdev_dev->cache_valid & VALID_POLICING) { + if (netdev_dev->netdev_policing_error) { + return netdev_dev->netdev_policing_error; + } + + if (netdev_dev->kbits_rate == kbits_rate && + netdev_dev->kbits_burst == kbits_burst) { + /* Assume that settings haven't changed since we last set them. */ + return 0; + } + netdev_dev->cache_valid &= ~VALID_POLICING; } COVERAGE_INC(netdev_set_policing); @@ -1693,7 +1741,7 @@ netdev_linux_set_policing(struct netdev *netdev, if (error) { VLOG_WARN_RL(&rl, "%s: removing policing failed: %s", netdev_name, strerror(error)); - return error; + goto out; } if (kbits_rate) { @@ -1701,22 +1749,26 @@ netdev_linux_set_policing(struct netdev *netdev, if (error) { VLOG_WARN_RL(&rl, "%s: adding policing qdisc failed: %s", netdev_name, strerror(error)); - return error; + goto out; } error = tc_add_policer(netdev, kbits_rate, kbits_burst); if (error){ VLOG_WARN_RL(&rl, "%s: adding policing action failed: %s", netdev_name, strerror(error)); - return error; + goto out; } } netdev_dev->kbits_rate = kbits_rate; netdev_dev->kbits_burst = kbits_burst; - netdev_dev->cache_valid |= VALID_POLICING; - return 0; +out: + if (!error || error == ENODEV) { + netdev_dev->netdev_policing_error = error; + netdev_dev->cache_valid |= VALID_POLICING; + } + return error; } static int @@ -1799,7 +1851,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)); @@ -1818,7 +1870,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)); @@ -1855,7 +1907,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)); @@ -1874,7 +1926,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)); @@ -1955,8 +2007,8 @@ 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; - struct shash details; + struct tc_queue *queue, *next_queue; + struct smap details; int last_error; int error; @@ -1968,9 +2020,10 @@ netdev_linux_dump_queues(const struct netdev *netdev, } last_error = 0; - shash_init(&details); - HMAP_FOR_EACH (queue, hmap_node, &netdev_dev->tc->queues) { - shash_clear(&details); + smap_init(&details); + HMAP_FOR_EACH_SAFE (queue, next_queue, hmap_node, + &netdev_dev->tc->queues) { + smap_clear(&details); error = netdev_dev->tc->ops->class_get(netdev, queue, &details); if (!error) { @@ -1979,7 +2032,7 @@ netdev_linux_dump_queues(const struct netdev *netdev, last_error = error; } } - shash_destroy(&details); + smap_destroy(&details); return last_error; } @@ -2224,7 +2277,7 @@ netdev_linux_get_next_hop(const struct in_addr *host, struct in_addr *next_hop, } static int -netdev_linux_get_status(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 = @@ -2232,17 +2285,18 @@ netdev_linux_get_status(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_status(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; } @@ -2330,7 +2384,7 @@ netdev_linux_change_seq(const struct netdev *netdev) } #define NETDEV_LINUX_CLASS(NAME, CREATE, GET_STATS, SET_STATS, \ - GET_STATUS) \ + GET_FEATURES, GET_STATUS) \ { \ NAME, \ \ @@ -2365,7 +2419,7 @@ netdev_linux_change_seq(const struct netdev *netdev) GET_STATS, \ SET_STATS, \ \ - netdev_linux_get_features, \ + GET_FEATURES, \ netdev_linux_set_advertisements, \ \ netdev_linux_set_policing, \ @@ -2399,7 +2453,8 @@ const struct netdev_class netdev_linux_class = netdev_linux_create, netdev_linux_get_stats, NULL, /* set_stats */ - netdev_linux_get_status); + netdev_linux_get_features, + netdev_linux_get_drv_info); const struct netdev_class netdev_tap_class = NETDEV_LINUX_CLASS( @@ -2407,7 +2462,8 @@ const struct netdev_class netdev_tap_class = netdev_linux_create_tap, netdev_tap_get_stats, NULL, /* set_stats */ - netdev_linux_get_status); + netdev_linux_get_features, + netdev_linux_get_drv_info); const struct netdev_class netdev_internal_class = NETDEV_LINUX_CLASS( @@ -2415,7 +2471,8 @@ const struct netdev_class netdev_internal_class = netdev_linux_create, netdev_internal_get_stats, netdev_vport_set_stats, - netdev_internal_get_status); + NULL, /* get_features */ + netdev_internal_get_drv_info); /* HTB traffic control class. */ @@ -2601,14 +2658,14 @@ 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) { - uint32_t current; + enum netdev_features current; netdev_get_features(netdev, ¤t, NULL, NULL, NULL); hc->max_rate = netdev_features_to_bps(current) / 8; @@ -2620,13 +2677,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); @@ -2684,7 +2741,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; @@ -2776,15 +2833,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; @@ -2800,24 +2857,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; @@ -3077,17 +3134,17 @@ 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) { - uint32_t current; + enum netdev_features current; netdev_get_features(netdev, ¤t, NULL, NULL, NULL); max_rate = netdev_features_to_bps(current) / 8; @@ -3099,7 +3156,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; @@ -3107,8 +3164,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); @@ -3209,7 +3266,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; @@ -3277,16 +3334,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; @@ -3304,21 +3361,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; @@ -3423,7 +3480,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; @@ -4049,7 +4106,7 @@ tc_query_qdisc(const struct netdev *netdev) } /* Instantiate it. */ - load_error = ops->tc_load((struct netdev *) netdev, qdisc); + load_error = ops->tc_load(CONST_CAST(struct netdev *, netdev), qdisc); assert((load_error == 0) == (netdev_dev->tc != NULL)); ofpbuf_delete(qdisc); @@ -4146,6 +4203,7 @@ netdev_linux_ethtool_set_flag(struct netdev *netdev, uint32_t flag, uint32_t new_flags; int error; + COVERAGE_INC(netdev_get_ethtool); memset(&evalue, 0, sizeof evalue); error = netdev_linux_do_ethtool(netdev_name, (struct ethtool_cmd *)&evalue, @@ -4154,6 +4212,7 @@ netdev_linux_ethtool_set_flag(struct netdev *netdev, uint32_t flag, return error; } + COVERAGE_INC(netdev_set_ethtool); evalue.data = new_flags = (evalue.data & ~flag) | (enable ? flag : 0); error = netdev_linux_do_ethtool(netdev_name, (struct ethtool_cmd *)&evalue, @@ -4162,6 +4221,7 @@ netdev_linux_ethtool_set_flag(struct netdev *netdev, uint32_t flag, return error; } + COVERAGE_INC(netdev_get_ethtool); memset(&evalue, 0, sizeof evalue); error = netdev_linux_do_ethtool(netdev_name, (struct ethtool_cmd *)&evalue, @@ -4362,17 +4422,22 @@ get_ifindex(const struct netdev *netdev_, int *ifindexp) { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev_)); - *ifindexp = 0; + if (!(netdev_dev->cache_valid & VALID_IFINDEX)) { int ifindex = do_get_ifindex(netdev_get_name(netdev_)); + if (ifindex < 0) { - return -ifindex; + netdev_dev->get_ifindex_error = -ifindex; + netdev_dev->ifindex = 0; + } else { + netdev_dev->get_ifindex_error = 0; + netdev_dev->ifindex = ifindex; } netdev_dev->cache_valid |= VALID_IFINDEX; - netdev_dev->ifindex = ifindex; } + *ifindexp = netdev_dev->ifindex; - return 0; + return netdev_dev->get_ifindex_error; } static int @@ -4432,7 +4497,6 @@ netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *ecmd, ifr.ifr_data = (caddr_t) ecmd; ecmd->cmd = cmd; - COVERAGE_INC(netdev_ethtool); if (ioctl(af_inet_sock, SIOCETHTOOL, &ifr) == 0) { return 0; } else {