Skip to content

Commit

Permalink
net: vlan: prepare for 802.1ad support
Browse files Browse the repository at this point in the history
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: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Patrick McHardy authored and David S. Miller committed Apr 19, 2013
1 parent 80d5c36 commit 1fd9b1f
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 84 deletions.
8 changes: 5 additions & 3 deletions drivers/net/bonding/bond_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,7 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)

/* rejoin all groups on vlan devices */
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);
if (vlan_dev)
__bond_resend_igmp_join_requests(vlan_dev);
Expand Down Expand Up @@ -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) {
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();
if (vlan_dev && ip == bond_confirm_addr(vlan_dev, 0, ip))
return 1;
Expand Down Expand Up @@ -2541,7 +2542,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_
return;
}
if (vlan_id) {
skb = vlan_put_tag(skb, vlan_id);
skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_id);
if (!skb) {
pr_err("failed to insert VLAN tag\n");
return;
Expand Down Expand Up @@ -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) {
rcu_read_lock();
vlan_dev = __vlan_find_dev_deep(bond->dev,
htons(ETH_P_8021Q),
vlan->vlan_id);
rcu_read_unlock();
if (vlan_dev == rt->dst.dev) {
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter,
if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
rcu_read_lock();
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)) {
struct net_device *upper_dev;

Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3346,7 +3346,7 @@ void qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)

rcu_read_lock();
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)
continue;
qlcnic_config_indev_addr(adapter, dev, event);
Expand Down
2 changes: 1 addition & 1 deletion include/linux/if_vlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ static inline int is_vlan_dev(struct net_device *dev)
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)

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 u16 vlan_dev_vlan_id(const struct net_device *dev);

Expand Down
87 changes: 30 additions & 57 deletions net/8021q/vlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,18 @@ const char vlan_version[] = DRV_VERSION;

/* 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;
unsigned int pidx, vidx;
unsigned int size;

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)
return 0;

Expand All @@ -67,7 +71,7 @@ static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id)
if (array == NULL)
return -ENOBUFS;

vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN] = array;
vg->vlan_devices_arrays[pidx][vidx] = array;
return 0;
}

Expand All @@ -93,7 +97,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
if (vlan->flags & VLAN_FLAG_GVRP)
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
* grace period is respected before device freeing,
* we dont need to call synchronize_net() here.
Expand All @@ -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).
*/
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 */
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;

Expand All @@ -127,7 +132,7 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
return -EOPNOTSUPP;
}

if (vlan_find_dev(real_dev, vlan_id) != NULL)
if (vlan_find_dev(real_dev, protocol, vlan_id) != NULL)
return -EEXIST;

return 0;
Expand All @@ -142,7 +147,7 @@ int register_vlan_dev(struct net_device *dev)
struct vlan_group *grp;
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)
return err;

Expand All @@ -160,7 +165,7 @@ int register_vlan_dev(struct net_device *dev)
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)
goto out_uninit_mvrp;

Expand All @@ -181,7 +186,7 @@ int register_vlan_dev(struct net_device *dev)
/* So, got the sucker initialized, now lets place
* 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++;

return 0;
Expand All @@ -195,7 +200,7 @@ int register_vlan_dev(struct net_device *dev)
if (grp->nr_vlan_devs == 0)
vlan_gvrp_uninit_applicant(real_dev);
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;
}

Expand All @@ -213,7 +218,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
if (vlan_id >= VLAN_VID_MASK)
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)
return err;

Expand Down Expand Up @@ -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->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)->real_dev = real_dev;
vlan_dev_priv(new_dev)->dent = NULL;
Expand Down Expand Up @@ -341,6 +347,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
int i, flgs;
struct net_device *vlandev;
struct vlan_dev_priv *vlan;
bool last = false;
LIST_HEAD(list);

if (is_vlan_dev(dev))
Expand All @@ -365,22 +372,13 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
switch (event) {
case NETDEV_CHANGE:
/* Propagate real device state to vlan devices */
for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;

vlan_group_for_each_dev(grp, i, vlandev)
netif_stacked_transfer_operstate(dev, vlandev);
}
break;

case NETDEV_CHANGEADDR:
/* Adjust unicast filters on underlying device */
for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;

vlan_group_for_each_dev(grp, i, vlandev) {
flgs = vlandev->flags;
if (!(flgs & IFF_UP))
continue;
Expand All @@ -390,11 +388,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
break;

case NETDEV_CHANGEMTU:
for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;

vlan_group_for_each_dev(grp, i, vlandev) {
if (vlandev->mtu <= dev->mtu)
continue;

Expand All @@ -404,26 +398,16 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,

case NETDEV_FEAT_CHANGE:
/* Propagate device features to underlying device */
for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;

vlan_group_for_each_dev(grp, i, vlandev)
vlan_transfer_features(dev, vlandev);
}

break;

case NETDEV_DOWN:
if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
vlan_vid_del(dev, htons(ETH_P_8021Q), 0);

/* Put all VLANs for this dev in the down state too. */
for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;

vlan_group_for_each_dev(grp, i, vlandev) {
flgs = vlandev->flags;
if (!(flgs & IFF_UP))
continue;
Expand All @@ -437,11 +421,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,

case NETDEV_UP:
/* Put all VLANs for this dev in the up state too. */
for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;

vlan_group_for_each_dev(grp, i, vlandev) {
flgs = vlandev->flags;
if (flgs & IFF_UP)
continue;
Expand All @@ -458,17 +438,15 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
if (dev->reg_state != NETREG_UNREGISTERING)
break;

for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;

vlan_group_for_each_dev(grp, i, vlandev) {
/* removal of last vid destroys vlan_info, abort
* afterwards */
if (vlan_info->nr_vids == 1)
i = VLAN_N_VID;
last = true;

unregister_vlan_dev(vlandev, &list);
if (last)
break;
}
unregister_netdevice_many(&list);
break;
Expand All @@ -482,13 +460,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_NOTIFY_PEERS:
case NETDEV_BONDING_FAILOVER:
/* Propagate to vlan devices */
for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;

vlan_group_for_each_dev(grp, i, vlandev)
call_netdevice_notifiers(event, vlandev);
}
break;
}

Expand Down
Loading

0 comments on commit 1fd9b1f

Please sign in to comment.