【计算机网络】Linux 内核网络概述

 文章目的

  • 了解 Linux 内核网络架构
  • 通过网络包过滤器或者防火墙获得使用的 IP 数据包(分组)管理技巧
  • 熟悉如何在 Linux 内核级别使用套接字

概述

        网络应用程序的开发过去这些年按照指数级增长,这样增加了对系统网络子系统的速度要求和产品化要求。网络子系统不是 Linux 内核必须的组件(Linux 内核可以在没有网络支持的情况下编译通过)。然而非常少的计算系统(即便是嵌入式设备)很难没有网络支持,因为它们都需要联网。现代操作系统使用 TCP/IP 协议栈,协议栈实现了传输层以下的所有协议层,应用层协议通常在用户空间实现(HTTP、FTP、SSH等)。

用户空间网络

        用户空间中,网络网络通信被抽象为套接字(socket),套接字抽象了通信通道,是基于内核 TCP/IP 协议栈交互接口。一个 IP 套接字和一个 IP 地址、传输层协议(TCP、UDP 等)、以及一个端口关联。使用套接字的普通函数调用包括:创建(socket)、初始化(bind)、连接(connect)、关闭套接字(close)。

        TCP 套接字通过 read/write 或者 recv/send 调用完成网络通信,而 UDP 使用 recvfrom/sento 接口调用完成网络调用。通信过程中的传输和接收操作对于应用程序来讲是透明的,即数据的封装以及网络传输由内核决定。然而,也可以通过原始套接字在用户空间实现 TCP/IP 协议栈(传教套接字时使用 PF_PACKET 选项),或者在内核实现应用层协议(比如 TUX web server)。

        更多关于用户空间使用套接字编程的信息,参考 Beej's Guide to Network Programming 

Linux 网络通信

        Linux 内核提供了网络包工作的三个基本数据结构:struct socket、struct sock、struct sk_buff。

        前两个是套接字的抽象:

  • struct socket 和用户空间的抽象非常相似,也就是用来编写网络应用程序的 BSD 套接字
  • struct sock 或者 Linux 术语中的 INET 套接字是套接字的网络层表示。

        这两个结构是有关联的:struct socket 包含 INET 套接字字段,struct sock 有一个 BSD 套接字包含它。

        struct sk_buff 结构是网络包及其状态的表示。当内核接到一个一个数据包时,就会创建这个结构,数据包可以是从用户空间传来的也可以是从网络接口传来的。

struct socket 结构

        struct socket 结构是 BSD 套接字在内核的表示,在它上面执行的操作和内核提供的操作非常类似(通过系统调用)。一些套接字的常见操作(创建、初始化/绑定、关闭等)会导致特定的系统调用,这些系统调用会使用 struct socket 结构。

        struct socket 操作在 net/socket.c 中实现,它是和具体协议类型无关的。因此,struct socket 结构是一个在各种网络操作实现上的一个通用接口。通常,这些操作以 sock_ 前缀开始。

socket 结构上的操作

creation

创建操作和用户空间调用 socket() 函数类似,但是创建出的套接字被存到了 res 参数中:

  • int sock_create(int family, int typ, int protocol, struct socket **res) 在 socket() 系统调用后创建一个套接字;
  • Int sock_create_kern(struct net *net, int family, int type, int protocol, struct socket **ret) 创建一个内核套接字;
  • int sock_create_lite(int family, int type, int protocol, struct **res) 创建一个内核套接字,不进行 sanity 检查

这些调用的如下:

  • net,是一个网络名字空间的引用,通常我们使用 init_net 初始化它
  • family 表示用于信息传输的协议家族,以 PF_  字符串开头,带上协议家族,这个常量表示协议家族,定义在 linux/socket.h 中,TCP/IP 通常使用 PF_INET
  • type 是套接字的类型,定义在 linux/net.h 中,通常面向连接的通信采用 SOCK_STREAM,而非连接通信采用 SOCK_DGRAM
  • protocol 表示采用的协议,和 type 相关,定义在 linux/in.h 中,TCP 使用 IPROTO_TCP,UDP 使用 IPROTO_UDP。

        在内核空间创建 TCP 套接字,必须调用:

