Linux-cp处理arp回复报文

在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;

TRACE信息

打印报文的接收接口索引,和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

LCP接口

命令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

你可能感兴趣的:(VPP,arp,lcp)