对于多线程VPP,为主线程和worker线程分别分配timer_wheel,处理函数为tcp_expired_timers_dispatch。

static clib_error_t *
tcp_main_enable (vlib_main_t * vm)
{vlib_thread_main_t *vtm = vlib_get_thread_main ();num_threads = 1 /* main thread */  + vtm->n_threads;vec_validate (tm->wrk_ctx, num_threads - 1);n_workers = num_threads == 1 ? 1 : vtm->n_threads;for (thread = 0; thread < num_threads; thread++){ wrk = &tm->wrk_ctx[thread];tcp_timer_initialize_wheel (&wrk->timer_wheel,tcp_expired_timers_dispatch,vlib_time_now (vm));}

超时处理函数中,首先根据线程号获得对应的tcp_worker_ctx_t上下文结构,并且获取当前待处理的定时器数量。

static void
tcp_expired_timers_dispatch (u32 * expired_timers)
{u32 thread_index = vlib_get_thread_index (), n_left, max_per_loop;u32 connection_index, timer_id, n_expired, max_loops;tcp_worker_ctx_t *wrk;tcp_connection_t *tc;int i;wrk = tcp_get_worker (thread_index);n_expired = vec_len (expired_timers);tcp_worker_stats_inc (wrk, timer_expirations, n_expired);n_left = clib_fifo_elts (wrk->pending_timers);

遍历超时的定时器,参数expired_timers的每个元素,最高的4位保存了定时器的ID,后28位保存了TCP连接的索引值。如果定时器ID为重传的SYN报文定时器,由函数tcp_half_open_connection_get获取TCP连接结构(实际上是根据连接索引,在线程号为0的TCP worker结构中获取TCP连接);否则,由函数tcp_connection_get根据当前的线程号和连接索引获取TCP连接结构。

此处将TCP连接的定时器处理句柄设置为无效,设置挂起定时器ID。

  /** Invalidate all timer handles before dispatching. This avoids dangling* index references to timer wheel pool entries that have been freed.*/for (i = 0; i < n_expired; i++){connection_index = expired_timers[i] & 0x0FFFFFFF;timer_id = expired_timers[i] >> 28;if (timer_id != TCP_TIMER_RETRANSMIT_SYN)tc = tcp_connection_get (connection_index, thread_index);elsetc = tcp_half_open_connection_get (connection_index);TCP_EVT (TCP_EVT_TIMER_POP, connection_index, timer_id);tc->timers[timer_id] = TCP_TIMER_HANDLE_INVALID;tc->pending_timers |= (1 << timer_id);}

将到期的定时器添加到worker结构中的挂起定时器。之后,计算每次循环最多处理的定时器数量。首先确定最大的循环次数max_loops,即最大时长0.5 * TCP_TIMER_TICK,乘以每一秒的循环数量,即最大的循环次数。其次,所有待处理的定时器(n_left+n_expired)除以max_loops即为每次循环的最大数量。最后,最大值不能大于每次最多可处理的最大向量长度VLIB_FRAME_SIZE(256),

  clib_fifo_add (wrk->pending_timers, expired_timers, n_expired);max_loops =clib_max ((u32) 0.5 * TCP_TIMER_TICK * wrk->vm->loops_per_second, 1);max_per_loop = clib_max ((n_left + n_expired) / max_loops, 10);max_per_loop = clib_min (max_per_loop, VLIB_FRAME_SIZE);wrk->max_timers_per_loop = clib_max (n_left ? wrk->max_timers_per_loop : 0,max_per_loop);if (thread_index == 0)session_queue_run_on_main_thread (wrk->vm);

挂起定时器处理函数tcp_dispatch_pending_timers如下,如果TCP线程结构中没有挂起的定时器,结束处理。

static void
tcp_dispatch_pending_timers (tcp_worker_ctx_t * wrk)
{u32 n_timers, connection_index, timer_id, thread_index, timer_handle;tcp_connection_t *tc;int i;if (!(n_timers = clib_fifo_elts (wrk->pending_timers)))return;

每次遍历处理的定时器数量不能超过以上计算得到到max_timers_per_loop的值,如果挂起定时器已经被重置,即TCP连接的pending_timers已经不再置位,不进行处理。

  thread_index = wrk->vm->thread_index;for (i = 0; i < clib_min (n_timers, wrk->max_timers_per_loop); i++){clib_fifo_sub1 (wrk->pending_timers, timer_handle);connection_index = timer_handle & 0x0FFFFFFF;timer_id = timer_handle >> 28;if (PREDICT_TRUE (timer_id != TCP_TIMER_RETRANSMIT_SYN))tc = tcp_connection_get (connection_index, thread_index);elsetc = tcp_half_open_connection_get (connection_index);if (PREDICT_FALSE (!tc))continue;/* Skip if the timer is not pending. Probably it was reset while* waiting for dispatch */if (PREDICT_FALSE (!(tc->pending_timers & (1 << timer_id))))continue;tc->pending_timers &= ~(1 << timer_id);/* Skip timer if it was rearmed while pending dispatch */if (PREDICT_FALSE (tc->timers[timer_id] != TCP_TIMER_HANDLE_INVALID))continue;

否则,调用定时器ID注册的超时处理函数,处理超时的TCP连接。

      (*timer_expiration_handlers[timer_id]) (tc);}if (thread_index == 0 && clib_fifo_elts (wrk->pending_timers))session_queue_run_on_main_thread (wrk->vm);
}

TCP连接定义了如下的四种定时器。

#define foreach_tcp_timer               \_(RETRANSMIT, "RETRANSMIT")           \_(PERSIST, "PERSIST")                 \_(WAITCLOSE, "WAIT CLOSE")            \_(RETRANSMIT_SYN, "RETRANSMIT SYN")   \typedef enum _tcp_timers
{
#define _(sym, str) TCP_TIMER_##sym,foreach_tcp_timer
#undef _TCP_N_TIMERS
} __clib_packed tcp_timers_e;

以上四种定时器对应如下四个超时处理函数。

static timer_expiration_handler *timer_expiration_handlers[TCP_N_TIMERS] =
{tcp_timer_retransmit_handler,tcp_timer_persist_handler,tcp_timer_waitclose_handler,tcp_timer_retransmit_syn_handler,
};

VPP TCP定时器相关推荐

  1. s6-9 TCP 定时器

    TCP 定时器管理  重传定时器(retransmission timer,Positive ackn. with retransmit) 最重要的定时器 TCP 定时器管理  持续定时器(per ...

  2. tcp协议栈实现,tcp定时器与滑动窗口实现

    要实现用户态协议栈,必须要搞懂TCP,TCP 11个状态.滑动窗口.拥塞控制.定时器等等. 要使用用户态协议栈,内核提供的epoll就不起作用了,我们需要自己实现用户态的epoll.epoll内部涉及 ...

  3. TCP的定时器系列 — 超时重传定时器(有图有代码有真相!!!)

    转载 主要内容:TCP定时器概述,超时重传定时器.ER延迟定时器.PTO定时器的实现. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd Q:一条TCP连接 ...

  4. TCP协议(标志位URG、PSH,定时器,连接的建立和断开)

    目录 ●TCP段格式 ●TCP定时器 ●TCP三次握手和四次挥手 ●TCP段格式 6位标志位有紧急标志URG.推送标志PSH.确认标志ACK.复位标志RST.链接同步标志SYN以及结束标志FIN. ○ ...

  5. Linux tcp xmit 定时器

    在tcp socket初始化的时候,会初始化设置三个定时器,isck_retransmit_timer.isck_delack_timer.sk_timer,本文主要描述下这三种tcp定时器. voi ...

  6. TCP/IP详解--第十九章

     第19章 TCP的交互数据流 19.1    引言   前一章我们介绍了 TCP连接的建立与释放,现在来介绍使用 TCP进行数据传输的有关问 题. 一些有关 TCP通信量的研究如[Cacereset ...

  7. LWIP之TCP协议

    IP协议提供了在各个主机之间传送数据报的功能,但是数据的最终目的地是主机上的特定应用程序.传输层协议就承担了这样的责任,典型的传输层协议有UDP和TCP两种. UDP只为应用程序提供了一种无连接的.不 ...

  8. Socket 系统调用深入研究(TCP协议的整个通信过程)

    说明 本文主要参考的原文:Know your TCP system call sequences socket api可以参考我的博客:socket API 介绍 TCP DEMO:tcp demo ...

  9. 了解 TCP 系统调用序列

    从内核到应用程序级别的函数调用序列 TCP/IP 编程接口提供各种系统调用,以帮助您有效地使用该协议.TCP 堆栈代码数量繁多,深入到内核级别的完整调用序列可以帮助您了解 TCP 堆栈.在本文中,将回 ...

  10. TCP/IP协议栈之LwIP(六)---网络传输管理之TCP协议

    文章目录 一.TCP协议简介 1.1 正面确认与超时重传 1.2 连接管理与保活机制 1.3 滑动窗口与缓冲机制 1.4 流量控制与拥塞控制 1.5 提高网络利用率的其他机制 二.TCP协议实现 2. ...

最新文章

  1. 服务器安装系统时无法创建新的分区,重装系统出现“我们无法创建新的分区,也找不到现有的分区”...
  2. MySQL加索引避免锁表:避开事务 lock_wait_timeout 副本
  3. WINIO64位模拟键鼠操作
  4. C语言 - 快速排序算法
  5. P2408 不同子串个数
  6. 创建一个带参数的formgoup_gin框架如何获取带文件的formData请求?
  7. SDN——转控分离、CPU保护机制——COPP技术案列详解及配置命令、
  8. AD原理图编译ERROR:GND contains Output Pin and Power Pin objects
  9. MVC中如何实现本地化的解决方案
  10. linux监听apache代码,linux系统使用python监控apache服务器进程脚本分享
  11. HTML 上标题栏把右标题栏遮挡,如何编辑组件的样式(编辑样式)?
  12. vmware workstation14密钥记录
  13. 如何查看Websphere(was)上的jdk版本
  14. 线性表的链式存储结构及操作的实现
  15. 徐思201771010132《面向对象程序设计(java)》第二周学习总结
  16. 忍无可忍?英特尔执行副总裁撰文《高通的诡辩被戳穿了》指责高通
  17. 百度百科创建对于文案和措辞有什么要求?
  18. jsapi 支付缺少appid ¬ify_url
  19. 安装docker-ce报错
  20. firefox 下载文件时处理此文件的方法

热门文章

  1. 完整版身份证前6位判断归属地
  2. 读书笔记之《Redis开发与运维》—— 一
  3. IDEA使用教程汇总
  4. Python(PyCharm)的下载安装汉化(2022)
  5. 收入时间序列——之预测总结篇
  6. Axure8授权激活码
  7. Axure 8.1.0.3382 激活码(转)
  8. 【目标跟踪】|MOSSE原理及对应代码解释 matlab C
  9. 华为交换机 tagged 与 untagged 的关系、H5C 开web管理、telnet管理
  10. workbench动力学周炬_ANSYS WORKBENCH有限元分析实例详解(动力学)