注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

TCP/IP驱动十三 ——内核中的路由4  

2013-09-23 17:28:11|  分类: TCPIP驱动 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

TCP/IP驱动十三  ——内核中的路由4

隔了一段时间,有些东西就记不清了,怪不得孔老二总说“温故而知新”。今天说说从connect方向过来的时候,路由的情况。

这里只简单说一下:

函数调用是从:

 

Syscall_socketcall()[net/socket.c]----sysconnect()[net/socket.c]----inet_stream_connect()[net/ipv4/af_inet.c]---tcp_v4_connect()[net/ipv4/tcp_ipv4.c]---ip_route_connect()[include/net/route.h]

这里面有两个函数调用是通过函数指针来实现的,需要核对一下:

1、  sysconnect()函数中:

asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr,

                        int addrlen)

{

struct socket *sock;

char address[MAX_SOCK_ADDR];

int err, fput_needed;

 

sock = sockfd_lookup_light(fd, &err, &fput_needed);

if (!sock)

           goto out;

err = move_addr_to_kernel(uservaddr, addrlen, address);

if (err < 0)

           goto out_put;

 

err =

    security_socket_connect(sock, (struct sockaddr *)address, addrlen);

if (err)

         goto out_put;

 

err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen,

                              sock->file->f_flags);

out_put:

fput_light(sock->file, fput_needed);

out:

return err;

}

看上面标红的函数,第一个是查找SOCKET,第二是拷贝数据到内核空间,第三个是SELINUX的相关函数,这里可以忽略不考虑。最后一个,sock->ops->connect这个函数指针是指向:

inet_stream_connect()的。这个在前面也提到过:

const struct proto_ops inet_stream_ops = {

         .family                  = PF_INET,

         .owner                  = THIS_MODULE,

         .release      = inet_release,

         .bind                      = inet_bind,

         .connect     = inet_stream_connect,

         .socketpair          = sock_no_socketpair,

         .accept                 = inet_accept,

         .getname             = inet_getname,

         .poll              = tcp_poll,

         .ioctl                      = inet_ioctl,

         .listen                   = inet_listen,

         .shutdown           = inet_shutdown,

         .setsockopt         = sock_common_setsockopt,

         .getsockopt         = sock_common_getsockopt,

         .sendmsg             = tcp_sendmsg,

         .recvmsg    = sock_common_recvmsg,

         .mmap                  = sock_no_mmap,

         .sendpage           = tcp_sendpage,

         .splice_read        = tcp_splice_read,

#ifdef CONFIG_COMPAT

         .compat_setsockopt = compat_sock_common_setsockopt,

         .compat_getsockopt = compat_sock_common_getsockopt,

#endif

};

其下还有一个变量:const struct proto_ops inet_dgram_ops,对应着数据报,这里不细谈。

 

2、  inet_stream_connect()

int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,

                    int addr_len, int flags)

{

struct sock *sk = sock->sk;

int err;

long timeo;

 

lock_sock(sk);

 

if (uaddr->sa_family == AF_UNSPEC) {

           err = sk->sk_prot->disconnect(sk, flags);

           sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;

           goto out;

}

 

switch (sock->state) {

default:

           err = -EINVAL;

           goto out;

……

case SS_UNCONNECTED:

           err = -EISCONN;

           if (sk->sk_state != TCP_CLOSE)

                    goto out;

 

           err = sk->sk_prot->connect(sk, uaddr, addr_len);

           if (err < 0)

                    goto out;

 

……

}

大家可以发现在这函数里根本找不到tcp_v4_connect()这个函数,那么只好找指针了。跳转到struct sock结构中:

#define sk_prot                            __sk_common.skc_prot

再跳转到:

struct sock_common {

……

atomic_t           skc_refcnt;

unsigned int              skc_hash;

struct proto             *skc_prot;

#ifdef CONFIG_NET_NS

struct net                *skc_net;

#endif

};

这个就发现是一个proto结构了,要想知道在哪里赋值,就得回到:

Net/core/sock.c

struct sock *sk_alloc(struct net *net, int family, gfp_t priority,

                         struct proto *prot)

{

         struct sock *sk;

 

         sk = sk_prot_alloc(prot, priority | __GFP_ZERO, family);

         if (sk) {

                   sk->sk_family = family;

                   /*

                    * See comment in struct sock definition to understand

                    * why we need sk_prot_creator -acme

                    */

                   sk->sk_prot = sk->sk_prot_creator = prot;

                   sock_lock_init(sk);

                   sock_net_set(sk, get_net(net));

         }

 

         return sk;

}

而它又被static int inet_create(struct net *net, struct socket *sock, int protocol)[net/ipv4Af_inet.c]这个函数调用:

static int inet_create(struct net *net, struct socket *sock, int protocol)

{

         struct sock *sk;

         struct list_head *p;

         struct inet_protosw *answer;

         struct inet_sock *inet;

         struct proto *answer_prot;

…….

lookup_protocol:

         err = -ESOCKTNOSUPPORT;

         rcu_read_lock();

         list_for_each_rcu(p, &inetsw[sock->type]) {

                   answer = list_entry(p, struct inet_protosw, list);

 

…….

 

         sock->ops = answer->ops;

         answer_prot = answer->prot;

         answer_no_check = answer->no_check;

         answer_flags = answer->flags;

         rcu_read_unlock();

 

         BUG_TRAP(answer_prot->slab != NULL);

 

         err = -ENOBUFS;

         sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot);

         if (sk == NULL)

                   goto out;

……

}

看到这里,大家是不是觉得很熟悉了,在“TCP/IP驱动十一   ——内核2.6.26inet_cskinet_sk两个函数推导”中有详细的说明,这里就不再重复了。

内核中的函数指针太灵活,但读起代码来,可就真是不好受了。

  评论这张
 
阅读(633)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017