Netfilter/iptables的一些新進展

來源:互聯網
上載者:User
關注了一下Netfilter的最新進展,新東西還真不少哇!但是最讓人心動的有兩個。
一.新的bpf模組

基於Linux kernel 3.9版本的patch是xt_bpf的支援,對應的iptables模組是libxt_bpf,這個在iptables-1.4.19版本中已經支援,顧名思義,bpf其實就是伯克利包過濾的縮寫,對於它的描述,參見《BPF(BSD Packet Filter)--應用和理念擴充》。從名稱上看,BPF理應就是iptables包過濾的首選技術,但是不知道什麼原因,xt_tables一直維護著自己的資料結構儲存rule的match和target,現在有了BPF的支援,我想核心協議棧在處理iptables規則時的效率會高很多,以往的一系列的多個match,現在封裝進一個match,該match可以通過bytecode參數來指示,它是已經編譯好的位元組碼,核心直接去執行,速度非常快。以往的match匹配基本就是遍曆,現在基於bpf的不再依賴遍曆了,而是去“執行”那段bytecode!
        tcpdump工具一直以來都是基於BPF的,雖然它的match在文法上和iptables的極其類似,其匹配效率卻比iptales高很多,類似
-i eth2 tcp port 1234 and host 1.2.3.4
這一串匹配在iptables中需要建立4個entry,然而使用BPF的話,就可以編譯成一段以下順序執行的代碼:
1.載入dev欄位
2.判斷dev欄位,如果不是eth2則跳到x
3.載入協議欄位
4.判斷協議欄位,如果不是tcp則跳到x
...
x.返回
這段代碼類似彙編代碼,被核心解釋執行。不過,我在kernel 2.6.32上開始沒有編譯成功,因為這個版本太老了,很多介面和新的核心都不相容,改了好久才勉強能運行,但是不能插入複雜的bytecode,否則就panic!
       不管怎樣,採用這個BPF的架構,核心空間的代碼執行效率會提高很多,並且代碼量也會減少很多,像ipt_do_table這個巨無霸函數也能瘦身了。
二.最新的nftables項目

說到iptables核心代碼的瘦身,Netfilter網站上開闢了另外一條路,那就是nftables項目,它旨在完全替換掉既有的iptables/ebtables/arptables以及對應的v6版本。
    nftables最主要的革新在於兩點,其一就是命令文法的完全改變,第二就是核心代碼的最佳化。它採取了類似BPF的過濾方式,其matches的匹配過程就是一個狀態機器轉換的過程,最終的終止節點就是target。在代碼層面,它徹底改變了iptables對match儲存的混亂場面,以下是匹配的核心代碼:

//更加合理的資料結構,比iptables的平坦化的資料結構布局好多了struct nft_expr {    const struct nft_expr_ops    *ops;    unsigned char            data[];};struct nft_rule {    struct list_head        list;    struct list_head        dirty_list;    struct rcu_head            rcu_head;    u64                handle:46,                    genmask:2,                    dlen:16;    unsigned char            data[]        __attribute__((aligned(__alignof__(struct nft_expr))));};//net/netfilter/nf_tables_core.cunsigned intnft_do_chain_pktinfo(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops){    const struct nft_chain *chain = ops->priv;    const struct nft_rule *rule;    const struct nft_expr *expr, *last;    struct nft_data data[NFT_REG_MAX + 1];    unsigned int stackptr = 0;    struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];    int rulenum = 0;    /*     * Cache cursor to avoid problems in case that the cursor is updated     * while traversing the ruleset.     */    unsigned int gencursor = chain->net->nft.gencursor;do_chain:    rule = list_entry(&chain->rules, struct nft_rule, list);next_rule:    data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;    list_for_each_entry_continue_rcu(rule, &chain->rules, list) {        /* This rule is not active, skip. */        if (unlikely(rule->genmask & (1 << gencursor)))            continue;        rulenum++;                       nft_rule_for_each_expr(expr, last, rule) {            if (expr->ops == &nft_cmp_fast_ops)                nft_cmp_fast_eval(expr, data);            else if (expr->ops != &nft_payload_fast_ops ||                 !nft_payload_fast_eval(expr, data, pkt))                expr->ops->eval(expr, data, pkt);            if (data[NFT_REG_VERDICT].verdict != NFT_CONTINUE)                break;        }        switch (data[NFT_REG_VERDICT].verdict) {        case NFT_BREAK:            data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;            /* fall through */        case NFT_CONTINUE:            continue;        }        break;    }    switch (data[NFT_REG_VERDICT].verdict) {       //結果判定        case NF_ACCEPT:    case NF_DROP:    case NF_QUEUE:        nft_chain_stats(chain, pkt, jumpstack, stackptr);        if (unlikely(pkt->skb->nf_trace))            nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);        return data[NFT_REG_VERDICT].verdict;    case NFT_JUMP:        //stack結構更好地組織了rule                if (unlikely(pkt->skb->nf_trace))            nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);        BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);        jumpstack[stackptr].chain = chain;        jumpstack[stackptr].rule  = rule;        jumpstack[stackptr].rulenum = rulenum;        stackptr++;        /* fall through */    case NFT_GOTO:        chain = data[NFT_REG_VERDICT].chain;        goto do_chain;    case NFT_RETURN:        if (unlikely(pkt->skb->nf_trace))            nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);        /* fall through */    case NFT_CONTINUE:        break;    default:        WARN_ON(1);    }    if (stackptr > 0) {        if (unlikely(pkt->skb->nf_trace))            nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN);        stackptr--;        chain = jumpstack[stackptr].chain;        rule  = jumpstack[stackptr].rule;        rulenum = jumpstack[stackptr].rulenum;        goto next_rule;    }    nft_chain_stats(chain, pkt, jumpstack, stackptr);    if (unlikely(pkt->skb->nf_trace))        nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_POLICY);    return nft_base_chain(chain)->policy;}

新的nftables瘦身的原因在於大量採用了回呼函數,使判定邏輯獨立出來,核心的do_tables變成了一個單純的狀態機器!這個抽取動作帶來了的效果就是rule更加靈活了,類似BPF的思想,資料包可以根據每一步的結果在不同的rule或者不同的match之間任意跳轉了。相比iptables在匹配過程中的大量判斷,結果寫入程式碼,nftables確實有一個質的飛躍,期待nftables早日出爐!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.