Skip to content

Commit 5d2c05b

Browse files
committed
batman-adv: add per VLAN interface attribute framework
Since batman-adv is now fully VLAN-aware, a proper framework able to handle per-vlan-interface attributes is needed. Those attributes will affect the associated VLAN interface only, rather than the real soft_iface (which would result in every vlan interface having the same attribute configuration). To make the code simpler and easier to extend, attributes associated to the standalone soft_iface are now treated like belonging to yet another vlan having a special vid. This vid is different from the others because it is made up by all zeros and the VLAN_HAS_TAG bit is not set. Signed-off-by: Antonio Quartulli <[email protected]> Signed-off-by: Marek Lindner <[email protected]>
1 parent be1db4f commit 5d2c05b

File tree

5 files changed

+197
-3
lines changed

5 files changed

+197
-3
lines changed

net/batman-adv/hard-interface.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,8 @@ static int batadv_hard_if_event(struct notifier_block *this,
643643

644644
if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) {
645645
batadv_sysfs_add_meshif(net_dev);
646+
bat_priv = netdev_priv(net_dev);
647+
batadv_softif_create_vlan(bat_priv, BATADV_NO_FLAGS);
646648
return NOTIFY_DONE;
647649
}
648650

net/batman-adv/main.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ int batadv_mesh_init(struct net_device *soft_iface)
113113
spin_lock_init(&bat_priv->gw.list_lock);
114114
spin_lock_init(&bat_priv->tvlv.container_list_lock);
115115
spin_lock_init(&bat_priv->tvlv.handler_list_lock);
116+
spin_lock_init(&bat_priv->softif_vlan_list_lock);
116117

117118
INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
118119
INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
@@ -122,6 +123,7 @@ int batadv_mesh_init(struct net_device *soft_iface)
122123
INIT_LIST_HEAD(&bat_priv->tt.roam_list);
123124
INIT_HLIST_HEAD(&bat_priv->tvlv.container_list);
124125
INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
126+
INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
125127

126128
ret = batadv_originator_init(bat_priv);
127129
if (ret < 0)
@@ -131,9 +133,6 @@ int batadv_mesh_init(struct net_device *soft_iface)
131133
if (ret < 0)
132134
goto err;
133135

134-
batadv_tt_local_add(soft_iface, soft_iface->dev_addr,
135-
BATADV_NO_FLAGS, BATADV_NULL_IFINDEX);
136-
137136
ret = batadv_bla_init(bat_priv);
138137
if (ret < 0)
139138
goto err;

net/batman-adv/soft-interface.c

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,166 @@ void batadv_interface_rx(struct net_device *soft_iface,
393393
return;
394394
}
395395

