在linux-cp插件中,新建feature,名称为lcp_arp_phy_arp_feat,其所属的ARC为arp。feature中的node节点为linux-cp-arp-phy。此feature位于arp-reply feature之前。
VNET_FEATURE_INIT (lcp_arp_phy_arp_feat, static) = {
.arc_name = "arp",
.node_name = "linux-cp-arp-phy",
.runs_before = VNET_FEATURES ("arp-reply"),
};
如下为node节点lcp_arp_phy_node的定义。
VLIB_REGISTER_NODE (lcp_arp_phy_node) = {
.name = "linux-cp-arp-phy",
.vector_size = sizeof (u32),
.format_trace = format_lcp_arp_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
.n_errors = LINUXCP_N_ERROR,
.error_counters = linuxcp_error_counters,
.n_next_nodes = LCP_ARP_N_NEXT,
.next_nodes = {
[LCP_ARP_NEXT_DROP] = "error-drop",
[LCP_ARP_NEXT_IO] = "interface-output",
},
};
如下show features命令,在ARP ARC中,新注册的feature linux-cp-arp-phy位于arping-reply之前。
vpp# show features verbose
Available feature paths
[ 1] arp:
[ 0]: vrrp4-arp-input
[ 1]: linux-cp-arp-phy
[ 2]: linux-cp-arp-host
[ 3]: arping-input
[ 4]: arp-reply
节点linux-cp-arp-phy在报文处理过程中与其它节点的前后关系如下,其之前唯一的节点为arp-input。
vpp# show node linux-cp-arp-phy
node linux-cp-arp-phy, type internal, state active, index 159
node function variants:
Name Priority Active Description
default 0 yes default
next nodes:
next-index node-index Node Vectors
0 701 error-drop 0
1 703 interface-output 0
2 341 arp-reply 0
3 340 arp-disabled 0
known previous nodes:
arp-input (339)
arp-input feature为arp ARC的首个节点。
VNET_FEATURE_ARC_INIT (arp_feat, static) =
{
.arc_name = "arp",
.start_nodes = VNET_FEATURES ("arp-input"),
.last_in_arc = "error-drop",
.arc_index_ptr = ðernet_arp_main.feature_arc_index,
};
节点处理函数lcp_arp_phy_node如下。
VLIB_NODE_FN (lcp_arp_phy_node)
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
{
u32 reply_copies[VLIB_FRAME_SIZE];
next_index = node->cached_next_index;
n_left_from = frame->n_vectors;
from = vlib_frame_vector_args (frame);
while (n_left_from > 0) {
vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
while (n_left_from > 0 && n_left_to_next > 0)
{
vlib_buffer_t *b0;
ethernet_arp_header_t *arp0;
bi0 = to_next[0] = from[0];
next0 = LCP_ARP_NEXT_DROP;
获取报文的arp头部信息,对于arp回复报文(opcode等于2),发送到linux中。函数vnet_feature_next获得报文在feature中下一个节点索引。
b0 = vlib_get_buffer (vm, bi0);
arp0 = vlib_buffer_get_current (b0);
vnet_feature_next (&next0, b0);
/* Replies might need to be received by the host, so we
* make a copy of them. */
arp_opcode = clib_host_to_net_u16 (arp0->opcode);
根据接收报文的VPP接口索引,找到linux-cp的接口对结构索引,再据此索引找到接口对结构(lcp_itf_pair_t)。
if (arp_opcode == ETHERNET_ARP_OPCODE_reply)
{
lcp_itf_pair_t *lip0 = 0;
vlib_buffer_t *c0;
u32 lipi0;
u8 len0;
lipi0 = lcp_itf_pair_find_by_phy (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
lip0 = lcp_itf_pair_get (lipi0);
首先获取L2头部的长度len0,其次将vlib_buffer_t当前数据指针后退len0长度,这时指向完整的ethernet报文,最后拷贝一份报文到c0,并且将原始报文b0的数据指针恢复。
报文c0的发送接口索引指定为接口对中的lip_host_sw_if_index(与linux中相通),将c0的索引报文到reply_copies数组中,之后统一发送。
if (lip0) {
/* rewind to reveal the ethernet header */
len0 = ((u8 *) vlib_buffer_get_current (b0) - (u8 *) ethernet_buffer_get_header (b0));
vlib_buffer_advance (b0, -len0);
c0 = vlib_buffer_copy (vm, b0);
vlib_buffer_advance (b0, len0);
if (c0) { /* Send to the host */
vnet_buffer (c0)->sw_if_index[VLIB_TX] = lip0->lip_host_sw_if_index;
reply_copies[n_copies++] = vlib_get_buffer_index (vm, c0);
}
}
}
处理trace信息,将报文发送到feature中的下一个节点。
if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED))) {
lcp_arp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
t->arp_opcode = arp_opcode;
}
vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
n_left_to_next, bi0, next0);
}
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}
对于要发送到linux中的报文,由函数vlib_buffer_enqueue_to_single_next完成处理。
if (n_copies)
vlib_buffer_enqueue_to_single_next (vm, node, reply_copies,
LCP_ARP_NEXT_IO, n_copies);
return frame->n_vectors;
打印报文的接收接口索引,和arp的opcode。
static u8 *
format_lcp_arp_trace (u8 *s, va_list *args)
{
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
lcp_arp_trace_t *t = va_arg (*args, lcp_arp_trace_t *);
s = format (s, "rx-sw-if-index: %u opcode: %u", t->rx_sw_if_index, t->arp_opcode);
return s;
如下trace信息,这里是接收到的arp请求报文(opcode等于1),没有送往linux中。可看到node处理流程:arp-input -> linux-cp-arp-phy -> arp-reply。
vpp# show trace
------------------- Start of thread 1 vpp_wk_0 -------------------
Packet 1
02:23:48:649165: dpdk-input
GigabitEthernet2/1/0 rx queue 0
buffer 0x99b2f1: current data 0, length 60, buffer-pool 0, ref-count 1, totlen-nifb 0, trace handle 0x1000000
ext-hdr-valid
l4-cksum-computed l4-cksum-correct
PKT MBUF: port 0, nb_segs 1, pkt_len 60
buf_len 2176, data_len 60, ol_flags 0x180, data_off 128, phys_addr 0xc76cbd40
packet_type 0x1 l2_len 0 l3_len 0 outer_l2_len 0 outer_l3_len 0
rss 0x0 fdir.hi 0x0 fdir.lo 0x0
Packet Offload Flags
PKT_RX_IP_CKSUM_GOOD (0x0080) IP cksum of RX pkt. is valid
PKT_RX_L4_CKSUM_GOOD (0x0100) L4 cksum of RX pkt. is valid
Packet Types
RTE_PTYPE_L2_ETHER (0x0001) Ethernet packet
ARP: 00:0d:e9:05:49:39 -> ff:ff:ff:ff:ff:ff
request, type ethernet/IP4, address size 6/4
00:0d:e9:05:49:39/17.1.2.2 -> 00:00:00:00:00:00/17.1.1.1
02:23:48:649175: ethernet-input
frame: flags 0x3, hw-if-index 1, sw-if-index 1
ARP: 00:0d:e9:05:49:39 -> ff:ff:ff:ff:ff:ff
02:23:48:649182: arp-input
request, type ethernet/IP4, address size 6/4
00:0d:e9:05:49:39/17.1.2.2 -> 00:00:00:00:00:00/17.1.1.1
02:23:48:649187: linux-cp-arp-phy
rx-sw-if-index: 1 opcode: 1
02:23:48:649189: arp-reply
request, type ethernet/IP4, address size 6/4
00:0d:e9:05:49:39/17.1.2.2 -> 00:00:00:00:00:00/17.1.1.1
02:23:48:649199: GigabitEthernet2/1/0-output
GigabitEthernet2/1/0
ARP: 00:60:e0:7a:6c:78 -> 00:0d:e9:05:49:39
reply, type ethernet/IP4, address size 6/4
00:60:e0:7a:6c:78/17.1.1.1 -> 00:0d:e9:05:49:39/17.1.2.2
02:23:48:649203: GigabitEthernet2/1/0-tx
GigabitEthernet2/1/0 tx queue 1
buffer 0x99b2f1: current data 0, length 60, buffer-pool 0, ref-count 1, totlen-nifb 0, trace handle 0x1000000
ext-hdr-valid
l4-cksum-computed l4-cksum-correct l2-hdr-offset 0 l3-hdr-offset 14
PKT MBUF: port 0, nb_segs 1, pkt_len 60
buf_len 2176, data_len 60, ol_flags 0x180, data_off 128, phys_addr 0xc76cbd40
packet_type 0x1 l2_len 0 l3_len 0 outer_l2_len 0 outer_l3_len 0
rss 0x0 fdir.hi 0x0 fdir.lo 0x0
Packet Offload Flags
PKT_RX_IP_CKSUM_GOOD (0x0080) IP cksum of RX pkt. is valid
PKT_RX_L4_CKSUM_GOOD (0x0100) L4 cksum of RX pkt. is valid
Packet Types
RTE_PTYPE_L2_ETHER (0x0001) Ethernet packet
ARP: 00:60:e0:7a:6c:78 -> 00:0d:e9:05:49:39
reply, type ethernet/IP4, address size 6/4
00:60:e0:7a:6c:78/17.1.1.1 -> 00:0d:e9:05:49:39/17.1.2.2
命令show lcp显示接口对信息:接口对索引([0])、VPP物理口名称(GigabitEthernet2/1/0)、VPP host连通接口(tap1)、linux接口名称和索引(linux-eth2 28),最后是linux接口类型。
vpp# show lcp
itf-pair: [0] GigabitEthernet2/1/0 tap1 linux-eth2 28 type tap
vpp#
vpp#
vpp# show interface addr
GigabitEthernet2/1/0 (up):
L3 17.1.1.1/16
tap1 (up):
arp回复报文在接口间的处理:GigabitEthernet2/1/0 -> tap1 -> linux-eth2。
如下为接口GigabitEthernet2/1/0开启的feature列表,其中arc arp中启用了linux-cp-arp-phy和arp-reply。
vpp# show interface features GigabitEthernet2/1/0
Feature paths configured on GigabitEthernet2/1/0...
arp:
linux-cp-arp-phy
arp-reply