前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >learning vpp:解析创建vlan子接口代码(1)

learning vpp:解析创建vlan子接口代码(1)

作者头像
dpdk-vpp源码解读
发布2024-04-02 16:24:17
2660
发布2024-04-02 16:24:17
举报
文章被收录于专栏:DPDK VPP源码分析DPDK VPP源码分析

前面一篇文章《learning:vpp实现dot1q终结功能配置》介绍了vlan dot1q终结子接口功能配置,下面参考vpp官方文档介绍一下创建vlan子接口的命令行。我们都知道vpp默认都是从物理或虚拟主接口收包,那么vpp如何识别vlan报文并将报文转发至vlan子接口上进行业务处理,本文将逐步展开学习。

创建vlan子接口的命令行如下所示:该命令用于为接口(也称为子接口)添加VLAN ID。此命令的主要输入是interface和subId (子接口 ID)参数。如果我们不指定VLAN ID,那么VLAN ID 等于subId,当然VLAN ID subId也可以配置不同,但是一般不建议这样配置。

代码语言:javascript
复制
create sub-interfaces <interface> {<subId> [default|untagged]} | {<subId>-<subId>} | {<subId> dot1q|dot1ad <vlanId>|any [inner-dot1q <vlanId>|any] [exact-match]}

vpp中提供了一个命令行设置接口tag数值,从代码上分析此设置转发中并没有使用的,可能是为了当接口vlan IDsubID 配置不同时,可以通过命令行查询到tag数值。

代码语言:javascript
复制
DBGvpp# set interface tag tap10.12 10
DBGvpp# show interface tap10.12 tag verbose
tap10.12: 10

该创建子接口命令行有许多种变体:

代码语言:javascript
复制
# 创建子接口来处理具有给定 802.1q VLAN ID(与 的值相同subId)的数据包。
create sub-interfaces <interface> <subId> 
# 添加该 default参数表示VLAN ID 与任何其他子接口都不匹配的数据包应发送到该子接口。
create sub-interfaces <interface> <subId> default 
# 添加该 untagged参数表示不应将没有VLAN ID 的数据包发送到该子接口。
create sub-interfaces <interface> <subId> untagged 
# 批量创建创建vlan子接口
create sub-interfaces <interface> <subId>-<subId> 
# 使用此命令指定外部VLAN ID,可以是显式的,也可以使 VLAN ID 不同于subId.
create sub-interfaces <interface> <subId> dot1q|dot1ad < vlan Id>|any [exact-match] 
# 使用此命令指定外部VLAN ID 和内部 VLAN ID,也就是qinq接口
create sub-interfaces <interface> <subId> dot1q|dot1ad < vlan Id>|any inside-dot1q <vlanId>|any [exact-match] - 

当显式输入dot1qdot1ad,子接口可以配置为精确匹配或非精确匹配。CLI 默认设置为非精确匹配。如果exact-match指定,则数据包必须具有与配置相同数量的vlan tag。对于非精确匹配,数据包必须至少有该数量的标签。L3(路由)接口必须配置为完全匹配。L2 接口通常配置为非精确匹配。如果未输入dot1qdot1ad,则默认行为是完全匹配exact-match模式。

802.1q(dot1q)802.1ad(QINQ)区别: 802.1Q就是我们常说的dot1qIEEE 802.1Q -英文缩写写为dot1q。是vlan的一种封装方式(插入适合的VLAN标记)。dot就是点的意思,就简写为dot1q了。 qinq就是在vlan的外层再封装一个vlan,扩充vlan数量,主要用途为电信供应商可以放置一个vlan标签作为通过外部网络的辨识,而不需变动客户的封包所带出的vlan标签。 dot1qdot1adTPIDTag Protocol Identifier,标签协议标识符)有不同的值。而dot1adTPID则有所不同,根据证据,802.1ad提出了使用0x88a8作为TPID,但也有提到Cisco使用了0x9200,并且有人提议将Dot1AD的TPID设置为0x9100。因此,可以得出结论,dot1q的TPID为0x8100,而dot1ad的TPID可能有不同的实现,包括但不限于0x88a8、0x92000x9100。目前vpp版本中判断报文是否携带tag,以上TPID都进行识别,代码如下:

