Commit 1fd9b1fc authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

net: vlan: prepare for 802.1ad support

Make the encapsulation protocol value a property of VLAN devices and change
the device lookup functions to take the protocol value into account.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 80d5c368
...@@ -782,7 +782,7 @@ static void bond_resend_igmp_join_requests(struct bonding *bond) ...@@ -782,7 +782,7 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
/* rejoin all groups on vlan devices */ /* rejoin all groups on vlan devices */
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
vlan_dev = __vlan_find_dev_deep(bond_dev, vlan_dev = __vlan_find_dev_deep(bond_dev, htons(ETH_P_8021Q),
vlan->vlan_id); vlan->vlan_id);
if (vlan_dev) if (vlan_dev)
__bond_resend_igmp_join_requests(vlan_dev); __bond_resend_igmp_join_requests(vlan_dev);
...@@ -2512,7 +2512,8 @@ static int bond_has_this_ip(struct bonding *bond, __be32 ip) ...@@ -2512,7 +2512,8 @@ static int bond_has_this_ip(struct bonding *bond, __be32 ip)
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
rcu_read_lock(); rcu_read_lock();
vlan_dev = __vlan_find_dev_deep(bond->dev, vlan->vlan_id); vlan_dev = __vlan_find_dev_deep(bond->dev, htons(ETH_P_8021Q),
vlan->vlan_id);
rcu_read_unlock(); rcu_read_unlock();
if (vlan_dev && ip == bond_confirm_addr(vlan_dev, 0, ip)) if (vlan_dev && ip == bond_confirm_addr(vlan_dev, 0, ip))
return 1; return 1;
...@@ -2541,7 +2542,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ ...@@ -2541,7 +2542,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_
return; return;
} }
if (vlan_id) { if (vlan_id) {
skb = vlan_put_tag(skb, vlan_id); skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_id);
if (!skb) { if (!skb) {
pr_err("failed to insert VLAN tag\n"); pr_err("failed to insert VLAN tag\n");
return; return;
...@@ -2603,6 +2604,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) ...@@ -2603,6 +2604,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
rcu_read_lock(); rcu_read_lock();
vlan_dev = __vlan_find_dev_deep(bond->dev, vlan_dev = __vlan_find_dev_deep(bond->dev,
htons(ETH_P_8021Q),
vlan->vlan_id); vlan->vlan_id);
rcu_read_unlock(); rcu_read_unlock();
if (vlan_dev == rt->dst.dev) { if (vlan_dev == rt->dst.dev) {
......
...@@ -185,7 +185,7 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter, ...@@ -185,7 +185,7 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter,
if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) { if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
rcu_read_lock(); rcu_read_lock();
if (vlan && vlan != VLAN_VID_MASK) { if (vlan && vlan != VLAN_VID_MASK) {
dev = __vlan_find_dev_deep(dev, vlan); dev = __vlan_find_dev_deep(dev, htons(ETH_P_8021Q), vlan);
} else if (netif_is_bond_slave(dev)) { } else if (netif_is_bond_slave(dev)) {
struct net_device *upper_dev; struct net_device *upper_dev;
......
...@@ -3346,7 +3346,7 @@ void qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event) ...@@ -3346,7 +3346,7 @@ void qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
rcu_read_lock(); rcu_read_lock();
for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) { for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) {
dev = __vlan_find_dev_deep(netdev, vid); dev = __vlan_find_dev_deep(netdev, htons(ETH_P_8021Q), vid);
if (!dev) if (!dev)
continue; continue;
qlcnic_config_indev_addr(adapter, dev, event); qlcnic_config_indev_addr(adapter, dev, event);
......
...@@ -86,7 +86,7 @@ static inline int is_vlan_dev(struct net_device *dev) ...@@ -86,7 +86,7 @@ static inline int is_vlan_dev(struct net_device *dev)
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev, extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
u16 vlan_id); __be16 vlan_proto, u16 vlan_id);
extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
extern u16 vlan_dev_vlan_id(const struct net_device *dev); extern u16 vlan_dev_vlan_id(const struct net_device *dev);
......
...@@ -51,14 +51,18 @@ const char vlan_version[] = DRV_VERSION; ...@@ -51,14 +51,18 @@ const char vlan_version[] = DRV_VERSION;
/* End of global variables definitions. */ /* End of global variables definitions. */
static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id) static int vlan_group_prealloc_vid(struct vlan_group *vg,
__be16 vlan_proto, u16 vlan_id)
{ {
struct net_device **array; struct net_device **array;
unsigned int pidx, vidx;
unsigned int size; unsigned int size;
ASSERT_RTNL(); ASSERT_RTNL();
array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; pidx = vlan_proto_idx(vlan_proto);
vidx = vlan_id / VLAN_GROUP_ARRAY_PART_LEN;
array = vg->vlan_devices_arrays[pidx][vidx];
if (array != NULL) if (array != NULL)
return 0; return 0;
...@@ -67,7 +71,7 @@ static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id) ...@@ -67,7 +71,7 @@ static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id)
if (array == NULL) if (array == NULL)
return -ENOBUFS; return -ENOBUFS;
vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN] = array; vg->vlan_devices_arrays[pidx][vidx] = array;
return 0; return 0;
} }
...@@ -93,7 +97,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) ...@@ -93,7 +97,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
if (vlan->flags & VLAN_FLAG_GVRP) if (vlan->flags & VLAN_FLAG_GVRP)
vlan_gvrp_request_leave(dev); vlan_gvrp_request_leave(dev);
vlan_group_set_device(grp, vlan_id, NULL); vlan_group_set_device(grp, vlan->vlan_proto, vlan_id, NULL);
/* Because unregister_netdevice_queue() makes sure at least one rcu /* Because unregister_netdevice_queue() makes sure at least one rcu
* grace period is respected before device freeing, * grace period is respected before device freeing,
* we dont need to call synchronize_net() here. * we dont need to call synchronize_net() here.
...@@ -112,13 +116,14 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) ...@@ -112,13 +116,14 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
* VLAN is not 0 (leave it there for 802.1p). * VLAN is not 0 (leave it there for 802.1p).
*/ */
if (vlan_id) if (vlan_id)
vlan_vid_del(real_dev, htons(ETH_P_8021Q), vlan_id); vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id);
/* Get rid of the vlan's reference to real_dev */ /* Get rid of the vlan's reference to real_dev */
dev_put(real_dev); dev_put(real_dev);
} }
int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) int vlan_check_real_dev(struct net_device *real_dev,
__be16 protocol, u16 vlan_id)
{ {
const char *name = real_dev->name; const char *name = real_dev->name;
...@@ -127,7 +132,7 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) ...@@ -127,7 +132,7 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
if (vlan_find_dev(real_dev, vlan_id) != NULL) if (vlan_find_dev(real_dev, protocol, vlan_id) != NULL)
return -EEXIST; return -EEXIST;
return 0; return 0;
...@@ -142,7 +147,7 @@ int register_vlan_dev(struct net_device *dev) ...@@ -142,7 +147,7 @@ int register_vlan_dev(struct net_device *dev)
struct vlan_group *grp; struct vlan_group *grp;
int err; int err;
err = vlan_vid_add(real_dev, htons(ETH_P_8021Q), vlan_id); err = vlan_vid_add(real_dev, vlan->vlan_proto, vlan_id);
if (err) if (err)
return err; return err;
...@@ -160,7 +165,7 @@ int register_vlan_dev(struct net_device *dev) ...@@ -160,7 +165,7 @@ int register_vlan_dev(struct net_device *dev)
goto out_uninit_gvrp; goto out_uninit_gvrp;
} }
err = vlan_group_prealloc_vid(grp, vlan_id); err = vlan_group_prealloc_vid(grp, vlan->vlan_proto, vlan_id);
if (err < 0) if (err < 0)
goto out_uninit_mvrp; goto out_uninit_mvrp;
...@@ -181,7 +186,7 @@ int register_vlan_dev(struct net_device *dev) ...@@ -181,7 +186,7 @@ int register_vlan_dev(struct net_device *dev)
/* So, got the sucker initialized, now lets place /* So, got the sucker initialized, now lets place
* it into our local structure. * it into our local structure.
*/ */
vlan_group_set_device(grp, vlan_id, dev); vlan_group_set_device(grp, vlan->vlan_proto, vlan_id, dev);
grp->nr_vlan_devs++; grp->nr_vlan_devs++;
return 0; return 0;
...@@ -195,7 +200,7 @@ int register_vlan_dev(struct net_device *dev) ...@@ -195,7 +200,7 @@ int register_vlan_dev(struct net_device *dev)
if (grp->nr_vlan_devs == 0) if (grp->nr_vlan_devs == 0)
vlan_gvrp_uninit_applicant(real_dev); vlan_gvrp_uninit_applicant(real_dev);
out_vid_del: out_vid_del:
vlan_vid_del(real_dev, htons(ETH_P_8021Q), vlan_id); vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id);
return err; return err;
} }
...@@ -213,7 +218,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) ...@@ -213,7 +218,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
if (vlan_id >= VLAN_VID_MASK) if (vlan_id >= VLAN_VID_MASK)
return -ERANGE; return -ERANGE;
err = vlan_check_real_dev(real_dev, vlan_id); err = vlan_check_real_dev(real_dev, htons(ETH_P_8021Q), vlan_id);
if (err < 0) if (err < 0)
return err; return err;
...@@ -255,6 +260,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) ...@@ -255,6 +260,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
new_dev->mtu = real_dev->mtu; new_dev->mtu = real_dev->mtu;
new_dev->priv_flags |= (real_dev->priv_flags & IFF_UNICAST_FLT); new_dev->priv_flags |= (real_dev->priv_flags & IFF_UNICAST_FLT);
vlan_dev_priv(new_dev)->vlan_proto = htons(ETH_P_8021Q);
vlan_dev_priv(new_dev)->vlan_id = vlan_id; vlan_dev_priv(new_dev)->vlan_id = vlan_id;
vlan_dev_priv(new_dev)->real_dev = real_dev; vlan_dev_priv(new_dev)->real_dev = real_dev;
vlan_dev_priv(new_dev)->dent = NULL; vlan_dev_priv(new_dev)->dent = NULL;
...@@ -341,6 +347,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, ...@@ -341,6 +347,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
int i, flgs; int i, flgs;
struct net_device *vlandev; struct net_device *vlandev;
struct vlan_dev_priv *vlan; struct vlan_dev_priv *vlan;
bool last = false;
LIST_HEAD(list); LIST_HEAD(list);
if (is_vlan_dev(dev)) if (is_vlan_dev(dev))
...@@ -365,22 +372,13 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, ...@@ -365,22 +372,13 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
switch (event) { switch (event) {
case NETDEV_CHANGE: case NETDEV_CHANGE:
/* Propagate real device state to vlan devices */ /* Propagate real device state to vlan devices */
for (i = 0; i < VLAN_N_VID; i++) { vlan_group_for_each_dev(grp, i, vlandev)
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
netif_stacked_transfer_operstate(dev, vlandev); netif_stacked_transfer_operstate(dev, vlandev);
}
break; break;
case NETDEV_CHANGEADDR: case NETDEV_CHANGEADDR:
/* Adjust unicast filters on underlying device */ /* Adjust unicast filters on underlying device */
for (i = 0; i < VLAN_N_VID; i++) { vlan_group_for_each_dev(grp, i, vlandev) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
flgs = vlandev->flags; flgs = vlandev->flags;
if (!(flgs & IFF_UP)) if (!(flgs & IFF_UP))
continue; continue;
...@@ -390,11 +388,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, ...@@ -390,11 +388,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
break; break;
case NETDEV_CHANGEMTU: case NETDEV_CHANGEMTU:
for (i = 0; i < VLAN_N_VID; i++) { vlan_group_for_each_dev(grp, i, vlandev) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
if (vlandev->mtu <= dev->mtu) if (vlandev->mtu <= dev->mtu)
continue; continue;
...@@ -404,14 +398,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, ...@@ -404,14 +398,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_FEAT_CHANGE: case NETDEV_FEAT_CHANGE:
/* Propagate device features to underlying device */ /* Propagate device features to underlying device */
for (i = 0; i < VLAN_N_VID; i++) { vlan_group_for_each_dev(grp, i, vlandev)
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
vlan_transfer_features(dev, vlandev); vlan_transfer_features(dev, vlandev);
}
break; break;
case NETDEV_DOWN: case NETDEV_DOWN:
...@@ -419,11 +407,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, ...@@ -419,11 +407,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
vlan_vid_del(dev, htons(ETH_P_8021Q), 0); vlan_vid_del(dev, htons(ETH_P_8021Q), 0);
/* Put all VLANs for this dev in the down state too. */ /* Put all VLANs for this dev in the down state too. */
for (i = 0; i < VLAN_N_VID; i++) { vlan_group_for_each_dev(grp, i, vlandev) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
flgs = vlandev->flags; flgs = vlandev->flags;
if (!(flgs & IFF_UP)) if (!(flgs & IFF_UP))
continue; continue;
...@@ -437,11 +421,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, ...@@ -437,11 +421,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_UP: case NETDEV_UP:
/* Put all VLANs for this dev in the up state too. */ /* Put all VLANs for this dev in the up state too. */
for (i = 0; i < VLAN_N_VID; i++) { vlan_group_for_each_dev(grp, i, vlandev) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
flgs = vlandev->flags; flgs = vlandev->flags;
if (flgs & IFF_UP) if (flgs & IFF_UP)
continue; continue;
...@@ -458,17 +438,15 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, ...@@ -458,17 +438,15 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
if (dev->reg_state != NETREG_UNREGISTERING) if (dev->reg_state != NETREG_UNREGISTERING)
break; break;
for (i = 0; i < VLAN_N_VID; i++) { vlan_group_for_each_dev(grp, i, vlandev) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
/* removal of last vid destroys vlan_info, abort /* removal of last vid destroys vlan_info, abort
* afterwards */ * afterwards */
if (vlan_info->nr_vids == 1) if (vlan_info->nr_vids == 1)
i = VLAN_N_VID; last = true;
unregister_vlan_dev(vlandev, &list); unregister_vlan_dev(vlandev, &list);
if (last)
break;
} }
unregister_netdevice_many(&list); unregister_netdevice_many(&list);
break; break;
...@@ -482,13 +460,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, ...@@ -482,13 +460,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_NOTIFY_PEERS: case NETDEV_NOTIFY_PEERS:
case NETDEV_BONDING_FAILOVER: case NETDEV_BONDING_FAILOVER:
/* Propagate to vlan devices */ /* Propagate to vlan devices */
for (i = 0; i < VLAN_N_VID; i++) { vlan_group_for_each_dev(grp, i, vlandev)
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
call_netdevice_notifiers(event, vlandev); call_netdevice_notifiers(event, vlandev);
}
break; break;
} }
......
...@@ -49,6 +49,7 @@ struct netpoll; ...@@ -49,6 +49,7 @@ struct netpoll;
* @ingress_priority_map: ingress priority mappings * @ingress_priority_map: ingress priority mappings
* @nr_egress_mappings: number of egress priority mappings * @nr_egress_mappings: number of egress priority mappings
* @egress_priority_map: hash of egress priority mappings * @egress_priority_map: hash of egress priority mappings
* @vlan_proto: VLAN encapsulation protocol
* @vlan_id: VLAN identifier * @vlan_id: VLAN identifier
* @flags: device flags * @flags: device flags
* @real_dev: underlying netdevice * @real_dev: underlying netdevice
...@@ -62,6 +63,7 @@ struct vlan_dev_priv { ...@@ -62,6 +63,7 @@ struct vlan_dev_priv {
unsigned int nr_egress_mappings; unsigned int nr_egress_mappings;
struct vlan_priority_tci_mapping *egress_priority_map[16]; struct vlan_priority_tci_mapping *egress_priority_map[16];
__be16 vlan_proto;
u16 vlan_id; u16 vlan_id;
u16 flags; u16 flags;
...@@ -87,10 +89,16 @@ static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev) ...@@ -87,10 +89,16 @@ static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev)
#define VLAN_GROUP_ARRAY_SPLIT_PARTS 8 #define VLAN_GROUP_ARRAY_SPLIT_PARTS 8
#define VLAN_GROUP_ARRAY_PART_LEN (VLAN_N_VID/VLAN_GROUP_ARRAY_SPLIT_PARTS) #define VLAN_GROUP_ARRAY_PART_LEN (VLAN_N_VID/VLAN_GROUP_ARRAY_SPLIT_PARTS)
enum vlan_protos {
VLAN_PROTO_8021Q = 0,
VLAN_PROTO_NUM,
};
struct vlan_group { struct vlan_group {
unsigned int nr_vlan_devs; unsigned int nr_vlan_devs;
struct hlist_node hlist; /* linked list */ struct hlist_node hlist; /* linked list */
struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS]; struct net_device **vlan_devices_arrays[VLAN_PROTO_NUM]
[VLAN_GROUP_ARRAY_SPLIT_PARTS];
}; };
struct vlan_info { struct vlan_info {
...@@ -103,37 +111,64 @@ struct vlan_info { ...@@ -103,37 +111,64 @@ struct vlan_info {
struct rcu_head rcu; struct rcu_head rcu;
}; };
static inline struct net_device *vlan_group_get_device(struct vlan_group *vg, static inline unsigned int vlan_proto_idx(__be16 proto)
{
switch (proto) {
case __constant_htons(ETH_P_8021Q):
return VLAN_PROTO_8021Q;
default:
BUG();
}
}
static inline struct net_device *__vlan_group_get_device(struct vlan_group *vg,
unsigned int pidx,
u16 vlan_id) u16 vlan_id)
{ {
struct net_device **array; struct net_device **array;
array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
array = vg->vlan_devices_arrays[pidx]
[vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL; 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);
}
static inline void vlan_group_set_device(struct vlan_group *vg, static inline void vlan_group_set_device(struct vlan_group *vg,
u16 vlan_id, __be16 vlan_proto, u16 vlan_id,
struct net_device *dev) struct net_device *dev)
{ {
struct net_device **array; struct net_device **array;
if (!vg) if (!vg)
return; return;
array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; 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; array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
} }
/* Must be invoked with rcu_read_lock or with RTNL. */ /* Must be invoked with rcu_read_lock or with RTNL. */
static inline struct net_device *vlan_find_dev(struct net_device *real_dev, static inline struct net_device *vlan_find_dev(struct net_device *real_dev,
u16 vlan_id) __be16 vlan_proto, u16 vlan_id)
{ {
struct vlan_info *vlan_info = rcu_dereference_rtnl(real_dev->vlan_info); struct vlan_info *vlan_info = rcu_dereference_rtnl(real_dev->vlan_info);
if (vlan_info) if (vlan_info)
return vlan_group_get_device(&vlan_info->grp, vlan_id); return vlan_group_get_device(&vlan_info->grp,
vlan_proto, vlan_id);
return NULL; return NULL;
} }
#define vlan_group_for_each_dev(grp, i, dev) \
for ((i) = 0; i < VLAN_PROTO_NUM * VLAN_N_VID; i++) \
if (((dev) = __vlan_group_get_device((grp), (i) / VLAN_N_VID, \
(i) % VLAN_N_VID)))
/* found in vlan_dev.c */ /* found in vlan_dev.c */
void vlan_dev_set_ingress_priority(const struct net_device *dev, void vlan_dev_set_ingress_priority(const struct net_device *dev,
u32 skb_prio, u16 vlan_prio); u32 skb_prio, u16 vlan_prio);
...@@ -142,7 +177,8 @@ int vlan_dev_set_egress_priority(const struct net_device *dev, ...@@ -142,7 +177,8 @@ int vlan_dev_set_egress_priority(const struct net_device *dev,
int vlan_dev_change_flags(const struct net_device *dev, u32 flag, u32 mask); int vlan_dev_change_flags(const struct net_device *dev, u32 flag, u32 mask);
void vlan_dev_get_realdev_name(const struct net_device *dev, char *result); void vlan_dev_get_realdev_name(const struct net_device *dev, char *result);
int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id); int vlan_check_real_dev(struct net_device *real_dev,
__be16 protocol, u16 vlan_id);
void vlan_setup(struct net_device *dev); void vlan_setup(struct net_device *dev);
int register_vlan_dev(struct net_device *dev); int register_vlan_dev(struct net_device *dev);
void unregister_vlan_dev(struct net_device *dev, struct list_head *head); void unregister_vlan_dev(struct net_device *dev, struct list_head *head);
......
...@@ -12,7 +12,7 @@ bool vlan_do_receive(struct sk_buff **skbp) ...@@ -12,7 +12,7 @@ bool vlan_do_receive(struct sk_buff **skbp)
struct net_device *vlan_dev; struct net_device *vlan_dev;
struct vlan_pcpu_stats *rx_stats; struct vlan_pcpu_stats *rx_stats;
vlan_dev = vlan_find_dev(skb->dev, vlan_id); vlan_dev = vlan_find_dev(skb->dev, htons(ETH_P_8021Q), vlan_id);
if (!vlan_dev) if (!vlan_dev)
return false; return false;
...@@ -62,12 +62,13 @@ bool vlan_do_receive(struct sk_buff **skbp) ...@@ -62,12 +62,13 @@ bool vlan_do_receive(struct sk_buff **skbp)
/* Must be invoked with rcu_read_lock. */ /* Must be invoked with rcu_read_lock. */
struct net_device *__vlan_find_dev_deep(struct net_device *dev, struct net_device *__vlan_find_dev_deep(struct net_device *dev,
u16 vlan_id) __be16 vlan_proto, u16 vlan_id)
{ {
struct vlan_info *vlan_info = rcu_dereference(dev->vlan_info); struct vlan_info *vlan_info = rcu_dereference(dev->vlan_info);
if (vlan_info) { if (vlan_info) {
return vlan_group_get_device(&vlan_info->grp, vlan_id); return vlan_group_get_device(&vlan_info->grp,
vlan_proto, vlan_id);
} else { } else {
/* /*
* Lower devices of master uppers (bonding, team) do not have * Lower devices of master uppers (bonding, team) do not have
...@@ -78,7 +79,8 @@ struct net_device *__vlan_find_dev_deep(struct net_device *dev, ...@@ -78,7 +79,8 @@ struct net_device *__vlan_find_dev_deep(struct net_device *dev,
upper_dev = netdev_master_upper_dev_get_rcu(dev); upper_dev = netdev_master_upper_dev_get_rcu(dev);
if (upper_dev) if (upper_dev)
return __vlan_find_dev_deep(upper_dev, vlan_id); return __vlan_find_dev_deep(upper_dev,
vlan_proto, vlan_id);
} }
return NULL; return NULL;
......
...@@ -99,6 +99,7 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, ...@@ -99,6 +99,7 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
const void *daddr, const void *saddr, const void *daddr, const void *saddr,
unsigned int len) unsigned int len)
{ {
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
struct vlan_hdr *vhdr; struct vlan_hdr *vhdr;
unsigned int vhdrlen = 0; unsigned int vhdrlen = 0;
u16 vlan_tci = 0; u16 vlan_tci = 0;
...@@ -120,8 +121,8 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, ...@@ -120,8 +121,8 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
else else
vhdr->h_vlan_encapsulated_proto = htons(len); vhdr->h_vlan_encapsulated_proto = htons(len);
skb->protocol = htons(ETH_P_8021Q); skb->protocol = vlan->vlan_proto;
type = ETH_P_8021Q; type = ntohs(vlan->vlan_proto);
vhdrlen = VLAN_HLEN; vhdrlen = VLAN_HLEN;
} }
...@@ -161,7 +162,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, ...@@ -161,7 +162,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
* NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING
* OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs... * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...
*/ */
if (veth->h_vlan_proto != htons(ETH_P_8021Q) || if (veth->h_vlan_proto != vlan->vlan_proto ||
vlan->flags & VLAN_FLAG_REORDER_HDR) { vlan->flags & VLAN_FLAG_REORDER_HDR) {
u16 vlan_tci; u16 vlan_tci;
vlan_tci = vlan->vlan_id; vlan_tci = vlan->vlan_id;
......
...@@ -32,6 +32,8 @@ int vlan_gvrp_request_join(const struct net_device *dev) ...@@ -32,6 +32,8 @@ int vlan_gvrp_request_join(const struct net_device *dev)
const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
__be16 vlan_id = htons(vlan->vlan_id); __be16 vlan_id = htons(vlan->vlan_id);
if (vlan->vlan_proto != htons(ETH_P_8021Q))
return 0;
return garp_request_join(vlan->real_dev, &vlan_gvrp_app, return garp_request_join(vlan->real_dev, &vlan_gvrp_app,
&vlan_id, sizeof(vlan_id), GVRP_ATTR_VID); &vlan_id, sizeof(vlan_id), GVRP_ATTR_VID);
} }
...@@ -41,6 +43,8 @@ void vlan_gvrp_request_leave(const struct net_device *dev) ...@@ -41,6 +43,8 @@ void vlan_gvrp_request_leave(const struct net_device *dev)
const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
__be16 vlan_id = htons(vlan->vlan_id); __be16 vlan_id = htons(vlan->vlan_id);
if (vlan->vlan_proto != htons(ETH_P_8021Q))
return;
garp_request_leave(vlan->real_dev, &vlan_gvrp_app, garp_request_leave(vlan->real_dev, &vlan_gvrp_app,
&vlan_id, sizeof(vlan_id), GVRP_ATTR_VID); &vlan_id, sizeof(vlan_id), GVRP_ATTR_VID);
} }
......
...@@ -38,6 +38,8 @@ int vlan_mvrp_request_join(const struct net_device *dev) ...@@ -38,6 +38,8 @@ int vlan_mvrp_request_join(const struct net_device *dev)
const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
__be16 vlan_id = htons(vlan->vlan_id); __be16 vlan_id = htons(vlan->vlan_id);
if (vlan->vlan_proto != htons(ETH_P_8021Q))
return 0;
return mrp_request_join(vlan->real_dev, &vlan_mrp_app, return mrp_request_join(vlan->real_dev, &vlan_mrp_app,
&vlan_id, sizeof(vlan_id), MVRP_ATTR_VID); &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
} }
...@@ -47,6 +49,8 @@ void vlan_mvrp_request_leave(const struct net_device *dev) ...@@ -47,6 +49,8 @@ void vlan_mvrp_request_leave(const struct net_device *dev)
const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
__be16 vlan_id = htons(vlan->vlan_id); __be16 vlan_id = htons(vlan->vlan_id);
if (vlan->vlan_proto != htons(ETH_P_8021Q))
return;
mrp_request_leave(vlan->real_dev, &vlan_mrp_app, mrp_request_leave(vlan->real_dev, &vlan_mrp_app,
&vlan_id, sizeof(vlan_id), MVRP_ATTR_VID); &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
} }
......
...@@ -118,11 +118,12 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev, ...@@ -118,11 +118,12 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
if (!real_dev) if (!real_dev)
return -ENODEV; return -ENODEV;
vlan->vlan_proto = htons(ETH_P_8021Q);
vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]); vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]);
vlan->real_dev = real_dev; vlan->real_dev = real_dev;
vlan->flags = VLAN_FLAG_REORDER_HDR; vlan->flags = VLAN_FLAG_REORDER_HDR;
err = vlan_check_real_dev(real_dev, vlan->vlan_id); err = vlan_check_real_dev(real_dev, vlan->vlan_proto, vlan->vlan_id);
if (err < 0) if (err < 0)
return err; return err;
......
...@@ -535,7 +535,8 @@ static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct ...@@ -535,7 +535,8 @@ static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct
if (brnf_pass_vlan_indev == 0 || !vlan_tx_tag_present(skb)) if (brnf_pass_vlan_indev == 0 || !vlan_tx_tag_present(skb))
return br; return br;
vlan = __vlan_find_dev_deep(br, vlan_tx_tag_get(skb) & VLAN_VID_MASK); vlan = __vlan_find_dev_deep(br, htons(ETH_P_8021Q),
vlan_tx_tag_get(skb) & VLAN_VID_MASK);
return vlan ? vlan : br; return vlan ? vlan : br;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment