VPP接口二层互联xconnect

2024-01-29 02:20

本文主要是介绍VPP接口二层互联xconnect,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

以下命令将接口设置为L2二层互联模式,如果要双向流量,需要两个口都设置成此模式。一个接口上接收到的报文将发送到另外一个接口,反之亦然。

vpp# set interface state HundredGigabitEthernet65/0/0 up
vpp# set interface state HundredGigabitEthernet65/0/1 up
vpp#
vpp# set interface l2 xconnect HundredGigabitEthernet65/0/0 HundredGigabitEthernet65/0/1
vpp# set interface l2 xconnect HundredGigabitEthernet65/0/1 HundredGigabitEthernet65/0/0
vpp#
vpp# show mode
l3 GigabitEthernet4/0/0
l3 GigabitEthernet5/0/0
l2 xconnect HundredGigabitEthernet65/0/0 HundredGigabitEthernet65/0/1
l2 xconnect HundredGigabitEthernet65/0/1 HundredGigabitEthernet65/0/0

一 设置接口二层互联

函数int_l2_xc处理接口二层互联。模式为MODE_L2_XC,要互联的接口为sw_if_index和xc_sw_if_index。

static clib_error_t *
int_l2_xc (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
{/* set the interface mode */if (set_int_l2_mode  (vm, vnm, MODE_L2_XC, sw_if_index, 0, L2_BD_PORT_TYPE_NORMAL,0, xc_sw_if_index)){error = clib_error_return (0, "invalid configuration for interface", format_unformat_error, input);goto done;}

核心函数set_int_l2_mode如下,获取到接口的二层输入配置l2_input_config_t,如果接口已经为互联接口,l2_if_adjust自减1,注意之后会自增回来。

u32 set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, u32 mode, u32 sw_if_index, u32 bd_index, l2_bd_port_type_t port_type, u32 shg, u32 xc_sw_if_index)
{l2output_main_t *l2om = &l2output_main;l2_output_config_t *out_config;l2_input_config_t *config;hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);config = l2input_intf_config (sw_if_index);if (l2_input_is_xconnect (config))l2_if_adjust--;vec_validate_init_empty (l2om->output_node_index_vec, sw_if_index, L2OUTPUT_NEXT_DROP);

以下设置接口为二层互联模式MODE_L2_XC,接口配置标志设置为L2_INPUT_FLAG_XCONNECT,互联的对端接口xc_sw_if_index设置到配置结构的output_sw_if_index成员。

清除二层网桥相关的配置,如二层MAC自学习,转发和泛洪。在feature_bitmap中设置互联feature:L2INPUT_FEAT_XCONNECT。

  /* Initialize the l2-input configuration for the interface */if (mode == MODE_L3) { ... }else {/* Add or update l2-output node next-arc and output_node_index_vec table for the interface */l2output_create_output_node_mapping (vm, vnet_main, sw_if_index);if (mode == MODE_L2_XC) {config->flags = L2_INPUT_FLAG_XCONNECT;config->output_sw_if_index = xc_sw_if_index;config->feature_bitmap |= L2INPUT_FEAT_DROP;/* Make sure bridging features are disabled */config->feature_bitmap &= ~(L2INPUT_FEAT_LEARN | L2INPUT_FEAT_FWD | L2INPUT_FEAT_FLOOD);config->feature_bitmap |= L2INPUT_FEAT_XCONNECT;shg = 0;      /* not used in xconnect */}/* set up split-horizon group and set output feature bit */config->shg = shg;

以下设置接口的二层输出配置l2_output_config_t,水平分割组shg设置为0,xconnect互联不需要。自增l2_if_adjust,如果l2_if_adjust为1,表明接口由三层转为二层模式。

      out_config = l2output_intf_config (sw_if_index);out_config->shg = shg;out_config->feature_bitmap |= L2OUTPUT_FEAT_OUTPUT;/** Test: remove this when non-IP features can be configured.* Enable a non-IP feature to test IP feature masking* config->feature_bitmap |= L2INPUT_FEAT_CTRL_PKT;*/l2_if_adjust++;bd_input_walk (bd_index, l2input_recache, NULL);}

更新接口所属的上层硬件接口hi的二层接口数量l2_if_count。如果硬件接口为以太网接口,在生成首个二层接口时,由于需要接收所有MAC地址的报文,这里开启混杂模式。

相反,如果所有二层接口都被去除,退出混杂模式,仅接收目的MAC地址为当前接口MAC的报文。

  hi->l2_if_count += l2_if_adjust;   /* Adjust count of L2 interfaces */if (hi->hw_class_index == ethernet_hw_interface_class.index) {if ((hi->l2_if_count == 1) && (l2_if_adjust == 1)) {/* Just added first L2 interface on this port Set promiscuous mode on the l2 interface */ethernet_set_flags (vnet_main, hi->hw_if_index, ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);}else if ((hi->l2_if_count == 0) && (l2_if_adjust == -1)) {/* Just removed only L2 subinterface on this port Disable promiscuous mode on the l2 interface */ethernet_set_flags (vnet_main, hi->hw_if_index, /*ETHERNET_INTERFACE_FLAG_DEFAULT_L3 */ 0);}}

设置以太网接口的L2/L3标志。以太网类设备ethernet_hw_interface_class,没有注册set_l2_mode_function函数。

  /* Set up the L2/L3 flag in the interface parsing tables */ethernet_sw_interface_set_l2_mode (vnm, sw_if_index, (mode != MODE_L3));dev_class = vnet_get_device_class (vnet_main, hi->dev_class_index);if (dev_class->set_l2_mode_function)dev_class->set_l2_mode_function (vnet_main, hi, l2_if_adjust);

二 L2OUTPUT下一节点

设置l2-output节点的下一个处理节点为硬件接口的输出节点hw0->output_node_index。在L2处理报文完毕之后,由物理接口发出报文。

/** Create a mapping in the next node mapping table for the given sw_if_index. */
void
l2output_create_output_node_mapping (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index)
{     vnet_hw_interface_t *hw0 = vnet_get_sup_hw_interface (vnet_main, sw_if_index);/* dynamically create graph node arc  */u32 next = vlib_node_add_next (vlib_main, l2output_node.index,hw0->output_node_index);l2output_main.output_node_index_vec[sw_if_index] = next;  

三 Bridge Domain成员

接口L2互联使用的bridge domain为0,遍历BD中的所有成员,每个成员调用l2input_recache处理。

u32 bd_input_walk (u32 bd_index, bd_input_walk_fn_t fn, void *data)
{    l2_flood_member_t *member;l2_bridge_domain_t *bd;sw_if_index = ~0;bd = bd_get (bd_index);vec_foreach (member, bd->members) {  if (WALK_STOP == fn (bd_index, member->sw_if_index)) {sw_if_index = member->sw_if_index;break;}}return (sw_if_index);

使用BD中的值mac_age,seq_num和feature_bitmap,更新所有接口的二层输入结构中对应的成员。对于L2互联,这些操作都没有用。

walk_rc_t l2input_recache (u32 bd_index, u32 sw_if_index)
{l2_input_config_t *input;l2_bridge_domain_t *bd;bd = bd_get (bd_index);input = l2input_intf_config (sw_if_index);input->bd_mac_age = bd->mac_age;input->bd_seq_num = bd->seq_num;input->bd_feature_bitmap = bd->feature_bitmap;return (WALK_CONTINUE);

四 接口二层配置

接口的二层输入配置位于l2input_main成员向量configs中,索引为sw_if_index。

l2_input_config_t *
l2input_intf_config (u32 sw_if_index)
{l2input_main_t *mp = &l2input_main;vec_validate (mp->configs, sw_if_index);return vec_elt_at_index (mp->configs, sw_if_index);
}

接口的二层输出配置位于l2output_main成员向量configs中,索引为sw_if_index。

l2_output_config_t *
l2output_intf_config (u32 sw_if_index)
{   l2output_main_t *mp = &l2output_main;vec_validate (mp->configs, sw_if_index);return vec_elt_at_index (mp->configs, sw_if_index);
} 

五 以太网二层配置

以太网接口将对应的子接口设置为二层模式SUBINT_CONFIG_L2,如果接口为主接口,而不是子接口,设置0,1,2,3层VLAN标志,即这些报文都可以通过主接口接收。

void ethernet_sw_interface_set_l2_mode (vnet_main_t * vnm, u32 sw_if_index, u32 l2)
{subint_config_t *subint;vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, sw_if_index);is_port = !(sw->type == VNET_SW_INTERFACE_TYPE_SUB);subint = ethernet_sw_interface_get_config (vnm, sw_if_index, &placeholder_flags, &placeholder_unsup);ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));if (l2) {subint->flags |= SUBINT_CONFIG_L2;if (is_port)subint->flags |= SUBINT_CONFIG_MATCH_0_TAG | SUBINT_CONFIG_MATCH_1_TAG| SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;

在ethernet_main中,物理接口属于没有任何tag的子接口,使用了main_intf_t结构的成员untagged_subint。

static subint_config_t *
ethernet_sw_interface_get_config (vnet_main_t * vnm, u32 sw_if_index, u32 * flags, u32 * unsupported)
{ethernet_main_t *em = &ethernet_main;main_intf_t *main_intf;subint_config_t *subint = 0;hi = vnet_get_sup_hw_interface (vnm, sw_if_index);vec_validate (em->main_intfs, hi->hw_if_index);main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);if ((si->sub.eth.flags.no_tags) || (si->sub.eth.raw_flags == 0)) {// if no flags are set then this is a main interface so treat as untaggedsubint = &main_intf->untagged_subint;*flags = SUBINT_CONFIG_MATCH_0_TAG;

在ethernet-input节点接收到报文之后,取得子接口配置untagged_subint,检查其成员flags是否设置了二层标志SUBINT_CONFIG_L2,为真表示物理口(主接口)处于二层模式。对于以上的xconnect配置,main_is_l3等于0。

eth_input_single_int (vlib_main_t * vm, vlib_node_runtime_t * node, vnet_hw_interface_t * hi, ...)
{ethernet_main_t *em = &ethernet_main;ethernet_interface_t *ei;ei = pool_elt_at_index (em->interfaces, hi->hw_instance);main_intf_t *intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);subint_config_t *subint0 = &intf0->untagged_subint;int main_is_l3 = (subint0->flags & SUBINT_CONFIG_L2) == 0;if (main_is_l3) { ... }else {if (hi->l3_if_count == 0) {eth_input_process_frame (vm, node, hi, from, n_pkts,/*is_l3 */ 0, ip4_cksum_ok, 0);

对于没有任何VLAN信息的报文,下一个处理节点为l2-input。

static_always_inline void
eth_input_process_frame (vlib_main_t * vm, vlib_node_runtime_t * node, vnet_hw_interface_t * hi,u32 * buffer_indices, u32 n_packets, int main_is_l3,...)
{ethernet_main_t *em = &ethernet_main;next_l2 = em->l2_next;if (main_is_l3 == 0 && etype[0] != et_vlan && etype[0] != et_dot1ad)next[0] = next_l2;

六 报文追踪

根据trace信息可知,接口HundredGigabitEthernet65/0/0接收到报文之后,处理的节点流程为:
dpdk-input --》ethernet-input --》l2-input --》l2-output --》HundredGigabitEthernet65/0/1-output --》HundredGigabitEthernet65/0/1-tx。

vpp# trace add dpdk-input 3
vpp# show trace
------------------- Start of thread 1 vpp_wk_0 -------------------
Packet 100:18:13:467725: dpdk-inputHundredGigabitEthernet65/0/0 rx queue 4IP4: 00:0d:e9:07:e4:75 -> 00:0d:e9:07:e4:74UDP: 17.1.1.100 -> 17.1.2.174
00:18:13:467752: ethernet-inputframe: flags 0x3, hw-if-index 3, sw-if-index 3IP4: 00:0d:e9:07:e4:75 -> 00:0d:e9:07:e4:74
00:18:13:467757: l2-inputl2-input: sw_if_index 3 dst 00:0d:e9:07:e4:74 src 00:0d:e9:07:e4:75 [l2-output ]
00:18:13:467758: l2-outputl2-output: sw_if_index 4 dst 00:0d:e9:07:e4:74 src 00:0d:e9:07:e4:75 data 08 00 45 00 05 dc cb bf 00 00 ff 11
00:18:13:467758: HundredGigabitEthernet65/0/1-outputHundredGigabitEthernet65/0/1IP4: 00:0d:e9:07:e4:75 -> 00:0d:e9:07:e4:74UDP: 17.1.1.100 -> 17.1.2.174tos 0x00, ttl 255, length 1500, checksum 0xc43d dscp CS0 ecn NON_ECNfragment id 0xcbbfUDP: 6006 -> 10000length 1480, checksum 0x8fc4
00:18:13:467759: HundredGigabitEthernet65/0/1-txHundredGigabitEthernet65/0/1 tx queue 1IP4: 00:0d:e9:07:e4:75 -> 00:0d:e9:07:e4:74

这篇关于VPP接口二层互联xconnect的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/655470

相关文章

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

Java后端接口中提取请求头中的Cookie和Token的方法

《Java后端接口中提取请求头中的Cookie和Token的方法》在现代Web开发中,HTTP请求头(Header)是客户端与服务器之间传递信息的重要方式之一,本文将详细介绍如何在Java后端(以Sp... 目录引言1. 背景1.1 什么是 HTTP 请求头?1.2 为什么需要提取请求头?2. 使用 Spr

Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果: 解密后的数据就是正常数据: 后端:使用的是spring-cloud框架,在gateway模块进行操作 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency> 编写一个AES加密

java线程深度解析(一)——java new 接口?匿名内部类给你答案

http://blog.csdn.net/daybreak1209/article/details/51305477 一、内部类 1、内部类初识 一般,一个类里主要包含类的方法和属性,但在Java中还提出在类中继续定义类(内部类)的概念。 内部类的定义:类的内部定义类 先来看一个实例 [html]  view plain copy pu

模拟实现vector中的常见接口

insert void insert(iterator pos, const T& x){if (_finish == _endofstorage){int n = pos - _start;size_t newcapacity = capacity() == 0 ? 2 : capacity() * 2;reserve(newcapacity);pos = _start + n;//防止迭代

京东物流查询|开发者调用API接口实现

快递聚合查询的优势 1、高效整合多种快递信息。2、实时动态更新。3、自动化管理流程。 聚合国内外1500家快递公司的物流信息查询服务,使用API接口查询京东物流的便捷步骤,首先选择专业的数据平台的快递API接口:物流快递查询API接口-单号查询API - 探数数据 以下示例是参考的示例代码: import requestsurl = "http://api.tanshuapi.com/a

股票数据接口-陈科肇

陈科肇 新浪财经 sz-深圳sh-上海历史分价表:http://market.finance.sina.com.cn/pricehis.php?symbol=sz000506&startdate=2016-12-27&enddate=2016-12-27历史成交明细(当日成交明细):http://vip.stock.finance.sina.com.cn/quotes_service/v

实例demo理解面向接口思想

浅显的理解面向接口编程 Android开发的语言是java,至少目前是,所以理解面向接口的思想是有必要的。下面通过一个简单的例子来理解。具体的概括我也不知道怎么说。 例子: 现在我们要开发一个应用,模拟移动存储设备的读写,即计算机与U盘、MP3、移动硬盘等设备进行数据交换。已知要实现U盘、MP3播放器、移动硬盘三种移动存储设备,要求计算机能同这三种设备进行数据交换,并且以后可能会有新的第三方的

对接话费充值API接口的开发步骤以及各种优势

对接话费充值API接口通常涉及以下步骤: 1.选择API提供商: 研究并选择一个可靠的话费充值API提供商。考虑因素包括覆盖范围、费率、交易限额、客户支持和用户评价。 2.注册和获取API密钥: 在选定的API提供商平台上注册账户,并获取API密钥或访问令牌,这是调用API时进行身份验证的必要信息。 3.阅读API文档: 仔细阅读API文档,了解如何构建请求、需要哪些参数、API的

java类中定义接口的有哪些好处

第一步:首先是是定义一个类,同时里面定义接口 public class Util { public interface Worker { void work(int a); } } 第二步:定义一个类去实现第一步类中定义的接口 public class Demo implements Worker { @Override public void work(int a) { System