1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
21da177e4SLinus Torvalds #ifndef __BEN_VLAN_802_1Q_INC__
31da177e4SLinus Torvalds #define __BEN_VLAN_802_1Q_INC__
41da177e4SLinus Torvalds
51da177e4SLinus Torvalds #include <linux/if_vlan.h>
69618e2ffSEric Dumazet #include <linux/u64_stats_sync.h>
75b9ea6e0SJiri Pirko #include <linux/list.h>
81da177e4SLinus Torvalds
95b9ea6e0SJiri Pirko /* if this changes, algorithm will have to be reworked because this
105b9ea6e0SJiri Pirko * depends on completely exhausting the VLAN identifier space. Thus
115b9ea6e0SJiri Pirko * it gives constant time look-up, but in many cases it wastes memory.
125b9ea6e0SJiri Pirko */
135b9ea6e0SJiri Pirko #define VLAN_GROUP_ARRAY_SPLIT_PARTS 8
145b9ea6e0SJiri Pirko #define VLAN_GROUP_ARRAY_PART_LEN (VLAN_N_VID/VLAN_GROUP_ARRAY_SPLIT_PARTS)
155b9ea6e0SJiri Pirko
161fd9b1fcSPatrick McHardy enum vlan_protos {
171fd9b1fcSPatrick McHardy VLAN_PROTO_8021Q = 0,
188ad227ffSPatrick McHardy VLAN_PROTO_8021AD,
191fd9b1fcSPatrick McHardy VLAN_PROTO_NUM,
201fd9b1fcSPatrick McHardy };
211fd9b1fcSPatrick McHardy
225b9ea6e0SJiri Pirko struct vlan_group {
235b9ea6e0SJiri Pirko unsigned int nr_vlan_devs;
245b9ea6e0SJiri Pirko struct hlist_node hlist; /* linked list */
251fd9b1fcSPatrick McHardy struct net_device **vlan_devices_arrays[VLAN_PROTO_NUM]
261fd9b1fcSPatrick McHardy [VLAN_GROUP_ARRAY_SPLIT_PARTS];
275b9ea6e0SJiri Pirko };
285b9ea6e0SJiri Pirko
295b9ea6e0SJiri Pirko struct vlan_info {
305b9ea6e0SJiri Pirko struct net_device *real_dev; /* The ethernet(like) device
315b9ea6e0SJiri Pirko * the vlan is attached to.
325b9ea6e0SJiri Pirko */
335b9ea6e0SJiri Pirko struct vlan_group grp;
345b9ea6e0SJiri Pirko struct list_head vid_list;
355b9ea6e0SJiri Pirko unsigned int nr_vids;
365b9ea6e0SJiri Pirko struct rcu_head rcu;
375b9ea6e0SJiri Pirko };
385b9ea6e0SJiri Pirko
vlan_proto_idx(__be16 proto)39d0186842SFlorian Fainelli static inline int vlan_proto_idx(__be16 proto)
401fd9b1fcSPatrick McHardy {
411fd9b1fcSPatrick McHardy switch (proto) {
42f0e78826SJoe Perches case htons(ETH_P_8021Q):
431fd9b1fcSPatrick McHardy return VLAN_PROTO_8021Q;
44f0e78826SJoe Perches case htons(ETH_P_8021AD):
458ad227ffSPatrick McHardy return VLAN_PROTO_8021AD;
461fd9b1fcSPatrick McHardy default:
47d0186842SFlorian Fainelli WARN(1, "invalid VLAN protocol: 0x%04x\n", ntohs(proto));
48d0186842SFlorian Fainelli return -EINVAL;
491fd9b1fcSPatrick McHardy }
501fd9b1fcSPatrick McHardy }
511fd9b1fcSPatrick McHardy
__vlan_group_get_device(struct vlan_group * vg,unsigned int pidx,u16 vlan_id)521fd9b1fcSPatrick McHardy static inline struct net_device *__vlan_group_get_device(struct vlan_group *vg,
531fd9b1fcSPatrick McHardy unsigned int pidx,
54536d1d4aSJiri Pirko u16 vlan_id)
55536d1d4aSJiri Pirko {
56536d1d4aSJiri Pirko struct net_device **array;
571fd9b1fcSPatrick McHardy
581fd9b1fcSPatrick McHardy array = vg->vlan_devices_arrays[pidx]
591fd9b1fcSPatrick McHardy [vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
60c1102e9dSDi Zhu
61c1102e9dSDi Zhu /* paired with smp_wmb() in vlan_group_prealloc_vid() */
62c1102e9dSDi Zhu smp_rmb();
63c1102e9dSDi Zhu
64536d1d4aSJiri Pirko return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL;
65536d1d4aSJiri Pirko }
66536d1d4aSJiri Pirko
vlan_group_get_device(struct vlan_group * vg,__be16 vlan_proto,u16 vlan_id)671fd9b1fcSPatrick McHardy static inline struct net_device *vlan_group_get_device(struct vlan_group *vg,
681fd9b1fcSPatrick McHardy __be16 vlan_proto,
691fd9b1fcSPatrick McHardy u16 vlan_id)
701fd9b1fcSPatrick McHardy {
71d0186842SFlorian Fainelli int pidx = vlan_proto_idx(vlan_proto);
72d0186842SFlorian Fainelli
73d0186842SFlorian Fainelli if (pidx < 0)
74d0186842SFlorian Fainelli return NULL;
75d0186842SFlorian Fainelli
76d0186842SFlorian Fainelli return __vlan_group_get_device(vg, pidx, vlan_id);
771fd9b1fcSPatrick McHardy }
781fd9b1fcSPatrick McHardy
vlan_group_set_device(struct vlan_group * vg,__be16 vlan_proto,u16 vlan_id,struct net_device * dev)79536d1d4aSJiri Pirko static inline void vlan_group_set_device(struct vlan_group *vg,
801fd9b1fcSPatrick McHardy __be16 vlan_proto, u16 vlan_id,
81536d1d4aSJiri Pirko struct net_device *dev)
82536d1d4aSJiri Pirko {
83d0186842SFlorian Fainelli int pidx = vlan_proto_idx(vlan_proto);
84536d1d4aSJiri Pirko struct net_device **array;
85d0186842SFlorian Fainelli
86d0186842SFlorian Fainelli if (!vg || pidx < 0)
87536d1d4aSJiri Pirko return;
88d0186842SFlorian Fainelli array = vg->vlan_devices_arrays[pidx]
891fd9b1fcSPatrick McHardy [vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
90536d1d4aSJiri Pirko array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
91536d1d4aSJiri Pirko }
92536d1d4aSJiri Pirko
9369ecca86SDavid Lamparter /* Must be invoked with rcu_read_lock or with RTNL. */
vlan_find_dev(struct net_device * real_dev,__be16 vlan_proto,u16 vlan_id)9469ecca86SDavid Lamparter static inline struct net_device *vlan_find_dev(struct net_device *real_dev,
951fd9b1fcSPatrick McHardy __be16 vlan_proto, u16 vlan_id)
9669ecca86SDavid Lamparter {
975b9ea6e0SJiri Pirko struct vlan_info *vlan_info = rcu_dereference_rtnl(real_dev->vlan_info);
9869ecca86SDavid Lamparter
995b9ea6e0SJiri Pirko if (vlan_info)
1001fd9b1fcSPatrick McHardy return vlan_group_get_device(&vlan_info->grp,
1011fd9b1fcSPatrick McHardy vlan_proto, vlan_id);
10269ecca86SDavid Lamparter
10369ecca86SDavid Lamparter return NULL;
10469ecca86SDavid Lamparter }
10569ecca86SDavid Lamparter
vlan_tnl_features(struct net_device * real_dev)1067dad9937SDavide Caratti static inline netdev_features_t vlan_tnl_features(struct net_device *real_dev)
1077dad9937SDavide Caratti {
1087dad9937SDavide Caratti netdev_features_t ret;
1097dad9937SDavide Caratti
1107dad9937SDavide Caratti ret = real_dev->hw_enc_features &
1119d72b8daSJakub Kicinski (NETIF_F_CSUM_MASK | NETIF_F_GSO_SOFTWARE |
1129d72b8daSJakub Kicinski NETIF_F_GSO_ENCAP_ALL);
1137dad9937SDavide Caratti
1147dad9937SDavide Caratti if ((ret & NETIF_F_GSO_ENCAP_ALL) && (ret & NETIF_F_CSUM_MASK))
1157dad9937SDavide Caratti return (ret & ~NETIF_F_CSUM_MASK) | NETIF_F_HW_CSUM;
1167dad9937SDavide Caratti return 0;
1177dad9937SDavide Caratti }
1187dad9937SDavide Caratti
1191fd9b1fcSPatrick McHardy #define vlan_group_for_each_dev(grp, i, dev) \
1201fd9b1fcSPatrick McHardy for ((i) = 0; i < VLAN_PROTO_NUM * VLAN_N_VID; i++) \
1211fd9b1fcSPatrick McHardy if (((dev) = __vlan_group_get_device((grp), (i) / VLAN_N_VID, \
1221fd9b1fcSPatrick McHardy (i) % VLAN_N_VID)))
1231fd9b1fcSPatrick McHardy
1249daae9bdSGal Pressman int vlan_filter_push_vids(struct vlan_info *vlan_info, __be16 proto);
1259daae9bdSGal Pressman void vlan_filter_drop_vids(struct vlan_info *vlan_info, __be16 proto);
1269daae9bdSGal Pressman
1271da177e4SLinus Torvalds /* found in vlan_dev.c */
128c17d8874SPatrick McHardy void vlan_dev_set_ingress_priority(const struct net_device *dev,
1299bb8582eSPatrick McHardy u32 skb_prio, u16 vlan_prio);
130c17d8874SPatrick McHardy int vlan_dev_set_egress_priority(const struct net_device *dev,
1319bb8582eSPatrick McHardy u32 skb_prio, u16 vlan_prio);
132*37aa50c5SXin Long void vlan_dev_free_egress_priority(const struct net_device *dev);
133b3ce0325SPatrick McHardy int vlan_dev_change_flags(const struct net_device *dev, u32 flag, u32 mask);
1349c153d38SKees Cook void vlan_dev_get_realdev_name(const struct net_device *dev, char *result,
1359c153d38SKees Cook size_t size);
1361da177e4SLinus Torvalds
1371fd9b1fcSPatrick McHardy int vlan_check_real_dev(struct net_device *real_dev,
13833fa3823SDavid Ahern __be16 protocol, u16 vlan_id,
13933fa3823SDavid Ahern struct netlink_ext_ack *extack);
14007b5b17eSPatrick McHardy void vlan_setup(struct net_device *dev);
14142ab19eeSDavid Ahern int register_vlan_dev(struct net_device *dev, struct netlink_ext_ack *extack);
14223289a37SEric Dumazet void unregister_vlan_dev(struct net_device *dev, struct list_head *head);
143308453aaSMike Manning bool vlan_dev_inherit_address(struct net_device *dev,
144308453aaSMike Manning struct net_device *real_dev);
14507b5b17eSPatrick McHardy
vlan_get_ingress_priority(struct net_device * dev,u16 vlan_tci)1467750f403SPatrick McHardy static inline u32 vlan_get_ingress_priority(struct net_device *dev,
1479bb8582eSPatrick McHardy u16 vlan_tci)
1487750f403SPatrick McHardy {
1497da82c06SJiri Pirko struct vlan_dev_priv *vip = vlan_dev_priv(dev);
1507750f403SPatrick McHardy
15105423b24SEric Dumazet return vip->ingress_priority_map[(vlan_tci >> VLAN_PRIO_SHIFT) & 0x7];
1527750f403SPatrick McHardy }
1537750f403SPatrick McHardy
15470c03b49SPatrick McHardy #ifdef CONFIG_VLAN_8021Q_GVRP
155348662a1SJoe Perches int vlan_gvrp_request_join(const struct net_device *dev);
156348662a1SJoe Perches void vlan_gvrp_request_leave(const struct net_device *dev);
157348662a1SJoe Perches int vlan_gvrp_init_applicant(struct net_device *dev);
158348662a1SJoe Perches void vlan_gvrp_uninit_applicant(struct net_device *dev);
159348662a1SJoe Perches int vlan_gvrp_init(void);
160348662a1SJoe Perches void vlan_gvrp_uninit(void);
16170c03b49SPatrick McHardy #else
vlan_gvrp_request_join(const struct net_device * dev)16270c03b49SPatrick McHardy static inline int vlan_gvrp_request_join(const struct net_device *dev) { return 0; }
vlan_gvrp_request_leave(const struct net_device * dev)16370c03b49SPatrick McHardy static inline void vlan_gvrp_request_leave(const struct net_device *dev) {}
vlan_gvrp_init_applicant(struct net_device * dev)16470c03b49SPatrick McHardy static inline int vlan_gvrp_init_applicant(struct net_device *dev) { return 0; }
vlan_gvrp_uninit_applicant(struct net_device * dev)16570c03b49SPatrick McHardy static inline void vlan_gvrp_uninit_applicant(struct net_device *dev) {}
vlan_gvrp_init(void)16670c03b49SPatrick McHardy static inline int vlan_gvrp_init(void) { return 0; }
vlan_gvrp_uninit(void)16770c03b49SPatrick McHardy static inline void vlan_gvrp_uninit(void) {}
16870c03b49SPatrick McHardy #endif
16970c03b49SPatrick McHardy
17086fbe9bbSDavid Ward #ifdef CONFIG_VLAN_8021Q_MVRP
171348662a1SJoe Perches int vlan_mvrp_request_join(const struct net_device *dev);
172348662a1SJoe Perches void vlan_mvrp_request_leave(const struct net_device *dev);
173348662a1SJoe Perches int vlan_mvrp_init_applicant(struct net_device *dev);
174348662a1SJoe Perches void vlan_mvrp_uninit_applicant(struct net_device *dev);
175348662a1SJoe Perches int vlan_mvrp_init(void);
176348662a1SJoe Perches void vlan_mvrp_uninit(void);
17786fbe9bbSDavid Ward #else
vlan_mvrp_request_join(const struct net_device * dev)17886fbe9bbSDavid Ward static inline int vlan_mvrp_request_join(const struct net_device *dev) { return 0; }
vlan_mvrp_request_leave(const struct net_device * dev)17986fbe9bbSDavid Ward static inline void vlan_mvrp_request_leave(const struct net_device *dev) {}
vlan_mvrp_init_applicant(struct net_device * dev)18086fbe9bbSDavid Ward static inline int vlan_mvrp_init_applicant(struct net_device *dev) { return 0; }
vlan_mvrp_uninit_applicant(struct net_device * dev)18186fbe9bbSDavid Ward static inline void vlan_mvrp_uninit_applicant(struct net_device *dev) {}
vlan_mvrp_init(void)18286fbe9bbSDavid Ward static inline int vlan_mvrp_init(void) { return 0; }
vlan_mvrp_uninit(void)18386fbe9bbSDavid Ward static inline void vlan_mvrp_uninit(void) {}
18486fbe9bbSDavid Ward #endif
18586fbe9bbSDavid Ward
186b3020061SStephen Hemminger extern const char vlan_fullname[];
187b3020061SStephen Hemminger extern const char vlan_version[];
188348662a1SJoe Perches int vlan_netlink_init(void);
189348662a1SJoe Perches void vlan_netlink_fini(void);
19007b5b17eSPatrick McHardy
19107b5b17eSPatrick McHardy extern struct rtnl_link_ops vlan_link_ops;
19207b5b17eSPatrick McHardy
193c7d03a00SAlexey Dobriyan extern unsigned int vlan_net_id;
194d9ed0f0eSPavel Emelyanov
195a59a8c1cSPavel Emelyanov struct proc_dir_entry;
196a59a8c1cSPavel Emelyanov
197d9ed0f0eSPavel Emelyanov struct vlan_net {
198a59a8c1cSPavel Emelyanov /* /proc/net/vlan */
199a59a8c1cSPavel Emelyanov struct proc_dir_entry *proc_vlan_dir;
200a59a8c1cSPavel Emelyanov /* /proc/net/vlan/config */
201a59a8c1cSPavel Emelyanov struct proc_dir_entry *proc_vlan_conf;
2027a17a2f7SPavel Emelyanov /* Determines interface naming scheme. */
2037a17a2f7SPavel Emelyanov unsigned short name_type;
204d9ed0f0eSPavel Emelyanov };
205d9ed0f0eSPavel Emelyanov
2061da177e4SLinus Torvalds #endif /* !(__BEN_VLAN_802_1Q_INC__) */
207