linux之网络子系统-本机发包到本机 实现

一、前言

linux之网络子系统-网络协议栈 发包收包详解-CSDN博客 文章中,详细介绍了跨主机之间的数据包发送的源码流程。除了跨主机,还有本机发包到本机是如何实现的?就是 saddr ip地址为 127.0.0.1 .

二、发送数据包到 127.0.0.1

首先,127.0.0.1 就是指 lo (本地回环网络设备):

这个lo设备是在 网络设备子系统 初始化时注册的:

static int __init net_dev_init(void)

{

.....

if (register_pernet_device(&loopback_net_ops))

goto out;

...

}

接着看 loopback_net_ops:

/* Registered in net/core/dev.c */

struct pernet_operations __net_initdata loopback_net_ops = {

.init = loopback_net_init,

};

接着 loopback_net_init:

/* Setup and register the loopback device. */

static __net_init int loopback_net_init(struct net *net)

{

struct net_device *dev;

int err;

err = -ENOMEM;

//初始化 lo 网络设备

dev = alloc_netdev(0, "lo", NET_NAME_UNKNOWN, loopback_setup);

if (!dev)

goto out;

dev_net_set(dev, net);

//注册lo 网络设备

err = register_netdev(dev);

if (err)

goto out_free_netdev;

BUG_ON(dev->ifindex != LOOPBACK_IFINDEX);

net->loopback_dev = dev;

return 0;

out_free_netdev:

free_netdev(dev);

out:

if (net_eq(net, &init_net))

panic("loopback: Failed to register netdevice: %d\n", err);

return err;

}

上面是 网络设备子系统初始化完成,那么如何被调用到?

根据之前的文章中,描述了跨主机的发包过程:

发包过程中,到达 网络设备子系统 dev_queue_xmit 时,会选择 lo 网络设备驱动的ndo_start_xmit 回调函数。这个驱动没有实际的硬件设备,纯属软件意义上的驱动。

lo 驱动是如何定义 ndo_start_xmit 回调函数?

函数调用链:

loopback_net_init ->

loopback_setup->

gen_lo_setup
static void loopback_setup(struct net_device *dev)

{

gen_lo_setup(dev, (64 * 1024), &loopback_ethtool_ops, &eth_header_ops,

&loopback_ops, loopback_dev_free);

}

loopback_ops 定义如下:

static const struct net_device_ops loopback_ops = {

.ndo_init = loopback_dev_init,

.ndo_start_xmit = loopback_xmit,

.ndo_get_stats64 = loopback_get_stats64,

.ndo_set_mac_address = eth_mac_addr,

};

本机发送数据包时,调用 loopback_xmit 函数:

/* The higher levels take care of making this non-reentrant (it's

* called with bh's disabled).

*/

static netdev_tx_t loopback_xmit(struct sk_buff *skb,

struct net_device *dev)

{

int len;

skb_tx_timestamp(skb);

/* do not fool net_timestamp_check() with various clock bases */

skb->tstamp = 0;

skb_orphan(skb);

/* Before queueing this packet to netif_rx(),

* make sure dst is refcounted.

*/

skb_dst_force(skb);

skb->protocol = eth_type_trans(skb, dev);

len = skb->len;

if (likely(netif_rx(skb) == NET_RX_SUCCESS)) // lo 驱动中直接调用 接收数据包的软中断。

dev_lstats_add(dev, len);

return NETDEV_TX_OK;

}

看到了驱动与网络设备子系统的接口函数netif_rx ,然后会触发软中断,接收数据包。

上面已经把主机发包到本机的流程已经分析完毕,和跨主机的流程基本一致,都是到驱动层。

本机网络 IO 需要进行 IP 分片吗?

因为和正常的网络层处理过程一样,如果 skb 大于 MTU 的话,仍然会进行分片。

只不过 lo 的 MTU 比 Ethernet 要大很多。

通过 ifconfig 命令就可以查到,普通网卡一般为 1500,而 lO 虚拟接口能有 65535。

在内核源码中, 65535 是用 (64*1024)表示的,单位是字节。

相关推荐
AlfredZhao6 小时前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户97183563346612 小时前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪14 小时前
linux 拷贝文件或目录到指定的位置
linux
大树881 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠1 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质1 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush41 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5201 天前
Linux 11 动态监控指令top
linux
Inhand陈工1 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
网络研究院1 天前
2026年网络安全
网络·安全·法律·法规·趋势·发展