上次打算通过 get_channels( )方法来获取队列的个数,不过我使用的内核的版本中,ethtool_ops 下并没有 get_channels( ) 方法。。。
那肿么办,如何获取网卡队列?
上次强制改过 RX 的个数为网卡中 RX 的个数,可惜行不通,还是找其他方法吧。
翻了翻我使用内核版本的源码,发现有 get_channels( ) 方法,不过并不在 ethtool_ops 中,而是作为扩展在struct ethtool_ops_ext 中:
struct ethtool_ops_ext {
size_t size;
u32 (*get_rxfh_indir_size)(struct net_device *);
int (*get_rxfh_indir)(struct net_device *, u32 *);
int (*set_rxfh_indir)(struct net_device *, const u32 *);
void (*get_channels)(struct net_device *, struct ethtool_channels *); // 在这里
int (*set_channels)(struct net_device *, struct ethtool_channels *);
int (*get_dump_flag)(struct net_device *, struct ethtool_dump *);
int (*get_dump_data)(struct net_device *, struct ethtool_dump *, void *);
int (*set_dump)(struct net_device *, struct ethtool_dump *);
int (*get_module_info)(struct net_device *, struct ethtool_modinfo *);
int (*get_module_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state);
int (*reset)(struct net_device *, u32 *);
int (*get_eee)(struct net_device *, struct ethtool_eee *);
int (*set_eee)(struct net_device *, struct ethtool_eee *);
int (*get_ts_info)(struct net_device *, struct ethtool_ts_info *);
};
static const struct ethtool_ops_ext ixgbe_ethtool_ops_ext = {
.size = sizeof(struct ethtool_ops_ext),
.get_channels = ixgbe_get_channels,
.set_channels = ixgbe_set_channels,
.get_ts_info = ixgbe_get_ts_info,
.get_module_info = ixgbe_get_module_info,
.get_module_eeprom = ixgbe_get_module_eeprom,
};
void ixgbe_set_ethtool_ops(struct net_device *netdev)
{
SET_ETHTOOL_OPS(netdev, &ixgbe_ethtool_ops); // ixgbe_ethtool_ops 是 ethtool_ops
set_ethtool_ops_ext(netdev, &ixgbe_ethtool_ops_ext); // ixgbe_ethtool_ops_ext 里面有我们要的 get_channels
}
那好,我们改动 netmap 关于通过 net_device 设置网卡收发队列的部分,加入 struct ethtool_ops_ext 的支持:
void nm_os_generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq)
{
#ifdef NETMAP_LINUX_HAVE_SET_CHANNELS
struct ethtool_channels ch;
memset(&ch, 0, sizeof(ch));
if ((ifp->ethtool_ops && ifp->ethtool_ops->get_channels) ||
(get_ethtool_ops_ext(ifp) && get_ethtool_ops_ext(ifp)->get_channels)) { // 这里添加 get_ethtool_ops_ext
if (ifp->ethtool_ops->get_channels) {
ifp->ethtool_ops->get_channels(ifp, &ch);
} else if (get_ethtool_ops_ext(ifp)->get_channels) { // 分支判断是否支持 ethtool_opt 的扩展
get_ethtool_ops_ext(ifp)->get_channels(ifp, &ch);
}
*txq = ch.tx_count ? ch.tx_count : ch.combined_count;
*rxq = ch.rx_count ? ch.rx_count : ch.combined_count;
} else
#endif /* HAVE_SET_CHANNELS */
{
*txq = ifp->real_num_tx_queues;
#if defined(NETMAP_LINUX_HAVE_REAL_NUM_RX_QUEUES)
*rxq = ifp->real_num_rx_queues;
#else
*rxq = 1;
#endif /* HAVE_REAL_NUM_RX_QUEUES */
}
}
重新编译源码,加载模块运行,嗯嗯,可以设置 RX 为 8 队列了,这回可以使用 8 队列收包了。^_^