Linux網卡混雜模式下收到mac地址不是本身的mac是否會上送網絡層處理

實驗環境

image.png
注:在ubuntu18:04環境中,建立了一個網絡命名空間mac,使用veth網卡與系統互聯。peer爲veth1,本端爲eth0。系統中海油一個docker0網卡,具體參數如上圖所示。docker

配置以下

sudo ip netns add mac
sudo ip link add veth1 type veth peer name eth0 netns mac
sudo ip link set veth1 up
sudo ip addr add 10.10.10.1/24 dev veth1
sudo ip link  set veth1 address 00:01:02:03:04:05 
sudo ip netns exec mac ip link 
sudo ip netns exec mac ip link set lo up
sudo ip netns exec mac ip link set eth0 up
sudo ip netns exec mac ip addr add 10.10.10.2/24 dev eth0
sudo ip netns exec mac ip route add default via 10.10.10.1 dev eth0

實驗

實驗1 ping網關

admin@ubuntu:~$ sudo ip netns exec mac ping 10.10.10.1
PING 10.10.10.1 (10.10.10.1) 56(84) bytes of data.
64 bytes from 10.10.10.1: icmp_seq=1 ttl=64 time=0.050 ms

--- 10.10.10.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.050/0.050/0.050/0.000 ms
admin@ubuntu:~$ 
#查看鄰居,是咱們網關veth0的地址
admin@ubuntu:~$ sudo ip netns exec mac ip neigh
10.10.10.1 dev eth0 lladdr 00:01:02:03:04:05 REACHABLE
admin@ubuntu:~$

實驗2 修改鄰居表,將網關地址改爲系統中另一個設備docker0的mac地址

admin@ubuntu:~$ ip link show docker0 
7: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default 
    link/ether 02:42:83:ca:a5:f3 brd ff:ff:ff:ff:ff:ff
admin@ubuntu:~$ 
admin@ubuntu:~$ sudo ip netns exec mac ip neigh replace 10.10.10.1 lladdr 02:42:83:ca:a5:f3 dev eth0
admin@ubuntu:~$ sudo ip netns exec mac ip neigh 
10.10.10.1 dev eth0 lladdr 02:42:83:ca:a5:f3 PERMANENT
admin@ubuntu:~$ 
#繼續ping網關,不能夠ping通
admin@ubuntu:~$ sudo ip netns exec mac ping 10.10.10.1 -c 1
PING 10.10.10.1 (10.10.10.1) 56(84) bytes of data.

--- 10.10.10.1 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

admin@ubuntu:~$ 

#在端口上抓包能夠看到目的mac爲02:42:83:ca:a5:f3
admin@ubuntu:~$ sudo tcpdump -i veth1 -eevvnn
tcpdump: listening on veth1, link-type EN10MB (Ethernet), capture size 262144 bytes
03:57:23.746932 aa:1b:28:83:ee:b5 > 02:42:83:ca:a5:f3, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 7402, offset 0, flags [DF], proto ICMP (1), length 84)
    10.10.10.2 > 10.10.10.1: ICMP echo request, id 10034, seq 12, length 64
3 packets captured
3 packets received by filter
0 packets dropped by kernel
admin@ubuntu:~$

實驗3 在錯誤的mac地址下,ping docker0上的IP:172.17.0.1。即發送的報文是docker0的IP地址和mac地址

# 能夠看到不能ping通
admin@ubuntu:~$ sudo ip netns exec mac ping 172.17.0.1 -c 1         
PING 172.17.0.1 (172.17.0.1) 56(84) bytes of data.

--- 172.17.0.1 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

admin@ubuntu:~$ 
#報文如咱們預期
admin@ubuntu:~$ sudo tcpdump -i veth1 -eevvnn
tcpdump: listening on veth1, link-type EN10MB (Ethernet), capture size 262144 bytes
04:01:39.957123 aa:1b:28:83:ee:b5 > 02:42:83:ca:a5:f3, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 65477, offset 0, flags [DF], proto ICMP (1), length 84)
    10.10.10.2 > 172.17.0.1: ICMP echo request, id 10113, seq 1, length 64

結論

