MPTCP 源码分析(三) 子路径选择

简述:

支持MPTCP的链路中存在多条子路径,因此在发送数据的时候需要选择最优路径来进行操作。

MPTCP利用内核通知链对MPTCP中各子路径进行增加路径、删除路径、修改路径优先级的操作。MPTCP根据

相应的策略进行路径选择。

路径选择的代码实现

路径选择的关键在于从多个子路径中选择其中一个进行数据的发送。此过程通过下面的函数实现:

"net/mptcp/mptcp_sched.c" line 114 of 496
114 static struct sock *get_available_subflow(struct sock *meta_sk,
115                       struct sk_buff *skb,
116                       bool zero_wnd_test)
117 {
118     struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb;   //MPTCP内核实现的三个组成部分之一:Multi-path control bock(mpcb)
119     struct sock *sk, *bestsk = NULL, *lowpriosk = NULL, *backupsk = NULL;
120     u32 min_time_to_peer = 0xffffffff, lowprio_min_time_to_peer = 0xffffffff;
121     int cnt_backups = 0;
122
123     /* if there is only one subflow, bypass the scheduling function */
124     if (mpcb->cnt_subflows == 1) {
125         bestsk = (struct sock *)mpcb->connection_list;
126         if (!mptcp_is_available(bestsk, skb, zero_wnd_test))
127             bestsk = NULL;
128         return bestsk;
129     }
130
131     /* Answer data_fin on same subflow!!! */
132     if (meta_sk->sk_shutdown & RCV_SHUTDOWN &&
133         skb && mptcp_is_data_fin(skb)) {
134         mptcp_for_each_sk(mpcb, sk) {
135             if (tcp_sk(sk)->mptcp->path_index == mpcb->dfin_path_index &&
136                 mptcp_is_available(sk, skb, zero_wnd_test))
137                 return sk;
138         }
139     }

第124行的代码是处理只有一个子路径的特殊情况。第132行是对关闭操作进行了处理,在

收包过程中对接收关闭包的子路径进行记录,然后回包的时候使用相同的子路径。

"net/mptcp/mptcp_input.c" line 876 of 2293
875     /* Record it, because we want to send our data_fin on the same path */
876     if (tp->mptcp->map_data_fin) {
877         mpcb->dfin_path_index = tp->mptcp->path_index;
878         mpcb->dfin_combined = !!(sk->sk_shutdown & RCV_SHUTDOWN);
879     }

第876行是对子路径关闭的处理,关于data_fin可以参考https://tools.ietf.org/html/rfc6824#section-3.3.3。

下面的代码遍历mpcb下管理的sk,选择最合适的sk。

"net/mptcp/mptcp_sched.c" line 142 of 496
141     /* First, find the best subflow */
142     mptcp_for_each_sk(mpcb, sk) {
143         struct tcp_sock *tp = tcp_sk(sk);
144
145         if (tp->mptcp->rcv_low_prio || tp->mptcp->low_prio)
146             cnt_backups++;
147
148         if ((tp->mptcp->rcv_low_prio || tp->mptcp->low_prio) &&
149             tp->srtt < lowprio_min_time_to_peer) {
150             if (!mptcp_is_available(sk, skb, zero_wnd_test))
151                 continue;
152
153             if (mptcp_dont_reinject_skb(tp, skb)) {
154                 backupsk = sk;
155                 continue;
156             }
157
158             lowprio_min_time_to_peer = tp->srtt;
159             lowpriosk = sk;
160         } else if (!(tp->mptcp->rcv_low_prio || tp->mptcp->low_prio) &&
161                tp->srtt < min_time_to_peer) {
162             if (!mptcp_is_available(sk, skb, zero_wnd_test))
163                 continue;
164
165             if (mptcp_dont_reinject_skb(tp, skb)) {
166                 backupsk = sk;
167                 continue;
168             }
169
170             min_time_to_peer = tp->srtt;
171             bestsk = sk;
172         }
173     }

从上面的代码可以看出,选择sk的依据有4条:

1. “tp->mptcp->rcv_low_prio ” which stands for priority level in the remote machine.

2.  "tp->mptcp->low_prio" which stands for priority level in the local machine.

3.   whether the skb has already been enqueued into this subsocket

4.   "tp->srtt" stands for smoothed round trip time.

"net/mptcp/mptcp_sched.c" line 175 of 496
175     if (mpcb->cnt_established == cnt_backups && lowpriosk) {
176         sk = lowpriosk;
177     } else if (bestsk) {
178         sk = bestsk;
179     } else if (backupsk) {
180         /* It has been sent on all subflows once - let‘s give it a
181          * chance again by restarting its pathmask.
182          */
183         if (skb)
184             TCP_SKB_CB(skb)->path_mask = 0;
185         sk = backupsk;
186     }
187
188     return sk;
189 }

第176行的情况说明所有的子路径都处于backup状态。而第178行则是存在bestsk。

总结:

1.控制路径选择的因素有下面四个:

此路径在对端机器的优先级

此路径在本地的优先级

此次发送的skb是否已经使用此路径发送过,不能在同一路径重复发送。

tp->srtt

2.调整 low_prio 和 rcv_low_prio 可以通过下面命令:

