BGP AS-PATH支持正则表达式源码分析
FRR的bgp实现正则表达式使用的是linux的正则表达式库函数:
#include <sys/types.h>
#include <regex.h>
int regcomp(regex_t *preg, const char *regex, int cflags);
int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
void regfree(regex_t *preg);
详细使用方法可以使用man进行查看。
本篇文章不是用来分析正则表达式如何使用的,而是为了说明BGP在使用正则表达式的独特差异时如何实现的。在FRR的正则表达式中有一个特殊符号,那就是'_'(下杠)。该符号在FRR中有特殊含义:它表示匹配[,{}() ]以及^和$,一共10个符号(包括空格也可以匹配)。
代码分析
/* Character `_' has special mean. It represents [,{}() ] and the
beginning of the line(^) and the end of the line ($).
(^|[,{}() ]|$) (记住有空格)*/
regex_t *bgp_regcomp(const char *regstr)
{
/* Convert _ character to generic regular expression. */
int i, j;
int len;
int magic = 0;
char *magic_str;
char magic_regexp[] = "(^|[,{}() ]|$)";
int ret;
regex_t *regex;
len = strlen(regstr);
//统计正则表达式中的下杠的个数
for (i = 0; i < len; i++)
if (regstr[i] == '_')
magic++;
//将下杠替换成magic_regexp,一共14个字符,实际只需要分配13个字符即可,这里重新分配内存
magic_str = XMALLOC(MTYPE_TMP, len + (14 * magic) + 1);
//将下杠替换成magic_regexp
for (i = 0, j = 0; i < len; i++) {
if (regstr[i] == '_') {
memcpy(magic_str + j, magic_regexp,
strlen(magic_regexp));
j += strlen(magic_regexp);
} else
magic_str[j++] = regstr[i];
}
magic_str[j] = '\0';
regex = XMALLOC(MTYPE,_BGP_REGEXP, sizeof(regex_t));
//将正则表达式进行预编译,REG_NOSUB表示不报告匹配的位置以及次数,能加速匹配,REG_EXTENDED表示使用扩展正则表达式集合
ret = regcomp(regex, magic_str, REG_EXTENDED | REG_NOSUB);
XFREE(MTYPE_TMP, magic_str);
if (ret != 0) {
XFREE(MTYPE_BGP_REGEXP, regex);
return NULL;
}
return regex;
}
//匹配函数
int bgp_regexec(regex_t *regex, struct aspath *aspath)
{
return regexec(regex, aspath->str, 0, NULL, 0);
}
void bgp_regex_free(regex_t *regex)
{
regfree(regex);
XFREE(MTYPE_BGP_REGEXP, regex);
}
具体使用代码分析
添加正则表达式,并编译
DEFUN(as_path, bgp_as_path_cmd,
"bgp as-path access-list WORD <deny|permit> LINE...",
BGP_STR
"BGP autonomous system path filter\n"
"Specify an access list name\n"
"Regular expression access list name\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
{
int idx = 0;
enum as_filter_type type;
struct as_filter *asfilter;
struct as_list *aslist;
regex_t *regex;
char *regstr;
if (argv_find(argv, argc, "ip", &idx)) {
vty_out(vty, "This config option is deprecated and is scheduled for removal.\n");
vty_out(vty, "if you are using this please migrate to the below command\n");
vty_out(vty, "'bgp as-path access-list WORD <deny|permit> LINE'\n");
zlog_warn("Deprecated option: 'ip as-path access-list WORD <deny|permit> LINE' being used");
}
/* Retrieve access list name */
argv_find(argv, argc, "WORD", &idx);
char *alname = argv[idx]->arg;
/* Check the filter type. */
type = argv_find(argv, argc, "deny", &idx) ? AS_FILTER_DENY
: AS_FILTER_PERMIT;
/* Check AS path regex. */
argv_find(argv, argc, "LINE", &idx);
regstr = argv_concat(argv, argc, idx);
//编译正则表达式
regex = bgp_regcomp(regstr);
if (!regex) {
vty_out(vty, "can't compile regexp %s\n", regstr);
XFREE(MTYPE_TMP, regstr);
return CMD_WARNING_CONFIG_FAILED;
}
//正则表达式合规检查
if (!config_bgp_aspath_validate(regstr)) {
vty_out(vty, "Invalid character in as-path access-list %s\n",
regstr);
return CMD_WARNING_CONFIG_FAILED;
}
//构建asfilter上下文
asfilter = as_filter_make(regex, regstr, type);
XFREE(MTYPE_TMP, regstr);
/* Install new filter to the access_list. */
aslist = as_list_get(alname);
/* Duplicate insertion check. */;
/* 加入到过滤链表中 */
if (as_list_dup_check(aslist, asfilter))
as_filter_free(asfilter);
else
as_list_filter_add(aslist, asfilter);
return CMD_SUCCESS;
}
具体使用正则表达式
/* Apply AS path filter to AS. */
enum as_filter_type as_list_apply(struct as_list *aslist, void *object)
{
struct as_filter *asfilter;
struct aspath *aspath;
aspath = (struct aspath *)object;
if (aslist == NULL)
return AS_FILTER_DENY;
for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) {
if (as_filter_match(asfilter, aspath))
return asfilter->type;
}
return AS_FILTER_DENY;
}
static int as_filter_match(struct as_filter *asfilter, struct aspath *aspath)
{
if (bgp_regexec(asfilter->reg, aspath) != REG_NOMATCH)
return 1;
return 0;
}

浙公网安备 33010602011771号