前面公众号文章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指令集来提高匹配效率,
代码语言:javascript复制所谓的SIMD指令,指的是single instruction multiple data,即单指令多数据运算,其目的就在于帮助CPU实现数据并行,提高运算效率。
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