DPDK NIC 초기화
constructor attribute
http://phoxis.org/2011/04/27/c-language-constructors-and-destructors-with-gcc/
constructor attribute을 가진 함수는 main 함수를 실행하기 전에 호출한다.
예제 (출처)
#include <stdio.h>
void begin (void) __attribute__((constructor));
void end (void) __attribute__((destructor));
int main (void)
{
printf ("\nInside main ()");
}
void begin (void)
{
printf ("\nIn begin ()");
}
void end (void)
{
printf ("\nIn end ()\n");
}
실행하면
In begin ()
Inside main ()
In end ()
DPDK
DPDK의 경우 device driver들을 모두 constructor attirbute을 사용해서 main 함수 전에 호출되록 한다.
PMD_REGISTER_DRIVER(pmd_igb_drv);
PMD_REGISTER_DRIVER(pmd_igbvf_drv);
PMD_REGISTER_DRIVER(em_pmd_drv);
Physical device 외에 virtual device들도 동일하게 등록한다.
PMD_REGISTER_DRIVER(cryptodev_aesni_mb_pmd_drv);
PMD_REGISTER_DRIVER(pmd_qat_drv);
PMD_REGISTER_DRIVER()
는 lib/librte_eal/common/include/rte_dev.h
에 다음과 같이 정의되어 있다.
#define PMD_REGISTER_DRIVER(d)\
void devinitfn_ ##d(void);\
void __attribute__((constructor, used)) devinitfn_ ##d(void)\
{\
rte_eal_driver_register(&d);\
}
rte_eal_deriver_register()
는 lib/librte_eal/common/eal_common_dev.c
에서 static 변수로 정의된 rte_driver_list[]
에 함수 인자로 넘겨진 driver를 등록한다.
인자는 다음 struct 형태로 정의된다.
/**
* A structure describing a device driver.
*/
struct rte_driver {
TAILQ_ENTRY(rte_driver) next; /**< Next in list. */
enum pmd_type type; /**< PMD Driver type */
const char *name; /**< Driver name. */
rte_dev_init_t *init; /**< Device init. function. */
rte_dev_uninit_t *uninit; /**< Device uninit. function. */
};
등록된 디바이스들은 rte_eal_init()
초기화 과정에서 호출되는 함수 rte_eal_dev_init()
에서 각 디바이스의 초기화 함수가 호출된다.
int
rte_eal_dev_init(void)
{
/* call the init function for each virtual device */
TAILQ_FOREACH(devargs, &devargs_list, next) {
if (devargs->type != RTE_DEVTYPE_VIRTUAL)
continue;
if (rte_eal_vdev_init(devargs->virt.drv_name,
devargs->args)) {
...
}
/* Once the vdevs are initalized, start calling all the pdev drivers */
TAILQ_FOREACH(driver, &dev_driver_list, next) {
if (driver->type != PMD_PDEV)
continue;
/* PDEV drivers don't get passed any parameters */
driver->init(NULL, NULL);
}
QAT device
static struct rte_driver pmd_qat_drv = {
.type = PMD_PDEV,
.init = rte_qat_pmd_init,
};
QAT PMD 초기화
rte_qat_pmd_init()
rte_cryptodev_pmd_driver_register()
rte_cryptodev_init()
&rte_eal_pci_register()
AESNI_MB device
static struct rte_driver cryptodev_aesni_mb_pmd_drv = {
.name = CRYPTODEV_NAME_AESNI_MB_PMD,
.type = PMD_VDEV,
.init = cryptodev_aesni_mb_init,
.uninit = cryptodev_aesni_mb_uninit
};
AESNI_MB 초기화
cryptodev_aesni_mb_init()
cryptodev_aesni_mb_create()
- CPU가 AES 연산을 지원하는 지 확인
- CPU가 AVX2/AVX/SSE4_1 중 최소 한 가지를 지원하는 지 확인
rte_cryptodev_pmd_virtual_dev_init()
를 이용해 PMD device로 등록
e1000
static int
rte_em_pmd_init(const char *name __rte_unused, const char *params __rte_unused)
{
rte_eth_driver_register(&rte_em_pmd);
return 0;
}
struct rte_driver em_pmd_drv = {
.type = PMD_PDEV,
.init = rte_em_pmd_init,
};
Physical NIC은 rte_eth_driver_register()
함수를 이용하여 rte_eth_dev
에 등록된다. 이때 등록되는 디바이스 구조체는 다음과 같다.
static struct eth_driver rte_em_pmd = {
.pci_drv = {
.name = "rte_em_pmd",
.id_table = pci_id_em_map,
.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
RTE_PCI_DRV_DETACHABLE,
},
.eth_dev_init = eth_em_dev_init,
.eth_dev_uninit = eth_em_dev_uninit,
.dev_private_size = sizeof(struct e1000_adapter),
};
rte_eth
구조체에 등록하는 함수 rte_eth_driver_register()
는 다음과 같이 구현되어 있어, PCI device list에 NIC을 등록한다. 등록된 PCI device들은 rte_eal_init()
과정에서 호출되는 PCI scan 과정을 통해 실제 NIC을 찾는 과정을 거친다.
/**
* Register an Ethernet [Poll Mode] driver.
*
* Function invoked by the initialization function of an Ethernet driver
* to simultaneously register itself as a PCI driver and as an Ethernet
* Poll Mode Driver.
* Invokes the rte_eal_pci_register() function to register the *pci_drv*
* structure embedded in the *eth_drv* structure, after having stored the
* address of the rte_eth_dev_init() function in the *devinit* field of
* the *pci_drv* structure.
* During the PCI probing phase, the rte_eth_dev_init() function is
* invoked for each PCI [Ethernet device] matching the embedded PCI
* identifiers provided by the driver.
*/
void
rte_eth_driver_register(struct eth_driver *eth_drv)
{
eth_drv->pci_drv.devinit = rte_eth_dev_init;
eth_drv->pci_drv.devuninit = rte_eth_dev_uninit;
rte_eal_pci_register(ð_drv->pci_drv);
}