diff --git a/include/gatekeeper_net.h b/include/gatekeeper_net.h index b48ab4ba..26cf430a 100644 --- a/include/gatekeeper_net.h +++ b/include/gatekeeper_net.h @@ -491,6 +491,20 @@ lacp_enabled(struct net_config *net, struct gatekeeper_if *iface) return __lacp_enabled(iface); } +/* + * If the return is zero, @link_speed_mbits has the guaranteed maximum + * transmision link speed of @iface. + * + * If @iface is bonded, guaranteed means that the value of @link_speed_mbits + * does not depend on the active members of the bond, but on the mode of + * the bond. + * + * If @iface is a single physical interface, @link_speed_mbits is + * the link speed of the physical interface. + */ +int iface_gmax_tx_speed(const struct gatekeeper_if *iface, + uint64_t *link_speed_mbits); + int lua_init_iface(struct gatekeeper_if *iface, const char *iface_name, const char **pci_addrs, uint8_t num_pci_addrs, const char **ip_cidrs, uint8_t num_ip_cidrs, uint16_t ipv4_vlan_tag, uint16_t ipv6_vlan_tag); diff --git a/lib/net.c b/lib/net.c index d7c06de3..24bc3c51 100644 --- a/lib/net.c +++ b/lib/net.c @@ -2904,3 +2904,104 @@ rss_flow_hash(const struct gatekeeper_if *iface, const struct ip_flow *flow) rte_panic("%s(): unknown protocol: %i\n", __func__, flow->proto); return 0; } + +static int +port_link_speed(const struct gatekeeper_if *iface, uint16_t port_id, + uint32_t *plink_speed) +{ + char if_name[MAX_LOG_IF_NAME]; + struct rte_eth_link link; + int ret; + + log_if_name(if_name, sizeof(if_name), iface, port_id); + + ret = rte_eth_link_get(port_id, &link); + if (unlikely(ret < 0)) { + G_LOG(ERR, "%s(%s): cannot get link information (errno=%i): %s\n", + __func__, if_name, -ret, rte_strerror(-ret)); + return ret; + } + + if (unlikely(link.link_speed == RTE_ETH_SPEED_NUM_NONE || + link.link_speed == RTE_ETH_SPEED_NUM_UNKNOWN)) { + G_LOG(ERR, "%s(%s): link speed is %s\n", + __func__, if_name, + link.link_speed == RTE_ETH_SPEED_NUM_NONE + ? "not available" : "unknown"); + return -ENOTSUP; + } + + *plink_speed = link.link_speed; + return 0; +} + +/* + * This function is based on + * dpdk/drivers/net/bonding/rte_eth_bond_pmd.c:bond_ethdev_link_update(). + */ +static int +bond_link_speed(const struct gatekeeper_if *iface, uint32_t *plink_speed) +{ + uint32_t computed_link_speed, link_speed; + int i, ret; + + switch (iface->bonding_mode) { + case BONDING_MODE_ROUND_ROBIN: + case BONDING_MODE_BALANCE: + case BONDING_MODE_8023AD: + case BONDING_MODE_TLB: + case BONDING_MODE_ALB: + /* Sum up the link speed of all the members. */ + computed_link_speed = 0; + for (i = 0; i < iface->num_ports; i++) { + ret = port_link_speed(iface, iface->ports[i], + &link_speed); + if (unlikely(ret < 0)) + return ret; + computed_link_speed += link_speed; + } + break; + + case BONDING_MODE_ACTIVE_BACKUP: + case BONDING_MODE_BROADCAST: + /* Return the slowest link speed, so it is guaranteed. */ + computed_link_speed = UINT32_MAX; + for (i = 0; i < iface->num_ports; i++) { + ret = port_link_speed(iface, iface->ports[i], + &link_speed); + if (unlikely(ret < 0)) + return ret; + computed_link_speed = RTE_MIN(computed_link_speed, + link_speed); + } + break; + + default: + G_LOG(CRIT, "%s(%s): unknown bonding mode %u\n", + __func__, iface->name, iface->bonding_mode); + return -ENOTSUP; + } + + *plink_speed = computed_link_speed; + return 0; +} + +int +iface_gmax_tx_speed(const struct gatekeeper_if *iface, + uint64_t *link_speed_mbits) +{ + uint32_t link_speed; + int ret = iface_bonded(iface) + /* + * rte_eth_link_get() returns a link speed that may vary with + * the number of active members of a bonded interface, so + * it is not a guaranteed maximum. + */ + ? bond_link_speed(iface, &link_speed) + : port_link_speed(iface, iface->id, &link_speed); + if (unlikely(ret < 0)) + return ret; + + *link_speed_mbits = link_speed; + return 0; +} diff --git a/sol/main.c b/sol/main.c index 97734465..b10551c1 100644 --- a/sol/main.c +++ b/sol/main.c @@ -367,46 +367,6 @@ mbits_to_bytes(double mbps) return mbps * (1000 * 1000 / 8); } -/* - * Retrieve the link speed of a Gatekeeper interface. If it - * is a bonded interface, the link speeds are summed. - */ -static int -iface_speed_bytes(struct gatekeeper_if *iface, uint64_t *link_speed_bytes) -{ - uint64_t link_speed_mbits = 0; - uint8_t i; - int ret; - - RTE_VERIFY(link_speed_bytes != NULL); - - for (i = 0; i < iface->num_ports; i++) { - struct rte_eth_link link; - ret = rte_eth_link_get(iface->ports[i], &link); - if (ret < 0) { - G_LOG(ERR, "net: querying port %hhu failed with err - %s\n", - iface->ports[i], rte_strerror(-ret)); - goto err; - } - - if (link.link_speed == RTE_ETH_SPEED_NUM_NONE || - link.link_speed == RTE_ETH_SPEED_NUM_UNKNOWN) { - ret = -ENOTSUP; - goto err; - } - - link_speed_mbits += link.link_speed; - } - - /* Convert to bytes per second. */ - *link_speed_bytes = mbits_to_bytes(link_speed_mbits); - return 0; - -err: - *link_speed_bytes = 0; - return ret; -} - /* * @sol_conf is allocated using rte_calloc_socket(), so initializations * to 0 are not strictly necessary in this function. @@ -423,19 +383,22 @@ req_queue_init(struct sol_config *sol_conf) int ret, i; /* Find link speed in bytes, even for a bonded interface. */ - ret = iface_speed_bytes(&sol_conf->net->back, &link_speed_bytes); - if (ret == 0) { - G_LOG(NOTICE, - "Back interface link speed: %"PRIu64" bytes per second\n", - link_speed_bytes); + ret = iface_gmax_tx_speed(&sol_conf->net->back, &link_speed_bytes); + if (likely(ret == 0)) { + /* Convert to bytes per second. */ + link_speed_bytes = mbits_to_bytes(link_speed_bytes); + G_LOG(NOTICE, "%s(): back interface link speed: %"PRIu64" bytes per second\n", + __func__, link_speed_bytes); /* Keep max number of bytes a float for later calculations. */ max_credit_bytes_precise = sol_conf->req_bw_rate * link_speed_bytes; } else { - G_LOG(NOTICE, "Back interface link speed: undefined\n"); + G_LOG(NOTICE, "%s(): back interface link speed: undefined\n", + __func__); if (sol_conf->req_channel_bw_mbps <= 0) { - G_LOG(ERR, "When link speed on back interface is undefined, parameter req_channel_bw_mbps must be calculated and defined\n"); - return -1; + G_LOG(ERR, "%s(): when link speed on back interface is undefined, parameter req_channel_bw_mbps must be calculated and defined\n", + __func__); + return -ERANGE; } max_credit_bytes_precise = mbits_to_bytes(sol_conf->req_channel_bw_mbps); @@ -459,15 +422,16 @@ req_queue_init(struct sol_config *sol_conf) cycles_per_byte_precise - cycles_per_byte_floor, sol_conf->tb_rate_approx_err, &a, &b); if (ret < 0) { - G_LOG(ERR, "Could not approximate the request queue's allocated bandwidth\n"); + G_LOG(ERR, "%s(): could not approximate the request queue's allocated bandwidth\n", + __func__); return ret; } /* Add integer number of cycles per byte to numerator. */ a += cycles_per_byte_floor * b; - G_LOG(NOTICE, "Cycles per byte (%f) represented as a rational: %u / %u\n", - cycles_per_byte_precise, a, b); + G_LOG(NOTICE, "%s(): cycles per byte (%f) represented as a rational: %u / %u\n", + __func__, cycles_per_byte_precise, a, b); now = rte_rdtsc();