热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MPTCP源码分析(二)建立子路径

简述MPTCP在进行三次握手之后,客户端和服务端会进行地址信息的交换,让对方知道彼此未用的地址信息。当客户端知道服务端的地址后就可以建立其他子路径。三次握手和建立子路径的过程如图1
简述
     MPTCP在进行三次握手之后,客户端和服务端会进行地址信息的交换,让对方知道彼此未用的地址信息。
当客户端知道服务端的地址后就可以建立其他子路径。三次握手和建立子路径的过程如图1:
技术分享
                                       图1
关于Token、随机数R、以及HMAC(Hash-based Message Authentication Code)的详细解释可以阅读参考文献[1]。
 
MPTCP的内核实现:
     这里我们主要关注建立子路径过程中,master sock对slave sock的影响。当客户端发送第一个SYN准备建立子路径的时候就会调用
mptcp_init4_subsockets来创建一个新的socket和相应的sock。
 
技术分享技术分享
 "net/mptcp/mptcp_ipv4.c" line 328 of 488
328 int mptcp_init4_subsockets(struct sock *meta_sk, const struct mptcp_loc4 *loc,
329                struct mptcp_rem4 *rem)
330 {
331     struct tcp_sock *tp;
332     struct sock *sk;
333     struct sockaddr_in loc_in, rem_in;
334     struct socket sock;
335     int ulid_size = 0, ret;
336
337     /** First, create and prepare the new socket */
338
339     sock.type = meta_sk->sk_socket->type;
340     sock.state = SS_UNCONNECTED;
341     sock.wq = meta_sk->sk_socket->wq;
342     sock.file = meta_sk->sk_socket->file;
343     sock.ops = NULL;
344
345     ret = inet_create(sock_net(meta_sk), &sock, IPPROTO_TCP, 1);
346     if (unlikely(ret <0)) {
347         mptcp_debug("%s inet_create failed ret: %d\n", __func__, ret);
348         return ret;
349     }
350
351     sk = sock.sk;
352     tp = tcp_sk(sk);
View Code
第345行的函数inet_create创建了子路径的socket和sock。
 
354     /* All subsockets need the MPTCP-lock-class */
355     lockdep_set_class_and_name(&(sk)->sk_lock.slock, &meta_slock_key, "slock-AF_INET-MPTCP");
356     lockdep_init_map(&(sk)->sk_lock.dep_map, "sk_lock-AF_INET-MPTCP", &meta_key, 0);
357
358     if (mptcp_add_sock(meta_sk, sk, loc->loc4_id, rem->rem4_id, GFP_KERNEL))
359         goto error;
360
361     tp->mptcp->slave_sk = 1;
362     tp->mptcp->low_prio = loc->low_prio;
363 
364     /* Initializing the timer for an MPTCP subflow */
365     setup_timer(&tp->mptcp->mptcp_ack_timer, mptcp_ack_handler, (unsigned long)sk);
第358行的mptcp_add_sock将master sock 和 子路径的sock联系起来。第361行表面此sock为 slave subsock。
第362行设置此子路径是否为备用路径。只有现在路径都不可用的情况下,才会通过备用子路径发送数据。
第365行设置的定时器用于重发建立子路径的最后一个ACK,这样做是为了保证上图中的HMAC-A可以送达。
 
技术分享技术分享
368            
369     ulid_size = sizeof(struct sockaddr_in);
370     loc_in.sin_family = AF_INET;
371     rem_in.sin_family = AF_INET;
372     loc_in.sin_port = 0;
373     if (rem->port)
374         rem_in.sin_port = rem->port;
375     else
376         rem_in.sin_port = inet_sk(meta_sk)->inet_dport;
377     loc_in.sin_addr = loc->addr;
378     rem_in.sin_addr = rem->addr;
379        
380     ret = sock.ops->bind(&sock, (struct sockaddr *)&loc_in, ulid_size);
381     if (ret <0) {
382         mptcp_debug("%s: MPTCP subsocket bind() failed, error %d\n",
383                 __func__, ret);
384         goto error;
385     }
386
387     mptcp_debug("%s: token %#x pi %d src_addr:%pI4:%d dst_addr:%pI4:%d\n",
388             __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token,
389             tp->mptcp->path_index, &loc_in.sin_addr,
390             ntohs(loc_in.sin_port), &rem_in.sin_addr,
391             ntohs(rem_in.sin_port));
392
393     if (tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v4)
394         tcp_sk(meta_sk)->mpcb->pm_ops->init_subsocket_v4(sk, rem->addr);
395
396     ret = sock.ops->connect(&sock, (struct sockaddr *)&rem_in,
397                 ulid_size, O_NONBLOCK);
398     if (ret <0 && ret != -EINPROGRESS) {
399         mptcp_debug("%s: MPTCP subsocket connect() failed, error %d\n",
400                 __func__, ret);
401         goto error;
402     }
View Code
第380行是将子路径的socket的与地址绑定。第396行此套接字将会调用tcp_v4_connect进行连接操作。
 
403
404     sk_set_socket(sk, meta_sk->sk_socket);
405     sk->sk_wq = meta_sk->sk_wq;
406
407     return 0;
408
409 error:
410     /* May happen if mptcp_add_sock fails first */
411     if (!mptcp(tp)) {
412         tcp_close(sk, 0);
413     } else {
414         local_bh_disable();
415         mptcp_sub_force_close(sk);
416         local_bh_enable();
417     }
418     return ret;
419 }
第404和405行将子路径的sk和master的socket建立联系,因为对于应用程序来说只有
master的socket是可见,而slave subsock的socket是不可见。
 
