zoukankan      html  css  js  c++  java
  • vlan 介绍

    简介
         在Linux中安装了802.1Q标签VLAN功能。VLAN是虚拟分配以太网的功能。
    使用VLAN ID从物理上将一个以太网分割开。在VLAN环境下,具有相同VLAN ID
    就可以相互通信,但是即使将LAN线连接到相同集线器或交换机上,VLAN ID不同
    也不能相互通信。
     
    802.1Q的以太帧格式
     
    由上图,唯一的变化是加入了一对2字节字段。第一个2字节是VLAN协议标识符,
    它的值总是0x8100.由于这个数值大于1500,因此,所有的以太网卡都不会将
    它解释成类型(type),而不是长度。第二个2字节包含三个子字段。最主要的是
    VLAN标识符字段,它占用低12位。优先级和CFI的作用不明显,具体可以参考【1】的第4.8.5一节。
     
    vlan在网卡驱动及协议栈的处理
         以igb网卡为例,从napi的poll函数开始调用情况如下:
    igb_poll
         ==》
              igb_clean_rx_irq
              ==》
                   igb_receive_skb
                 
    在igb_clean_rx_irq实现中:
    5988
    5989         if (igb_test_staterr(rx_desc, E1000_RXDEXT_STATERR_LB) &&
    5990             test_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &rx_ring->flags))
    5991             vlan_tag = be16_to_cpu(rx_desc->wb.upper.vlan);
    5992         else
    5993             vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan);
    5994
    5995         total_bytes += skb->len;
    5996         total_packets++;
    5997
    5998         skb->protocol = eth_type_trans(skb, rx_ring->netdev);
    5999
    6000         igb_receive_skb(q_vector, skb, vlan_tag);
    6001
    View Code

    第5989到5993行会读取vlan_tag。

    函数igb_receive_skb的实现如下:

    5829 static void igb_receive_skb(struct igb_q_vector *q_vector,
    5830                             struct sk_buff *skb,
    5831                             u16 vlan_tag)
    5832 {
    5833     struct igb_adapter *adapter = q_vector->adapter;
    5834
    5835     if (vlan_tag && adapter->vlgrp)
    5836         vlan_gro_receive(&q_vector->napi, adapter->vlgrp,
    5837                          vlan_tag, skb);
    5838     else
    5839         napi_gro_receive(&q_vector->napi, skb);
    5840 }
    View Code
    内核模块捕获VLAN
         通过 vlan_gro_receive 和  napi_gro_receive的数据帧是有区别的。当我们使用命令
    vconfig add eth1 22 创建vlan设备后,数据帧将会通过vlan_gro_receive,否则将会通过
    napi_gro_receive到达netif_receive_skb。
         对于依然带有VLAN信息的数据包,捕获相应的数据包可采用jprobe的方法,按如下实现:
    int jpf_netif_receive_skb(struct sk_buff *skb)
    {
            unsigned short sport, dport;
            __be32 saddr, daddr;
            char dsthost[16];
            struct iphdr *iph;
            struct tcphdr *tcph;
    
            skb_linearize(skb);
            iph = (struct iphdr *)(skb->data + 4);
            tcph = (struct tcphdr *)((skb->data + 4) + (iph->ihl << 2));
    
            if (iph->protocol == IPPROTO_TCP) {
                    sport = tcph->source;
                    dport = tcph->dest;
                    saddr = iph->saddr;
                    daddr = iph->daddr;
    
                   snprintf(dsthost, 16, "%pI4", &daddr);
                   printk(KERN_INFO "ip is:%s", dsthost);
            }
            jprobe_return();
            return 0;
    }
     
    struct jprobe jps_netif_receive_skb = {
        .entry = jpf_netif_receive_skb,
        .kp = {
            .symbol_name = "netif_receive_skb",
        }, 
    };
    View Code
    如果vconfig的方式创建了VLAN设备,那么不需要对skb->data进行4字节的偏移就可以捕获到想要的数据包。
     
    参考资料
    【0】LINUX内核精髓(精通LINUX内核必会的75个技巧)
    【1】计算机网络 第5版 严伟,潘爱民译
  • 相关阅读:
    2. 两数相加
    1. 两数之和
    x-pack elasticsearch
    简单的文档
    PHP imagepng函数 问题
    Nginx 配置
    nginx内置变量
    TCP通信
    mysql 的一些操作
    ubuntu 软件包降级
  • 原文地址:https://www.cnblogs.com/lxgeek/p/4895464.html
Copyright © 2011-2022 走看看