struct socket *sock;
int err;err = sock_create_kern(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
if (err < 0) {/* handle error */
}

        创建一个 UDP 套接字:

struct socket *sock;
int err;err = sock_create_kern(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
if (err < 0) {/* handle error */
}

         sys_socket() 系统调用处理函数(handler)中有相关使用举例:

SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
{int retval;struct socket *sock;int flags;/* Check the SOCK_* constants for consistency.  */BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC);BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK);BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK);BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK);flags = type & ~SOCK_TYPE_MASK;if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))return -EINVAL;type &= SOCK_TYPE_MASK;if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;retval = sock_create(family, type, protocol, &sock);if (retval < 0)goto out;return sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
}

closing

        关闭连接(面向连接的套接字)并释放相关资源:

  • void sock_release(struct socket *sock) 调用套接字结构 ops 字段的  release  函数:
void sock_release(struct socket *sock)
{if (sock->ops) {struct module *owner = sock->ops->owner;sock->ops->release(sock);sock->ops = NULL;module_put(owner);}//...
}

sending/receiving 消息

        使用下面函数进行消息发送和接收:

int sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags);
int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t size, int flags);
int sock_sendmsg(struct socket *sock, struct msghdr *msg);
int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t size);

        消息发送和接收函数会调用套接字 ops 字段的 sendmsg、recvmsg 函数,具有 kernel_ 前缀的函数是套接字在内核中使用的。

        参数如下:

  • msg,是一个 struct msghdr 结构,包含着需要发送接收的消息。这个结构中最重要的成员是 msg_name 和 msg_namelen,对于 UDP 套接字,必须填充为发送消息的目标地址(struct sockaddr_in)
  • vec,一个 struct kvec 结构,包含一个指向缓冲器(包含数据和大小)的指针,这个结构和 struct iovec 结构类似(struct iovec 结构用于用户空间,而 struct kvec 结构用于内核空间数据)

        sys_sendto() 系统调用处理函数里有一些使用例程:

SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,unsigned int, flags, struct sockaddr __user *, addr,int, addr_len)
{struct socket *sock;struct sockaddr_storage address;int err;struct msghdr msg;struct iovec iov;int fput_needed;err = import_single_range(WRITE, buff, len, &iov, &msg.msg_iter);if (unlikely(err))return err;sock = sockfd_lookup_light(fd, &err, &fput_needed);if (!sock)goto out;msg.msg_name = NULL;msg.msg_control = NULL;msg.msg_controllen = 0;msg.msg_namelen = 0;if (addr) {err = move_addr_to_kernel(addr, addr_len, &address);if (err < 0)goto out_put;msg.msg_name = (struct sockaddr *)&address;msg.msg_namelen = addr_len;}if (sock->file->f_flags & O_NONBLOCK)flags |= MSG_DONTWAIT;msg.msg_flags = flags;err = sock_sendmsg(sock, &msg);out_put:fput_light(sock->file, fput_needed);
out:return err;
}

        struct socket 的字段:

/***  struct socket - general BSD socket*  @state: socket state (%SS_CONNECTED, etc)*  @type: socket type (%SOCK_STREAM, etc)*  @flags: socket flags (%SOCK_NOSPACE, etc)*  @ops: protocol specific socket operations*  @file: File back pointer for gc*  @sk: internal networking protocol agnostic socket representation*  @wq: wait queue for several uses*/
struct socket {socket_state            state;short                   type;unsigned long           flags;struct socket_wq __rcu  *wq;struct file             *file;struct sock             *sk;const struct proto_ops  *ops;
};

        需要解释的字段有:

  • ops   -  这个结构存储一些协议相关的函数指针
  • sk     -  和套接字相关的 INET socket

struct proto_ops 结构

        struct proto_ops 结构包含特定操作的实现(TCP/UDP 等),这些函数会被 struct socket(sock_release(), sock_sendmsg() 等) 普通函数调用。

        struct proto_ops 结构也就包含了一些指向这些协议实现的指针:

struct proto_ops {int             family;struct module   *owner;int             (*release)   (struct socket *sock);int             (*bind)      (struct socket *sock,struct sockaddr *myaddr,int sockaddr_len);int             (*connect)   (struct socket *sock,struct sockaddr *vaddr,int sockaddr_len, int flags);int             (*socketpair)(struct socket *sock1,struct socket *sock2);int             (*accept)    (struct socket *sock,struct socket *newsock, int flags, bool kern);int             (*getname)   (struct socket *sock,struct sockaddr *addr,int peer);//...
}

        struct socket 的 ops 字段的初始化是通过 __sock_create() 函数实现的,通过调用 create() 函数,指定每个协议。一个等效的调用是 __sock_create() 函数的实现:

