机顶盒+AP 根据VLAN进行数据分流 技术实现

阅读: 评论:0

机顶盒+AP 根据VLAN进行数据分流 技术实现

机顶盒+AP 根据VLAN进行数据分流 技术实现

一、 Linux对VLAN数据的处理

(1)VLAN初始化

static struct packet_type vlan_packet_type __read_mostly = {

.type =cpu_to_be16(ETH_P_8021Q),

.func = vlan_skb_recv, /*VLAN receive method */

};

 

vlan_proto_init调用dev_add_pack(&vlan_packet_type)函数进行VLAN的注册,把ETH_P_8021Q 处理函数挂在ptype_base下,即数据接收的VLAN的入口函数为vlan_skb_recv

 

(2)VLAN数据处理

     内核中的vlan模块就是工作在协议栈里,通过注册dev_add_pack注册了8021Q的协议类型,netif_receive_skb->__netif_receive_skb遍历所有的协议类型时发现了它,于是进入了vlan的接收函数vlan_skb_recv(vlan_dev.c),这个函数里剥离vlan层,重置以太网层的proto,重新调用netif_rx进入真正的协议栈处理流程。

对于Linux,无论什么数据包通过网卡驱动后都会进入__netif_receive_skb函数。该函数中对VLAN的处理如下:

static int__netif_receive_skb(struct sk_buff *skb)

{

     … …

 

     //遍历ptye_all链表

     list_for_each_entry_rcu(ptype, &ptype_all,list) {

         if (ptype->dev == null_or_orig || ptype->dev ==skb->dev ||

             ptype->dev ==orig_dev) {

              if (pt_prev)

                   ret = deliver_skb(skb, pt_prev, orig_dev);

              pt_prev = ptype;

         }

     }

 

… …

 

     // bridge逻辑

     /* Handle special case of bridge or macvlan */

     rx_handler = rcu_dereference(skb->dev->rx_handler);

     if (rx_handler) {

         if (pt_prev) {

              ret = deliver_skb(skb, pt_prev, orig_dev);

              pt_prev = NULL;

         }

         skb = rx_handler(skb);

         if (!skb)

              goto out;

     }

 

     … …

 

     //遍历ptype_base

     type = skb->protocol;  //如果是VLAN,则这里type被置为VLAN协议,即0x8100(经过VLAN处理后,protocol会被重置)

     list_for_each_entry_rcu(ptype,

              &ptype_base[ntohs(type) & PTYPE_HASH_MASK],list) {

         if (ptype->type == type && (ptype->dev ==null_or_orig ||

              ptype->dev ==skb->dev || ptype->dev == orig_dev ||

              ptype->dev ==orig_or_bond)) {

              if (pt_prev){

                   // deliver_skb函数最终调用paket_type.func(),如果是VLAN,由于type为802.1Q的协议,所以会调用其对应的协议处理函数:vlan_skb_recv

                   ret = deliver_skb(skb, pt_prev, orig_dev);

}

              pt_prev = ptype;

         }

     }

 

     … …

}

 

二、 vlan_skb_recv函数解析

定义几个vlan接口和vlan ID相关的宏:

#define   MTC_STP_PACKET_VLAN_ID           4094

#define   MTC_WAN_VLAN_ID                  2

#define   MTC_LAN_VLAN_ID                  1

#define   MTC_WAN_IFNAME                   "eth2.2"

#define   MTC_LAN_IFNAME                   "eth2.1"

 

int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,

       struct packet_type *ptype, struct net_device*orig_dev)

{

… …

 

// 从skb解析出对应的vlan_id

vhdr = (struct vlan_hdr*)skb->data;

vlan_tci =ntohs(vhdr->h_vlan_TCI);

vlan_id = vlan_tci &VLAN_VID_MASK;

    

… …

 

//这里dev指向的是真实的dev,通过__find_vlan_dev函数根据vlan_id找到对应接口的dev(比如现在用的系统真实dev接口名称为eth2; vlan_id==1的接口名称为eth2.1; vlan_id==2的接口名称为eth2.2)

vlan_dev =__find_vlan_dev(dev, vlan_id);

 

//以下处理是为了确保vlan_id为非1和非2的时候数据包不会被丢掉

#ifdef PRODUCT_MT7628STPAP_MTC

/*

There is not any device attachto the MTC_STP_PACKET_VLAN_ID(4094) vlan id,

In order to pass the normalprocessing of vlan_skb_recv function,

we set the vlan_dev toMTC_WAN_IFNAME(eth2.2).

by wwk,20170426

*/

if(MTC_STP_PACKET_VLAN_ID ==vlan_id_back)         

{              

     vlan_dev = __dev_get_by_name(&init_net,MTC_LAN_IFNAME);

}  

#endif

 

/* If the VLAN device isdefined, we use it.

 * If not, and the VID is 0, it is a 802.1ppacket (not

 * really a VLAN), so we will just netif_rx itlater to the

 * original interface, but with the skb->protoset to the

 * wrapped proto: we do nothing here.

 */

if (!vlan_dev) {

     if (vlan_id) {

          pr_debug("%s:ERROR: No net_device for VID: %u on dev: %sn",

                __func__, vlan_id, dev->name);

 

          //如果通过上面的函数__find_vlan_dev没找到vlan_dev,则把数据包扔掉,当前系统默认仅支持MTC_WAN_IFNAME和MTC_LAN_IFNAME,即VLAN ID为2和VLAN ID为1的VLAN

          goto err_unlock;

     }

     else

     {

          … …

}

} else {

     … …

}

 

//以下为对从WAN进来的包进行处理:从WAN进来的包copy一份同步发到LAN端,发送之前把把vlan_id设置为4096

#ifdef PRODUCT_MT7628STPAP_MTC

/*

if pkg from vlanMTC_WAN_VLAN_ID, then forward one copy to MTC_LAN_IFNAME(vlan_id isMTC_STP_PACKET_VLAN_ID)

<wan-->add 4096vlan_tag-->vlan 4096-->send pkg from MTC_LAN_IFNAME interface>

Must be called beforeskb_pull_rcsum() ,vlan_set_encap_proto() and vlan_check_reorder_header()

by wwk,20170426

*/

… … //实现细节

#endif

 

//使用以下三个函数用来剥离VLAN层和重置以太网层的proto: skb_pull_rcsum、vlan_set_encap_proto、vlan_check_reorder_header

 

skb_pull_rcsum(skb,VLAN_HLEN);

vlan_set_encap_proto(skb,vhdr);

 

if (vlan_dev) {

     skb = vlan_check_reorder_header(skb);

     if (!skb) {

          rx_stats->rx_errors++;

          goto err_unlock;

     }

}

 

#ifdef PRODUCT_MT7628STPAP_MTC

if(MTC_LAN_VLAN_ID ==vlan_id_back)

{          

    //  从MTC_LAN_IFNAME进来的数据包,视情况对VLAN进行处理

     … … //实现细节

}

 

//if pkg from vlanMTC_STP_PACKET_VLAN_ID, then forward to MTC_WAN_IFNAME

 if(MTC_STP_PACKET_VLAN_ID == vlan_id_back)

{              

     … … //实现细节

     /*

     There is not any deviceattach to the MTC_STP_PACKET_VLAN_ID(4094) vlan id,

     so don't need netif_rx skbagain

     */

     goto err_unlock;

}  

#endif

//netif_rx函数会让数据包重新进入__netif_receive_skb函数处理

netif_rx(skb);

 

rcu_read_unlock();

return NET_RX_SUCCESS;

 

err_unlock:

rcu_read_unlock();

err_free:

kfree_skb(skb);

return NET_RX_DROP;

}

 

数据包进来后先修改为对应的vlan_id,然后直接通过dev_queue_xmit函数把数据包发出去,仅对对应的VLAN包进行转发,其他数据包按照路由器的处理机制处理。

通过以上处理,实现VLAN数据的分流。


本文发布于:2024-02-01 13:41:42,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170676610237006.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:机顶盒   数据   技术   VLAN   AP
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23