【协议森林】基于DPDK的原生态协议栈DPDK-ANS

1.简述

ANS(加速网络堆栈)是DPDK本地TCP/IP堆栈,也参考FreeBSD实现。ANS提供了一个与Intel DPDK一起使用的用户空间TCP/IP堆栈。

2.框架

ans:加速网络堆栈过程

  • librte_ans:TCP/IP 堆栈静态库。ANS 使用 dpdk mbuf、ring、memzone、mempool、timer、spinlock。所以在 dpdk 和 ANS 之间零拷贝 mbuf。
  • librte_anssock:应用程序的 ANS 套接字库,ANS 和应用程序之间的零复制。
  • librte_anscli:用于路由/ip/neigh/link 配置的 ANS cli 库。
  • cli:用于配置 ANS tcp/ip 堆栈的命令。
  • 示例:ANS 应用示例。
  • 测试:带有 ANS 的示例应用程序,用于测试 ANS tcp/ip 堆栈
    在这里插入图片描述

3.代码架构

在这里插入图片描述
支持环境

  • EAL 基于 dpdk-18.11;
  • linux 版本: 4.4.0-45-generic (Ubuntu 16.04.1 LTS)。
  • gcc 版本: gcc 版本 5.4.0 20160609。

支持功能:

  • ANS 初始化;
  • ANS 在容器中运行;
  • Ether,NIC 和 ANS TCP/IP 堆栈之间的零复制;
  • ARP,ARP超时;
  • IP层,IP分片和重组;
  • 高性能路由;
  • ICMP;
  • 访问控制列表;
  • 绕过流量到linux内核;
  • 从 linux 内核同步 IP/路由;
  • 支持动态路由(OSPF/BGP…);
  • 支持DHCP客户端;

命令行界面:

  • 添加、删除、显示IP地址;
  • 添加、删除、显示静态路由;
  • 显示邻居表;
  • 显示界面和统计信息;
  • 显示 IP 统计信息;
  • 添加、删除、显示ACL;
  • 添加、删除、显示绕过规则;
  • 显示端口队列 lcore 映射;
  • 添加、删除、显示流量过滤规则;
  • UDP协议;
  • 套接字层;
    Socket API兼容BSD,APP可以基于开关选择ANS socket或linux socket。
    socket/bind/connect/listen/close/send/recv/epoll/writev/readv/shutdown…;
    支持openssl;
  • TCP协议;
  • 支持可靠传输;
  • 支持基于dupack的重传,基于超时的重传;
  • 支持流量控制;
  • 支持拥塞控制:newreno/cubic/vegas…;
  • 支持最大段大小;
  • 支持选择性确认;
  • 支持窗口缩放;
  • 支持TCP时间戳;
  • 支持TCP ECN;
  • 支持保持活力;
  • 支持SO_REUSEPORT,多个应用可以监听同一个端口;
  • 支持多核tcp堆栈,每个lcore每个tcp堆栈;
  • 支持TSO。
  • 路由器;
  • 支持虚拟主机;
  • 支持虚拟用户;
  • 支撑刀;
  • 支持敲击;

硬件;

  • x86:broadwell、haswell、ivybridge、knl、sandybridge、westmere 等。
  • arm:arm64 SoC 和边缘计算机;

4.http_server

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <unistd.h>
#include <sys/times.h>

#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <netinet/in.h>
#include <termios.h>
#include <sys/epoll.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#ifndef __linux__
#ifdef __FreeBSD__
#include <sys/socket.h>
#else
#include <net/socket.h>
#endif
#endif

#include <sys/time.h>
#include "anssock_intf.h"
#include "ans_errno.h"


#define BUFFER_SIZE 5000
#define MAX_EVENTS 512
#define MAX_CPUS 8

char *http_200 = "HTTP/1.0 200 OK\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Connection: close\r\n"
                 "Content-Type: text/html\r\n"
                 "\r\n"
                 "<html><body><h1>200 OK</h1>\nHello world.\n</body></html>\n";

static int HandleReadEvent(int epoll_fd, struct epoll_event ev)
{
    int rd;
    int i;
    int len;
    int sent;
    char recv_buf[BUFFER_SIZE];
    int sockid = ev.data.fd;
    /* HTTP request handling */
    rd = anssock_recvfrom(sockid, recv_buf, BUFFER_SIZE, 0, NULL, NULL);

    if (rd <= 0) {
        return rd;
    }
    /* just response http 200*/
    len = strlen(http_200);
    sent = anssock_send(ev.data.fd, http_200, len, 0);

    ev.events = EPOLLIN | EPOLLOUT;
    anssock_epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sockid, NULL);