//...err = pf->create(net, sock, protocol, kern);if (err < 0)goto out_module_put;
//...

        这个会初始化这些函数指针为套接字指定协议类型的函数,sock_register() 和 sock_unregister() 调用用来填充 net_fanilies 向量。

        对于剩余的 socket 操作(除了创建、关闭、发送接收外),也会通过指针来调用,比如 bind 函数:

#define MY_PORT 60000struct sockaddr_in addr = {.sin_family = AF_INET,.sin_port = htons (MY_PORT),.sin_addr = { htonl (INADDR_LOOPBACK) }
};//...err = sock->ops->bind (sock, (struct sockaddr *) &addr, sizeof(addr));if (err < 0) {/* handle error */}
//...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/146544.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

5.外部中断

中断初始化配置步骤&#xff1a; IO口初始化配置 开启中断总允许EA 打开某个IO口的中断允许 打开IO口的某一位的中断允许 配置该位的中断触发方式 中断函数&#xff1a; #pragma vector PxINT_VECTOR __interrupt void 函数名(void){}#pragma vector PxINT_VECTOR __int…

喝健康白酒 有益生心健康

中国的制酒史源远流长&#xff0c;酒渗透在中华五千年的文化中。酒与烟不同&#xff0c;烟对人体有百害而无一利&#xff0c;而对于酒&#xff0c;若掌握好饮酒的度&#xff0c;对人体有一定的养生作用&#xff0c;所以我们通常会说“戒烟限酒”。 据一些专家研究&#xff0c;…

云原生Kubernetes:对外服务之 Ingress

目录 一、理论 1.Ingress 2.部署 nginx-ingress-controller(第一种方式) 3.部署 nginx-ingress-controller(第二种方式) 二、实验 1.部署 nginx-ingress-controller(第一种方式) 2.部署 nginx-ingress-controller(第二种方式) 三、问题 1.启动 nginx-ingress-controll…

什么是 MyBatis?与 Hibernate 的区别

引言 在现代的应用程序开发中&#xff0c;与数据库的交互是至关重要的。为了简化数据库访问&#xff0c;许多开发者选择使用ORM&#xff08;对象-关系映射&#xff09;框架。MyBatis和Hibernate都是流行的ORM框架&#xff0c;它们可以帮助开发者更轻松地将Java对象映射到数据库…

Java-API简析_java.util.Objects类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/133463511 出自【进步*于辰的博客】 因为我发现目前&#xff0c;我对Java-API的学习意识比较薄弱…

Polygon Miden交易模型:Actor模式 + ZKP => 并行 + 隐私

1. 引言 前序博客&#xff1a; Polygon Miden&#xff1a;扩展以太坊功能集的ZK-optimized rollupPolygon Miden zkRollup中的UTXO账户混合状态模型 Polygon Miden为&#xff1a; ZK-optimized rollup由客户端生成证明完善Polygon ZK系列解决方案&#xff0c;致力于成为网络…

消息队列-RabbitMQ(二)

接上文《消息队列-RabbitMQ&#xff08;一&#xff09;》 Configuration public class RabbitMqConfig {// 消息的消费方json数据的反序列化Beanpublic RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(ConnectionFactory connectionFactory){Simple…

数据结构-哈希表

系列文章目录 1.集合-Collection-CSDN博客​​​​​​ 2.集合-List集合-CSDN博客 3.集合-ArrayList源码分析(面试)_喜欢吃animal milk的博客-CSDN博客 4.数据结构-哈希表_喜欢吃animal milk的博客-CSDN博客 文章目录 目录 系列文章目录 文章目录 前言 一 . 什么是哈希表&a…

【教学类-38-02】20230724京剧脸谱2.0——竖版(小彩图 大面具)(Python 彩图彩照转素描线描稿)

结果展示 背景需求&#xff1a; 前文体运用Python颜色提取功能&#xff0c;将“京剧脸谱”彩色图片转化为线描图案。 【教学类-38】20230724京剧脸谱1.0——横版“彩图线图等大”&#xff08;Python 彩图彩照转素描线描稿&#xff09;_reasonsummer的博客-CSDN博客 存在问题&…

