ip_route_out route ip_rcv_finis

IP层路由适配(IP route)

  路由表以及规则组成的系统,可以完成路由的管理以及查找的工作,但是为了使得IP层的路由工作更加的高效,linux的路由体系里,route.c里完成大多数IP层与RPDB的适配工作,以及路由缓冲(route cache)的功能。

  调用接口

  IP层的路由接口分为发送路由接口以及接收路由接口:

  发送路由接口

  IP层在发送数据时如果需要进行路由工作的时候,就会调用ip_route_out函数。这个函数在完成一些键值的简单转换以后,就会调用ip_route_output_key函数,这个函数首先在缓存里寻找路由,如果失败就会调用ip_route_output_slow,ip_route_output_slow里调用fib_lookup在路由表里寻找路由,如果命中,首先在缓存里添加这个路由,然后返回结果。

ip_route_out route.h
ip_route_output_key route.c 1984;
ip_route_output_slow route.c 1690;"

  接收路由接口

  IP层接到一个数据包以后,如果需要进行路由,就调用函数ip_route_input,ip_route_input现在缓存里寻找,如果失败则ip_route_inpu调用ip_route_input_slow, ip_route_input_slow里调用fib_lookup在路由表里寻找路由,如果命中,首先在缓存里添加这个路由,然后返回结果。

ip_route_input_slow route.c 1312;" f
ip_route_input route.c 1622;" f

  cache

  路由缓存保存的是最近使用的路由。当IP在路由表进行路由以后,如果命中就会在路由缓存里增加该路由。同时系统还会定时检查路由缓存里的项目是否失效,如果失效则清除。


/*
 * 接收完数据包后的后续处理函数
 */
static int ip_rcv_finish(struct sk_buff *skb)
{
	const struct iphdr *iph = ip_hdr(skb);
	struct rtable *rt;

	 /*
	  * 激活ip_route_input,确定报文的路由,如果ip_route_input无法从FIB中找到路由
	  * 则丢弃数据报<strong>文,ip_route_input将在IP路由中的专题中进行讲解</strong>
	  */
	<strong><span style="color:#ff0000;">if (skb_dst(skb) == NULL) {</span>
		int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev);
		if (unlikely(err)) {</strong>
			goto drop;
		}
	}

	/*检查IP报头里面是否含有选项,如果含有建立ip_options*/
	if (iph->ihl > 5 && ip_rcv_options(skb))
		goto drop;

	<strong><span style="color:#ff0000;">/*根据dst_entry的结果,使用skb_dst(skb)->input(skb)进行IP的路由选择
	 *传递给本地计算机的单播或多播,进入 ip_local_deliver();
	 *单播转发的报文进入ip_forward()
	 *多播转发进入ip_mr_input()
	 */</span></strong>
	return dst_input(skb);
	{
		skb_dst(skb)->input(skb)
	}

drop:
	kfree_skb(skb);
	return NET_RX_DROP;
}



#include <linux/ip.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/version.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/dst.h>
#include <net/netfilter/nf_conntrack_acct.h>


MODULE_AUTHOR("xtt");
MODULE_DESCRIPTION("gll");
MODULE_LICENSE("GPL");
MODULE_ALIAS("XTT and GLL");

struct nf_conn_priv {
        struct nf_conn_counter ncc[IP_CT_DIR_MAX];
        struct dst_entry *dst[IP_CT_DIR_MAX];
};

static unsigned int ipv4_conntrack_getdst (unsigned int hooknum,
                                      struct sk_buff *skb,
                                      const struct net_device *in,
                                      const struct net_device *out,
                                      int (*okfn)(struct sk_buff *))
{
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
        struct nf_conn_counter *acct;
        struct nf_conn_priv *dst_info;
        ct = nf_ct_get(skb, &ctinfo);
        if (!ct || ct == &nf_conntrack_untracked)
                return NF_ACCEPT;
        acct = nf_conn_acct_find(ct);
        if (acct) {
                int dir = CTINFO2DIR(ctinfo);
                dst_info = (struct nf_conn_priv *)acct;
                if (dst_info->dst[dir] == NULL) {
                        dst_hold(skb_dst(skb));
                        dst_info->dst[dir] = skb_dst(skb);
                }
        }
        return NF_ACCEPT;
}

static unsigned int ipv4_conntrack_setdst (unsigned int hooknum,
                                      struct sk_buff *skb,
                                      const struct net_device *in,
                                      const struct net_device *out,
                                      int (*okfn)(struct sk_buff *))
{
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
        struct nf_conn_counter *acct;
        struct nf_conn_priv *dst_info;
        ct = nf_ct_get(skb, &ctinfo);
        if (!ct || ct == &nf_conntrack_untracked)
                return NF_ACCEPT;
        acct = nf_conn_acct_find(ct);
        if (acct) {
                int dir = CTINFO2DIR(ctinfo);
                dst_info = (struct nf_conn_priv *)acct;
                if (dst_info->dst[dir] != NULL) {
                      // 如果在此设置了skb的dst,那么在ip_rcv_finish中就不会再去查找路由表了
                        skb_dst_set(skb, dst_info->dst[dir]);

                }
        }
        return NF_ACCEPT;
}
static struct nf_hook_ops ipv4_conn_dst_info[] __read_mostly = {
        {
                .hook          = ipv4_conntrack_getdst,
                .owner          = THIS_MODULE,
                .pf            = NFPROTO_IPV4,
                .hooknum        = NF_INET_POST_ROUTING,
                .priority      = NF_IP_PRI_CONNTRACK + 1,
        },
        {
                .hook          = ipv4_conntrack_getdst,
                .owner          = THIS_MODULE,
                .pf            = NFPROTO_IPV4,
                .hooknum        = NF_INET_LOCAL_IN,
                .priority      = NF_IP_PRI_CONNTRACK + 1,
        },
        {
                .hook          = ipv4_conntrack_setdst,
                .owner          = THIS_MODULE,
                .pf            = NFPROTO_IPV4,
                .hooknum        = NF_INET_PRE_ROUTING,
                .priority      = NF_IP_PRI_CONNTRACK + 1,
        },
};

static int __init test_info_init(void)
{
        int err;
        err = nf_register_hooks(ipv4_conn_dst_info, ARRAY_SIZE(ipv4_conn_dst_info));
        if (err) {
                return err;
        }
        return err;
}

static void __exit test_info_exit(void)
{
        nf_unregister_hooks(ipv4_conn_dst_info, ARRAY_SIZE(ipv4_conn_dst_info));
}

module_init(test_info_init);
module_exit(test_info_exit);


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值