java中的接口是类吗
438
2022-10-12
Linux内核中VLAN的实现过程(6)-设备打开、关闭和数据发送(划分vlan的命令)
Linux内核中VLAN的实现过程(6)
本节主要关注和解析vlan设备的打开、关闭以及数据发送实现,代码位于net/8021q/vlan_dev.c文件中。
打开设备
static int vlan_dev_open(struct net_device *dev) { // 获取vlan设备的私有信息 struct vlan_dev_priv *vlan = vlan_dev_priv(dev); // 宿主设备 struct net_device *real_dev = vlan->real_dev; int err; if (!(real_dev->flags & IFF_UP) && !(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) return -ENETDOWN; // 检查设备mac地址:vlan设备mac地址等于宿主设备mac地址 if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr) && !vlan_dev_inherit_address(dev, real_dev)) { // 为vlan设备添加第二个单播mac地址(Add a secondary unicast address to the device or increase the reference count if it already exists.) err = dev_uc_add(real_dev, dev->dev_addr); if (err < 0) goto out; } // allmulti如promiscuity一样,是一个计数器而不是简单的布尔值。当此变量由0变为非0时,就会调用dev_set_allmulti函数,以指示该端口监听所有的多播地址;当allmulti变为0时则反之。 if (dev->flags & IFF_ALLMULTI) { // 设备监听所有多播地址 err = dev_set_allmulti(real_dev, 1); if (err < 0) goto del_unicast; } if (dev->flags & IFF_PROMISC) { // 开启混杂模式 err = dev_set_promiscuity(real_dev, 1); if (err < 0) goto clear_allmulti; } // 宿主设备的mac保存到vlan设备私有信息中 ether_addr_copy(vlan->real_dev_addr, real_dev->dev_addr); // 加入GARP VLAN注册协议 if (vlan->flags & VLAN_FLAG_GVRP) vlan_gvrp_request_join(dev); // 加入Multiple VLAN注册协议 if (vlan->flags & VLAN_FLAG_MVRP) vlan_mvrp_request_join(dev); /* 网卡在物理上具有载波侦听的功能,当网络连接完整或者网络链接断开时,网卡芯片硬件会自动设置寄存器标志位来标识。 如网线链接断开的时候,会将LinkSts清位;重新链接网线,则硬件自动将此位置位。 这样,在网卡驱动中读写该位信息就可一判断网络是否链接通路。 网卡驱动程序通过netif_carrier_on/netif_carrier_off/netif_carrier_ok来和内核网络子系统传递信息。 netif_carrier_on:告诉内核子系统网络链接完整。 netif_carrier_off:告诉内核子系统网络断开。 netif_carrier_ok:查询网络断开还是链接。 */ // 设置网络连接 if (netif_carrier_ok(real_dev) && !(vlan->flags & VLAN_FLAG_BRIDGE_BINDING)) netif_carrier_on(dev); return 0; clear_allmulti: if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(real_dev, -1); del_unicast: if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr)) dev_uc_del(real_dev, dev->dev_addr); out: // 设置网络断开 netif_carrier_off(dev); return err; }
关闭设备
static int vlan_dev_stop(struct net_device *dev) { struct vlan_dev_priv *vlan = vlan_dev_priv(dev); struct net_device *real_dev = vlan->real_dev; // 删除由 dev_mc_sync() 添加到目标设备的所有地址 dev_mc_unsync(real_dev, dev); // 删除由 dev_uc_sync() 添加到目标设备的所有地址 dev_uc_unsync(real_dev, dev); // 关闭多播 if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(real_dev, -1); // 关闭混杂 if (dev->flags & IFF_PROMISC) dev_set_promiscuity(real_dev, -1); // 移除单播mac地址 if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr)) dev_uc_del(real_dev, dev->dev_addr); // 设置网络断开 if (!(vlan->flags & VLAN_FLAG_BRIDGE_BINDING)) netif_carrier_off(dev); return 0; }
发送数据
static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct vlan_dev_priv *vlan = vlan_dev_priv(dev); // 带vlan的以太网头 struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); unsigned int len; int ret; /* Handle non-VLAN frames if they are sent to us, for example by DHCP. * * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs... */ if (veth->h_vlan_proto != vlan->vlan_proto || vlan->flags & VLAN_FLAG_REORDER_HDR) { // 无vlan tag,则添加vlan tag u16 vlan_tci; vlan_tci = vlan->vlan_id; // 获取出口qos优先级 vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb->priority); // 添加vlan tag __vlan_hwaccel_put_tag(skb, vlan->vlan_proto, vlan_tci); } // 修改数据包发送网卡为宿主设备 skb->dev = vlan->real_dev; len = skb->len; // 如果ndo_start_xmit是由netpool调用,则返回非零值 if (unlikely(netpoll_tx_running(dev))) // 使用netpool发送数据包 return vlan_netpoll_send_skb(vlan, skb); // 将数据包加入发送队列 ret = dev_queue_xmit(skb); // dev_queue_xmit返回成功或者拥塞 if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { struct vlan_pcpu_stats *stats; stats = this_cpu_ptr(vlan->vlan_pcpu_stats); // 序列计数器 u64_stats_update_begin(&stats->syncp); // 更新设备统计信息:发包个数和发包字节数 stats->tx_packets++; stats->tx_bytes += len; u64_stats_update_end(&stats->syncp); } else { // 丢弃,并更新设备统计信息:丢包个数 this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped); } return ret; } static inline netdev_tx_t vlan_netpoll_send_skb(struct vlan_dev_priv *vlan, struct sk_buff *skb) { #ifdef CONFIG_NET_POLL_CONTROLLER // 使用netpool发送数据包 return netpoll_send_skb(vlan->netpoll, skb); #else BUG(); return NETDEV_TX_OK; #endif }
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~