第12章 网络 (6)

12.8 网络层

12.8.4 分组转发

转发IP分组,根据目标地址分为:

        1. 直接和本地相连。

        2. 不直接相连,需要网关转发。

int    ip_route_input_noref(skb,   daddr,   saddr,   tos,   net_dev):

        //查找路由表。

如果 skb->_skb_refdst 成员缓存了 struct   dst_entry 信息,无需查找路由表。

ip_forward 流程:

ip_forward_options:

        处理IP选项。

最后调用 skb->dst->output,即 ip_output。

struct   sock   {

        struct   dst_entry   *sk_dst_cache;         //缓存的路由结构体。

}

如何缓存一个struct   dst_entry     dst ?

        rcu_assign_pointer(sk->sk_dst_cache,   dst);

所以若同一 socket 的所有分组的目的地址都相同,则只需在发送第一个分组时查找 struct  dst_entry。

        后续分组可使用缓存的 struct  dst_entry。

12.8.5 发送分组

ip_queue_xmit:更高层协议使用,如TCP,UDP。

举例:

tcp_transmit_skb ->

        icsk->icsk_af_ops->queue_xmit(skb,   &inet->cork.fl);

                // 即 ip_queue_xmit ()

所以 转发和本地发送的数据,都最终调用 ip_output。

1. 转移到网络访问层

int   ip_output(struct  sk_buff   *skb)

{

        struct net_device  *dev   =   skb_dst(skb)->dev;

        skb->dev   =   dev;         //将skb->dev改为路由表指示的出口设备。

        NF_HOOK_COND(NFPROTO_IPV4,   NF_INET_POST_ROUTING,   skb,   ,   dev,

 ip_finish_output,  );

}

dst->neighbour->output   =   dev_queue_xmit;

        neighbour:ARP层相关。

dev_queue_xmit

        -> dev_hard_start_xmit

                -> ops->ndo_start_xmit(skb, dev); //不同网卡的驱动自定义。

2. 分片

分片原理:

ip_fragment:实现分片,并发送。

        包括:

                设置分片偏移量。

                除最后一个分片都设置MF标志。

3. 路由

struct   dst_entry   {         // 路由查找时填充成员。

        struct   net_device         *dev;

        int         (*input)(struct sk_buff   *);           //  处理进入分组。

        int         (*output)(struct sk_buff   *);         // 处理外出分组。

};

                                本地                         转发

input指针                 ip_local_deliver        ip_forward

output指针               ip_ouput                   ip_ouput

struct   neighbour    {         //就是ARP表项,存储本地网络的IP和硬件地址。

        struct neighbour           *next;

        struct neigh_table         *tbl;

        unsigned char         ha[ALIGN(MAX_ADDR_LEN,   sizeof(unsigned long))];

                //硬件地址

        int                 (*output)(struct  neighbour   *,    struct  sk_buff   *);

                // 用于转发数据包时发送数据包到邻居设备上。

                //通常为dev_queue_xmit; ,最终调用网卡实现的 ndo_start_xmit 函数指针。

        struct   net_device         *dev;

};

12.8.6 netfilter

1. 扩展网络功能

netfilter可扩展的功能:

        1. 不同方向的包过滤。

        2. NAT。

        3. 拆分、修改包。

2. 调用钩子函数

netfilter钩子函数会中断网络层函数。

如何调用钩子函数?

        使用宏 NF_HOOK

int   NF_HOOK(uint8_t pf,   unsigned int   hook,   struct sk_buff   *skb,   struct net_device   *in, struct net_device   *out,   int   (*okfn)(struct sk_buff *))

NF_HOOK

        -> NF_HOOK_THRESH(INT_MIN)

int   NF_HOOK_THRESH(pf,   hook,   skb,   in,   out,   okfn,   INT_MIN)

        //所有钩子函数都执行,因为INT_MIN值的最小

{

        int   ret    =    nf_hook_thresh(pf,   hook,    skb,    in,   out,    okfn,   thresh);

                //nf_hook_thresh->nf_hook_slow

        if (ret    ==    1)         //ret=1 即没有注册钩子函数

                ret    =    okfn(skb);

}

