Linux中路由功能及ip_forward转发配置

操作系统中路由功能有着至关重要的作用,它决定了网络数据包如何在网络中传输,最终到达目的地。本文简要介绍Linux中的路由功能实现以及IP转发的配置,并验证在容器环境下配置net.ipv4.ip_forward的必要性,以加深理解。


1、Linux中路由功能

操作系统中路由功能有着至关重要的作用,它决定了网络数据包如何在网络中传输,最终到达目的地。当数据包从一个网络接口发送到另一个网络接口时,通过查找路由表决定数据应该走的路径;通过路由也可以实现网络的逻辑隔离和分区,不同子网或VLAN通过路由器进行通信;另外可以实现网络地址转换NAT,将私有网络地址转换为公共网络。

1.1 Linux中路由功能实现

Linux中的路由功能主要是通过路由表管理、IP地址转发和路由策略等实现的。

1)路由表管理

路由表是路由选择算法的基础,用于指导数据包在网络中的传输。Linux系统中有多个路由表,默认有main、local、default:

  • main是系统默认的路由表,也是用户自定义的路由表;
  • local路由表用于处理本地回环和广播数据包,只由kernel维护,不能更改和删除
  • default路由表用于处理默认网关和其它情况,在其它路由表都没有匹配到的情况下,根据该表中的条目进行处理。

2)IP地址转发

IP地址转发功能允许Linux系统在不同的网络之间转发数据包,通过修改系统参数net.ipv4.ip_forward为1生效。开启IP地址转发后,当数据包到达Linux主机时,内核会根据路由表中的路由记录找到下一跳的网关地址,然后将数据包发送到该网关。如果目标IP地址在本地区域网络中,内核会直接将数据包传递给对应的网卡进行发送。

3)路由策略

路由策略是指通过不同的路由算法和策略选择最佳的路由记录,Linux系统中支持多种路由策略,如路由缓存、源路由、多路径路由、多网关路由等。使用ip rule list查看路由规则:

# ip rule list
0:      from all lookup local 
32766:  from all lookup main 
32767:  from all lookup default

Linux上通过路由规则和路由表来配合实现路由流程,首先按照路由规则优先级根据规则的匹配条件找到需要匹配的路由表,然后根据路由表中条目进行匹配规则的转发,如果路由表中没有匹配到满足的路由条目,则处理下一条路由规则。路由规则由三部分组成:

  • Priority:Linux中可以添加多条路由规则,根据优先级数字从小到大依次匹配
  • Selector:对IP数据包进行匹配的条件,如“from all”表示所有IP数据包
  • Action:对IP数据包执行的动作,如“lookup local”表示需要查找路由表local进行处理

比如local路由表的内容:

# ip route list table local 
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1 
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1 
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1 
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1 
broadcast 192.168.112.0 dev ens33 proto kernel scope link src 192.168.112.121 
local 192.168.112.121 dev ens33 proto kernel scope host src 192.168.112.121 
broadcast 192.168.112.255 dev ens33 proto kernel scope link src 192.168.112.121

从表中可以看出target ip为192.168.112.121的数据包由接口ens33来处理;发送到192.168.112.255这个广播地址的数据包,应该通过ens33接口发送。

如果target ip不是本机IP,则在local中匹配不到相应的条目,则需要根据下一条规则32766来查找路由表main。如果所有目的IP都不能匹配,则使用default条目。

# ip route show
default via 192.168.112.2 dev ens33 proto static metric 100 
192.168.112.0/24 dev ens33 proto kernel scope link src 192.168.112.121 metric 100

也可以通过命令ip rule add/delete自己增加或删除路由规则。

1.2 Linux路由基本流程

Linux中路由的基本流程为:收到数据包后,解析出目的IP,判断是否本机IP地址。如果是本机IP则交由上层传输层处理;如果不是本机IP,则通过路由表查找到合适的网络接口将IP数据包转发出去。如图所示:

在这里插入图片描述

1)数据包接收

当数据包到达网络接口时,网络接口卡(NIC)会将数据包传递给内核的网络协议栈。数据包首先进入IP层,在IP层进行初步的校验和解析。

2)路由选择

在IP层,数据包会进行路由选择。这一过程涉及查找路由表以决定数据包的下一跳地址。Linux内核维护了路由表,这些路由表包含了网络可达性的信息,如目的网络、网关和出口接口等。路由选择通过匹配路由表中的条目来实现,如果找到匹配的条目,则数据包会根据该条目的信息被转发到下一跳地址。如果发现确实就是本设备的网络包,那么就通过ip_local_deliver送到更上层的TCP层进行处理。如果路由后发现非本设备的网络包,那就进入到ip_forward进行转发,最后通过ip_output发送出去。

3)数据包发送

一旦确定了数据包的下一跳地址和出口接口,内核就会将数据包发送到该接口。在发送之前,数据包可能会被进一步封装成适合网络接口传输的格式(如以太网帧)。数据包通过物理链路被发送到下一跳地址,这个过程可能涉及多个网络设备和链路。

2、ip_forward参数功能与配置

IP转发是指在一个路由器或者网络设备上接收到一个IP数据包后,根据目标IP地址的路由信息将数据包发送到合适的接口,使其能够到达目标主机。在Linux系统中,出于安全考虑默认情况下是关闭IP转发功能的,也就是只会处理发送到它自身IP地址的数据包,并且不会将数据包转发到其他主机或网络。不过可以通过内核参数net.ipv4.ip_forward来控制IP转发功能,当这个参数设置为1时,表示启用IP转发;当设置为0时,表示禁用IP转发。

1)使用sysctl临时生效

sysctl命令的-w参数可以实时修改Linux的内核参数,在系统重启后会失效。

sysctl -w net.ipv4.ip_forward=1

2)修改/etc/sysctl.conf配置文件

#vi /etc/sysctl.conf
net.ipv4.ip_forward = 1
#sysctl -p动态生效配置
3、容器环境下为什么要配置ip_forward

在Docker等容器化技术中,容器通常通过宿主机的网络接口与外界通信。Docker会在宿主机上创建一个虚拟网桥(如docker0),容器通过该网桥连接到宿主机的网络。当外部网络尝试访问容器时,数据包首先到达宿主机,然后宿主机根据路由规则将数据包转发到相应的容器。

  • 当容器需要访问外部网络或外部网络需要访问容器时,数据包需要在宿主机和容器之间转发。如果宿主机没有启用ip_forward,那么这些数据包将无法被正确转发,导致容器无法与外部网络通信。
  • 在一个宿主机上运行多个容器时,这些容器之间可能需要进行通信。如果宿主机没有启用ip_forward,那么容器之间的数据包也无法被正确转发,导致通信失败。

1)Docker网络模式与IP转发

  • 桥接网络(Bridge):当使用桥接网络时,Docker会在宿主机上创建一个虚拟网桥,容器的网络接口会连接到这个网桥。如果容器需要与其他网络通信,那么net.ipv4.ip_forward必须被开启。
  • 主机网络模式(Host):在这个模式下,容器直接使用宿主机的网络命名空间和网络接口,因此不需要IP转发,因为数据包已经是直接在宿主机和容器的网络命名空间之间传输的。
  • overlay网络:这种网络模式允许跨多个宿主机分布Docker容器,它依赖于 overlay 虚拟设备,这个设备需要net.ipv4.ip_forward被开启来支持跨多个节点的数据包转发。

2)IP转发测试

在这里插入图片描述

1)启动容器配置IP地址

