ipset原始碼分析之kadt和uadt回撥函式
一定要清楚自己在幹什麼,每行程式碼在幹什麼,這樣寫的程式碼才能做到心中有數。
之前看到ip_set_hash_ip.chash_ip4_uadt和hash_ip4_kadt函式,就一直很好奇這兩個函式是幹什麼呢?
下面我來帶你一步步剖析這兩個函式
一、kadt和uadt回撥函式的註冊
首先看下struct ip_set_type_variant結構體變數
**kadt回撥函式的註冊在以下三個位置**
1.ip_set_bitmap_gen.h的.kadt = mtype_kadt,
static const struct ip_set_type_variant mtype = {
.kadt = mtype_kadt,
.uadt = mtype_uadt,
.adt = {
[IPSET_ADD] = mtype_add,
[IPSET_DEL] = mtype_del,
[IPSET_TEST] = mtype_test,
},
......
};
2.ip_set_hash_gen.h的.kadt = mtype_kadt,
static const struct ip_set_type_variant mtype_variant = {
.kadt = mtype_kadt,
.uadt = mtype_uadt,
.adt = {
[IPSET_ADD] = mtype_add,
[IPSET_DEL] = mtype_del,
[IPSET_TEST] = mtype_test,
},
......
};
正好對應set模組的三種資料型別bitmap,hash。
其中
.kadt = mtype_kadt,
.uadt = mtype_uadt,
搜尋mtype_kadt,是一個巨集定義,將MTYPE巨集定義和_kadt拼接起來
#define CONCAT(a, b) a##b
#define TOKEN(a, b) CONCAT(a, b)
#define mtype_kadt TOKEN(MTYPE, _kadt)
MTYPE有不同的定義,對於hash:ip集合,為hash_ip4
#define MTYPE hash_ip4
那麼mtype_kadt巨集經過拼裝以後得到的是hash_ip4_kadt,即我之前一直疑惑的hash_ip4_kadt函式
ipset的每種型別都需要實現一個xxx_kadt的函式,不信的同學可以開啟原始碼自己看哦。
二、kadt回撥函式的呼叫位置
呼叫位置有三處,分別對應於ip_set_test,ip_set_add,ip_set_del函式
1.ip_set_test函式
ret = set->variant->kadt(set, skb, par, IPSET_TEST, opt);
2.ip_set_add函式
ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
3.ip_set_del函式
ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
以hash_ip4_kadt為例子進行講解
hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
const struct hash_ip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ip4_elem e = {};
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
__be32 ip;
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
ip &= ip_set_netmask(h->netmask);
if (ip == 0)
return -EINVAL;
e.ip = ip;
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
在kadt回撥函式中會呼叫adtfn函式
ipset_adtfn adtfn = set->variant->adt[adt];
因此其最終呼叫還是註冊的adt回撥函式
在ip_set_hash_gen.h檔案中有mtype_add這個函式
那系統是在何時呼叫ip_set_add呢?
在target回撥函式中
這點很好理解了,target回撥函式可以說是執行一條指令的最後一步,一切都準備就緒,在target回撥函式中呼叫新增、刪除、修改等操作,也是有情可原的。
總結起來流程圖如下所示
三、uadt回撥函式的呼叫位置
uadt的呼叫位置有兩個
1.call_ad函式
2.IPSET_CBFN(ip_set_utest, struct net *net, struct sock *ctnl,struct sk_buff *skb,const struct nlmsghdr *nlh,
const struct nlattr * const attr[],struct netlink_ext_ack *extack)
其中IPSET_CBFN巨集的功能是建立並實現一個以第一個引數為函式名稱的函式,即ip_set_utest函式
搜尋ip_set_utest函式,得到結果
其中在IPSET_CMD_TEST項對應的call回撥函式用ip_set_utest來賦值,那麼call何時呼叫呢?我們猜測是當IPSET_CMD_TEST請求命令到來時呼叫call,這些call是核心模組呼叫的。
暫時沒有找到call回撥函式是誰來呼叫的