ovs-dpdk源码阅读笔记(v2.17.2)
1. vswitchd
守护进程主函数
int
main(int argc, char *argv[])
{
daemonize_start(true);
while (!exiting) {
bridge_run();
}
return 0;
}
2. dpdk netdev 注册
2.1 注册 dpdk 类型的三种 netdev
main() -> bridge_run() -> dpdk_init() -> dpdk_init__() -> netdev_dpdk_register()
void
netdev_dpdk_register(void)
{
netdev_register_provider(&dpdk_class);
netdev_register_provider(&dpdk_vhost_class);
netdev_register_provider(&dpdk_vhost_client_class);
}
2.2 定义 struct netdev_class
int
netdev_register_provider(const struct netdev_class *new_class)
OVS_EXCLUDED(netdev_class_mutex, netdev_mutex)
{
error = new_class->init ? new_class->init() : 0;
return error;
}
struct netdev_class {
const char *type;
bool is_pmd;
int (*init)(void);
void (*run)(const struct netdev_class *netdev_class);
void (*wait)(const struct netdev_class *netdev_class);
struct netdev *(*alloc)(void);
int (*construct)(struct netdev *);
void (*destruct)(struct netdev *);
void (*dealloc)(struct netdev *);
int (*send)(struct netdev *netdev, int qid, struct dp_packet_batch *batch, bool concurrent_txq);
int (*rxq_recv)(struct netdev_rxq *rx, struct dp_packet_batch *batch, int *qfill);
}
2.3 dpdk 类型的 netdev_class
实例化
#define NETDEV_DPDK_CLASS_COMMON \
.is_pmd = true,
#define NETDEV_DPDK_CLASS_BASE \
NETDEV_DPDK_CLASS_COMMON, \
.init = netdev_dpdk_class_init,
.rxq_recv = netdev_dpdk_rxq_recv
static const struct netdev_class dpdk_class = {
.type = "dpdk",
NETDEV_DPDK_CLASS_BASE,
.send = netdev_dpdk_eth_send,
};
static const struct netdev_class dpdk_vhost_class = {
.type = "dpdkvhostuser",
NETDEV_DPDK_CLASS_COMMON,
.send = netdev_dpdk_vhost_send,
.rxq_recv = netdev_dpdk_vhost_rxq_recv,
};
static const struct netdev_class dpdk_vhost_client_class = {
.type = "dpdkvhostuserclient",
NETDEV_DPDK_CLASS_COMMON,
.send = netdev_dpdk_vhost_send,
.rxq_recv = netdev_dpdk_vhost_rxq_recv,
};
3. PMD创建流程
3.1 以 add port 为例
static int
dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
odp_port_t *port_nop)
{
error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no);
return error;
}
3.2 创建 PMD 线程并轮询
do_add_port() -> reconfigure_datapath() -> reconfigure_pmd_threads() -> ovs_thread_create(ds_cstr(&name),pmd_thread_main, pmd)
static void *
pmd_thread_main(void *f_)
{
for (;;) {
dp_netdev_process_rxq_port(pmd, poll_list[i].rxq,poll_list[i].port_no);
}
if (!rx_packets) {
tx_packets = dp_netdev_pmd_flush_output_packets(pmd, false);
}
}
return NULL;
}
3.2.1 dp_netdev_process_rxq_port
函数
static int
dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd,
struct dp_netdev_rxq *rxq,
odp_port_t port_no)
{
error = netdev_rxq_recv(rxq->rx, &batch, qlen_p);
if (!error) {
dp_netdev_input(pmd, &batch, port_no);
dp_netdev_pmd_flush_output_packets(pmd, false);
}
return batch_cnt;
}
3.2.2 dp_netdev_input
三级流表匹配 + 执行 action
dp_netdev_input() -> dp_netdev_input__()
static void
dp_netdev_input__(struct dp_netdev_pmd_thread *pmd,
struct dp_packet_batch *packets,
bool md_is_valid, odp_port_t port_no)
{
dfc_processing(pmd, packets, keys, missed_keys, batches, &n_batches,
fast_path_processing(pmd, packets, missed_keys,
for (i = 0; i < n_batches; i++) {
packet_batch_per_flow_execute(&batches[i], pmd);
}
}
3.2.3 packet_batch_per_flow_execute
执行流表 action
packet_batch_per_flow_execute() -> dp_netdev_execute_actions() -> odp_execute_actions() -> dp_execute_cb()
dp_execute_cb()
3.2.4dp_netdev_pmd_flush_output_packets
发包过程
dp_netdev_pmd_flush_output_packets() -> dp_netdev_pmd_flush_output_on_port() -> netdev_send() -> netdev->netdev_class->send()