struct net (network namespace)

本文介绍了一个针对Linux内核网络堆栈的补丁集,旨在通过引入网络命名空间来支持多个独立的网络配置。该实现涉及对核心网络结构的修改,确保每个命名空间内的网络设备、套接字等资源独立。

 35 struct net {
 36         atomic_t                count;          /* To decided when the network
 37                                                  *  namespace should be freed.
 38                                                  */
 39 #ifdef NETNS_REFCNT_DEBUG
 40         atomic_t                use_count;      /* To track references we
 41                                                  * destroy on demand
 42                                                  */
 43 #endif
 44         struct list_head        list;           /* list of network namespaces */
 45         struct list_head        cleanup_list;   /* namespaces on death row */
 46         struct list_head        exit_list;      /* Use only net_mutex */
 47 
 48         struct proc_dir_entry   *proc_net;
 49         struct proc_dir_entry   *proc_net_stat;
 50 
 51 #ifdef CONFIG_SYSCTL
 52         struct ctl_table_set    sysctls;
 53 #endif
 54 
 55         struct net_device       *loopback_dev;          /* The loopback */
 56 
 57         struct list_head        dev_base_head;
 58         struct hlist_head       *dev_name_head;
 59         struct hlist_head       *dev_index_head;
 60 
 61         /* core fib_rules */
 62         struct list_head        rules_ops;
 63         spinlock_t              rules_mod_lock;
 64 
 65         struct sock             *rtnl;                  /* rtnetlink socket */
 66         struct sock             *genl_sock;
 67 
 68         struct netns_core       core;
 69         struct netns_mib        mib;
 70         struct netns_packet     packet;
 71         struct netns_unix       unx;
 72         struct netns_ipv4       ipv4;
 73 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 74         struct netns_ipv6       ipv6;
 75 #endif
 76 #if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
 77         struct netns_dccp       dccp;
 78 #endif
 79 #ifdef CONFIG_NETFILTER
 80         struct netns_xt         xt;
 81 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 82         struct netns_ct         ct;
 83 #endif
 84         struct sock             *nfnl;
 85         struct sock             *nfnl_stash;
 86 #endif
 87 #ifdef CONFIG_XFRM
 88         struct netns_xfrm       xfrm;
 89 #endif
 90 #ifdef CONFIG_WEXT_CORE
 91         struct sk_buff_head     wext_nlevents;
 92 #endif
 93         struct net_generic      *gen;
 94 };

The following patchset was built against the latest net-2.6.24
tree, and should be safe to apply assume not issues are found during
the review.  In the interest of keeping the patcheset to a reviewable
size, just the core of the network stack has been covered.


The 10,000 foot overview.  We want to make it look to user space 
like the kernel implements multiple network stacks.

To implement this some of the currently global variables in the
network stack need to have one instance per network namespace,
or the global data structure needs to have a network namespace
field.

Currently control enters the network stack in one of 4 major ways.
Through operations on a socket, through a packet coming in
from a network device, through miscellaneous syscalls from
a process, and through operations on a virtual filesystem.
So the current design calls for placing a pointer to 
struct net (the network namespace structure) on network
devices, sockets, processes, and on filesystems so we
have a clear understanding of which network namespace
operations should be done in the context of.

Packets do not contain a pointer to a network device structure.
Instead their network device is derived from which network
device or which socket they are passing through.

On the input path we only need to look at the network namespace
to determine which routing tables to use, and which sockets the
packet can be destined for.

Similarly on the output path we only need to consult the network
namespace for the output routing tables which point to which
network devices we can use.

So while there are accesses to the network namespace as
we process each packet they are in well contained spots that occur
rarely.

Where the network namespace appears most is on the control,
setup, and clean up code paths, in the network stack that we
change rarely.  There we currently don't have anything except
a global context so modifications are necessary, but since
the network parameter is not implicit it should not require
much thought to use.

The implementation strategy follows the classic global
lock reduction pattern.  First all of the interfaces
at a given level in the network stack are made to filter
out traffic from anything except the initial network namespace,
and then those interfaces are allowed to see packets from
any network namespace.  Then some subset of those interfaces
are taught to handle packets from all namespaces, after the
more specific protocol layers below them have been made to
filter those packets.