代码语言:javascript
复制
static_always_inline int
ethernet_frame_is_tagged (u16 type)
{
#ifdef CLIB_HAVE_VEC128
  return !u16x8_is_all_zero (tagged_ethertypes == u16x8_splat (type));
#else
  if ((type == ETHERNET_TYPE_VLAN) /*8100*/||
      (type == ETHERNET_TYPE_DOT1AD) /*88a8*/||
      (type == ETHERNET_TYPE_VLAN_9100) || (type == ETHERNET_TYPE_VLAN_9200))
    return 1;
#endif
  return 0;
}

下面我们在腾讯云主机环境来分别验证一下上面配置的不同。创建一个tap10接口,并创建VLAN子接口 10 来处理 802.1q VLAN ID 10 上的数据包的示例,在vppctl命令行视图配置如下:

代码语言:javascript
复制
#创建一个tap10接口
create tap id 10 host-if-name tap10
#创建一个VLan id 10的子接口,并设置接口up及配置ip地址。
create sub-interfaces tap10 10
set interface state tap10 up
set interface state tap10.10 up
set interface ip address tap10.10 192.168.1.1/24

在vpp中接口默认情况下是L3_mode,当接口加入到网桥(二层域)中会切换到L2_mode。子接口只有在exact-match模式下,才允许配置ip地址的。下面我们尝试在非exact-match模式下,配置ip地址时提示错误。 DBGvpp# create tap id 10 host-if-name tap10 tap10 DBGvpp# create sub-interfaces tap10 10 dot1q 10 tap10.10 DBGvpp# set interface ip addr tap10.10 192.168.1.1/24 set interface ip address: sub-interface without exact-match doesn't support IP addressing

在linux内核配置如下:

代码语言:javascript
复制
ip link add link tap10 name tap10.10 type vlan id 10
ip link set tap10.10 up
ip addr add 192.168.1.2/24 dev tap10.10

接口在内核发起ping 网关192.168.1.1,可以正常ping通,这里就不再展示了。上图中我们使用命令create sub-interfaces tap10 10来创建一个vlan id 10的子接口tap10.10,此命令行等同于create sub-interfaces tap10 10 dot1q 10 exact-match这里就不再测试了。

下面我们从代码层面来分析创建子接口函数调用及关键数据结构体说明。下面是在命令行中输入create sub-interfaces的之后,完成解析命令行输入参数调用函数create_sub_interfaces完成子接口的创建及vlan资源的申请及初始化。

代码语言:javascript
复制
#命令行接口子接口配置并进入创建子接口流程。
create_sub_interfaces()
    #创建子接口入口函数
    vnet_create_sw_interface()
        #向vnet接口管理模块申请vnet_sw_interface_t存储区,不触发接口添加删除回调函数
        vnet_create_sw_interface_no_callbacks()
        #触发接口添加和删除的回调函数,完成ethernet子接口属性设置。
        vnet_sw_interface_set_flags_helper()
             ethernet_sw_interface_add_del()
                 #配置子接口相关属性
                 ethernet_sw_interface_get_config()

我梳理完了创建子接口的相关结构体关系,将结构体分成了配置数据和转发数据结构体。配置数据创建了当前子接口的软件接口资源sw_interfaces并根据命令行参数完成vnet_sub_interface_t sub结构的设置。转发数据存储结构是在ethernet_input node节点通过输入的报文tag信息查询到匹配的配置,从而找到对应的接口索引,将vlib_buffer_t结构接口rx赋值当前匹配的接口(也就是下面标红的存储的接口索引),再送入下一个节点处理。

这里有一个关键的信息,就是sunint_config_t存储的接口索引是在什么时候完成赋值的。在创建子接口阶段通过ethernet_sw_interface_add_del函数调用ethernet_sw_interface_get_config函数之后对接口索引进行赋值~0(因为接口状态默认初始化为down状态),flags信息缺省是L3模式。

当我们通过设置接口状态up时,会触发响应的回调函数ethernet_sw_interface_up_down,查询接口对应子接口信息,将sunint_config_t结构中sw_if_index接口进行赋值。

至此我们完成了创建子接口的相关代码及结构体的分析。文章中的结构体关系图放在个人git仓库https://github.com/jin13417/dpdk-vpp-learning感兴趣的可以自取。分析有问题的地方请各位指正。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档