前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >learning vnet:L2 vSwitch shg 水平分割组 (3)

learning vnet:L2 vSwitch shg 水平分割组 (3)

作者头像
dpdk-vpp源码解读
发布2024-05-14 18:27:42
960
发布2024-05-14 18:27:42
举报
文章被收录于专栏:DPDK VPP源码分析DPDK VPP源码分析

本文讲解在二层桥接域下水平分割组的应用。当接口加入到桥接域中时可以指定shg(水平分割组标识符)。可与任何承载2层数据的接口(例如硬件接口、L2 GRE 隧道等)一起使用,但主要与 VXLAN 接口一起使用。

SHG功能主要应用于桥接或VLAN环境,以防止广播、多播或者某些单播流量在网络中形成环路。具体来说,L2 SHG的作用如下:

  • 防止环路形成:类似于路由协议中的水平分割原则,L2 SHG确保从某个接口接收到的二层帧不会被转发回原接口所在的网络段,从而避免了广播风暴和多播流量的无限循环传播,保证了网络的稳定性和效率。
  • 优化数据传输:通过限制不必要的流量复制和转发,SHG有助于减少网络中的冗余流量,提升带宽的有效利用率。
  • 支持复杂网络设计:在复杂的网络架构中,比如那些包含多个VLAN或桥接域的设计,L2 SHG提供了更为细粒度的控制手段,使得网络工程师能够针对特定的接口或接口组定制水平分割规则,以适应特殊的需求或避免特定的环路场景。

下面是接口加入BD域命令行配置:

代码语言:javascript
复制
set interface l2 bridge <interface> <bridge-domain-id> [bvi|uu-fwd] [shg]

当在桥接域的成员上配置非零 SHG 时,VPP不会将到达该接口的数据包转发到配置有相同 SHG 标识符的桥接域的任何其他成员。这对于防止数据包在对等点之间互连的成员接口之间环回很有用。默认情况下shg数值为0,表示禁用SHG检查。

接下来搭建环境来验证SHG功能,创建3个tap接口,tap1和tap2接口分别加入命名空间pc1和pc2中,tap3默认在内核,其中tap2和tap3指定设置水平分割1。 具体组网如下:

首先需要在内核创建2个命名空间pc1和pc1,然后再vpp的命令行视图下上配置如下命令。

代码语言:javascript
复制
create bridge-domain 1

creat tap id 1 host-ns pc1 host-ip4-addr 192.168.1.1/24 host-if-name tap1

creat tap id 2 host-ns pc2 host-ip4-addr 192.168.1.2/24 host-if-name tap2

creat tap id 3  host-ip4-addr 192.168.1.3/24 host-if-name tap3

set interface state tap1 up
set interface state tap2 up
set interface state tap3 up
set interface l2 bridge tap1 1
set interface l2 bridge tap2 1 1
set interface l2 bridge tap3 1 1

可以通过命令行show bridge-domain 1 detail查询BD域1下面接口配置信息,其中可以看到tap1 SHG=0,tap2和tap3 SHG=1.

代码语言:javascript
复制
dpdk-vpp源码分析: show bridge-domain 1 detail
  BD-ID   Index   BSN  Age(min)  Learning  U-Forwrd   UU-Flood   Flooding  ARP-Term  arp-ufwd Learn-co Learn-li   BVI-Intf 
    1       1      0     off        on        on       flood        on       off       off        3    16777216     N/A    
span-l2-input l2-input-classify l2-input-feat-arc l2-policer-classify l2-input-acl vpath-input-l2 l2-ip-qos-record l2-input-vtr l2-learn l2-rw l2-fwd l2-flood l2-flood l2-output 

           Interface           If-idx ISN  SHG  BVI  TxFlood        VLAN-Tag-Rewrite       
             tap1                1     1    0    -      *                 none             
             tap2                2     1    1    -      *                 none             
             tap3                3     1    1    -      *                 none             
#l2fib表学习情况
dpdk-vpp源码分析: show l2fib bd_id 1
    Mac-Address     BD-Idx If-Idx BSN-ISN Age(min) static filter bvi         Interface-Name        
 02:fe:a6:ce:4a:d4    1      1      0/1      -       -      -     -               tap1             
 02:fe:2e:4d:7d:cc    1      3      0/1      -       -      -     -               tap3             
 02:fe:18:13:4f:a2    1      2      0/1      -       -      -     -               tap2             
L2FIB total/learned entries: 3/3  Last scan time: 0.0000e0sec  Learn limit: 500 

接下来我们在内核上分别ping tap1和tap2接口ip地址,预期tap1接口192.168.1.1可以ping通,但无法ping通tap2接口ip地址。

接下来在命名空间PC1上分别ping tap2和tap3接口ip地址,预期结果都可以ping通。

