docker 默认 bridge

目前 C1容器内的ping -> c1 容器内的网卡eth0 -> 宿主机内的vethacea5a5-> 宿主机内的Linux Bridge -> 宿主机内Bridge 上的vethb7b238f-> C2 容器内的网卡eth0

 

docker exec xxxx  ping 192.168.222.2 -c2 -W1
PING 192.168.222.2 (192.168.222.2) 56(84) bytes of data.
64 bytes from 192.168.222.2: icmp_seq=1 ttl=64 time=0.613 ms
64 bytes from 192.168.222.2: icmp_seq=2 ttl=64 time=0.110 ms

网络不通;

目前netfilter配置

# cat /proc/sys/net/bridge/bridge-nf-call-iptables
1

同时配置了ip_forward

iptables被告知要干涉Linux Bridge的封包管理后,所有经过的封包都会让iptables来进行检查,但是此时配置了ip_forward = 1

当前结论是通的。

如果关闭ip_forwading;还是能ping通

sysctl  -w net.ipv4.ip_forward=0
net.ipv4.ip_forward = 0
docker exec xxxx  ping 192.168.222.2  -c2 -W1
PING 192.168.222.2 (192.168.222.2) 56(84) bytes of data.
64 bytes from 192.168.222.2: icmp_seq=1 ttl=64 time=0.060 ms
64 bytes from 192.168.222.2: icmp_seq=2 ttl=64 time=0.108 ms

--- 192.168.222.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms

如果此时:还是通的

echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables
[root@localhost ~]# cat /proc/sys/net/bridge/bridge-nf-call-iptables
0


docker exec xxxx  ping 192.168.222.2  -c2 -W1
PING 192.168.222.2 (192.168.222.2) 56(84) bytes of data.
64 bytes from 192.168.222.2: icmp_seq=1 ttl=64 time=0.048 ms
64 bytes from 192.168.222.2: icmp_seq=2 ttl=64 time=0.090 ms

--- 192.168.222.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms

 

如果默认 forward drop;iptables -P FORWARD DROP默认策略(policy)整个 FORWARD 链在无匹配规则时的最终默认处理方式

iptables -P FORWARD DROP
[root@localhost ~]# docker exec xxx  ping 192.168.222.2  -c2 -W1
PING 192.168.222.2 (192.168.222.2) 56(84) bytes of data.
64 bytes from 192.168.222.2: icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from 192.168.222.2: icmp_seq=2 ttl=64 time=0.088 ms

--- 192.168.222.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.046/0.067/0.088/0.021 ms
[root@localhost ~]# iptables --policy FORWARD DROP
[root@localhost ~]# docker exec xxx   ping 192.168.222.2  -c2 -W1
PING 192.168.222.2 (192.168.222.2) 56(84) bytes of data.
64 bytes from 192.168.222.2: icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from 192.168.222.2: icmp_seq=2 ttl=64 time=0.089 ms

--- 192.168.222.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.046/0.067/0.089/0.023 ms

 

bridge 需要iptable过滤打开;也正常

cat  /proc/sys/net/bridge/bridge-nf-call-iptables
1
[root@localhost ~]# docker exec xxx  ping 192.168.222.2  -c2 -W1
PING 192.168.222.2 (192.168.222.2) 56(84) bytes of data.
64 bytes from 192.168.222.2: icmp_seq=1 ttl=64 time=0.064 ms
64 bytes from 192.168.222.2: icmp_seq=2 ttl=64 time=0.106 ms

--- 192.168.222.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.064/0.085/0.106/0.021 ms

 

 

此时环境下:

关闭 ip_forward、设置 FORWARD DROP、关闭 bridge-nf-call-iptables,容器之间的 ping 仍然是通的!

bridge 网络中,容器之间通过 veth pair + bridge 转发数据,内核层面是 L2 以太网转发,可能不会进入 FORWARD 链或被 ip_forward 控制。

此时 bridge-nf-call-iptables 打开 ;同时 FORWARD DROP 还是能ping通;开下bridge--->ebtale---iptable 的路径代码?

 

iptables -I FORWARD 1 -j DROP
[root@localhost ~]# docker exec xxxx   ping 192.168.222.2  -c2 -W1
PING 192.168.222.2 (192.168.222.2) 56(84) bytes of data.

--- 192.168.222.2 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1000ms

 

也就是环境里面有别的rule,会forward,即使默认drop都不行,只能在第一条插入drop才行

测试一下bridge-nfcall-iptable为0时,不调用iptable来处理,此时不涉及到iptable forward;结果是可以ping通,


[root@localhost ~]# cat  /proc/sys/net/bridge/bridge-nf-call-iptables
1
[root@localhost ~]# echo "0" >   /proc/sys/net/bridge/bridge-nf-call-iptables
[root@localhost ~]# docker exec xxxx  ping 192.168.222.2  -c2 -W1
PING 192.168.222.2 (192.168.222.2) 56(84) bytes of data.
64 bytes from 192.168.222.2: icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from 192.168.222.2: icmp_seq=2 ttl=64 time=0.085 ms

--- 192.168.222.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.046/0.065/0.085/0.021 ms

测试一下bridge-nfcall-iptable为0时,不调用iptable来处理, 此时“ebtables 默认 FORWARD DROP or ACCEPT 决定结果

[root@ubuntu22 ~]# ebtables -L
Bridge table: filter

Bridge chain: INPUT, entries: 1, policy: ACCEPT
--log-level debug --log-prefix "ebtable/filter-INPUT" -j CONTINUE

Bridge chain: FORWARD, entries: 1, policy: ACCEPT
--log-level debug --log-prefix "ebtable/filter-FORWARD" -j CONTINUE

Bridge chain: OUTPUT, entries: 1, policy: ACCEPT
--log-level debug --log-prefix "ebtable/filter-OUTPUT" -j CONTINUE
[root@ubuntu22 ~]# 
[root@ubuntu22 ~]# ebtables -P FORWARD DROP
[root@ubuntu22 ~]# docker exec xxx  ping 192.168.222.2  -c2 -W1
PING 192.168.222.2 (192.168.222.2) 56(84) bytes of data.

--- 192.168.222.2 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1025ms

[root@ubuntu22 ~]# ^C
[root@ubuntu22 ~]# ebtables -P FORWARD ACCEPT
[root@ubuntu22 ~]# docker exec xx  ping 192.168.222.2  -c2 -W1
PING 192.168.222.2 (192.168.222.2) 56(84) bytes of data.
64 bytes from 192.168.222.2: icmp_seq=1 ttl=64 time=0.064 ms
64 bytes from 192.168.222.2: icmp_seq=2 ttl=64 time=0.102 ms

--- 192.168.222.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1037ms
rtt min/avg/max/mdev = 0.064/0.083/0.102/0.019 ms

也就是br_forward 的时候 会涉及到bridge的forward 等链处理;

br_handle_frame 为bridge 报文input入口,根据

 详细代码就不看了,就是二层交换机处理逻辑

static int nf_hook_bridge_pre(struct sk_buff *skb, struct sk_buff **pskb)
{
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
    struct nf_hook_entries *e = NULL;
    struct nf_hook_state state;
    unsigned int verdict, i;
    struct net *net;
    int ret;

    net = dev_net(skb->dev);
#ifdef HAVE_JUMP_LABEL
    if (!static_key_false(&nf_hooks_needed[NFPROTO_BRIDGE][NF_BR_PRE_ROUTING]))
        goto frame_finish;
#endif

    e = rcu_dereference(net->nf.hooks_bridge[NF_BR_PRE_ROUTING]);
    if (!e)
        goto frame_finish;

    nf_hook_state_init(&state, NF_BR_PRE_ROUTING,
               NFPROTO_BRIDGE, skb->dev, NULL, NULL,
               net, br_handle_frame_finish);

    for (i = 0; i < e->num_hook_entries; i++) {
        verdict = nf_hook_entry_hookfn(&e->hooks[i], skb, &state);
        switch (verdict & NF_VERDICT_MASK) {
        case NF_ACCEPT:
            if (BR_INPUT_SKB_CB(skb)->br_netfilter_broute) {
                *pskb = skb;
                return RX_HANDLER_PASS;
            }
            break;
        case NF_DROP:
            kfree_skb(skb);
            return RX_HANDLER_CONSUMED;
        case NF_QUEUE:
            ret = nf_queue(skb, &state, i, verdict);
            if (ret == 1)
                continue;
            return RX_HANDLER_CONSUMED;
        default: /* STOLEN */
            return RX_HANDLER_CONSUMED;
        }
    }
frame_finish:
    net = dev_net(skb->dev);
    br_handle_frame_finish(net, NULL, skb);
#else
    br_handle_frame_finish(dev_net(skb->dev), NULL, skb);
#endif
    return RX_HANDLER_CONSUMED;
}

 

static void __br_forward(const struct net_bridge_port *to,
             struct sk_buff *skb, bool local_orig)
{
    struct net_bridge_vlan_group *vg;
    struct net_device *indev;
    struct net *net;
    int br_hook;

    vg = nbp_vlan_group_rcu(to);
    skb = br_handle_vlan(to->br, to, vg, skb);
    if (!skb)
        return;

    indev = skb->dev;
    skb->dev = to->dev;
    if (!local_orig) {
        if (skb_warn_if_lro(skb)) {
            kfree_skb(skb);
            return;
        }
        br_hook = NF_BR_FORWARD;
        skb_forward_csum(skb);
        net = dev_net(indev);
    } else {
        if (unlikely(netpoll_tx_running(to->br->dev))) {
            skb_push(skb, ETH_HLEN);
            if (!is_skb_forwardable(skb->dev, skb))
                kfree_skb(skb);
            else
                br_netpoll_send_skb(to, skb);
            return;
        }
        br_hook = NF_BR_LOCAL_OUT;
        net = dev_net(skb->dev);
        indev = NULL;
    }

    NF_HOOK(NFPROTO_BRIDGE, br_hook,
        net, NULL, skb, indev, skb->dev,
        br_forward_finish);
}

 

posted @ 2025-05-14 19:48  codestacklinuxer  阅读(32)  评论(0)    收藏  举报