【协议森林】基于DPDK的F-Stack原理、基本使用及TCP通信

1.简述

随着网卡性能的飞速发展,10GE 网卡已经大规模普及,25GE/40GE/100GE 网卡也在逐步推广,linux 内核在网络数据包处理上的瓶颈也越发明显,在传统的内核协议栈中,网卡通过硬件中断通知协议栈有新的数据包到达,内核的网卡驱动程序负责处理这个硬件中断,将数据包从网卡队列拷贝到内核开辟的缓冲区中(DMA),然后数据包经过一系列的协议处理流程,最后送到用户程序指定的缓冲区中。在这个过程中中断处理、内存拷贝、系统调用(锁、软中断、上下文切换)等严重影响了网络数据包的处理能力。操作系统的对应用程序和数据包处理的调度可能跨 CPU 调度,局部性失效进一步影响网络性能。
在这里插入图片描述
而互联网的快速发展亟需高性能的网络处理能力,kernel bypass 方案也越来被人所接受,市场上也出现了多种类似技术,如 DPDK、NETMAP、PF_RING 等,其核心思想就是内核只用来处理控制流,所有数据流相关操作都在用户态进行处理,从而规避内核的包拷贝、线程调度、系统调用、中断等性能瓶颈,并辅以各种性能调优手段,从而达到更高的性能。其中 DPDK 因为更彻底的脱离内核调度以及活跃的社区支持从而得到了更广泛的使用。
在这里插入图片描述

2.F-Stack 开发框架

F-Stack 是一款兼顾高性能、易用性和通用性的网络开发框架,传统上 DPDK 大多用于 SDN、NFV、DNS 等简单的应用场景下,对于复杂的 TCP 协议栈上的七层应用很少,市面上已出现了部分用户态协议栈,如 mTCP、Mirage、lwIP、NUSE 等,也有用户态的编程框架,如 SeaStar 等,但统一的特点是应用程序接入门槛较高,不易于使用。
F-Stack 使用纯 C 实现,充当胶水粘合了 DPDK、FreeBSD 用户态协议栈、Posix API、微线程框架和上层应用(Nginx、Redis),使绝大部分的网络应用可以通过直接修改配置或替换系统的网络接口即可接入 F-Stack,从而获得更高的网络性能。
在实践过程中,发现F-Stack对ARM体系兼容性不好,关于CPU方面的编译一直报错,本人并未实践成功。
在这里插入图片描述
F-Stack 总体架构如上图所示,具有以下特点:

  • 使用多进程无共享架构。
  • 各进程绑定独立的网卡队列和 CPU,请求通过设置网卡 RSS 散落到各进程进行处理。
  • 各进程拥有独立的协议栈、PCB 表等资源。
  • 每个 NUMA 节点使用独立的内存池。
  • 进程间通信通过无锁环形队列(rte_ring)进行。
  • 使用 DPDK 作为网络 I/O 模块,将数据包从网卡直接接收到用户态。
  • 移植 FreeBSD Release 11.0.1 协议栈到用户态并与 DPDK 对接。

代码地址:github-fstack
官网论坛:腾讯云

3.快速开始

 # clone F-Stack
  mkdir -p /data/f-stack
  git clone https://github.com/F-Stack/f-stack.git /data/f-stack

  # Install libnuma-dev
  yum install numactl-devel          # on Centos
  sudo apt-get install libnuma-dev  # on Ubuntu

  cd f-stack
  # Compile DPDK,此处注意meson版本
  cd dpdk/
  meson -Denable_kmods=true build
  ninja -C build
  ninja -C build install

 # Set hugepage
 # single-node system
 echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

  # or NUMA
  echo 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
  echo 1024 > /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages

  # Using Hugepage with the DPDK
  mkdir /mnt/huge
  mount -t hugetlbfs nodev /mnt/huge

  # Close ASLR; it is necessary in multiple process
  echo 0 > /proc/sys/kernel/randomize_va_space

  # Install python for running DPDK python scripts
  sudo apt install python # On ubuntu

  # Offload NIC
  modprobe uio
  insmod /data/f-stack/dpdk/build/kernel/linux/igb_uio/igb_uio.ko
  insmod /data/f-stack/dpdk/build/kernel/linux/kni/rte_kni.ko carrier=on # carrier=on is necessary, otherwise need to be up `veth0` via `echo 1 > /sys/class/net/veth0/carrier`
  python dpdk-devbind.py --status
  ifconfig eth0 down
  python dpdk-devbind.py --bind=igb_uio eth0 # assuming that use 10GE NIC and eth0

  # On Ubuntu, use gawk instead of the default mawk.
  #sudo apt-get install gawk  # or execute `sudo update-alternatives --config awk` to choose gawk.

  # Install dependencies for F-Stack
  sudo apt install gcc make libssl-dev # On ubuntu

  # Upgrade pkg-config while version < 0.28
  #cd /data
  #wget https://pkg-config.freedesktop.org/releases/pkg-config-0.29.2.tar.gz
  #tar xzvf pkg-config-0.29.2.tar.gz
  #cd pkg-config-0.29.2
  #./configure --with-internal-glib
  #make
  #make install
  #mv /usr/bin/pkg-config /usr/bin/pkg-config.bak
  #ln -s /usr/local/bin/pkg-config /usr/bin/pkg-config

  # Compile F-Stack
  export FF_PATH=/data/f-stack
  export PKG_CONFIG_PATH=/usr/lib64/pkgconfig:/usr/local/lib64/pkgconfig:/usr/lib/pkgconfig
  cd /data/f-stack/lib/
  make

  # Install F-STACK
  # libfstack.a will be installed to /usr/local/lib
  # ff_*.h will be installed to /usr/local/include
  # start.sh will be installed to /usr/local/bin/ff_start
  # config.ini will be installed to /etc/f-stack.conf
  make install

4.具体过程

  • 编译dpkp过程中注意meson版本,版本过低,编译不起来,需要手动安装meson(>meson-0.47.1)。
ln meson.py -srf /usr/local/bin/meson.py
  • 本篇文章基于x86架构操作,ARM操作编译会有一些问题。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

5.TCPServer

主要函数ff_init、ff_accept、ff_write、ff_read、ff_bind、ff_socket等。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <assert.h>

#include "ff_config.h"
#include "ff_api.h"

#define MAX_EVENTS 512

/* kevent set */
struct kevent kevSet;
/* events */
struct kevent events[MAX_EVENTS];
/* kq */
int kq;
int sockfd;

char html[] = 
"HTTP/1.1 200 OK\r\n"
"Server: F-Stack\r\n"
"Date: Sat, 25 Feb 2017 09:26:33 GMT\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 438\r\n"
"Last-Modified: Tue, 21 Feb 2017 09:44:03 GMT\r\n"
"Connection: keep-alive\r\n"
"Accept-Ranges: bytes\r\n"
"\r\n"
"<!DOCTYPE html>\r\n"
"<html>\r\n"
"<head>\r\n"
"<title>Welcome to F-Stack!</title>\r\n"
"<style>\r\n"
"    body {  \r\n"
"        width: 35em;\r\n"
"        margin: 0 auto; \r\n"
"        font-family: Tahoma, Verdana, Arial, sans-serif;\r\n"
"    }\r\n"
"</style>\r\n"
"</head>\r\n"
"<body>\r\n"
"<h1>Welcome to F-Stack!</h1>\r\n"
"\r\n"
"<p>For online documentation and support please refer to\r\n"
"<a href=\"http://F-Stack.org/\">F-Stack.org</a>.<br/>\r\n"
"\r\n"
"<p><em>Thank you for using F-Stack.</em></p>\r\n"
"</body>\r\n"
"</html>";

int loop(void *arg)
{
    /* Wait for events to happen */
    unsigned nevents = ff_kevent(kq, NULL, 0, events, MAX_EVENTS, NULL);
    unsigned i;

    for (i = 0; i < nevents; ++i) {
        struct kevent event = events[i];
        int clientfd = (int)event.ident;

        /* Handle disconnect */
        if (event.flags & EV_EOF) {
            /* Simply close socket */
            ff_close(clientfd);
        } else if (clientfd == sockfd) {
            int available = (int)event.data;
            do {
                int nclientfd = ff_accept(clientfd, NULL, NULL);
                if (nclientfd < 0) {
                    printf("ff_accept failed:%d, %s\n", errno,
                        strerror(errno));
                    break;
                }

                /* Add to event list */
                EV_SET(&kevSet, nclientfd, EVFILT_READ, EV_ADD, 0, 0, NULL);

                if(ff_kevent(kq, &kevSet, 1, NULL, 0, NULL) < 0) {
                    printf("ff_kevent error:%d, %s\n", errno,
                        strerror(errno));
                    return -1;
                }

                available--;
            } while (available);
        } else if (event.filter == EVFILT_READ) {
            char buf[256];
            size_t readlen = ff_read(clientfd, buf, sizeof(buf));

            ff_write(clientfd, html, sizeof(html) - 1);
        } else {
            printf("unknown event: %8.8X\n", event.flags);
        }
    }
}

int main(int argc, char * argv[])
{
    ff_init(argc, argv);

    assert((kq = ff_kqueue()) > 0);

    sockfd = ff_socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        printf("ff_socket failed, sockfd:%d, errno:%d, %s\n", sockfd, errno, strerror(errno));
        exit(1);
    }

    struct sockaddr_in my_addr;
    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(80);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    int ret = ff_bind(sockfd, (struct linux_sockaddr *)&my_addr, sizeof(my_addr));
    if (ret < 0) {
        printf("ff_bind failed, sockfd:%d, errno:%d, %s\n", sockfd, errno, strerror(errno));
        exit(1);
    }

     ret = ff_listen(sockfd, MAX_EVENTS);
    if (ret < 0) {
        printf("ff_listen failed, sockfd:%d, errno:%d, %s\n", sockfd, errno, strerror(errno));
        exit(1);
    }

    EV_SET(&kevSet, sockfd, EVFILT_READ, EV_ADD, 0, MAX_EVENTS, NULL);
    /* Update kqueue */
    ff_kevent(kq, &kevSet, 1, NULL, 0, NULL);

    ff_run(loop, NULL);
    return 0;
}

