本文主要是介绍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);
这篇关于ip_route_out route ip_rcv_finis的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!