UDP控制块

// udp ctrl block
struct localhost {

    int fd;

    uint8_t localmac[RTE_ETHER_ADDR_LEN];
    uint32_t localip;
    uint16_t localport;

    uint8_t protocol;

    struct rte_ring* sendbuf;
    struct rte_ring* recvbuf;

    struct localhost* prev;
    struct localhost* next;

    pthread_mutex_t mutex;
    pthread_cond_t cond;
};
  • fd:文件句柄

  • localmac:硬件地址

  • localip:IP地址

  • localport:端口号

  • protocol:协议

  • sendbuf:发送缓冲区

  • recvbuf:接收缓冲区

  • prev:链表指向前一个节点

  • next:链表指向下一个节点

  • mutex:互斥锁

  • cond:条件变量

Posix API

参考前一篇中的api说明。

int nsocket(__attribute__((unused)) int domain, int type, __attribute__((unused)) int protocol) {

    int fd = get_fd_frombitmap();

    struct localhost* host = rte_malloc("localhost", sizeof(struct localhost), 0);
    if (host == NULL) {

        return -1;
    }

    host->fd = fd;

    if (type == SOCK_DGRAM) {

        host->protocol = IPPROTO_UDP;
    }

    host->recvbuf = rte_ring_create("recv buf", RING_SIZE, rte_socket_id(), RING_F_SC_DEQ | RING_F_SP_ENQ);
    if (host->recvbuf == NULL) {

        rte_free(host);
        return -1;
    }

    host->sendbuf = rte_ring_create("send buf", RING_SIZE, rte_socket_id(), RING_F_SC_DEQ | RING_F_SP_ENQ);
    if (host->sendbuf == NULL) {

        rte_ring_free(host->recvbuf);
        rte_free(host);
        return -1;
    }

    pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;
    pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;
    rte_memcpy(&host->mutex, &blank_mutex, sizeof(pthread_mutex_t));
    rte_memcpy(&host->cond, &blank_cond, sizeof(pthread_cond_t));

    return 0;
}

int nbind(int sockfd, const struct sockaddr *addr, __attribute__((unused)) socklen_t addrlen) {

    struct localhost* host = get_host_fromfd(sockfd);
    if (host == NULL) {

        return -1;
    }

    const struct sockaddr_in* laddr = (const struct sockaddr_in*)addr;
    host->localport = laddr->sin_port;
    rte_memcpy(&host->localip, &laddr->sin_addr.s_addr, sizeof(uint32_t));
    rte_memcpy(host->localmac, nSrcMac, RTE_ETHER_ADDR_LEN);

    return 0;
}

ssize_t nrecvfrom(int sockfd, void *buf, size_t len, __attribute__((unused)) int flags, struct sockaddr *src_addr, __attribute__((unused)) socklen_t *addrlen) {

    struct localhost* host = get_host_fromfd(sockfd);
    if (host == NULL) {

        return -1;
    }

    struct offload* ol = NULL;
    uint8_t* ptr = NULL;

    struct sockaddr_in* laddr = (struct sockaddr_in*)src_addr;

    int nb = -1;
    pthread_mutex_lock(&host->mutex);
    while ((nb = rte_ring_mc_dequeue(host->recvbuf, (void**)&ol)) < 0) {

        pthread_cond_wait(&host->cond, &host->mutex);
    }
    pthread_mutex_unlock(&host->mutex);

    laddr->sin_port = ol->sport;
    rte_memcpy(&laddr->sin_addr.s_addr, &ol->sip, sizeof(uint32_t));

    if (len < ol->length) {

        rte_memcpy(buf, ol->data, len);

        ptr = rte_malloc("ol buf", ol->length - len, 0);
        rte_memcpy(ptr, ol->data + len, ol->length - len);

        ol->length = ol->length - len;
        rte_free(ol->data);
        ol->data = ptr;

        rte_ring_mp_enqueue(host->recvbuf, (void**)ol);

        return len;
    }
    else {

        rte_memcpy(buf, ol->data, ol->length);
        rte_free(ol->data);
        rte_free(ol);

        return ol->length;
    }

}

ssize_t nsendto(int sockfd, const void *buf, size_t len, __attribute__((unused)) int flags, const struct sockaddr *dest_addr, __attribute__((unused)) socklen_t addrlen) {

    struct localhost* host = get_host_fromfd(sockfd);
    if (host == NULL) {

        return -1;
    }

    const struct sockaddr_in* daddr = (const struct sockaddr_in*)dest_addr;

    struct offload* ol = rte_malloc("ol", sizeof(struct offload), 0);
    if (ol == NULL) {

        return -1;
    }
    ol->dip = daddr->sin_addr.s_addr;
    ol->dport = daddr->sin_port;
    ol->sport = host->localport;
    ol->sip = host->localip;
    ol->data = rte_malloc("ol data", len, 0);
    rte_memcpy(ol->data, buf, len);
    if (ol->data == NULL) {

        rte_free(ol);
        return -1;
    }

    rte_memcpy(ol->data, buf, len);

    rte_ring_mp_enqueue(host->sendbuf, (void**)ol);

    return len;
}

int nclose(int fd) {

    struct localhost* host = get_host_fromfd(fd);
    if (host == NULL) {

        return -1;
    }

    LL_REMOVE(host, lhost);

    if (host->recvbuf) {

        rte_ring_free(host->recvbuf);
    }

    if (host->sendbuf) {

        rte_ring_free(host->sendbuf);
    }

    rte_free(host);

    return 0;
}

项目地址

项目地址