计算机图形学、贝塞尔曲线及绘制方法、反走样问题的解决(附完整代码)

贝塞尔曲线 1. 本次作业实现的函数及简单描述&#xff08;详细代码见后&#xff09;2. 与本次作业有关的基础知识整理3. 代码描述&#xff08;详细&#xff09;4. 完整代码5. 参考文献 &#xff08;本篇为作者学习计算机图形学时根据作业所撰写的笔记&#xff0c; 如有同课程请…

数字时代古文的传承———云南文化瑰宝“爨文化“(我为家乡发声)

文章目录 前言⭐ "爨"意味着什么&#xff0c;究竟何为"爨文化"&#xff1f;⭐ 爨文化鲜明的特点1.经济生活2.政治生活3.文化艺术 ⭐ 数字时代古文的传承与传播1.藏品数字化2.建立数据库3.传播大众化 前言 爨文化是继古滇文化之后崛起于珠江正源南盘江流域…

根据GWAS数据估算样本量N和使用千人基因组填充maf的参考文献

https://github.com/GenomicSEM/GenomicSEM/wiki/2.1-Calculating-Sum-of-Effective-Sample-Size-and-Preparing-GWAS-Summary-Statistics

【SQL】mysql创建定时任务执行存储过程--20230928

1.先设定时区 https://blog.csdn.net/m0_46629123/article/details/133382375 输入命令show variables like “%time_zone%”;&#xff08;注意分号结尾&#xff09;设置时区&#xff0c;输入 set global time_zone “8:00”; 回车,然后退出重启&#xff08;一定记得重启&am…

【C++】手撕vector(vector的模拟实现)

手撕vector目录&#xff1a; 一、基本实现思路方针 二、vector的构造函数剖析&#xff08;构造歧义拷贝构造&#xff09; 2.1构造函数使用的歧义问题 2.2 vector的拷贝构造和赋值重载&#xff08;赋值重载不是构造哦&#xff0c;为了方便写在一起&#xff09; 三、vector的…

Apollo自动驾驶系统概述(文末参与活动赠送百度周边)

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

算法基础课第二部分

算法基础课 第四讲 数学知识AcWing1381. 阶乘(同余&#xff0c;因式分解) 质数AcWing 866. 质数的判定---试除法AcWing 868. 质数的判定---埃氏筛AcWing867. 分解质因数---试除法AcWing 197. 阶乘---分解质因数---埃式筛 约数AcWing 869. 求约数---试除法AcWing 870. 约数个数-…

云可观测性安全平台——掌动智能

云可观测性安全平台是一个跨架构、跨平台的可观测性方案&#xff0c;实现对云环境下的细粒度数据可视化&#xff0c;满足安全部门对云内部安全领域的多场景诉求&#xff0c;包括敏感数据动态监管、云网攻击回溯分析、攻击横移风险监控、云异常流量分析。本文将介绍掌动智能云可…

腾讯云中使用ubuntu安装属于自己的overleaf

在自己的云服务器上安装overleaf的需求是从写论文开始的&#xff0c;总担心自己的论文放在一个网站上被泄露&#xff0c;所以想要在自己的服务器上安装自己的overleaf&#xff0c;正好手边有一个云服务器&#xff0c;现在开始。 配置腾讯云 因为使用overleaf的优势就是在不同…

SQLAlchemy常用数据类型

目录 SQLAlchemy常用数据类型 代码演示 代码分析 SQLAlchemy常用数据类型 SQLAlchemy 是一个Python的SQL工具库和对象关系映射(ORM)工具&#xff0c;它提供了一种在Python中操作数据库的高效方式。下面是SQLAlchemy中常用的一些数据类型&#xff1a; Integer&#xff1a;整形&…

【数据结构】选择排序 堆排序(二)

目录 一&#xff0c;选择排序 1&#xff0c;基本思想 2&#xff0c; 基本思路 3&#xff0c;思路实现 二&#xff0c;堆排序 1&#xff0c;直接选择排序的特性总结&#xff1a; 2&#xff0c;思路实现 3&#xff0c;源代码 最后祝大家国庆快乐&#xff01; 一&#xf…