structuk_netbuf { structuk_netbuf *next; structuk_netbuf *prev; // netbuf 的标志 uint8_t flags; /**< Flags for this netbuf */ // 指向负载的开始部分 void *data; /**< Payload start, is part of buf. */ // 负载长度 uint16_t len; /**< Payload length (should be <= buflen). */ // 引用次数 __atomic refcount; /**< Reference counter */ // 指向 private meta data 部分 void *priv; /**< Reference to user-provided private data */ // 指向整个 buffer 的起始部分 void *buf; /**< Start address of contiguous buffer. */ size_t buflen; /**< Length of buffer. */ // 校验和的起始位置 uint16_t csum_start; /**< Used if UK_NETBUF_F_PARTIAL_CSUM is set; * Offset within this netbuf's data segment to * begin checksumming */ // 校验和偏移量 uint16_t csum_offset; /**< Used if UK_NETBUF_F_PARTIAL_CSUM is set; * Number of bytes starting from `csum_start` * pointing to the checksum field */ // 析构函数 uk_netbuf_dtor_t dtor; /**< Destructor callback */ structuk_alloc *_a;/**< @internal Allocator for free'ing */ void *_b; /**< @internal Base address for free'ing */ };
/* Place headroom and buf at the beginning of the allocation, * This is done in order to forward potential alignments of the * underlying allocation directly to the netbuf data area. * `m` (followed by `m->priv` if privlen > 0) will be placed at * the end of the given memory. */ // meta_len长度为netbuf结构体大小+private部分大小并向上对齐 meta_len = NETBUF_ADDR_ALIGN_UP(sizeof(*m) + privlen); // 元数据长度大于总长度则无法分配 if (meta_len > NETBUF_ADDR_ALIGN_DOWN((__uptr) mem + size)) returnNULL; // *m 所指向的位置是总长度减去 meta data 的长度 m = (struct uk_netbuf *) (NETBUF_ADDR_ALIGN_DOWN((__uptr) mem + size) - meta_len); // 调用函数对分配的空间进行初始化 uk_netbuf_init_indir(m, mem, (size_t) ((__uptr) m - (__uptr) mem), headroom, privlen > 0 ? (void *) ((__uptr) m+ sizeof(*m)) : NULL, dtor); return m; }
/* We want to return the next element of m as the * remaining head of the chain. If there is no next element * there was no chain. */ remhead = m->next;
/* Reconnect the chains before and after m. */ if (m->prev) m->prev->next = m->next; if (m->next) m->next->prev = m->prev;
/* Disconnect m. */ m->prev = NULL; m->next = NULL;
/* Decrease refcount and call destructor and free up memory * when last reference was released. */ // 当引用次数等于 1 时才可释放此 netbuf if (uk_refcount_release(&m->refcount) == 1) { uk_pr_debug("Freeing netbuf %p (next: %p)\n", m, m->next);
/* Disconnect this netbuf from the chain. */ uk_netbuf_disconnect(m);
/* Copy the reference of the allocator and base address * in case the destructor is free'ing up our memory * (e.g., uk_netbuf_init_indir() used). * In such a case `a` and `b` should be (NULL), * however we need to access them for a check after * we have called the destructor. */ a = m->_a; b = m->_b;
if (m->dtor) m->dtor(m); if (a && b) uk_free(a, b); } else { uk_pr_debug("Not freeing netbuf %p (next: %p): refcount greater than 1", m, m->next); } }
netdev_core.h
此报头包含所有 API 数据类型。其中⼀些是公共 API 和⼀些是内部 API 的⼀部分。设备的数据与操作是分离的。这种分割允许函数指针和驱动程序数据分散在每个进程中,但实际上共享设备的配置数据。
#ifdef CONFIG_LIBUKNETDEV_DISPATCHERTHREADS /* If we do not have a callback, we do not need a thread */ // 若不存在回调函数则无需创建线程 if (!callback) return0; // 初始化变量以及传递信息所用的信号量 h->dev = dev; h->queue_id = queue_id; uk_semaphore_init(&h->events, 0); h->dispatcher_s = s;
/* Create a name for the dispatcher thread. * In case of errors, we just continue without a name */ if (asprintf(&h->dispatcher_name, "netdev%"PRIu16"-%s[%"PRIu16"]", dev->_data->id, queue_type_str, queue_id) < 0) { h->dispatcher_name = NULL; } // 新建线程运行调度函数 h->dispatcher = uk_sched_thread_create(h->dispatcher_s, h->dispatcher_name, NULL, _dispatcher, h); if (!h->dispatcher) { if (h->dispatcher_name) free(h->dispatcher_name); h->dispatcher_name = NULL; return -ENOMEM; } #endif
if (dev->_data->state != UK_NETDEV_CONFIGURED) return -EINVAL;
/* Make sure that we are not initializing this queue a second time */ if (!PTRISERR(dev->_rx_queue[queue_id])) return -EBUSY; // 调用函数进行事件处理器的配置 err = _create_event_handler(rx_conf->callback, rx_conf->callback_cookie, #ifdef CONFIG_LIBUKNETDEV_DISPATCHERTHREADS dev, queue_id, "rxq", rx_conf->s, #endif &dev->_data->rxq_handler[queue_id]); if (err) goto err_out; // 进行配置 dev->_rx_queue[queue_id] = dev->ops->rxq_configure(dev, queue_id, nb_desc, rx_conf); if (PTRISERR(dev->_rx_queue[queue_id])) { err = PTR2ERR(dev->_rx_queue[queue_id]); goto err_destroy_handler; }