ipset源代码中添加新类型

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haolipengzhanshen/article/details/85093282

首先我们先来分析下ipset_hash_mac.c文件

在每个文件的开始位置

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <[email protected]>");
IP_SET_MODULE_DESC("hash:mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
MODULE_ALIAS("ip_set_hash:mac");

下面好好看下这个宏,IP_SET_MODULE_DESC

从字面意思上看,IP_SET_MODULE_DESC:ipset模块的描述

#define _IP_SET_MODULE_DESC(a, b, c)        \
    MODULE_DESCRIPTION(a " type of IP sets, revisions " b "-" c)
#define IP_SET_MODULE_DESC(a, b, c)        \
    _IP_SET_MODULE_DESC(a, __stringify(b), __stringify(c))

__stringify是个什么东西?

把传入的参数直接转化为字符串

https://blog.csdn.net/duanlove/article/details/7974889

最开始的时候,我就是IP_SET_MODULE_DESC这块第一个参数填写错了,

dimension的含义

opt设置的IPSET_OPT_ETHER

.opt = IPSET_OPT_ETHER

因为我们要添加新的类型,所以可能需要创建IPSET_OPT_STRING

1.枚举定义

data.h文件中的

enum ipset_opt {
    IPSET_OPT_NONE = 0,
    /* Common ones */
    IPSET_SETNAME,
    IPSET_OPT_TYPENAME,
    IPSET_OPT_FAMILY,
    
    /* ADT-specific options */
    IPSET_OPT_ETHER,//mac对应的枚举在这里!!!
    IPSET_OPT_NAME,
    IPSET_OPT_NAMEREF,
    IPSET_OPT_IP2,
    IPSET_OPT_CIDR2,
    IPSET_OPT_IP2_TO,
    IPSET_OPT_PROTO,
    IPSET_OPT_IFACE,

};

2 注册时添充need和full的值

3.IPSET_ADT_FLAGS宏定义,这个宏的调用位置?

#define IPSET_ADT_FLAGS            \
    (IPSET_FLAG(IPSET_OPT_IP)    \
    | IPSET_FLAG(IPSET_OPT_IP_TO)    \
    | IPSET_FLAG(IPSET_OPT_CIDR)    \
    | IPSET_FLAG(IPSET_OPT_MARK)    \
    | IPSET_FLAG(IPSET_OPT_PORT)    \
    | IPSET_FLAG(IPSET_OPT_PORT_TO)    \
    | IPSET_FLAG(IPSET_OPT_TIMEOUT)    \
    | IPSET_FLAG(IPSET_OPT_ETHER)    \
    | IPSET_FLAG(IPSET_OPT_NAME)    \
    | IPSET_FLAG(IPSET_OPT_NAMEREF)    \
    | IPSET_FLAG(IPSET_OPT_IP2)    \
    | IPSET_FLAG(IPSET_OPT_CIDR2)    \
    | IPSET_FLAG(IPSET_OPT_PROTO)    \
    | IPSET_FLAG(IPSET_OPT_IFACE) \
    | IPSET_FLAG(IPSET_OPT_CADT_FLAGS)\
    | IPSET_FLAG(IPSET_OPT_BEFORE) \
    | IPSET_FLAG(IPSET_OPT_PHYSDEV) \
    | IPSET_FLAG(IPSET_OPT_NOMATCH) \
    | IPSET_FLAG(IPSET_OPT_PACKETS)    \
    | IPSET_FLAG(IPSET_OPT_BYTES)    \
    | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)\
    | IPSET_FLAG(IPSET_OPT_SKBMARK)    \
    | IPSET_FLAG(IPSET_OPT_SKBPRIO)    \
    | IPSET_FLAG(IPSET_OPT_SKBQUEUE))

另外还有一个IPSET_CREATE_FLAGS是做什么使用的?

4.ipset_data_sizeof  计算特定数据类型的长度

其中计算IPSET_OPT_ETHER类型的长度,

case IPSET_OPT_ETHER:
        return ETH_ALEN;

5.ipset_data_get函数

case IPSET_OPT_ETHER:
        return data->adt.ether;

亲自验证下何时调用ipset_data_get函数中的IPSET_OPT_ETHER分支?

6.ipset_data_set函数

/* ADT-specific options */
    case IPSET_OPT_ETHER:
        memcpy(data->adt.ether, value, ETH_ALEN);
        break;

在编写输出函数时遇到了问题

在ipset_hash_mac.c文件中,ipset_hash_mac0结构体定义如下:

 parse回调函数,负责解析用户输入的参数,并设置到内核中

print回调函数,在执行ipset list命令时,显示字符串

何时调用elem的parse函数呢?

在parse.c文件中的parse_elem宏,去解析每一个元素,这个解析的是命令行内容,

#define parse_elem(s, t, d, str)                    \

do {                                    \

    if (!(t)->elem[d - 1].parse)                    \

        goto internal;                        \

    ret = (t)->elem[d - 1].parse(s, (t)->elem[d - 1].opt, str);    \

    if (ret)                            \

        goto out;                        \

} while (0)

ipset_parse_elem函数中调用的parse_elem宏,

根据type->dimension的值是否为IPSET_DIM_ONE,IPSET_DIM_TWO,IPSET_DIM_THREE来进一步调用parse_elem函数

何时调用elem的print回调函数呢?

int
ipset_print_elem(char *buf, unsigned int len,
		 const struct ipset_data *data, enum ipset_opt opt UNUSED,
		 uint8_t env)
{
	const struct ipset_type *type;
	int size, offset = 0;

	assert(buf);
	assert(len > 0);
	assert(data);

	type = ipset_data_get(data, IPSET_OPT_TYPE);
	if (!type)
		return -1;

	size = type->elem[IPSET_DIM_ONE - 1].print(buf, len, data,
			type->elem[IPSET_DIM_ONE - 1].opt, env);
	SNPRINTF_FAILURE(size, len, offset);
	IF_D(ipset_data_test(data, type->elem[IPSET_DIM_TWO - 1].opt),
	     "print second elem");
	if (type->dimension == IPSET_DIM_ONE ||
	    (type->last_elem_optional &&
	     !ipset_data_test(data, type->elem[IPSET_DIM_TWO - 1].opt)))
		return offset;

	size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
	SNPRINTF_FAILURE(size, len, offset);
	size = type->elem[IPSET_DIM_TWO - 1].print(buf + offset, len, data,
			type->elem[IPSET_DIM_TWO - 1].opt, env);
	SNPRINTF_FAILURE(size, len, offset);
	if (type->dimension == IPSET_DIM_TWO ||
	    (type->last_elem_optional &&
	     !ipset_data_test(data, type->elem[IPSET_DIM_THREE - 1].opt)))
		return offset;

	size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
	SNPRINTF_FAILURE(size, len, offset);
	size = type->elem[IPSET_DIM_THREE - 1].print(buf + offset, len, data,
			type->elem[IPSET_DIM_THREE - 1].opt, env);
	SNPRINTF_FAILURE(size, len, offset);

	return offset;
}

现在使用ipset add命令时,报错   ipset v7.1: Element cannot be added to the set: it's already added

我先过一下hash:mac类型的集合的流程,然后再考虑说其他的。

参考文章

云风的博客

https://blog.codingnow.com/2018/05/ineffective_debugger.html

猜你喜欢

转载自blog.csdn.net/haolipengzhanshen/article/details/85093282