宏的参数介绍:

        pf:

                调用哪个协议族的钩子函数。

        hook:钩子编号。如:

                NF_IP_FORWORD

                NF_IP_LOCAL_OUT

        okfn:

                钩子函数结构后执行。

        thresh:

                优先级高于该值的钩子函数都将执行。

                最小为:INT_MIN,此时所有钩子函数都执行。

使用举例:

int    ip_forward(struct    sk_buff    *skb)

{

        ...

        return   NF_HOOK(NFPROTO_IPV4,    NF_INET_FORWARD,   skb,   skb->dev,

  rt->dst.dev,   ip_forward_finish);

}

所以 NF_INET_FORWARD 钩子函数执行完后,就调用okfn函数,即ip_forward_finish。

如果:

        1. 内核没有开启CONFIG_NETFILTER。

                或

        2. 没有注册对应pf,hook钩子函数。

则不调用钩子函数,直接执行okfn函数,即ip_forward_finish。

ip_forward_finish:实现转发操作,包含:

        1. 递减TTL(生存时间)。

        2. 修改 IP包头。

        3. 调用dev_queue_xmit。

        4. 更新路由缓存项,以加速下一次路由。

当没有配置CONFIG_NETFILTER:

        #define    NF_HOOK(pf,    hook,    skb,    indev,    outdev,   okfn)

                (okfn)(skb)

3. 扫描挂钩表

nf_hook_slow:扫描钩子链表。

所有的钩子函数保存在:

struct list_head    nf_hooks [ NFPROTO_NUMPROTO ] [ NF_MAX_HOOKS ];

NFPROTO_NUMPROTO:

        支持的协议族数量。如IPV4,IPV6,ARP,BRIDGE。

        默认值:13。

NF_MAX_HOOKS:

        一个协议族最多的挂钩链表。

        默认值:8。

最多链表数量:13 * 8。

IPV4协议族定义 5 个链表:

        NF_INET_PRE_ROUTING

        NF_INET_LOCAL_IN

        NF_INET_FORWARD

        NF_INET_LOCAL_OUT

        NF_INET_POST_ROUTING

这 5 个链表中连接了各自钩子函数。

钩子函数用 nf_hook_ops 表示:

        struct nf_hook_ops         *arpfilter_ops;

        struct nf_hook_ops         *mangle_ops;

        struct nf_hook_ops         *filter_ops;

        struct nf_hook_ops         *ipv4_conntrack_ops;

        struct nf_hook_ops         *rawtable_ops;

        struct nf_hook_ops         *ebt_ops_filter;

struct   nf_hook_ops   {

        struct list_head    list;

        nf_hookfn            *hook;         // 钩子函数。

        u_int8_t                pf;             // 协议族。

        unsigned int         hooknum;

                // 钩子编号,如 NF_INET_POST_ROUTING

        int                         priority;

                // 钩子的优先级。按先后执行。

                //如 INT_MIN

};

nf_hook_slow

        -> nf_iterate

nf_iterate:执行指定协议族,指定钩子编号中注册的所有钩子函数。

        如:

                协议族为NFPROTO_IPV4,

                钩子编号为NF_INET_POST_ROUTING。

                (当然是,大于指定优先级的所有钩子函数。)

4. 激活钩子函数

钩子函数的返回值:

        1. NF_ACCEPT:

                包通过当前检查点,继续协议栈后续处理。

        2. NF_DROP:

                该包将被丢弃。无需其他处理。

        3. NF_QUEUE:

                包被送到用户空间的一个队列中,供用户态程序后续处理。

                不再执行其他钩子函数。

        4. NF_REPEAT

                重复执行当前hook链规则检查。

12.8.7 IPv6

1. 概述

IPv6地址长度:128位。

注:IPv5名称被STP协议使用。

IPv6 报文格式:

2. 实现

IPv6低层和IPv4低层一样。

IPv6不会分片,所以帧格式中无需分片信息。

IPv6处理流程:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山下小童

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值