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)表示的,单位是字节。

相关推荐
chirrupy_hamal8 分钟前
如何避免 SYN 攻击?
网络·tcp
xcs1940510 分钟前
集运维 麒麟桌面版v10 sp1 2403 aarch64 离线java开发环境自动化安装
运维·自动化
BAOYUCompany13 分钟前
暴雨服务器成功中标华中科技大学集成电路学院服务器采购项目
运维·服务器
怦然星动_36 分钟前
ip网络基础
网络·智能路由器
超龄超能程序猿1 小时前
Bitvisse SSH Client 安装配置文档
运维·ssh·github
数据与人工智能律师1 小时前
数字资产革命中的信任之锚:RWA法律架构的隐形密码
大数据·网络·人工智能·云计算·区块链
奈斯ing1 小时前
【Redis篇】数据库架构演进中Redis缓存的技术必然性—高并发场景下穿透、击穿、雪崩的体系化解决方案
运维·redis·缓存·数据库架构
鳄鱼皮坡2 小时前
仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器
运维·服务器
菜包eo2 小时前
二维码驱动的独立站视频集成方案
网络·python·音视频
即将头秃的程序媛2 小时前
centos 7.9安装tomcat,并实现开机自启
linux·运维·centos