2005-04-17 02:20:36 +04:00
# ifndef __BEN_VLAN_802_1Q_INC__
# define __BEN_VLAN_802_1Q_INC__
# include <linux/if_vlan.h>
2010-06-24 04:55:06 +04:00
# include <linux/u64_stats_sync.h>
2011-12-08 08:11:18 +04:00
# include <linux/list.h>
2005-04-17 02:20:36 +04:00
2011-12-08 08:11:18 +04:00
/* if this changes, algorithm will have to be reworked because this
* depends on completely exhausting the VLAN identifier space . Thus
* it gives constant time look - up , but in many cases it wastes memory .
*/
# define VLAN_GROUP_ARRAY_SPLIT_PARTS 8
# define VLAN_GROUP_ARRAY_PART_LEN (VLAN_N_VID / VLAN_GROUP_ARRAY_SPLIT_PARTS)
2013-04-19 06:04:29 +04:00
enum vlan_protos {
VLAN_PROTO_8021Q = 0 ,
net: vlan: add 802.1ad support
Add support for 802.1ad VLAN devices. This mainly consists of checking for
ETH_P_8021AD in addition to ETH_P_8021Q in a couple of places and check
offloading capabilities based on the used protocol.
Configuration is done using "ip link":
# ip link add link eth0 eth0.1000 \
type vlan proto 802.1ad id 1000
# ip link add link eth0.1000 eth0.1000.1000 \
type vlan proto 802.1q id 1000
52:54:00:12:34:56 > 92:b1:54:28:e4:8c, ethertype 802.1Q (0x8100), length 106: vlan 1000, p 0, ethertype 802.1Q, vlan 1000, p 0, ethertype IPv4, (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
20.1.0.2 > 20.1.0.1: ICMP echo request, id 3003, seq 8, length 64
92:b1:54:28:e4:8c > 52:54:00:12:34:56, ethertype 802.1Q-QinQ (0x88a8), length 106: vlan 1000, p 0, ethertype 802.1Q, vlan 1000, p 0, ethertype IPv4, (tos 0x0, ttl 64, id 47944, offset 0, flags [none], proto ICMP (1), length 84)
20.1.0.1 > 20.1.0.2: ICMP echo reply, id 3003, seq 8, length 64
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-04-19 06:04:31 +04:00
VLAN_PROTO_8021AD ,
2013-04-19 06:04:29 +04:00
VLAN_PROTO_NUM ,
} ;
2011-12-08 08:11:18 +04:00
struct vlan_group {
unsigned int nr_vlan_devs ;
struct hlist_node hlist ; /* linked list */
2013-04-19 06:04:29 +04:00
struct net_device * * vlan_devices_arrays [ VLAN_PROTO_NUM ]
[ VLAN_GROUP_ARRAY_SPLIT_PARTS ] ;
2011-12-08 08:11:18 +04:00
} ;
struct vlan_info {
struct net_device * real_dev ; /* The ethernet(like) device
* the vlan is attached to .
*/
struct vlan_group grp ;
struct list_head vid_list ;
unsigned int nr_vids ;
struct rcu_head rcu ;
} ;
2013-04-19 06:04:29 +04:00
static inline unsigned int vlan_proto_idx ( __be16 proto )
{
switch ( proto ) {
2014-03-12 21:04:15 +04:00
case htons ( ETH_P_8021Q ) :
2013-04-19 06:04:29 +04:00
return VLAN_PROTO_8021Q ;
2014-03-12 21:04:15 +04:00
case htons ( ETH_P_8021AD ) :
net: vlan: add 802.1ad support
Add support for 802.1ad VLAN devices. This mainly consists of checking for
ETH_P_8021AD in addition to ETH_P_8021Q in a couple of places and check
offloading capabilities based on the used protocol.
Configuration is done using "ip link":
# ip link add link eth0 eth0.1000 \
type vlan proto 802.1ad id 1000
# ip link add link eth0.1000 eth0.1000.1000 \
type vlan proto 802.1q id 1000
52:54:00:12:34:56 > 92:b1:54:28:e4:8c, ethertype 802.1Q (0x8100), length 106: vlan 1000, p 0, ethertype 802.1Q, vlan 1000, p 0, ethertype IPv4, (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
20.1.0.2 > 20.1.0.1: ICMP echo request, id 3003, seq 8, length 64
92:b1:54:28:e4:8c > 52:54:00:12:34:56, ethertype 802.1Q-QinQ (0x88a8), length 106: vlan 1000, p 0, ethertype 802.1Q, vlan 1000, p 0, ethertype IPv4, (tos 0x0, ttl 64, id 47944, offset 0, flags [none], proto ICMP (1), length 84)
20.1.0.1 > 20.1.0.2: ICMP echo reply, id 3003, seq 8, length 64
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-04-19 06:04:31 +04:00
return VLAN_PROTO_8021AD ;
2013-04-19 06:04:29 +04:00
default :
BUG ( ) ;
2013-04-21 04:09:32 +04:00
return 0 ;
2013-04-19 06:04:29 +04:00
}
}
static inline struct net_device * __vlan_group_get_device ( struct vlan_group * vg ,
unsigned int pidx ,
u16 vlan_id )
2011-07-20 08:54:49 +04:00
{
struct net_device * * array ;
2013-04-19 06:04:29 +04:00
array = vg - > vlan_devices_arrays [ pidx ]
[ vlan_id / VLAN_GROUP_ARRAY_PART_LEN ] ;
2011-07-20 08:54:49 +04:00
return array ? array [ vlan_id % VLAN_GROUP_ARRAY_PART_LEN ] : NULL ;
}
2013-04-19 06:04:29 +04:00
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 ) ;
}
2011-07-20 08:54:49 +04:00
static inline void vlan_group_set_device ( struct vlan_group * vg ,
2013-04-19 06:04:29 +04:00
__be16 vlan_proto , u16 vlan_id ,
2011-07-20 08:54:49 +04:00
struct net_device * dev )
{
struct net_device * * array ;
if ( ! vg )
return ;
2013-04-19 06:04:29 +04:00
array = vg - > vlan_devices_arrays [ vlan_proto_idx ( vlan_proto ) ]
[ vlan_id / VLAN_GROUP_ARRAY_PART_LEN ] ;
2011-07-20 08:54:49 +04:00
array [ vlan_id % VLAN_GROUP_ARRAY_PART_LEN ] = dev ;
}
2011-07-17 12:53:12 +04:00
/* Must be invoked with rcu_read_lock or with RTNL. */
static inline struct net_device * vlan_find_dev ( struct net_device * real_dev ,
2013-04-19 06:04:29 +04:00
__be16 vlan_proto , u16 vlan_id )
2011-07-17 12:53:12 +04:00
{
2011-12-08 08:11:18 +04:00
struct vlan_info * vlan_info = rcu_dereference_rtnl ( real_dev - > vlan_info ) ;
2011-07-17 12:53:12 +04:00
2011-12-08 08:11:18 +04:00
if ( vlan_info )
2013-04-19 06:04:29 +04:00
return vlan_group_get_device ( & vlan_info - > grp ,
vlan_proto , vlan_id ) ;
2011-07-17 12:53:12 +04:00
return NULL ;
}
2013-04-19 06:04:29 +04:00
# 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 ) ) )
2005-04-17 02:20:36 +04:00
/* found in vlan_dev.c */
2007-06-13 23:05:22 +04:00
void vlan_dev_set_ingress_priority ( const struct net_device * dev ,
2008-07-08 14:24:44 +04:00
u32 skb_prio , u16 vlan_prio ) ;
2007-06-13 23:05:22 +04:00
int vlan_dev_set_egress_priority ( const struct net_device * dev ,
2008-07-08 14:24:44 +04:00
u32 skb_prio , u16 vlan_prio ) ;
2008-07-06 08:26:27 +04:00
int vlan_dev_change_flags ( const struct net_device * dev , u32 flag , u32 mask ) ;
2007-06-13 23:05:22 +04:00
void vlan_dev_get_realdev_name ( const struct net_device * dev , char * result ) ;
2005-04-17 02:20:36 +04:00
2013-04-19 06:04:29 +04:00
int vlan_check_real_dev ( struct net_device * real_dev ,
__be16 protocol , u16 vlan_id ) ;
2007-06-13 23:07:54 +04:00
void vlan_setup ( struct net_device * dev ) ;
int register_vlan_dev ( struct net_device * dev ) ;
2009-10-27 10:06:36 +03:00
void unregister_vlan_dev ( struct net_device * dev , struct list_head * head ) ;
2007-06-13 23:07:54 +04:00
2008-07-08 14:23:36 +04:00
static inline u32 vlan_get_ingress_priority ( struct net_device * dev ,
2008-07-08 14:24:44 +04:00
u16 vlan_tci )
2008-07-08 14:23:36 +04:00
{
2011-12-08 08:11:15 +04:00
struct vlan_dev_priv * vip = vlan_dev_priv ( dev ) ;
2008-07-08 14:23:36 +04:00
2009-10-27 04:40:35 +03:00
return vip - > ingress_priority_map [ ( vlan_tci > > VLAN_PRIO_SHIFT ) & 0x7 ] ;
2008-07-08 14:23:36 +04:00
}
2008-07-06 08:26:57 +04:00
# ifdef CONFIG_VLAN_8021Q_GVRP
2013-10-19 00:48:22 +04:00
int vlan_gvrp_request_join ( const struct net_device * dev ) ;
void vlan_gvrp_request_leave ( const struct net_device * dev ) ;
int vlan_gvrp_init_applicant ( struct net_device * dev ) ;
void vlan_gvrp_uninit_applicant ( struct net_device * dev ) ;
int vlan_gvrp_init ( void ) ;
void vlan_gvrp_uninit ( void ) ;
2008-07-06 08:26:57 +04:00
# else
static inline int vlan_gvrp_request_join ( const struct net_device * dev ) { return 0 ; }
static inline void vlan_gvrp_request_leave ( const struct net_device * dev ) { }
static inline int vlan_gvrp_init_applicant ( struct net_device * dev ) { return 0 ; }
static inline void vlan_gvrp_uninit_applicant ( struct net_device * dev ) { }
static inline int vlan_gvrp_init ( void ) { return 0 ; }
static inline void vlan_gvrp_uninit ( void ) { }
# endif
2013-02-08 21:17:07 +04:00
# ifdef CONFIG_VLAN_8021Q_MVRP
2013-10-19 00:48:22 +04:00
int vlan_mvrp_request_join ( const struct net_device * dev ) ;
void vlan_mvrp_request_leave ( const struct net_device * dev ) ;
int vlan_mvrp_init_applicant ( struct net_device * dev ) ;
void vlan_mvrp_uninit_applicant ( struct net_device * dev ) ;
int vlan_mvrp_init ( void ) ;
void vlan_mvrp_uninit ( void ) ;
2013-02-08 21:17:07 +04:00
# else
static inline int vlan_mvrp_request_join ( const struct net_device * dev ) { return 0 ; }
static inline void vlan_mvrp_request_leave ( const struct net_device * dev ) { }
static inline int vlan_mvrp_init_applicant ( struct net_device * dev ) { return 0 ; }
static inline void vlan_mvrp_uninit_applicant ( struct net_device * dev ) { }
static inline int vlan_mvrp_init ( void ) { return 0 ; }
static inline void vlan_mvrp_uninit ( void ) { }
# endif
2008-10-29 08:12:36 +03:00
extern const char vlan_fullname [ ] ;
extern const char vlan_version [ ] ;
2013-10-19 00:48:22 +04:00
int vlan_netlink_init ( void ) ;
void vlan_netlink_fini ( void ) ;
2007-06-13 23:07:54 +04:00
extern struct rtnl_link_ops vlan_link_ops ;
2008-04-16 11:49:09 +04:00
extern int vlan_net_id ;
2008-04-16 11:51:51 +04:00
struct proc_dir_entry ;
2008-04-16 11:49:09 +04:00
struct vlan_net {
2008-04-16 11:51:51 +04:00
/* /proc/net/vlan */
struct proc_dir_entry * proc_vlan_dir ;
/* /proc/net/vlan/config */
struct proc_dir_entry * proc_vlan_conf ;
2008-04-16 11:54:39 +04:00
/* Determines interface naming scheme. */
unsigned short name_type ;
2008-04-16 11:49:09 +04:00
} ;
2005-04-17 02:20:36 +04:00
# endif /* !(__BEN_VLAN_802_1Q_INC__) */