ip link set dev eth0 multipath backup

当通讯双方的一端被设置为backup后,可以通过MP_PRIO

通知对端。具体内容可以参考:https://tools.ietf.org/html/rfc6824#section-3.3.8

3.srtt的调整通过函数 tcp_ack_update_rtt 实现。

时间: 2024-08-30 17:36:14

MPTCP 源码分析(三) 子路径选择的相关文章

MPTCP 源码分析(五) 接收端窗口值

简述: 在TCP协议中影响数据发送的三个因素分别为:发送端窗口值.接收端窗口值和拥塞窗口值. 本文主要分析MPTCP中各个子路径对接收端窗口值rcv_wnd的处理. 接收端窗口值的初始化 根据<MPTCP 源码分析(二) 建立子路径>中描述服务端在发送完SYN/ACK并接收到ACK的时候建立新的sock. 在内核实现中,针对连接请求分为两个步骤处理: SYN队列处理:当服务端收到SYN的时候,此连接请求request_sock将被存放于listening socket的SYN队列,服务端发送S

Nouveau源码分析(三):NVIDIA设备初始化之nouveau_drm_probe

Nouveau源码分析(三) 向DRM注册了Nouveau驱动之后,内核中的PCI模块就会扫描所有没有对应驱动的设备,然后和nouveau_drm_pci_table对照. 对于匹配的设备,PCI模块就调用对应的probe函数,也就是nouveau_drm_probe. // /drivers/gpu/drm/nouveau/nouveau_drm.c 281 static int nouveau_drm_probe(struct pci_dev *pdev, 282 const struct

[Android]Fragment源码分析(三) 事务

Fragment管理中,不得不谈到的就是它的事务管理,它的事务管理写的非常的出彩.我们先引入一个简单常用的Fragment事务管理代码片段: FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction(); ft.add(R.id.fragmentContainer, fragment, "tag"); ft.addToBackStack("<span style="fo

baksmali和smali源码分析(三)

baksmali 的源码分析 在baksmali进行源码分析之前,需要读者掌握一条主线,因为本身笔者只是由于项目需要用到这套源码,在工作之余的时间里面来进行学习也没有时间和精力熟读源码的每个文件每个方法,但是依据这条主线,至少能够猜出并且猜对baksmali里面的源码的文件大概的作用是什么,这样在修改问题和移植的时候才能做到游刃有余. 这条主线是,baksmali其实只是利用了dexlib2提供的接口,将dex文件读入到一块内存中,这块内存或者说数据结构开辟的大小是跟输入的dex文件相关的,而这

横屏小游戏--萝莉快跑源码分析三

主角出场: 初始化主角 hero = new GameObjHero(); hero->setScale(0.5); hero->setPosition(ccp(100,160)); hero->setVisible(false); addChild(hero,1); 进入GameObjHero类ccp文件 创建主角及动作 this->setContentSize(CCSizeMake(85,90)); //接收触摸事件 CCDirector* pDirector = CCDire

哇!板球 源码分析三

守门员出场 守门员出场,每个守门员是从屏幕的右侧中间的位置随机方向向左侧移动 FielderSprite* fielderSprite1 = FielderSprite::create("pic/fielder.png"); //守门员精灵初始位置为右侧中间位置 fielderSprite1->setPosition(ccp(GOALKEEPER_X, GOALKEEPER_Y)); fielderSprite1->setAnchorPoint(ccp(0.5, 0.5))

Android 中View的绘制机制源码分析 三

到目前为止,measure过程已经讲解完了,今天开始我们就来学习layout过程,不过在学习layout过程之前,大家有没有发现我换了编辑器,哈哈,终于下定决心从Html编辑器切换为markdown编辑器,这里之所以使用"下定决心"这个词,是因为毕竟Html编辑器使用好几年了,很多习惯都已经养成了,要改变多年的习惯确实不易,相信这也是还有很多人坚持使用Html编辑器的原因.这也反应了一个现象,当人对某一事物非常熟悉时,一旦出现了新的事物想取代老的事物时,人们都有一种抵触的情绪,做技术的

Android触摸屏事件派发机制详解与源码分析三(Activity篇)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 该篇承接上一篇<Android触摸屏事件派发机制详解与源码分析二(ViewGroup篇)>,阅读本篇之前建议先阅读. 1 背景 还记得前面两篇从Android的基础最小元素控件(View)到ViewGroup控件的触摸屏事件分发机制分析吗?你可能看完会有疑惑,View的事件是ViewGro

Django搭建及源码分析(三)---+uWSGI+nginx

每个框架或者应用都是为了解决某些问题才出现旦生的,没有一个事物是可以解决所有问题的.如果觉得某个框架或者应用使用很不方便,那么很有可能就是你没有将其使用到正确的地方,没有按开发者的设计初衷来使用它,当你将一个框架的优势使用到极致时一定是非常舒服和顺手的一件事.但同时也有可能衍生另一个问题,这个框架只解决了你的问题一,没有解决问题二.三等等,因此,就出现了多个框架/应用相结合的情况.比如Django + uWSGI + nginx. 本人初学python,找了一些实例进行了一些操作,以下纯属目前的