由于Vpp中的ACL功能涉及到众多的底层网络协议和数据结构,因此需要使用相应的Vpp API进行实现。下面是一个简单的示例代码,用于演示如何使用Vpp API实现ACL的功能:
#include <vlib/vlib.h>
#include <vnet/ip/ip.h>
#include <vnet/ip/ip6.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/vnet.h>
#include <vnet/dpo/load_balance.h>
#include <vppinfra/bihash_40_8.h>
/* 定义ACL规则 */
typedef struct {
u32 src_ip;
u32 dst_ip;
u16 src_port;
u16 dst_port;
} acl_rule_t;
/* 初始化ACL表 */
static void acl_table_init (acl_rule_t *rules, int n_rules)
{
/* 创建ACL表 */
vnet_acl_add_del_list_t list = {0};
list.name = "acl_table";
list.rules = 0;
list.count = 0;
vnet_classify_add_del_table_t table = {0};
table.mask_len = 64;
table.nbuckets = 65536;
table.memory_size = 64<<20; /* 64MB */
table.skip_n_vectors = 2;
table.match_n_vectors = 2;
table.next_table_index = ~0;
table.table_id = ~0;
vnet_classify_add_del_table (&table, &list);
/* 添加ACL规则 */
int i;
for (i = 0; i < n_rules; i++) {
vnet_acl_rule_t r = {0};
r.is_permit = 1;
r.src_prefixlen = 32;
r.dst_prefixlen = 32;
r.l4.src_port_start = rules[i].src_port;
r.l4.src_port_end = rules[i].src_port;
r.l4.dst_port_start = rules[i].dst_port;
r.l4.dst_port_end = rules[i].dst_port;
r.match.n_vectors = 2;
r.match.l3.proto = IP_PROTOCOL_TCP;
r.match.l3.src_address[0] = (rules[i].src_ip >> 24) & 0xff;
r.match.l3.src_address[1] = (rules[i].src_ip >> 16) & 0xff;
r.match.l3.src_address[2] = (rules[i].src_ip >> 8) & 0xff;
r.match.l3.src_address[3] = rules[i].src_ip & 0xff;
r.match.l3.dst_address[0] = (rules[i].dst_ip >> 24) & 0xff;
r.match.l3.dst_address[1] = (rules[i].dst_ip >> 16) & 0xff;
r.match.l3.dst_address[2] = (rules[i].dst_ip >> 8) & 0xff;
r.match.l3.dst_address[3] = rules[i].dst_ip & 0xff;
vnet_classify_add_del_session_t session = {0};
session.table_index = table.new_table_index;
session.hit_next_index = 0;
vnet_classify_add_del_acl (&list, &r, &session);
}
}
/* 处理ACL */
static uword acl_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
{
u32 n_left_from, *from;
from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors;
while (n_left_from > 0) {
u32 n_this_iteration = vlib_buffer_free_list_length (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
n_this_iteration = clib_min (n_this_iteration, n_left_from);
/* 将数据包分类 */
classify_table_index_t ti;
vnet_classify_main_t *cm = &vnet_classify_main;
ti = cm->tables[0].miss_next_index;
vnet_classify_session_t *s = &cm->sessions[ti];
vnet_classify_bucket_t *b = &cm->buckets[s->current_data_bucket];
int i;
for (i = 0; i < n_this_iteration; i++) {
u32 bi = from[i];
vlib_buffer_t *b = vlib_get_buffer (vm, bi);
ethernet_header_t *eth = vlib_buffer_get_current (b);
ip4_header_t *ip4 = (void*)(eth + 1);
tcp_header_t *tcp = (void*)(ip4 + 1);
vnet_classify_entry_t *e = vnet_classify_find_entry (cm, ti, &ip4->src_address, &ip4->dst_address,
tcp->src_port, tcp->dst_port, 0, 0);
if (e == 0) {
/* 匹配失败 */
vlib_buffer_advance (b, sizeof(ethernet_header_t) + sizeof(ip4_header_t));
vnet_buffer(b)->sw_if_index[VLIB_RX] = 0;
vnet_buffer(b)->sw_if_index[VLIB_TX] = (u32) ~0;
} else {
/* 匹配成功 */
vlib_buffer_advance (b, sizeof(ethernet_header_t) + sizeof(ip4_header_t));
vnet_buffer(b)->sw_if_index[VLIB_TX] = e->data[0];
}
}
/* 发送数据包 */
u32 n_sent = vlib_process_buffer (vm, from, n_this_iteration, node->node_index, 0);
n_left_from -= n_sent;
from += n_sent;
}
return frame->n_vectors;
}
/* 注册ACL节点 */
VLIB_REGISTER_NODE (acl_node, { .name = "acl", .function = acl_node_fn });
int main (int argc, char *argv[])
{
acl_rule_t rules[] = {
/* 添加ACL规则 */
{ 0x01020304, 0x05060708, 80, 8080 }, /* 允许来自ip地址为1.2.3.4,目的地址为5.6.7.8,源端口为80,目的端口为8080的TCP数据包通过 */
{ 0x090a0b0c, 0x0d0e0f10, 22, 2222 }, /* 允许来自ip地址为9.10.11.12,目的地址为13.14.15.16,源端口为22,目的端口为2222的TCP数据包通过 */
};
int n_rules = sizeof(rules)/sizeof(rules[0]);
/* 初始化VPP */
vlib_main_t *vm = vlib_create_main (argc, argv);
ethernet_init (vm);
ip4_init (vm);
ip6_init (vm);
vnet_register_format_buffer (vm, eth_header_format);
vnet_register_format_buffer (vm, ip4_header_format);
/* 初始化ACL表 */
acl_table_init (rules, n_rules);
/* 运行VPP */
vlib_start_main (vm);
return 0;
}
以上是一个简单的ACL示例,仅供参考。在实际应用中,还需要根据具体场景进行相应的调整和优化。