3.2 register_pernet_subsys [net\\8021q\\vlan.c]
register_pernet_subsys函数调用关系:
register_pernet_subsys()->register_pernet_operations()->ida_get_new_above() 而ida_get_new_above的作用如它注释所描述的。分配一个新的ID大于等于一个起始ID
ida_get_new_above():ida_get_new_above - allocate new ID above or equal to a start id。
另外register_pernet_operations()中通过调用 __register_pernet_operations函数,再通过调用ops_init(ops, &init_net),调用会调用子空间的初始化函数vlan_init_net(),而vlan_init_net()的作用就是有关vlan的proc文件系统信息。
即register_pernet_operations()的调用关系如下: register_pernet_operations()->__register_pernet_operations()->ops_init()->vlan_init_net() 3.3 register_netdevice_notifier [/net/core/dev.c]
当使用SIOCBRADDBR调用ioctl时,会通过br_add_bridge函数创建新的网桥。在这 err = register_netdevice_notifier(&vlan_notifier_block); static struct notifier_block vlan_notifier_block __read_mostly = { .notifier_call = vlan_device_event, };
参考http://blog.csdn.net/qy532846454/article/details/6529166,分析的很详细
3.4 dev_add_pack [/net/core/dev.c]
void dev_add_pack(struct packet_type *pt) {
struct list_head *head = ptype_head(pt); spin_lock(&ptype_lock); list_add_rcu(&pt->list, head); spin_unlock(&ptype_lock); }
static struct packet_type vlan_packet_type __read_mostly = { .type = cpu_to_be16(ETH_P_8021Q),
.func = vlan_skb_recv, /* VLAN receive method */ };
参考http://blog.csdn.net/qy532846454/article/details/6529166,里面相关部分很详细
3.5 vlan_skb_recv [/net/core/dev.c]
int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) {
struct vlan_hdr *vhdr;
struct vlan_pcpu_stats *rx_stats; struct net_device *vlan_dev; u16 vlan_id; u16 vlan_tci;
skb = skb_share_check(skb, GFP_ATOMIC); //检查skb是否被多个协议模块引用 if (skb == NULL) goto err_free;
if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) goto err_free;
vhdr = (struct vlan_hdr *)skb->data; vlan_tci = ntohs(vhdr->h_vlan_TCI); vlan_id = vlan_tci & VLAN_VID_MASK;
rcu_read_lock();
vlan_dev = vlan_find_dev(dev, vlan_id);
/* If the VLAN device is defined, we use it.
if (!vlan_dev) { if (vlan_id) {
pr_debug(\ __func__, vlan_id, dev->name); goto err_unlock; }
rx_stats = NULL; } else {
skb->dev = vlan_dev; //设置skb->dev为虚拟vlan设备
rx_stats = this_cpu_ptr(vlan_dev_info(skb->dev)->vlan_pcpu_stats);
u64_stats_update_begin(&rx_stats->syncp); //更新网卡接收报文的信息 rx_stats->rx_packets++; rx_stats->rx_bytes += skb->len;
skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);
pr_debug(\ __func__, skb->priority, vlan_tci);
switch (skb->pkt_type) { case PACKET_BROADCAST:
* If not, and the VID is 0, it is a 802.1p packet (not * really a VLAN), so we will just netif_rx it later to the * original interface, but with the skb->proto set to the * wrapped proto: we do nothing here. */
/* Yeah, stats collect these together.. */ /* stats->broadcast ++; // no such counter :-( */ break;
case PACKET_MULTICAST: rx_stats->rx_multicast++; break;
case PACKET_OTHERHOST:
/* Our lower layer thinks this is not local, let's make
* sure.
* This allows the VLAN to have a different MAC than the * underlying device, and still route correctly. */
if (!compare_ether_addr(eth_hdr(skb)->h_dest, skb->dev->dev_addr)) skb->pkt_type = PACKET_HOST; break; default: break; }
u64_stats_update_end(&rx_stats->syncp); }
skb_pull_rcsum(skb, VLAN_HLEN); //偏移过vlan标签
vlan_set_encap_proto(skb, vhdr); //重置skb->protocol为vlan标签后面接的协议类型,之前的protocol为0x8100(即ETH_P_8021Q)
if (vlan_dev) {
skb = vlan_check_reorder_header(skb); if (!skb) {
rx_stats->rx_errors++;
goto err_unlock; } }
netif_rx(skb); //将skb重新放入接收队列中,让skb在协议栈中继续向上走
rcu_read_unlock(); return NET_RX_SUCCESS;
err_unlock:
rcu_read_unlock(); err_free:
atomic_long_inc(&dev->rx_dropped); kfree_skb(skb); return NET_RX_DROP; }
3.5 vlan_ioctl_set [ /net/socket.c]
void vlan_ioctl_set(int (*hook) (struct net *, void __user *)) {
mutex_lock(&vlan_ioctl_mutex); vlan_ioctl_hook = hook;
mutex_unlock(&vlan_ioctl_mutex); }