396+
/**
397+
* batadv_softif_vlan_free_ref - decrease the vlan object refcounter and
398+
* possibly free it
399+
* @softif_vlan: the vlan object to release
400+
*/
401+
static void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan)
402+
{
403+
if (atomic_dec_and_test(&softif_vlan->refcount))
404+
kfree_rcu(softif_vlan, rcu);
405+
}
406+
407+
/**
408+
* batadv_softif_vlan_get - get the vlan object for a specific vid
409+
* @bat_priv: the bat priv with all the soft interface information
410+
* @vid: the identifier of the vlan object to retrieve
411+
*
412+
* Returns the private data of the vlan matching the vid passed as argument or
413+
* NULL otherwise. The refcounter of the returned object is incremented by 1.
414+
*/
415+
static struct batadv_softif_vlan *
416+
batadv_softif_vlan_get(struct batadv_priv *bat_priv, unsigned short vid)
417+
{
418+
struct batadv_softif_vlan *vlan_tmp, *vlan = NULL;
419+
420+
rcu_read_lock();
421+
hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) {
422+
if (vlan_tmp->vid != vid)
423+
continue;
424+
425+
if (!atomic_inc_not_zero(&vlan_tmp->refcount))
426+
continue;
427+
428+
vlan = vlan_tmp;
429+
break;
430+
}
431+
rcu_read_unlock();
432+
433+
return vlan;
434+
}
435+
436+
/**
437+
* batadv_create_vlan - allocate the needed resources for a new vlan
438+
* @bat_priv: the bat priv with all the soft interface information
439+
* @vid: the VLAN identifier
440+
*
441+
* Returns 0 on success, a negative error otherwise.
442+
*/
443+
int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
444+
{
445+
struct batadv_softif_vlan *vlan;
446+
447+
vlan = batadv_softif_vlan_get(bat_priv, vid);
448+
if (vlan) {
449+
batadv_softif_vlan_free_ref(vlan);
450+
return -EEXIST;
451+
}
452+
453+
vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
454+
if (!vlan)
455+
return -ENOMEM;
456+
457+
vlan->vid = vid;
458+
atomic_set(&vlan->refcount, 1);
459+
460+
/* add a new TT local entry. This one will be marked with the NOPURGE
461+
* flag
462+
*/
463+
batadv_tt_local_add(bat_priv->soft_iface,
464+
bat_priv->soft_iface->dev_addr, vid,
465+
BATADV_NULL_IFINDEX);
466+
467+
spin_lock_bh(&bat_priv->softif_vlan_list_lock);
468+
hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
469+
spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
470+
471+
return 0;
472+
}
473+
474+
/**
475+
* batadv_softif_destroy_vlan - remove and destroy a softif_vlan object
476+
* @bat_priv: the bat priv with all the soft interface information
477+
* @vlan: the object to remove
478+
*/
479+
static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv,
480+
struct batadv_softif_vlan *vlan)
481+
{
482+
spin_lock_bh(&bat_priv->softif_vlan_list_lock);
483+
hlist_del_rcu(&vlan->list);
484+
spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
485+
486+
/* explicitly remove the associated TT local entry because it is marked
487+
* with the NOPURGE flag
488+
*/
489+
batadv_tt_local_remove(bat_priv, bat_priv->soft_iface->dev_addr,
490+
vlan->vid, "vlan interface destroyed", false);
491+
492+
batadv_softif_vlan_free_ref(vlan);
493+
}
494+
495+
/**
496+
* batadv_interface_add_vid - ndo_add_vid API implementation
497+
* @dev: the netdev of the mesh interface
498+
* @vid: identifier of the new vlan
499+
*
500+
* Set up all the internal structures for handling the new vlan on top of the
501+
* mesh interface
502+
*
503+
* Returns 0 on success or a negative error code in case of failure.
504+
*/
505+
static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
506+
unsigned short vid)
507+
{
508+
struct batadv_priv *bat_priv = netdev_priv(dev);
509+
510+
/* only 802.1Q vlans are supported.
511+
* batman-adv does not know how to handle other types
512+
*/
513+
if (proto != htons(ETH_P_8021Q))
514+
return -EINVAL;
515+
516+
vid |= BATADV_VLAN_HAS_TAG;
517+
518+
return batadv_softif_create_vlan(bat_priv, vid);
519+
}
520+
521+
/**
522+
* batadv_interface_kill_vid - ndo_kill_vid API implementation
523+
* @dev: the netdev of the mesh interface
524+
* @vid: identifier of the deleted vlan
525+
*
526+
* Destroy all the internal structures used to handle the vlan identified by vid
527+
* on top of the mesh interface
528+
*
529+
* Returns 0 on success, -EINVAL if the specified prototype is not ETH_P_8021Q
530+
* or -ENOENT if the specified vlan id wasn't registered.
531+
*/
532+
static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
533+
unsigned short vid)
534+
{
535+
struct batadv_priv *bat_priv = netdev_priv(dev);
536+
struct batadv_softif_vlan *vlan;
537+
538+
/* only 802.1Q vlans are supported. batman-adv does not know how to
539+
* handle other types
540+
*/
541+
if (proto != htons(ETH_P_8021Q))
542+
return -EINVAL;
543+
544+
vlan = batadv_softif_vlan_get(bat_priv, vid | BATADV_VLAN_HAS_TAG);
545+
if (!vlan)
546+
return -ENOENT;
547+
548+
batadv_softif_destroy_vlan(bat_priv, vlan);
549+
550+
/* finally free the vlan object */
551+
batadv_softif_vlan_free_ref(vlan);
552+
553+
return 0;
554+
}
555+
396556
/* batman-adv network devices have devices nesting below it and are a special
397557
* "super class" of normal network devices; split their locks off into a
398558
* separate class since they always nest.
@@ -432,13 +592,21 @@ static void batadv_set_lockdep_class(struct net_device *dev)
432592
*/
433593
static void batadv_softif_destroy_finish(struct work_struct *work)
434594
{
595+
struct batadv_softif_vlan *vlan;
435596
struct batadv_priv *bat_priv;
436597
struct net_device *soft_iface;
437598

438599
bat_priv = container_of(work, struct batadv_priv,
439600
cleanup_work);
440601
soft_iface = bat_priv->soft_iface;
441602

603+
/* destroy the "untagged" VLAN */
604+
vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS);
605+
if (vlan) {
606+
batadv_softif_destroy_vlan(bat_priv, vlan);
607+
batadv_softif_vlan_free_ref(vlan);
608+
}
609+
442610
batadv_sysfs_del_meshif(soft_iface);
443611

