2010年3月29日 星期一

vconfig


802.1Q VLAN很早就被納入kernel中,而MAC-VLAN在2.6.29版時納入。在編譯kernel時,需要將VLAN編譯進去,接著就可以透過vconfig/ip進行操作,不過建議使用ip。

ip
Usage: ip link add link DEV [ name ] NAME
                   [ txqueuelen PACKETS ]
                   [ address LLADDR ]
                   [ broadcast LLADDR ]
                   [ mtu MTU ]
                   type TYPE [ ARGS ]
       ip link delete DEV type TYPE [ ARGS ]

       ip link set DEVICE [ { up | down } ]
                   [ arp { on | off } ]
                   [ dynamic { on | off } ]
                   [ multicast { on | off } ]
                   [ allmulticast { on | off } ]
                   [ promisc { on | off } ]
                   [ trailers { on | off } ]
                   [ txqueuelen PACKETS ]
                   [ name NEWNAME ]
                   [ address LLADDR ]
                   [ broadcast LLADDR ]
                   [ mtu MTU ]
                   [ netns PID ]
     [ alias NAME ]
       ip link show [ DEVICE ]

TYPE := { vlan | veth | dummy | ifb | macvlan }

vconfig
Usage: add             [interface-name] [vlan_id]
       rem             [vlan-name]
       set_dflt        [interface-name] [vlan_id]
       add_port        [port-name]      [vlan_id]
       rem_port        [port-name]      [vlan_id]
       set_egress_map  [vlan-name]      [skb_priority]   [vlan_qos]
       set_ingress_map [vlan-name]      [skb_priority]   [vlan_qos]
       set_name_type   [name-type]
       set_bind_mode   [bind-type]

對於VLAN Net Device的命名規則則有四種:
  • VLAN_PLUS_VID (vlan0005)
  • VLAN_PLUS_VID_NO_PAD (vlan5)
  • DEV_PLUS_VID (eth0.0005)
  • DEV_PLUS_VID_NO_PAD (eth0.5)


double-tag
所謂的double tag,就是在vlan上,再切vlan,所以在linux的指令也就是vconfig add <vlan_netdev> <vid>。






參考資料:
http://www.candelatech.com/~greear/vlan.html

2010年3月22日 星期一

Linux Kernel(12)- netfilter


netfilter是一個packet mangling的framework,主要在protocol stack中提供一些hook point(NF_IP_PRE_ROUTING、NF_IP_LOCAL_IN、NF_IP_FORWARD、NF_IP_POST_ROUTING和NF_IP_LOCAL_OUT),讓user可以在這些hook point上註冊並且執行一些hook function,根據hook function傳回來的數值來決定是否要丟棄(NF_DROP)、pass(NF_ACCEPT)、或者queue(NF_QUEUE)等等。



NF_ACCEPT︰ continue traversal as normal.
NF_DROP︰ drop the packet; don't continue traversal.
NF_STOLEN: I've take over the packet; don't continue traversal.
NF_QUEUE︰ queue the packet.
NF_REPEAT︰ call this hook again.

struct nf_hook_ops
{
    struct list_head list;

    /* User fills in from here down. */
    nf_hookfn *hook;
    struct module *owner;
    u_int8_t pf;
    unsigned int hooknum;
    /* Hooks are ordered in ascending priority. */
    int priority;
};
pf是protocol family,目前有NFPROTO_UNSPEC、NFPROTO_IPV4、NFPROTO_ARP、NFPROTO_BRIDGE、NFPROTO_IPV6和NFPROTO_DECNET等等。這些值也等同sock的protocol family。
hooknum則是填入hook point num,netfilter是一個framework,會在很多地方設立hook point,而我們可以使用nf_register_hook()/nf_register_hooks()將我們的hook function掛在這些點上,以IPv4來說(上面的圖示),就提供了五個hook point,包含:
HookCalled
NF_IP_PRE_ROUTINGAfter sanity checks, before routing decisions.
NF_IP_LOCAL_INAfter routing decisions if packet is for this host.
NF_IP_FORWARDIf the packet is destined for another interface.
NF_IP_LOCAL_OUTFor packets coming from local processes on their way out.
NF_IP_POST_ROUTINGJust before outbound packets "hit the wire".