编译出来,并加载配置文件config.ini,就可以运行。

6.参与讨论

在这里插入图片描述

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 腾讯的开源协议栈f-stack.pdf是在DPDK技术峰会上推出的一项重要技术创新。DPDK技术峰会是一个技术交流平台,旨在推动数据平面开发工具包(DPDK)技术的发展和应用。f-stack.pdf是腾讯开源的一套协议栈,它通过与DPDK集成,提供了高性能的网络数据包处理能力。 f-stack.pdf具有以下几个特点:高性能、轻量级和易使用。它基于零拷贝技术,能够以卓越的性能处理数据包。同时,f-stack.pdf采用了轻量级设计,只依赖于DPDK的核心功能,避免了不必要的复杂性,使得使用起来更加简单和灵活。 f-stack.pdf在应用层提供了一系列网络协议的支持,例如TCP、UDP和IP等。它提供了高度可扩展和定制化的接口,使得开发者可以根据具体需求进行定制和优化。另外,f-stack.pdf还提供了丰富的功能和工具,方便开发者进行网络应用的开发和调试。 该协议栈不仅适用于云服务器、网络设备和高速存储等领域,还可以广泛应用于物联网、5G通信和金融等行业。它的高性能和低延迟使得在大规模并发场景下的数据处理更加高效和稳定。 腾讯的开源协议栈f-stack.pdf在DPDK技术峰会上的推出,标志着中国企业在高性能网络技术领域的一次重要突破。它的出现将有助于促进我国网络技术的创新和发展,并提升我国在全球高性能网络领域的竞争力。 ### 回答2: 腾讯的开源协议栈f-stackDPDK技术峰会上推出的一项重要的技术成果。该技术是基于DPDK(Data Plane Development Kit)开发的一套网络数据包处理框架,旨在提供高性能的网络数据包处理和协议栈功能。 f-stack的特点可以从以下几个方面来描述。首先,它采用了用户态的网络协议栈设计,将协议处理功能从内核态迁移到用户态,避免了内核态和用户态的频繁切换,提高了数据包处理的效率。其次,f-stack提供了一套完整的网络协议栈功能,包括TCP/IP协议栈、套接字接口、事件驱动机制等,可以支持常见的网络应用开发。此外,f-stack还提供了网络收发模块、队列管理、内存池等高性能的数据结构和算法,以进一步提升数据包处理的吞吐量和延迟。 通过使用f-stack,开发者可以轻松地构建高性能的网络应用,无论是在云计算、大数据分析还是边缘计算等场景中,都能够获得更好的性能和响应速度。与传统的网络协议栈相比,f-stack具有更低的延迟、更高的吞吐量和更好的可扩展性,能够更好地满足现代网络应用对于高性能数据处理的需求。 最后,开源协议栈f-stack的推出也体现了腾讯在网络技术领域的创新能力和开放合作的精神。通过开源的方式,腾讯可以与其他行业的开发者和研究机构共同探索和推进网络技术的发展,形成合力并推动整个行业的进步。 总的来说,腾讯的开源协议栈f-stackDPDK技术峰会上的推出,为高性能网络数据包处理和协议栈开发提供了一个有力的工具和平台,对于促进网络技术的创新和发展具有重要意义。 ### 回答3: 腾讯的开源协议栈f-stack.pdf是关于dpdk技术峰会的一个重要文档。DPDK技术峰会是一个旨在促进DPDK技术发展和交流的会议,汇集了众多DPDK技术领域的专家和爱好者。 在f-stack.pdf中,腾讯团队分享了他们开发的开源协议栈f-stack的技术细节和应用场景。f-stack是一个高性能、可扩展的协议栈,基于DPDK技术开发,旨在提供更好的网络性能和更高的数据包处理能力。 f-stack的设计目标主要包括:轻量级、高性能、可扩展和易用性。它采用了一系列的优化技术,如零拷贝、多队列和事件驱动等,以提高数据包的处理效率。f-stack支持多种协议,如TCP、UDP和IP等,可以满足不同应用场景的需求。 此外,f-stack还提供了一些额外的功能,如高效的内存管理、负载均衡和安全性等。这些功能使得f-stack在网络应用程序的开发中更加方便和灵活。 f-stack已经在腾讯内部得到广泛的应用和验证,取得了良好的性能和稳定性。它已经成为了腾讯云和腾讯游戏等业务的核心组件。 总的来说,f-stack的出现充分展示了腾讯在DPDK技术领域的创新能力和技术实力。它为广大开发者提供了一个高效、可扩展的协议栈解决方案,有助于进一步推动DPDK技术的应用和发展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值