444612
rtnl_lock();
@@ -594,6 +762,8 @@ static const struct net_device_ops batadv_netdev_ops = {
594762
.ndo_open = batadv_interface_open,
595763
.ndo_stop = batadv_interface_release,
596764
.ndo_get_stats = batadv_interface_stats,
765+
.ndo_vlan_rx_add_vid = batadv_interface_add_vid,
766+
.ndo_vlan_rx_kill_vid = batadv_interface_kill_vid,
597767
.ndo_set_mac_address = batadv_interface_set_mac_addr,
598768
.ndo_change_mtu = batadv_interface_change_mtu,
599769
.ndo_set_rx_mode = batadv_interface_set_rx_mode,
@@ -633,6 +803,7 @@ static void batadv_softif_init_early(struct net_device *dev)
633803

634804
dev->netdev_ops = &batadv_netdev_ops;
635805
dev->destructor = batadv_softif_free;
806+
dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
636807
dev->tx_queue_len = 0;
637808

638809
/* can't call min_mtu, because the needed variables

net/batman-adv/soft-interface.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@ struct net_device *batadv_softif_create(const char *name);
2828
void batadv_softif_destroy_sysfs(struct net_device *soft_iface);
2929
int batadv_softif_is_valid(const struct net_device *net_dev);
3030
extern struct rtnl_link_ops batadv_link_ops;
31+
int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid);
3132

3233
#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */

net/batman-adv/types.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,22 @@ struct batadv_priv_nc {
530530
struct batadv_hashtable *decoding_hash;
531531
};
532532

533+
/**
534+
* struct batadv_softif_vlan - per VLAN attributes set
535+
* @vid: VLAN identifier
536+
* @kobj: kobject for sysfs vlan subdirectory
537+
* @list: list node for bat_priv::softif_vlan_list
538+
* @refcount: number of context where this object is currently in use
539+
* @rcu: struct used for freeing in a RCU-safe manner
540+
*/
541+
struct batadv_softif_vlan {
542+
unsigned short vid;
543+
struct kobject *kobj;
544+
struct hlist_node list;
545+
atomic_t refcount;
546+
struct rcu_head rcu;
547+
};
548+
533549
/**
534550
* struct batadv_priv - per mesh interface data
535551
* @mesh_state: current status of the mesh (inactive/active/deactivating)
@@ -566,6 +582,9 @@ struct batadv_priv_nc {
566582
* @primary_if: one of the hard interfaces assigned to this mesh interface
567583
* becomes the primary interface
568584
* @bat_algo_ops: routing algorithm used by this mesh interface
585+
* @softif_vlan_list: a list of softif_vlan structs, one per VLAN created on top
586+
* of the mesh interface represented by this object
587+
* @softif_vlan_list_lock: lock protecting softif_vlan_list
569588
* @bla: bridge loope avoidance data
570589
* @debug_log: holding debug logging relevant data
571590
* @gw: gateway data
@@ -613,6 +632,8 @@ struct batadv_priv {
613632
struct work_struct cleanup_work;
614633
struct batadv_hard_iface __rcu *primary_if; /* rcu protected pointer */
615634
struct batadv_algo_ops *bat_algo_ops;
635+
struct hlist_head softif_vlan_list;
636+
spinlock_t softif_vlan_list_lock; /* protects softif_vlan_list */
616637
#ifdef CONFIG_BATMAN_ADV_BLA
617638
struct batadv_priv_bla bla;
618639
#endif

0 commit comments

Comments
 (0)