下面通过l2_flood 节点代码来走读一下泛洪处理逻辑。在l2_input节点时会通过RX接口查询到接口的配置信息BD_index和shg数值记录到报文元数据中。在l2_flood节点从报文元数据中获取到BD_index,查询BD域的配置信息。具体结构体如下:

其中members记录当前BD域下成员口信息;flood_count记录当前BD成员口需要泛洪的数量。遍历待泛洪成员口信息,判断是否需要泛洪。下面两种情况不在泛洪成员中,1、泛洪成员口接口索引等于入接口索引;2、设置了SHG,且泛洪成员口SHG数值等于入接口SHG数值。下面是具体代码逻辑

代码语言:javascript
复制
VLIB_NODE_FN (l2flood_node) (vlib_main_t * vm,
                 vlib_node_runtime_t * node, vlib_frame_t * frame)
{
                .....

    b0 = vlib_get_buffer (vm, bi0);
    /*获取BD的配置,bd_index和shg是在l2 input 节点赋值的*/
    bd_config = vec_elt_at_index (l2input_main.bd_configs,
                    vnet_buffer (b0)->l2.bd_index);
    /*记录入接口shg数值*/
    in_shg = vnet_buffer (b0)->l2.shg;
    sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];

   vec_validate (msm->members[thread_index],vec_len (bd_config->members));
   vec_reset_length (msm->members[thread_index]);
   /*查询当前BD域下,需要泛洪的成员口,加入到当前线程临时缓存区*/
   for (mi = bd_config->flood_count - 1; mi >= 0; mi--)
   {
      member = &bd_config->members[mi];
      /*泛洪口需要排除下面几中情况,1、泛洪接口索引等于入接口索引
        2、设置水平分割组,切与入接口水平分割相同时*/
      if ((member->sw_if_index != sw_if_index0) &&
         (!in_shg || (member->shg != in_shg)))
       {
            vec_add1 (msm->members[thread_index], member);
       }
    }
    /*查询当前报文需要泛洪的数量*/
    n_clones = vec_len (msm->members[thread_index]);
    if (0 == n_clones)
    {
     /*需泛洪成员口数量为0时,报文丢弃处理*/    
    }
    else if (n_clones > 1)
    {
         /*大于1时,报文进行泛洪处理*/
    }
    else {
        /*只有一个待泛洪接口*/
     ci0 = bi0;
     member = msm->members[thread_index][0];
    }

}

在遍历BD域成员口是否需要泛洪时,采用的倒序的处理方式,这里在接口加入BD域时会更具接口泛洪类型按照顺序来插入到成员口中。具体顺序如下:[bvi, normal/tun_masters..., tun_normals... no_flood]。下面是接口flood_class类型。

当泛洪时,bvi接口(如果存在)必须是最后处理的成员,因为bvi处理可以改变数据包。为了实现这个顺序,我们将bvi接口设置为向量中的第一个接口,并使泛洪以相反的方式遍历向量。计数flood_count决定从成员列表的哪个位置开始泛洪。flood_count数据也是根据接口flood类型来计算的。具体代码如下:

代码语言:javascript
复制
static void
update_flood_count (l2_bridge_domain_t * bd_config)
{
  bd_config->flood_count = (vec_len (bd_config->members) -
                (bd_config->tun_master_count ?
                 bd_config->tun_normal_count : 0));
  bd_config->flood_count -= bd_config->no_flood_count;
}
void
bd_add_member (l2_bridge_domain_t * bd_config, l2_flood_member_t * member)
{
  u32 ix = 0;
  vnet_sw_interface_t *sw_if = vnet_get_sw_interface
    (vnet_get_main (), member->sw_if_index);

  switch (sw_if->flood_class)
    {
    case VNET_FLOOD_CLASS_NO_FLOOD:
      bd_config->no_flood_count++;
      ix = vec_len (bd_config->members);
      break;
    case VNET_FLOOD_CLASS_BVI:
      ix = 0;
      break;
    case VNET_FLOOD_CLASS_TUNNEL_MASTER:
      bd_config->tun_master_count++;
      /* Fall through */
    case VNET_FLOOD_CLASS_NORMAL:
      ix = (vec_len (bd_config->members) -
        bd_config->tun_normal_count - bd_config->no_flood_count);
      break;
    case VNET_FLOOD_CLASS_TUNNEL_NORMAL:
      ix = (vec_len (bd_config->members) - bd_config->no_flood_count);
      bd_config->tun_normal_count++;
      break;
    }

  vec_insert_elts (bd_config->members, member, 1, ix);
  update_flood_count (bd_config);
}

由此可见,不是加入到BD接口所有接口都会泛洪,还存在一些处理逻辑。

总结,在Bridge-Domain并添加接口时,可以通过设置不同的SHG来控制哪些接口间的流量应该被阻止回传,以此达到管理和优化数据平面流量的目的。这在虚拟化环境、数据中心网络、以及需要高性能数据包处理的场景中尤为重要。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DPDK VPP源码分析 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档