下面的情景是服务端收到上图1中ACK/MP_JOIN(HMAC-A)包,这时状态将由SYN_RECV变为ESTABLISHED。函数的调用
关系如下:
tcp_v4_rcv
          =》tcp_v4_do_rcv
               =》mptcp_v4_do_rcv
                    =》tcp_v4_hnd_req
                         =》tcp_check_req
                              =》mptcp_check_req_child
                                    =》mptcp_add_sock
 
在函数tcp_check_req中将会建立新的sock。主要代码如下:
"net/ipv4/tcp_minisocks.c" line 766 of 872
760     /* OK, ACK is valid, create big socket and
761      * feed this segment to it. It will repeat all
762      * the tests. THIS SEGMENT MUST MOVE SOCKET TO
763      * ESTABLISHED STATE. If it will be dropped after
764      * socket is created, wait for troubles.
765      */
766 #ifdef CONFIG_MPTCP
767     if (mptcp(tcp_sk(sk)))
768         /* MPTCP: We call the mptcp-specific syn_recv_sock */
769         child = tcp_sk(sk)->mpcb->syn_recv_sock(sk, skb, req, NULL);
770     else
771 #endif
772         child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb,
773                 req, NULL);
774
775     if (child == NULL)
776         goto listen_overflow;
第769行将会调用mptcp_syn_recv_sock和tcp_v4_syn_recv_sock和tcp_create_openreq_child创建新的sock并进行初始化。
函数mptcp_check_req_child和mptcp_add_sock会将此sock和master sock建立联系,并且设置此sock的属性slave_sk为1. 
 
结论:
1. MPTCP利用Token、随机数R、以及HMAC(Hash-based Message Authentication Code)这些信息的交换保证构建子路径正确。
2.sub sock是在meta sock基础上建立,只有meta对于应用层是可见,其余sub sock并不可见。
 
 
参考文献:
[1] https://tools.ietf.org/html/rfc6824#section-3.2
 
问题:
1.第394行函数作用未知?
 
2.函数mptcp_v4_add_lsrr的功能?

MPTCP 源码分析(二) 建立子路径


推荐阅读
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了一种解析GRE报文长度的方法,通过分析GRE报文头中的标志位来计算报文长度。具体实现步骤包括获取GRE报文头指针、提取标志位、计算报文长度等。该方法可以帮助用户准确地获取GRE报文的长度信息。 ... [详细]
  • 本文内容为asp.net微信公众平台开发的目录汇总,包括数据库设计、多层架构框架搭建和入口实现、微信消息封装及反射赋值、关注事件、用户记录、回复文本消息、图文消息、服务搭建(接入)、自定义菜单等。同时提供了示例代码和相关的后台管理功能。内容涵盖了多个方面,适合综合运用。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • 在project.properties添加#Projecttarget.targetandroid-19android.library.reference.1..Sliding ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • PDF内容编辑的两种小方法,你知道怎么操作吗?
    本文介绍了两种PDF内容编辑的方法:迅捷PDF编辑器和Adobe Acrobat DC。使用迅捷PDF编辑器,用户可以通过选择需要更改的文字内容并设置字体形式、大小和颜色来编辑PDF文件。而使用Adobe Acrobat DC,则可以通过在软件中点击编辑来编辑PDF文件。PDF文件的编辑可以帮助办公人员进行文件内容的修改和定制。 ... [详细]
author-avatar
窝大华_221
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有