learning:vet/classify(1)

2023-03-07 17:30:50 浏览数 (1)

前面公众号文章learning:vet/policer介绍了policer的基本结构及基于接口in方向的policer限速的配置及使用。文章结尾讲到classify-policer 基于流的policer限速功能实现,本文就介绍一下classify的基本原理及相关命令行。

VPP Classifier 简介

Classifier 是一组规则的集合。在某种程度上,VPP Classifier 提供了一套使用相当简单的控制平面API。给定一个传入数据包,它搜索一个(掩码,匹配)表的有序列表。如果Classifier找到匹配的条目,它将采取指定的操作。如果不能,它将采取最后的行动。Classifier 是FD.io vpp 最灵活的报文匹配形式,允许用户匹配报文头的前80个字节。

The most flexible form of ACLs in FD.io VPP enable the user to match anywhere in the first 80 bytes of the packet header.

classify在报文匹配时按照每16字节分割匹配的,所以在下发classify表中代码会判断match的最大数量不能超过5,也就是上面说的最多匹配80字节。

代码语言:javascript复制
      if (match < 1 || match > 5)
        return VNET_API_ERROR_INVALID_VALUE;

vpp在报文匹配时,使用SIMD指令集来提高匹配效率,

所谓的SIMD指令,指的是single instruction multiple data,即单指令多数据运算,其目的就在于帮助CPU实现数据并行,提高运算效率。

代码语言:javascript复制
static inline vnet_classify_entry_t *
vnet_classify_find_entry_inline (vnet_classify_table_t *t, const u8 *h,
                 u64 hash, f64 now)
{
#ifdef CLIB_HAVE_VEC128  #使用SIMD
  const u32x4u *data = (const u32x4u *) h;
  for (i = 0; i < limit; i  )
    {
      key = v->key;
      result.as_u32x4 = (data[0   t->skip_n_vectors] & mask[0]) ^ key[0];
      switch (t->match_n_vectors)
    {
    case 5:
      result.as_u32x4 |= (data[4   t->skip_n_vectors] & mask[4]) ^ key[4];
      /* FALLTHROUGH */
    case 4:
      result.as_u32x4 |= (data[3   t->skip_n_vectors] & mask[3]) ^ key[3];
      /* FALLTHROUGH */
    case 3:
      result.as_u32x4 |= (data[2   t->skip_n_vectors] & mask[2]) ^ key[2];
      /* FALLTHROUGH */
    case 2:
      result.as_u32x4 |= (data[1   t->skip_n_vectors] & mask[1]) ^ key[1];
      /* FALLTHROUGH */
    case 1:
      break;
    default:
      abort ();
    }

      if (u32x4_zero_byte_mask (result.as_u32x4) == 0xffff)
    {
      if (PREDICT_TRUE (now))
        {
          v->hits  ;
          v->last_heard = now;
        }
      return (v);
    }
      v = vnet_classify_entry_at_index (t, v, 1);
    }
#else #不支持情况处理
  u32 skip_u64 = t->skip_n_vectors * 2;
  const u64 *data64 = (const u64 *) h;
  for (i = 0; i < limit; i  )
    {
      key = v->key;

      result.as_u64[0] =
    (data64[0   skip_u64] & ((u64 *) mask)[0]) ^ ((u64 *) key)[0];
      result.as_u64[1] =
    (data64[1   skip_u64] & ((u64 *) mask)[1]) ^ ((u64 *) key)[1];
      switch (t->match_n_vectors)
    {
    case 5:
      result.as_u64[0] |=
        (data64[8   skip_u64] & ((u64 *) mask)[8]) ^ ((u64 *) key)[8];
      result.as_u64[1] |=
        (data64[9   skip_u64] & ((u64 *) mask)[9]) ^ ((u64 *) key)[9];
      /* FALLTHROUGH */
    case 4:
      result.as_u64[0] |=
        (data64[6   skip_u64] & ((u64 *) mask)[6]) ^ ((u64 *) key)[6];
      result.as_u64[1] |=
        (data64[7   skip_u64] & ((u64 *) mask)[7]) ^ ((u64 *) key)[7];
      /* FALLTHROUGH */
    case 3:
      result.as_u64[0] |=
        (data64[4   skip_u64] & ((u64 *) mask)[4]) ^ ((u64 *) key)[4];
      result.as_u64[1] |=
        (data64[5   skip_u64] & ((u64 *) mask)[5]) ^ ((u64 *) key)[5];
      /* FALLTHROUGH */
    case 2:
      result.as_u64[0] |=
        (data64[2   skip_u64] & ((u64 *) mask)[2]) ^ ((u64 *) key)[2];
      result.as_u64[1] |=
        (data64[3   skip_u64] & ((u64 *) mask)[3]) ^ ((u64 *) key)[3];
      /* FALLTHROUGH */
    case 1:
      break;
    default:
      abort ();
    }

      if (result.as_u64[0] == 0 && result.as_u64[1] == 0)
    {
      if (PREDICT_TRUE (now))
        {
          v->hits  ;
          v->last_heard = now;
        }
      return (v);
    }

      v = vnet_classify_entry_at_index (t, v, 1);
    }
#endif /* CLIB_HAVE_VEC128 */
  return 0;
}

配置步骤

classify mask-and-match匹配操作步骤三步 1、创建一个classify匹配规则表,用于指定当前表中匹配mask信息,

