当前位置: 首页 > news >正文

tcp_v4_connect函数的解析

源码:

int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{// 解析输入的地址结构struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;// 获取 TCP 协议栈的全局 death_row 对象struct inet_timewait_death_row *tcp_death_row;// 获取输入的套接字的 inet_sock 和 tcp_sock 结构struct inet_sock *inet = inet_sk(sk);struct tcp_sock *tp = tcp_sk(sk);// 获取输入套接字的 IP 选项struct ip_options_rcu *inet_opt;// 获取套接字的网络命名空间struct net *net = sock_net(sk);__be16 orig_sport, orig_dport;__be32 daddr, nexthop;struct flowi4 *fl4;struct rtable *rt;int err;// 检查地址的有效性if (addr_len < sizeof(struct sockaddr_in))return -EINVAL;if (usin->sin_family != AF_INET)return -EAFNOSUPPORT;// 获取目标地址和下一跳地址nexthop = daddr = usin->sin_addr.s_addr;inet_opt = rcu_dereference_protected(inet->inet_opt,lockdep_sock_is_held(sk));if (inet_opt && inet_opt->opt.srr) {if (!daddr)return -EINVAL;nexthop = inet_opt->opt.faddr;}// 保存原始的源端口号和目的端口号orig_sport = inet->inet_sport;orig_dport = usin->sin_port;// 获取并设置用于连接的路由fl4 = &inet->cork.fl.u.ip4;rt = ip_route_connect(fl4, nexthop, inet->inet_saddr,sk->sk_bound_dev_if, IPPROTO_TCP, orig_sport,orig_dport, sk);// 检查路由连接的结果if (IS_ERR(rt)) {err = PTR_ERR(rt);if (err == -ENETUNREACH)IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES);return err;}// 检查路由是否指向多播或广播地址if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {ip_rt_put(rt);return -ENETUNREACH;}// 更新目标地址为路由的目标地址if (!inet_opt || !inet_opt->opt.srr)daddr = fl4->daddr;// 获取 TCP 协议栈的 death_row 对象tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row;// 更新源 IP 地址if (!inet->inet_saddr) {err = inet_bhash2_update_saddr(sk,  &fl4->saddr, AF_INET);if (err) {ip_rt_put(rt);return err;}} else {sk_rcv_saddr_set(sk, inet->inet_saddr);}// 重置 TCP 相关的状态if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr) {tp->rx_opt.ts_recent    = 0;tp->rx_opt.ts_recent_stamp = 0;if (likely(!tp->repair))WRITE_ONCE(tp->write_seq, 0);}// 设置目的端口号和目标地址inet->inet_dport = usin->sin_port;sk_daddr_set(sk, daddr);// 设置扩展头长度inet_csk(sk)->icsk_ext_hdr_len = 0;if (inet_opt)inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen;// 设置最大报文段长度tp->rx_opt.mss_clamp = TCP_MSS_DEFAULT;// 设置套接字的状态为 SYN-SENT,并将其插入哈希表tcp_set_state(sk, TCP_SYN_SENT);err = inet_hash_connect(tcp_death_row, sk);if (err)goto failure;// 设置套接字的转发散列值sk_set_txhash(sk);// 设置新的端口并更新路由表rt = ip_route_newports(fl4, rt, orig_sport, orig_dport,inet->inet_sport, inet->inet_dport, sk);// 检查路由表更新的结果if (IS_ERR(rt)) {err = PTR_ERR(rt);rt = NULL;goto failure;}// 设置套接字的 GSO 类型并设置能力sk->sk_gso_type = SKB_GSO_TCPV4;sk_setup_caps(sk, &rt->dst);rt = NULL;// 设置初始化的 TCP 序列号和时间戳if (likely(!tp->repair)) {if (!tp->write_seq)WRITE_ONCE(tp->write_seq,secure_tcp_seq(inet->inet_saddr,inet->inet_daddr,inet->inet_sport,usin->sin_port));tp->tsoffset = secure_tcp_ts_off(net, inet->inet_saddr,inet->inet_daddr);}// 为套接字分配一个随机的标识符inet->inet_id = get_random_u16();// 如果启用了 TCP 快速打开,进行相应处理if (tcp_fastopen_defer_connect(sk, &err))return err;if (err)goto failure;// 发送 TCP 连接请求err = tcp_connect(sk);if (err)goto failure;return 0;failure:// 失败时处理的操作tcp_set_state(sk, TCP_CLOSE);inet_bhash2_reset_saddr(sk);ip_rt_put(rt);sk->sk_route_caps = 0;inet->inet_dport = 0;return err;
}EXPORT_SYMBOL(tcp_v4_connect);

tcp_v4_connect() 函数是在 Linux 内核中的 net/ipv4/tcp_ipv4.c 文件中定义的。它用于在 IPv4 网络上建立 TCP 连接。
该函数接受一个 TCP 套接字(sock)、目标地址(uaddr)和地址长度(addr_len)作为参数。
函数的主要功能包括解析地址、配置路由、设置套接字状态、分配序列号、设置时间戳、发送连接请求等步骤,最终返回连接的结果。

问题1:TCP 协议栈的 death_row 对象是什么?

TCP 协议栈的 death_row 对象是一个全局的数据结构,用于管理网络连接的生命周期。它的主要作用是处理关闭的连接,并在适当的时间回收连接资源。

