gre包分片及gro、gso等offload特性的应用

                       

                                                                          图1

直接上图,再分别简单介绍各部分:

PC:笔记本电脑。

gw1:使用一台微型服务器模拟企业用户网关,同时添加静态路由使具备简单路由功能。

gw2:模拟ISP,同时添加静态路由使具备简单路由功能。

TPB:使用linux bridge桥接eth2、eth3。这里有个特殊功能,修改linux内核网络协议栈源码,使内核在不使用GRE模块情况下,具有对IP数据报的加封装和解封装GRE包头功能,同时具备GRE数据包的分片功能。

POP:模拟网络服务(如VPN服务等)提供点,这里省略了很多的网络功能,然后为了能够访问外网,对应于TPB具有加封装和解封装GRE包头功能,也是修改的linux内核网络协议栈源码。

GW3:pfsense(软防火墙和路由器),连接公司网关通往外网。

 

  • iptables 对数据包打标记

iptables -t mangle -A FORWARD -d x.x.x.x/x -j MARK --set-mark 47

这样代码中可以识别出数据包在内核缓存中是否被标记:

if(skb->mark == 47)
    ... ...

然后对这些被识别出的数据包添加GRE包头, 这里的GRE包头是数据包包头的最外层IP层和GRE层的总称。

 

  • 加封装和解封装GRE包头(GRE over IPv4)

这里以内核版本版本2.6.32-431.el6.x86_64为例。

下面是ip_gre模块中从加封装GRE包头到发送的代码流程:

netif_receive_skb  -->  deliver_skb  -->  ip_rcv  -->  ip_rcv_finish  -->  dst_input  -->  ip_forward  --> ip_forward_finish  --> dst_output  -->  ip_output  --> ip_finish_output  -->  ip_finish_output2  --> arp_constructor -->  dev_queue_xmit  -->  dev_hard_start_xmit  -->  ipgre_xmit  -->  __gre_xmit  -->  gre_build_header  -->  ip_tunnel_xmit  -->  ip_local_out  -->  dst_output  -->  dev_queue_xmit  

流程比较复杂,这里附上最简版的添加GRE包头的代码,下面代码是经过测试的,但不是在内核源码任何地方都可以用,使用前必须保证skb->data初始位置在MAC层位置上:

int TPB_xmit(struct sk_buff *skb)
{
    struct gre_base_hdr *greh;
    struct iphdr *iph, *inner_iph;
    int needed_headroom = 38;
    int tunnel_hlen = 4;
    unsigned char eth_addr[ETH_ALEN];

    unsigned char hh_data[14]; 
    struct ethhdr *eth1, *eth2;
    const u8 *p1;
    u8 eth_daddr[ETH_ALEN];

    skb->encapsulation = 1;
    skb_reset_network_header(skb);   
   
    if (skb_cow_head(skb, needed_headroom))  //扩展包头,以容得下新添加的IP层和GRE层
        return 0;
    skb_pull(skb, 14);                       //将skb->data向数据方向后移14个字节(即mac层长度)的位置,IP头的位置
    eth1 = eth_hdr(skb);
    memcpy(eth_addr, eth1->h_source, ETH_ALEN);
    memcpy(eth_daddr, eth1->h_dest, ETH_ALEN);
    inner_iph = (struct iphdr*)skb->data;
    skb_push(skb, tunnel_hlen);          //将skb->data向数据方向反向移动4个字节(GRE包头长度)
    greh = (struct gre_base_hdr *)skb->data;
    greh->flags = 0;
    greh->protocol = skb->protocol;

    skb_push(skb, sizeof(struct iphdr)); //将skb->data向数据方向反向移动sizeof(struct iphdr)个字节(即IP层长度)的位置,设置为最外层IP头的位置
    skb_reset_network_header(skb);

    iph = ip_hdr(skb);
    iph->version    =       4;
    iph->ihl        =       sizeof(struct iphdr) >> 2;
    iph->frag_off   =       0;
    iph->protocol   =       IPPROTO_GRE;
    iph->tot_len = inner_iph->tot_len + htons(24);
    iph->tos        =       0;
    iph->daddr      =       ip_array_TPB[1];
    iph->saddr      =       ip_array_TPB[0];
    iph->ttl        =       64;
    iph->id = inner_iph->id;
    iph->check = 0;
    iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
    
    eth2 = (struct ethhdr*) (((u8 *) hh_data) );
    eth2->h_proto = skb->protocol;
    memcpy(eth2->h_source, eth_addr, ETH_ALEN);
    memcpy(eth2->h_dest, eth_daddr, ETH_ALEN);
    p1= (const u8*)hh_data;

    skb_push(skb, 14);   //将skb->data向数据方向反向移动14个字节(即MAC层长度),设置为MAC头的位置
    skb_reset_mac_header(skb);
    memcpy(skb->data, hh_data, 14);
    return 0;
}

接下来的解封装GRE包头介绍,以下ip_gre模块中解封装GRE包头的代码流程:

netif_receive_skb  -->  deliver_skb  -->  ip_rcv  -->  ip_rcv_finish  -->  dst_input  -->  ip_local_deliver  -->  ip_local_deliver_finish  -->  gre_rcv  -->  gre_cisco_rcv  -->  ipgre_rcv  -->  ip_tunnel_lookup  -->  ip_tunnel_rcv  -->  gro_cells_receive  -->  napi_schedule  -->  __napi_schedule  -->  ____napi_schedule  -->  netif_receive_skb  -->  deliver_skb  -->  ip_rcv  -->  ip_rcv_finish  -->  dst_input  -->  ip_forward  --> ip_forward_finish  -->  dst_output  -->  dev_queue_xmit

同样,流程比较复杂,这里附上最简版解封装GRE包头代码:

struct sk_buff* TPB_trim_gre_header(struct sk_buff *skb)
{
        unsigned char hh_data[14];
        unsigned char* skb_data_ptr; 
        skb->data = skb_mac_header(skb);
        skb_data_ptr = skb->data;
        memcpy(hh_data, skb_data_ptr, 14);
        skb_pull(skb, 24);
        skb_reset_mac_header(skb);
        memcpy(skb->data, hh_data, 14);
        skb_pull(skb, 14);
        skb_reset_network_header(skb);
        skb_push(skb, 14);
        return skb;
}

 

  • GRE包头分片

目前硬件还不支持GRE分片,只能在代码层对GRE包头进行分片。看下整个协议栈的GSO处理逻辑:

      

                                                   图2

详情参考博客: https://www.cnblogs.com/lvyilong316/p/6818710.html

这里在图中tcp_tso_segment处做更改,如下:

dev_hard_start_xmit --> dev_gso_segment  -->  skb_gso_segment  --> skb_mac_gso_segment  -->  inet_gso_segment

-->  gre_gso_segment -->  skb_mac_gso_segment  -->  inet_gso_segment  --> tcp_tso_segment

static const struct net_offload gre_offload = {
        .gso_send_check =       gre_gso_send_check,
        .gso_segment    =       gre_gso_segment,
};

inet_add_offload(&gre_offload, IPPROTO_GRE);

static int gre_gso_send_check(struct sk_buff *skb)
{
        if (!skb->encapsulation)
                return -EINVAL;
        return 0;
}

static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
                                       int features)
{
    ... ...
}

注意:

在图1中,TPB节点和POP节点都具有加封装和解封装GRE包头功能,在POP节点接收来自TPB节点的加封装的数据包,并且进行GRE分片,如果没有关闭网卡eth3的generic-receive-offload 特性,这里分片的数据包会合并,由于数据包长超过MTU值,会被丢弃, 这里可以暂时将该特性关闭,执行命令 ethtool -K eth3 gro off。

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LRO (Large Receive Offload) 和 GRO (Generic Receive Offload) 是网络协议栈中的两种技术,用于优化数据的接收处理。 LRO 主要用于 TCP,而 GRO 则适用于所有传输协议 。 LRO 是一种在网卡上进行数据处理的技术,它将多个接收到的小数据合并成一个大的数据,减少了处理的开销。这种技术可以有效地提高网络性能和吞吐量。然而,LRO 只适用于 TCP 协议 。 GRO 是在内核网络协议栈中实现的技术,它通过合并接收到的数据来减少处理的开销,提高网络性能。与 LRO 不同,GRO 可以应用于所有传输协议,而不仅限于 TCP。GRO 还保留了每个接收到的数据的熵信息,这对于像路由器这样的应用非常重要。通过匹配条件,如源/目的地址、TOS/协议字段、源/目的端口等,可以进行适当的数据合并 。 TSO (TCP Segmentation Offload) 和 GSO (Generic Segmentation Offload) 是用于发送数据的技术。它们的作用是将大的数据分割成更小的片段,以提高传输效率。TSO 主要用于 TCP,而 GSO 则适用于所有传输协议 。 总结起来,LRO 和 GRO 是用于接收数据的技术,通过合并数据减少处理的开销。TSO 和 GSO 是用于发送数据的技术,通过分割大的数据提高传输效率。这些技术都在 Linux 内核的网络协议栈中发挥着重要的作用,提高了网络性能和吞吐量 。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Linux环境中的网络分段卸载技术 GSO/TSO/UFO/LRO/GRO](https://blog.csdn.net/Rong_Toa/article/details/108748689)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值