What this means is that we start out with large intrusive
stupid patches and end up with small patches that enable
small bits of functionality in the secondary network
namespaces.

Eric
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

是的,**`struct ifaddrs` 中没有直接包含内核接口索引(interface index)的字段**,但它可以通过其内部的 `struct sockaddr` 关联信息间接获取。 --- ### 🔍 详细解释 #### `struct ifaddrs` 定义(来自 `<ifaddrs.h>`) ```c struct ifaddrs { struct ifaddrs *ifa_next; // 下一个接口地址条目 char *ifa_name; // 接口名称,如 "eth0" unsigned int ifa_flags; // 接口标志(IFF_UP, IFF_LOOPBACK 等) struct sockaddr *ifa_addr; // 接口地址(IPv4/IPv6、MAC等) struct sockaddr *ifa_netmask; // 子网掩码 struct sockaddr *ifa_broadaddr;// 广播地址(仅IPv4) struct sockaddr *ifa_dstaddr; // P2P目标地址 void *ifa_data; // 地址族相关数据(可选) }; ``` 🔍 **关键点:** - `ifa_name` 是接口名(例如 `"lo"` 或 `"wlan0"`) - 没有像 Netlink 中那样的 `ifa_index` 字段 - 但你可以通过 `ifa_name` 转换为接口索引 --- ## ✅ 如何从 `struct ifaddrs` 获取接口索引(index)? 使用标准函数: ```c unsigned int if_nametoindex(const char *ifname); ``` 头文件: ```c #include <net/if.h> ``` ### 示例代码:遍历所有接口并打印名称和索引 ```c #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <ifaddrs.h> #include <netinet/in.h> #include <arpa/inet.h> #include <net/if.h> int main() { struct ifaddrs *ifaddr, *ifa; int family, s; if (getifaddrs(&ifaddr) == -1) { perror("getifaddrs"); exit(EXIT_FAILURE); } for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) continue; family = ifa->ifa_addr->sa_family; // 获取接口索引 unsigned int index = if_nametoindex(ifa->ifa_name); if (index == 0) { printf("Failed to get index for interface: %s\n", ifa->ifa_name); continue; } printf("Interface: %s (index: %u), ", ifa->ifa_name, index); if (family == AF_INET || family == AF_INET6) { char host[NI_MAXHOST]; s = getnameinfo(ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (s != 0) { printf("getnameinfo() failed: %s\n", gai_strerror(s)); } else { printf("Address: %s", host); if (family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr)) { printf("%%%s", ifa->ifa_name); // 显示 IPv6 链路本地地址的 zone index } } } else { printf("Other address family (%d)", family); } printf("\n"); } freeifaddrs(ifaddr); return 0; } ``` --- ### 🧩 输出示例 ``` Interface: lo (index: 1), Address: 127.0.0.1 Interface: lo (index: 1), Address: ::1 Interface: eth0 (index: 2), Address: 192.168.1.100 Interface: eth0 (index: 2), Address: fe80::a00:27ff:fe45:6789%eth0 ``` 可以看到: - 多个 IP 可能共享同一个接口名和索引 - 即使是一个接口的不同地址(IPv4、IPv6、别名),它们都对应相同的 `if_nametoindex(ifa->ifa_name)` --- ## ✅ 总结 | 问题 | 回答 | |------|------| | `struct ifaddrs` 是否有 `ifa_index`? | ❌ 没有直接字段 | | 如何获取接口 index? | ✅ 使用 `if_nametoindex(ifa->ifa_name)` | | `ifa_name` 是否总是有效? | ⚠️ 否!某些虚拟接口或隧道可能无名(需判断空指针) | | 是否线程安全? | ✅ `if_nametoindex()` 是线程安全的 | --- ## ✅ 注意事项 1. **检查 `ifa_name` 是否为空**: ```c if (ifa->ifa_name == NULL) continue; ``` 2. **注意权限与命名空间**: - 在容器或 network namespace 中,某些接口可能不可见 - 导致 `if_nametoindex()` 返回 0 3. **性能考虑**: - `if_nametoindex()` 内部查表,建议缓存结果(尤其在频繁访问时) 4. **与 Netlink 对比**: - `getifaddrs()` 更简单易用,适合用户态读取当前状态 - Netlink 更强大,可用于监听动态事件(如 IP 添加/删除) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值