當然有了nf_register_hook()/nf_register_hooks()提供註冊,也會提供nf_unregister_hook()/nf_unregister_hooks()做unregister。
以下就是一個分別在IPv4的五個hook點上,印出saddr和daddr。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>

MODULE_LICENSE("GPL");

inline void dumpIpHdr(const char *fn, const struct sk_buff *skb)
{
    const struct iphdr *ip = ip_hdr(skb);

    printk("%s, saddr:%pI4, daddr:%pI4\n", fn, &ip->saddr, &ip->daddr);
}

static unsigned int
prerouting(unsigned int hook, struct sk_buff *skb,
        const struct net_device *in, const struct net_device *out,
        int (*okfn)(struct sk_buff*))
{
    dumpIpHdr(__FUNCTION__, skb);
    return NF_ACCEPT;
}

static unsigned int
localin(unsigned int hook, struct sk_buff *skb,
        const struct net_device *in, const struct net_device *out,
        int (*okfn)(struct sk_buff*))
{
    dumpIpHdr(__FUNCTION__, skb);
    return NF_ACCEPT;
}

static unsigned int
localout(unsigned int hook, struct sk_buff *skb,
        const struct net_device *in, const struct net_device *out,
        int (*okfn)(struct sk_buff*))
{
    dumpIpHdr(__FUNCTION__, skb);
    return NF_ACCEPT;
}

static unsigned int
postrouting(unsigned int hook, struct sk_buff *skb,
        const struct net_device *in, const struct net_device *out,
        int (*okfn)(struct sk_buff*))
{
    dumpIpHdr(__FUNCTION__, skb);
    return NF_ACCEPT;
}

static unsigned int
fwding(unsigned int hook, struct sk_buff *skb,
        const struct net_device *in, const struct net_device *out,
        int (*okfn)(struct sk_buff*))
{
    dumpIpHdr(__FUNCTION__, skb);
    return NF_ACCEPT;
}

static struct nf_hook_ops brook_ops[] __read_mostly = {
    {
        .hook = prerouting,
        .pf = PF_INET,
        .hooknum = NF_INET_PRE_ROUTING,
        .priority = NF_IP_PRI_RAW,
        .owner = THIS_MODULE,
    }, {
        .hook = localin,
        .pf = PF_INET,
        .hooknum = NF_INET_LOCAL_IN,
        .priority = NF_IP_PRI_RAW,
        .owner = THIS_MODULE,
    }, {
        .hook = fwding,
        .pf = PF_INET,
        .hooknum = NF_INET_FORWARD,
        .priority = NF_IP_PRI_RAW,
        .owner = THIS_MODULE,
    }, {
        .hook = localout,
        .pf = PF_INET,
        .hooknum = NF_INET_LOCAL_OUT,
        .priority = NF_IP_PRI_RAW,
        .owner = THIS_MODULE,
    }, {
        .hook = postrouting,
        .pf = PF_INET,
        .hooknum = NF_INET_POST_ROUTING,
        .priority = NF_IP_PRI_RAW,
        .owner = THIS_MODULE,
    },
};

static int __init init_modules(void)
{
    if (nf_register_hooks(brook_ops, ARRAY_SIZE(brook_ops)) < 0) {
        printk("nf_register_hook failed\n");
    }
    return 0;
}

static void __exit exit_modules(void)
{
    nf_unregister_hooks(brook_ops, ARRAY_SIZE(brook_ops));
}

module_init(init_modules);
module_exit(exit_modules);



以下這張是更為清楚的netfilter packet flow: