Linux 网络协议栈开发代码分析篇之VLAN(一)—— vlan 功能模块分析

本文深入分析Linux 3.14版本的VLAN功能,包括相关数据结构如vlan_ethhdr、vlan_hdr、vlan_group,以及VLAN设备的添加、删除和配置流程。探讨了vlan_dev_hard_header、vlan_dev_hard_start_xmit等关键接口函数,并讨论了VLAN设备与socket模块的交互,以及在不同内核版本中VLAN处理的差异。
摘要由CSDN通过智能技术生成

整理自:http://blog.csdn.net/lickylin/article/details/41832967

本文代码基于linux3.14

      Vlan即虚拟局域网,一个vlan能够模拟一个常规的交换网络,实现了将一个物理的交换机划分成多个逻辑的交换网络。而不同的vlan之间如果要进行通信就要通过三层协议来实现。

     在linux中vlan的配置使用vconfig,使用vconfig配置一个交换网络,大致的流程如下:


# vconfig add eth0 100

# ifconfig eth0.100 up
# brctl  addbr br1
# ifconfig br1 up
# brctl addif br1 eth0.100
# brctl addif br1 eth2

这样就实现了将从eth0 口进来的vlan id 为100的数据流与eth2放在了一个逻辑交换网络中。

下面开始分析linux vlan模块


一、相关的数据结构

1.1 struct vlan_ethhdr

     包含vlan头部的二层头部结构体

/**
 *	struct vlan_ethhdr - vlan ethernet header (ethhdr + vlan_hdr)
 *	@h_dest: destination ethernet address
 *	@h_source: source ethernet address
 *	@h_vlan_proto: ethernet protocol
 *	@h_vlan_TCI: priority and VLAN ID
 *	@h_vlan_encapsulated_proto: packet type ID or len
 */
struct vlan_ethhdr {
	unsigned char	h_dest[ETH_ALEN];
	unsigned char	h_source[ETH_ALEN];
	__be16		h_vlan_proto;
	__be16		h_vlan_TCI;
	__be16		h_vlan_encapsulated_proto;
};

1.2 struct vlan_hdr

      vlan头部关联的结构体

/*
 * 	struct vlan_hdr - vlan header
 * 	@h_vlan_TCI: priority and VLAN ID
 *	@h_vlan_encapsulated_proto: packet type ID or len
 */
struct vlan_hdr {
	__be16	h_vlan_TCI;
	__be16	h_vlan_encapsulated_proto;
};

1.3 struct vlan_group 

     该结构体主要是实现将一个real device关联的vlan device设备存放在vlan_devices_arrays,(该变量首先是一个数组,数组里的每一个指针都是一个二级指针)

struct vlan_group {
	unsigned int		nr_vlan_devs;
	struct hlist_node	hlist;	/* linked list */
	struct net_device **vlan_devices_arrays[VLAN_PROTO_NUM]
					       [VLAN_GROUP_ARRAY_SPLIT_PARTS];
};

     该变量也是比较重要的一个数据结构,可以保证一个real device针对每一个vlan id创建的vlan device都是唯一的。

     Vlan group是通过全局变量vlan_group_hash的hash链表链接在一起的,其定义如下:

static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE];

      由于vlan device、real device都是使用的struct net_device变量,因此目前代码中,没有将vlan_group定义在net_device中,而是重新定义了一个全局的hash链表数组中。

      那么问题来了,可不可以在struct net_device中增加一个链表头指针,将该real device关联的vlan device设备都添加到该链表中呢?

      当然是可以的,这样做的话,在查找一个real device关联的所有vlan device时,其查找时间肯定比当前的查找时间要快的(因为不用进行hash相关的操作),但是每一个struct net_device变量都增加了一个链表指针,增加了对内存的使用,这个就需要在内存与性能之间做取舍了。

      相应的set与get的接口函数如下:

/*
功能:根据vlan id以及vlan_group变量,查找符合条件的vlan device
*/
static inline struct net_device *__vlan_group_get_device(struct vlan_group *vg,
							 unsigned int pidx,
							 u16 vlan_id)
{
	struct net_device **array;

	array = vg->vlan_devices_arrays[pidx]
				       [vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
	return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL;
}

static inline struct net_device *vlan_group_get_device(struct vlan_group *vg,
						       __be16 vlan_proto,
						       u16 vlan_id)
{
	return __vlan_group_get_device(vg, vlan_proto_idx(vlan_proto), vlan_id);
}

/*
功能:根据vlan id 以及vlan group变量,在vlan_devices_arrays中增加相应的vlan设备
     由于是直接增加设备,没有进行存在性判断,因此在调用该函数之前,
	 应该调用vlan_group_get_device判断要添加的vlan设备是否已存在。
*/
static inline void vlan_group_set_device(struct vlan_group *vg,
					 __be16 vlan_proto, u16 vlan_id,
					 struct net_device *dev)
{
	struct net_device **array;
	if (!vg)
		return;
	array = vg->vlan_devices_arrays[vlan_proto_idx(vlan_proto)]
				       [vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
	array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
}

1.4 struct vlan_dev_info 

     (linux3.14中没有找到该结构体定义)

     vlan设备相关的信息结构体

     该结构体定义了vlan device相关的一些信息,包括输入/输出方向优先级映射、vlan id、关联的real device、性能统计相关的信息等。

     该结构相关的变量被定义在struct net_device的priv指针变量指向的内存空间中。

/**
 *	struct vlan_dev_info - VLAN private device data
 *	@nr_ingress_mappings: number of ingress priority mappings
 *	@ingress_priority_map: ingress priority mappings
 *	@nr_egress_mappings: number of egress priority mappings
 *	@egress_priority_map: hash of egress priority mappings
 *	@vlan_id: VLAN identifier
 *	@flags: device flags
 *	@real_dev: underlying netdevice
 *	@real_dev_addr: address of underlying netdevice
 *	@dent: proc dir entry
 *	@cnt_inc_headroom_on_tx: statistic - number of skb expansions on TX
 *	@cnt_encap_on_xmit: statistic - number of skb encapsulations on TX
 */
struct vlan_dev_info {
	unsigned int				nr_ingress_mappings;
	u32					ingress_priority_map[8];
	unsigned int				nr_egress_mappings;
	struct vlan_priority_tci_mapping	*egress_priority_map[16];

	u16					vlan_id;
	u16					flags;

	struct net_device			*real_dev;
	unsigned char				real_dev_addr[ETH_ALEN];

	struct proc_dir_entry			*dent;
	unsigned long				cnt_inc_headroom_on_tx;
	unsigned long				cnt_encap_on_xmit;
};


以上就是主要相关的数据

  • 2
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值