本文主要是介绍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 = ðernet_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 = ðernet_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 = ðernet_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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!