在網卡開啓混雜模式下,網卡能夠接收目的MAC不是本機的報文,報文只會在鏈路層處理,不會送到網絡層。即便對應的mac地址是系統中的另一個網卡的mac地址。shell

查看代碼

咱們以intel的igb網卡爲例進行分析,在該網卡的驅動代碼中有以下函數:ubuntu

/**
 *  igb_process_skb_fields - Populate skb header fields from Rx descriptor
 *  @rx_ring: rx descriptor ring packet is being transacted on
 *  @rx_desc: pointer to the EOP Rx descriptor
 *  @skb: pointer to current skb being populated
 *
 *  This function checks the ring, descriptor, and packet information in
 *  order to populate the hash, checksum, VLAN, timestamp, protocol, and
 *  other fields within the skb.
 **/
static void igb_process_skb_fields(struct igb_ring *rx_ring,
                   union e1000_adv_rx_desc *rx_desc,
                   struct sk_buff *skb)
{
    struct net_device *dev = rx_ring->netdev;

    igb_rx_hash(rx_ring, rx_desc, skb);

    igb_rx_checksum(rx_ring, rx_desc, skb);

    if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TS) &&
        !igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP))
        igb_ptp_rx_rgtstamp(rx_ring->q_vector, skb);

    if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
        igb_test_staterr(rx_desc, E1000_RXD_STAT_VP)) {
        u16 vid;

        if (igb_test_staterr(rx_desc, E1000_RXDEXT_STATERR_LB) &&
            test_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &rx_ring->flags))
            vid = be16_to_cpu(rx_desc->wb.upper.vlan);
        else
            vid = le16_to_cpu(rx_desc->wb.upper.vlan);

        __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
    }

    skb_record_rx_queue(skb, rx_ring->queue_index);
    //調用eth_type_trans函數肯定網絡層協議類型
    skb->protocol = eth_type_trans(skb, rx_ring->netdev);
}
/**
 * eth_type_trans - determine the packet's protocol ID.
 * @skb: received socket data
 * @dev: receiving network device
 *
 * The rule here is that we
 * assume 802.3 if the type field is short enough to be a length.
 * This is normal practice and works for any 'now in use' protocol.
 */
__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
    unsigned short _service_access_point;
    const unsigned short *sap;
    const struct ethhdr *eth;

    skb->dev = dev;
    skb_reset_mac_header(skb);

    eth = (struct ethhdr *)skb->data;
    skb_pull_inline(skb, ETH_HLEN);
    // 肯定報文的類型,廣播,組播,單播
    if (unlikely(is_multicast_ether_addr_64bits(eth->h_dest))) {
        if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast))
            skb->pkt_type = PACKET_BROADCAST;
        else
            skb->pkt_type = PACKET_MULTICAST;
    }
    // 單播報文,比較是否與本設備的mac地址一致,不一致則設置skb->pkt_type = PACKET_OTHERHOST;
    else if (unlikely(!ether_addr_equal_64bits(eth->h_dest,
                           dev->dev_addr)))
        skb->pkt_type = PACKET_OTHERHOST;

    ......
}
EXPORT_SYMBOL(eth_type_trans);

從上面的代碼能夠看出,對於報文的目的MAC不是本機的單播報文會設置skb->pkt_type = PACKET_OTHERHOST。網絡

咱們繼續看網絡層如何處理該字段:

/*
 *     Main IP Receive routine.
 */
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
    const struct iphdr *iph;
    struct net *net;
    u32 len;

    /* When the interface is in promisc. mode, drop all the crap
     * that it receives, do not try to analyse it.
     * 對於skb->pkt_type == PACKET_OTHERHOST的報文(目的MAC不是本機)直接丟棄
     * 並且在NF_INET_PRE_ROUTING節點以前。
     */
    if (skb->pkt_type == PACKET_OTHERHOST)
        goto drop;

    ......

    return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
               net, NULL, skb, dev, NULL,
               ip_rcv_finish);

csum_error:
    __IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS);
inhdr_error:
    __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
drop:
    kfree_skb(skb);
out:
    return NET_RX_DROP;
}
相關文章
相關標籤/搜索