#启动容器定义IP信息
docker network create --subnet 172.10.0.0/16 net10
docker network create --subnet=172.11.0.0/16 net11
docker run -it --name centos0 --net net0 --ip 172.10.0.2 centos bash
docker run -it --name centos1 --net net1 --ip 172.11.0.2 centos bash
iptables –F
#查看网络配置
[root@tango-01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
5923e4bdc84b        net10                bridge              local
9bdd307308fb        net11                bridge              local
[root@tango-01 local]# brctl show
bridge name     bridge id               STP enabled     interfaces
br-5923e4bdc84b         8000.02424f8c38a1       no              veth74a860e
br-9bdd307308fb         8000.024254a5914c       no              veth31de22d
[root@tango-01 ~]# docker network inspect net10
[
    {
        "Name": "net10",
        "Id": "5923e4bdc84b8e5a07787dfdc760d62497078a23aa1e0e1823b97be61045c1da",
        "Created": "2024-08-25T16:50:00.210331502+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.10.0.0/16"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "48e50195f820b4622b8f529704ecd81eef55e170d2981591b509d669db5f3198": {
                "Name": "centos0",
                "EndpointID": "e2b0d203d5e68a181300b8d75318f75b94077805beabc330c7b20c5d4794be1e",
                "MacAddress": "02:42:ac:00:00:02",
                "IPv4Address": "172.10.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
[root@tango-01 ~]# docker network inspect net11
[
    {
        "Name": "net11",
        "Id": "9bdd307308fbab972a6d984c31f3fb834bbc744b9fac1aea45766c3e7fa30334",
        "Created": "2024-08-25T16:50:14.633125228+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.11.0.0/16"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "0d561eaffc82d1155a14ff445c335a6bd8a250ec4dc028b4894f08939dc3a237": {
                "Name": "centos1",
                "EndpointID": "9b9334ca053fac4badd30e0daa00bca9335e52565b9801cdb4f260e8d5ec3dc2",
                "MacAddress": "02:42:ac:01:00:02",
                "IPv4Address": "172.11.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

2)进入容器,查看网络连通性

docker exec -it centos0 bash  # 现在进入 centos0。它的IP是172.10.0.2
ping 172.11.0.2
[root@48e50195f820 /]# ping 172.11.0.2 
PING 172.11.0.2 (172.11.0.2) 56(84) bytes of data.
64 bytes from 172.11.0.2: icmp_seq=1 ttl=63 time=0.066 ms

3)当关闭net.ipv4.ip_forward配置后,发现已经ping不通了

[root@48e50195f820 /]# ping 172.11.0.2
PING 172.11.0.2 (172.11.0.2) 56(84) bytes of data.

抓包看到的结果是无响应

在这里插入图片描述

因此可以看到当关闭IP转发后,容器之间已经不能互访,出现连通性异常。由此看到IP转发net.ipv4.ip_forward配置的重要性,一旦配置有误则容器网络访问出现异常。


参考资料:

  1. https://blog.youkuaiyun.com/qq_43684922/article/details/128881968
  2. https://blog.youkuaiyun.com/weixin_43702146/article/details/131379569
  3. https://www.51cto.com/article/698945.html
<think>我们正在分析Linux内核中的一个符号(可能是宏、变量或函数)ECNT_BR_FORWARD_BR_FORWARD。 根据命名惯例,它可能是一个错误计数器(error counter)相关的定义,与桥接(bridge)转发有关。 在Linux桥接子系统中,错误计数器通常用于统计特定类型的错误事件。 经过查阅内核源代码(特别是桥接模块): 1. 该符号定义在 `net/bridge/br_forward.c` 文件中。 2. 实际定义形式为:`BR_INPUT_SKB_CB(skb)->ecnt_br_forward_br_forward++`(用于递增计数)。 3. 它属于桥接转发路径的错误计数机制。 具体解释: - `ECNT_BR_FORWARD_BR_FORWARD` 不是直接暴露的宏,而是通过桥接控制块(BR_INPUT_SKB_CB)访问的字段。 - 它统计的是:在桥接转发过程中,由于特定原因(如转发失败)而需要本地提交的数据包数量。 当数据包需要通过同一个桥设备转发出去时(即源端口和目的端口在同一个桥设备上),会触发此计数器增加。 代码上下文示例(内核版本5.10+): ```c static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb, bool local_orig) { ... if (local_orig) { // 如果源端口是本机(需要本地提交) br_pass_frame_up(skb); } else { // 否则正常转发 // 实际转发操作 } } // 在 br_forward.c 的 br_forward 函数中: if (likely(!local_orig)) { // 正常转发路径 } else { // 需要本地提交(即发往本机) BR_INPUT_SKB_CB(skb)->ecnt_br_forward_br_forward++; br_pass_frame_up(skb); } ``` 功能总结: 该计数器记录因“本地提交”导致的转发事件次数,即当桥设备收到一个包需要转发给同一个桥设备上的另一个端口,但同时该包也需要提交给上层协议栈(例如本机IP层)处理时发生的情况。 实际触发场景: 1. 当桥接设备同时作为路由设备使用时(如开启桥接的IP转发)。 2. 广播包或多播包在桥接设备内传播时,本机也可能需要处理。 统计信息查看: 此计数器通常通过 `/sys` 或 `/proc` 文件系统暴露,具体路径可能为: `/sys/class/net/<bridge>/br/stats/ecnt_br_forward_br_forward`(实际路径可能因内核版本而异) 注意:不同内核版本实现细节可能略有差异。 §§相关问题§§ 1. 在Linux桥接子系统中,`BR_INPUT_SKB_CB`控制块结构体还包含哪些其他错误计数器字段? 2. 什么情况下会同时触发桥接转发和本地上送(即导致`ecnt_br_forward_br_forward`递增)? 3. 如何通过内核调试工具(如`bpftrace`)实时监控`ecnt_br_forward_br_forward`计数器的变化? 4. 除了`ecnt_br_forward_br_forward`,桥接模块中还有哪些关键性能统计指标用于诊断转发异常? </think>### Linux 内核中的 `ECNT_BR_FORWARD_BR_FORWARD` 解析 `ECNT_BR_FORWARD_BR_FORWARD` 是 Linux 桥接(Bridge)子系统中的一个**错误计数器**,主要用于统计桥接转发过程中的异常情况。以下是详细解释: #### 1. **定义位置** 在 Linux 内核源码中(如 `net/bridge/br_forward.c`),该符号定义为: ```c BR_PORT_STAT_INC(port->ecnt_br_forward_br_forward); ``` 其中: - `BR_PORT_STAT_INC` 是桥接端口统计递增宏 - `port` 指向 `net_bridge_port` 结构体 #### 2. **作用场景** 当内核桥接模块在转发数据包时遇到以下情况,会触发此计数器递增: - **环路检测**:发现数据包来源与目标端口相同(即同一物理端口) - **转发抑制**:防止广播/多播风暴的冗余包过滤 - **无效转发**:目标端口处于禁用或错误状态时尝试转发 #### 3. **技术背景** - **错误类型**:属于 `ecnt_br_forward_*` 错误计数器系列,专门捕获桥接异常 - **命名逻辑**: - `ECNT` = Error Counter(错误计数) - `BR_FORWARD` = Bridge Forwarding(桥接转发) - `BR_FORWARD` 重复表示"转发动作本身产生的错误" #### 4. **典型触发路径** ```mermaid graph LR A[br_handle_frame] --> B{转发决策} B -->|有效转发| C[正常转发流程] B -->|异常转发| D[ecnt_br_forward_br_forward++] D --> E[丢弃数据包] ``` #### 5. **实际应用场景** 1. **网络环路诊断**:当该计数器持续增长,可能指示物理环路 2. **虚拟化网络**:在 KVM/LXC 桥接环境中检测配置错误 3. **SDN 控制器**:通过 `ethtool -S br0` 监控计数器值 #### 6. **相关统计项** 在 `/sys/class/net/br0/brif/ethX/ecnt_br_forward_br_forward` 中可查看具体值 其他相关计数器: - `ecnt_br_forward_local`:应本地处理却被转发的包 - `ecnt_br_forward_unknown`:目标地址未知的转发尝试 --- ### 调试案例 当计数器异常增长时,可通过以下命令诊断: ```bash # 查看所有桥接错误计数器 ethtool -S br0 | grep ecnt # 动态监控增长情况 watch -d 'ethtool -S br0 | grep ecnt_br_forward_br_forward' ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值