在 TCP 协议中,当一条连接结束时(如连接被关闭或出现错误),该连接不会立即被释放,而是被放置在 death_row 中。death_row 在一段时间后会检查这些连接,并判断是否可以安全地回收它们。这段时间通常称为 “TIME_WAIT” 状态的时间。

在 TIME_WAIT 状态下,TCP 协议栈会保留连接的信息,以便处理网络中可能延迟到达的重复数据包。这样可以确保在网络中的所有数据包都被正确处理,从而保证可靠的连接关闭。

death_row 对象负责管理 TIME_WAIT 状态的连接。它维护了一个定时器,定期检查连接是否可以被回收。当连接经过一定时间后,death_row 将安全地释放这些连接占用的资源,以便可以重用这些资源来建立新的连接。

总的来说**,TCP 协议栈的 death_row 对象是用于管理关闭的 TCP 连接,并实现连接的安全释放和资源回收。**

问题2:struct flowi4在哪定义的?
struct flowi4 结构体是在 Linux 内核的头文件 include/net/flow.h 中定义的。该头文件是网络子系统中的一个重要头文件,包含了与网络流量处理相关的结构体和函数的声明。

下面是 struct flowi4 结构体的定义:

struct flowi4 {__aligned_u32    daddr;             /* Destination address */__aligned_u32    saddr;             /* Source address */__aligned_u16    flowi4_oif;        /* Output interface index */__aligned_u8     flowi4_tos;        /* TOS / traffic class */
#define       FLOWI4_TOS_MASK        0x1E
#define       FLOWI4_TOS_SHIFT       1__aligned_u8     flowi4_scope;      /* Scope */
#define       FLOWI4_SCOPE_MASK      0x0F
#define       FLOWI4_SCOPE_SHIFT     0__aligned_u32    flowi4_proto;      /* Protocol */__aligned_u8     flowi4_flags;      /* Flags */__aligned_u8     flowi4_secid;      /* SELinux security ID */
};

struct flowi4 结构体用于表示 IPv4 流量的路由查找信息。它的成员变量包括目标地址(daddr)、源地址(saddr)、输出接口索引(flowi4_oif)、TOS/流量类别(flowi4_tos)、作用域(flowi4_scope)、协议(flowi4_proto)、标志(flowi4_flags)和 SELinux 安全标识符(flowi4_secid)等。

该结构体提供了描述和标识 IPv4 流量路由的必要信息,用于在网络栈中进行路由查找和转发决策。

问题3:sk_daddr_set是什么?inet_csk是什么?在哪里定义的?

sk_daddr_set() 是 Linux 内核中的一个函数,用于设置套接字(socket)的目标地址(destination address)。它在文件 net/core/sock.c 中定义。

sk_daddr_set() 函数的定义如下:

static inline void sk_daddr_set(struct sock *sk, __be32 daddr)
{sk->__sk_common.skc_daddr = daddr;
}

sk_daddr_set() 函数通过修改套接字的 skc_daddr 成员变量来设置目标地址。这个成员变量保存了套接字关联的目标 IP 地址。

inet_csk 是一个宏,用于获取 TCP 套接字(struct sock)中 inet 控制块(struct inet_connection_sock)的指针。它定义在 include/net/inet_connection_sock.h 中。

下面是 inet_csk 宏的定义:

#define inet_csk(sk)        ((struct inet_connection_sock *)(sk)->sk_prot->data)

通过这个宏,可以方便地访问和操作与 TCP 连接相关的状态和参数,例如 TCP 的扩展头长度、SACK(Selective Acknowledgment)选项等。

http://www.lryc.cn/news/168686.html

相关文章:

  • go-channel
  • K8s操作命令
  • 【MySQL】 MySQL数据库基础
  • vscode 下载安装
  • springboot对接postgres
  • [python 刷题] 242 Valid Anagram
  • 算法通过村第七关-树(递归/二叉树遍历)青铜笔记|手撕递归
  • #循循渐进学51单片机#点亮你的LED#not.2
  • 基于Java+SpringBoot+Vue+uniapp点餐小程序(亮点:协同过滤算法、会员系统,购物车结算、在线聊天)
  • 深度学习-全连接神经网络-详解梯度下降从BGD到ADAM - [北邮鲁鹏]
  • 数据结构--二叉排序树
  • Python | 根据子列表中的第二个元素对列表进行排序
  • qsort函数详细讲解以及利用冒泡排序模拟实现qsort函数
  • C++QT day6
  • List与ArrayList
  • 【C++】特殊类的设计
  • 机器学习:PCA(Principal Component Analysis主成分)降维
  • linux服务器slab缓存回收方案设计
  • Apache Spark 的基本概念
  • 通讯协议介绍CoAP 协议解析
  • React 开发一个移动端项目(2)
  • 51单片机 点阵矩阵 坤坤代码
  • Android13-图片视频选择器
  • 【问题处理】GIT合并解决冲突后,导致其他人代码遗失的排查
  • H264视频压缩格式
  • 动态的中秋爱心演示送女友用python生成爱心软件文末附c++语言写法
  • macOS - 使用VLC
  • java微服务项目整合skywalking链路追踪框架
  • pandas 笔记: interpolate
  • 应用程序接口(API)安全的入门指南