代码语言:javascript复制
#创建匹配规则表,并设置hash 桶数量是16.
learning_vpp2#classify table mask l3 ip4 src buckets 16
#查询匹配规则表信息。
learning_vpp2# show classify tables index 3 verbose
  TableIdx  Sessions   NextTbl  NextNode
         3         0        -1        -1
  Heap: base 0x7fffc8dea000, size 2m, locked, unmap-on-destroy, name 'classify'
          page stats: page-size 4K, total 512, mapped 2, not-mapped 0, unknown 510
            numa 0: 2 pages, 8k bytes
          total: 1.99M, used: 1.09K, free: 1.99M, trimmable: 1.99M
# 桶个数16,skip 1(指从报文data开始跳过一个16字节) match 1(匹配1个16字节)
  nbuckets 16, skip 1 match 1 flag 0 offset 0
#FFFFFFFF位置就是ip报文src的位置。
#这里需要注意二层信息默认不带tag报文来计算,如果带tag报文,需要注意。
  mask 00000000000000000000ffffffff0000
  linear-search buckets 0
    0 active elements
    0 free lists
    0 linear-search buckets

2、往当前规则表里添加规则。

代码语言:javascript复制
#这里使用classify实现deny功能。table-index:3,这里是第一步创建规则表后返回的表索引。
learning_vpp2# classify session acl-hit-next deny table-index 3 match l3 ip4 src 192.168.100.2
learning_vpp2# show classify tables index 3 verbose                                           
  TableIdx  Sessions   NextTbl  NextNode
         3         1        -1        -1
  Heap: base 0x7fffc8dea000, size 2m, locked, unmap-on-destroy, name 'classify'
          page stats: page-size 4K, total 512, mapped 2, not-mapped 0, unknown 510
            numa 0: 2 pages, 8k bytes
          total: 1.99M, used: 1.34K, free: 1.99M, trimmable: 1.99M
  nbuckets 16, skip 1 match 1 flag 0 offset 0
  mask 00000000000000000000ffffffff0000
  linear-search buckets 0
#当前匹配规则放在了桶5中。
[5]: heap offset 1280, elts 2, normal
    0: [1280]: next_index 0 advance 0 opaque -1 action 0 metadata 0
        k: 00000000000000000000c0a864020000
        hits 0, last_heard 0.00

    1 active elements
    1 free lists
    0 linear-search buckets

3、当前匹配规则表绑定接口上

代码语言:javascript复制
#讲匹配规则表3绑定到接口上,
 set int input acl intfc GigabitEthernetb/0/0 ip4-table 3
show interface feat GigabitEthernetb/0/0
ip4-unicast:
  ip4-inacl

我们发起一个ping 192.168.100.2 报文,发现ping不通了。说明配置生效了。trace 抓包如下:

代码语言:javascript复制
Packet 1

06:20:12:560399: dpdk-input
  GigabitEthernetb/0/0 rx queue 0
  buffer 0x99077: current data 0, length 110, 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 110
    buf_len 2176, data_len 110, ol_flags 0x80, data_off 128, phys_addr 0x28441e40
    packet_type 0x91 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
    Packet Types
      RTE_PTYPE_L2_ETHER (0x0001) Ethernet packet
      RTE_PTYPE_L3_IPV4_EXT_UNKNOWN (0x0090) IPv4 packet with or without extension headers
  IP4: 00:0c:29:17:0a:58 -> 00:0c:29:17:0a:3a
  ICMP: 192.168.100.2 -> 192.168.100.1
    tos 0x00, ttl 64, length 96, checksum 0x368f dscp CS0 ecn NON_ECN
    fragment id 0xfab9
  ICMP echo_reply checksum 0x10d id 57016
06:20:12:560512: ethernet-input
  frame: flags 0x1, hw-if-index 1, sw-if-index 1
  IP4: 00:0c:29:17:0a:58 -> 00:0c:29:17:0a:3a
06:20:12:560536: ip4-input
  ICMP: 192.168.100.2 -> 192.168.100.1
    tos 0x00, ttl 64, length 96, checksum 0x368f dscp CS0 ecn NON_ECN
    fragment id 0xfab9
  ICMP echo_reply checksum 0x10d id 57016
06:20:12:560555: ip4-inacl
  INACL: sw_if_index 1, next_index 0, table 3, offset 1280
06:20:12:560584: ip4-drop
    ICMP: 192.168.100.2 -> 192.168.100.1
      tos 0x00, ttl 64, length 96, checksum 0x368f dscp CS0 ecn NON_ECN
      fragment id 0xfab9

参考文章

1、VPP classify ACL https://blog.csdn.net/qq_22026161/article/details/101196112 2、FD.IO-VPP研究及使用四(Qos策略) https://blog.csdn.net/weixin_40815457/article/details/86524227 3、VPP/Introduction To N-tuple Classifiers https://wiki.fd.io/view/VPP/Introduction_To_N-tuple_Classifiers 4、vpp classify cli https://docs.fd.io/vpp/21.10/d0/d01/clicmd_src_vnet_classify.html 5、VPP中ACL(访问控制列表)的使用——系列二 https://blog.csdn.net/turbock/article/details/102397894 6、L2 policy in VPP https://docs.google.com/document/d/1XckxjgNYzl_U3D9M8DZ6xQuagbksnQN_FSfPWldMJtA/edit#heading=h.qtsq4ktypjwv

0 人点赞