//    printf("read and close sockid:%d\n", sockid); //test purpose
    return rd;
}


int RunServerThread()
{
    int ret;
    int server_sockfd;
    int client_sockfd;
    struct sockaddr_in my_addr;
    struct sockaddr_in remote_addr;
    int sin_size;
    int do_accept;
    int opt_val = 1;

    ret = anssock_init(NULL);
    if (ret != 0)
        printf("init sock failed \n");

    // end initialized
    memset(&my_addr, 0, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_addr.s_addr = INADDR_ANY;
    my_addr.sin_port = htons(8089);

    if ((server_sockfd = anssock_socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("socket error \n");
        return 1;
    }

    if(anssock_setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEPORT, &opt_val, sizeof(int)) < 0)
    {
        printf("set socket option failed \n");
    }

    if (anssock_bind(server_sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) < 0)
    {
        printf("bind error \n");
        return 1;
    }

    if (anssock_listen(server_sockfd, 2048) < 0)
    {
        printf("listen error \n");
        return 1;
    }

    sin_size = sizeof(struct sockaddr_in);
    /* wait for incoming accept events */
    /* create epoll descriptor */
    int epoll_fd;
    epoll_fd = anssock_epoll_create(MAX_EVENTS);
    if (epoll_fd == -1)
    {
        printf("epoll_create failed \n");
        return 1;
    }

    struct epoll_event ev;
    struct epoll_event events[MAX_EVENTS];
    ev.events = EPOLLIN | EPOLLET;
    ev.data.fd = server_sockfd;

    if (anssock_epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_sockfd, &ev) == -1)
    {
        printf("epll_ctl:server_sockfd register failed");
        anssock_close(server_sockfd);
        anssock_close(epoll_fd);
        return 1;
    }

    int nfds;
    struct sockaddr_in* pV4Addr = (struct sockaddr_in*)&my_addr;
    int ipAddr = pV4Addr->sin_addr.s_addr;
    char ipstr[INET_ADDRSTRLEN];
    inet_ntop( AF_INET, &ipAddr, ipstr, INET_ADDRSTRLEN );
    printf("open socket on ip:%s  port: %d\n", ipstr, ntohs(my_addr.sin_port));

    while (1)
    {
        nfds = anssock_epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (nfds == -1)  {
            printf("start epoll_wait failed");
            anssock_close(server_sockfd);
            anssock_close(epoll_fd);
            return 1;
        }

        int i;
        do_accept = 0;
        for (i = 0; i < nfds; i++)
        {
            int sockid = events[i].data.fd;
            if (sockid == server_sockfd) { //accept case
                do_accept = 1;
            }
            else
            {
                if (events[i].events & EPOLLERR) { //epoll error event
                    int err;
                    socklen_t len = sizeof(err);

                    /* error on the connection */
                    anssock_epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sockid, NULL);
                    anssock_close(sockid);
                }
                if (events[i].events == EPOLLIN) { //epollin  read and write
                    int ret = HandleReadEvent(epoll_fd, events[i]);
                    anssock_close(sockid);
                }
                if (events[i].events == EPOLLOUT) { //epollout write
                    int LEN = strlen(http_200);
                    anssock_send(sockid, http_200, LEN, 0);
                    anssock_epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sockid, NULL);
                    anssock_close(sockid);
                }
                if (events[i].events == EPOLLHUP) { //remote close the socket
                    anssock_epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sockid, NULL);
                    anssock_close(sockid);
                }
            }
        }
        if (do_accept) {
            while (1) {
                int c = anssock_accept(server_sockfd, NULL, NULL);
                if (c >= 0) {
                    struct epoll_event ev;
                    //accept connection and wait EPOLLIN EVENT
                    ev.events = EPOLLIN | EPOLLET;
                    ev.data.fd = c;
                    anssock_epoll_ctl(epoll_fd, EPOLL_CTL_ADD, c, &ev);
                    //      printf("Socket %d registered.\n", c);
                } else {  //c<0
                    /*     printf("mtcp_accept() error %s\n",
                               strerror(errno));*/
                    break;
                }
            }
        }//end if
    }
    anssock_close(server_sockfd);

    return 0;
}


int main(int argc, char *argv[])
{
    int core =0;

    if(argc >= 2)
    {
        core = atoi(argv[1]);
        printf("affinity to core %d \n", core);
    }
    else
    {
        printf("affinity to 0 core by default \n");
    }

      /*initialize thread bind cpu*/
    cpu_set_t cpus;

    CPU_ZERO(&cpus);
    CPU_SET((unsigned)core, &cpus);
    sched_setaffinity(0, sizeof(cpus), &cpus);

    RunServerThread();
}

5.参与讨论

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值