linux .forward,linux forward的实现

对于linux的数据包流向,大家应该是比较了解,如果还不是很了解,可以参考《OReilly.Understanding.Linux.Network.Internals.Dec.2005》,其中有一个图非常清楚的描述了数据包的流向。

ip的数据包接收函数是ip_rcv()==>ip_rcv_finish()

在ip_rcv_finish()中:

if (skb->dst == NULL) {

int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,

skb->dev);

刚接收到的数据包,skb->dst项是空的,因此会调用ip_route_input()函数,我们来追踪ip_route_input函数:

ip_route_input()==>ip_route_input_slow()

在ip_route_input_slow()中:

if ((err = fib_lookup(&fl, &res)) != 0) {

if (!IN_DEV_FORWARD(in_dev))

goto e_hostunreach;

goto no_route;

}

调用fib_lookup()函数用来在fib中查询路由信息,将路由查询结果保存在fib_result结构的res中。

接下来:

if (res.type == RTN_LOCAL) {

int result;

result = fib_validate_source(saddr, daddr, tos,

loopback_dev.ifindex,

dev, &spec_dst, &itag);

if (result < 0)

goto martian_source;

if (result)

flags |= RTCF_DIRECTSRC;

spec_dst = daddr;

/*设置skb->dst->input=ip_local_deliver*/

goto local_input;

}

如果查询的结果显示,路由类型RTN_LOCAL的话,跳转到local_input段,设置skb->dst->input = ip_local_deliver

接下来,路由类型是RTN_LOCAL的已经跳转到下面去了,剩下的就是非LCOAL的,也就是Forward的:

if (!IN_DEV_FORWARD(in_dev))

goto e_hostunreach;

if (res.type != RTN_UNICAST)

goto martian_destination;

/*设置skb->dst->input=ip_forward*/

err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);

调用IN_DEV_FORWARD宏来判断网络设备是否处于FORWARD状态;调用ip_mkroute_input()函数来设置skb->dst->input=ip_forward

我们来分析一下IN_DEV_FORWARD这个宏:

#define IN_DEV_FORWARD(in_dev)    ((in_dev)->cnf.forwarding)

在ipv4_sysctl_forward()函数中调用inet_forward_change()函数:

在inet_forward_change()函数中:

int on = ipv4_devconf.forwarding;

in_dev->cnf.forwarding = on;

在sysctl_net_ipv4.c中

{

.ctl_name    = NET_IPV4_FORWARD,

.procname    = "ip_forward",

.data        = &ipv4_devconf.forwarding,

.maxlen        = sizeof(int),

.mode        = 0644,

.proc_handler    = &ipv4_sysctl_forward,

.strategy    = &ipv4_sysctl_forward_strategy

},

这样,我们通过

echo 1 > /proc/sys/net/ipv4/ip_forward

来打开forward功能,实际上就调用了

ipv4_sysctl_forward()==>inet_forward_change()

设置了in_dev->cnf.forwarding = 1;

这样IN_DEV_FORWARD(in_dev)返回为1,当forward的数据包到来的时候,能够调用ip_mkroute_input()函数,设置skb->dst->input=ip_forward。

==========

再回到ip_rcv_finish()中,最后函数调用了dst_input函数,我们来追踪一下dst_input()函数:

dst_input()==>skb->dst->input

对于LOCAL的数据包来说调用的是:ip_local_deliver()函数

对于FORWARD的数据包来说调用的是:ip_forward()函数

对于fib_lookup的细节,可以参考:

http://blog.chinaunix.net/u/28366/showart_215922.html

阅读(4638) | 评论(0) | 转发(0) |

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值