Skip to content

Commit 07b5b17

Browse files
kaberDavid S. Miller
authored andcommitted
[VLAN]: Use rtnl_link API
Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent a4bf3af commit 07b5b17

File tree

5 files changed

+300
-11
lines changed

5 files changed

+300
-11
lines changed

include/linux/if_link.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,4 +153,38 @@ enum
153153

154154
#define IFLA_INFO_MAX (__IFLA_INFO_MAX - 1)
155155

156+
/* VLAN section */
157+
158+
enum
159+
{
160+
IFLA_VLAN_UNSPEC,
161+
IFLA_VLAN_ID,
162+
IFLA_VLAN_FLAGS,
163+
IFLA_VLAN_EGRESS_QOS,
164+
IFLA_VLAN_INGRESS_QOS,
165+
__IFLA_VLAN_MAX,
166+
};
167+
168+
#define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1)
169+
170+
struct ifla_vlan_flags {
171+
__u32 flags;
172+
__u32 mask;
173+
};
174+
175+
enum
176+
{
177+
IFLA_VLAN_QOS_UNSPEC,
178+
IFLA_VLAN_QOS_MAPPING,
179+
__IFLA_VLAN_QOS_MAX
180+
};
181+
182+
#define IFLA_VLAN_QOS_MAX (__IFLA_VLAN_QOS_MAX - 1)
183+
184+
struct ifla_vlan_qos_mapping
185+
{
186+
__u32 from;
187+
__u32 to;
188+
};
189+
156190
#endif /* _LINUX_IF_LINK_H */

net/8021q/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
obj-$(CONFIG_VLAN_8021Q) += 8021q.o
66

7-
8021q-objs := vlan.o vlan_dev.o
7+
8021q-objs := vlan.o vlan_dev.o vlan_netlink.o
88

99
ifeq ($(CONFIG_PROC_FS),y)
1010
8021q-objs += vlanproc.o

net/8021q/vlan.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,22 @@ static int __init vlan_proto_init(void)
9797

9898
/* Register us to receive netdevice events */
9999
err = register_netdevice_notifier(&vlan_notifier_block);
100-
if (err < 0) {
101-
dev_remove_pack(&vlan_packet_type);
102-
vlan_proc_cleanup();
103-
return err;
104-
}
100+
if (err < 0)
101+
goto err1;
105102

106-
vlan_ioctl_set(vlan_ioctl_handler);
103+
err = vlan_netlink_init();
104+
if (err < 0)
105+
goto err2;
107106

107+
vlan_ioctl_set(vlan_ioctl_handler);
108108
return 0;
109+
110+
err2:
111+
unregister_netdevice_notifier(&vlan_notifier_block);
112+
err1:
113+
vlan_proc_cleanup();
114+
dev_remove_pack(&vlan_packet_type);
115+
return err;
109116
}
110117

111118
/* Cleanup all vlan devices
@@ -136,6 +143,7 @@ static void __exit vlan_cleanup_module(void)
136143
{
137144
int i;
138145

146+
vlan_netlink_fini();
139147
vlan_ioctl_set(NULL);
140148

141149
/* Un-register us from receiving netdevice events */
@@ -306,7 +314,7 @@ static int unregister_vlan_dev(struct net_device *real_dev,
306314
return ret;
307315
}
308316

309-
static int unregister_vlan_device(struct net_device *dev)
317+
int unregister_vlan_device(struct net_device *dev)
310318
{
311319
int ret;
312320

@@ -361,7 +369,7 @@ static int vlan_dev_init(struct net_device *dev)
361369
return 0;
362370
}
363371

364-
static void vlan_setup(struct net_device *new_dev)
372+
void vlan_setup(struct net_device *new_dev)
365373
{
366374
SET_MODULE_OWNER(new_dev);
367375

@@ -410,7 +418,7 @@ static void vlan_transfer_operstate(const struct net_device *dev, struct net_dev
410418
}
411419
}
412420

413-
static int vlan_check_real_dev(struct net_device *real_dev, unsigned short vlan_id)
421+
int vlan_check_real_dev(struct net_device *real_dev, unsigned short vlan_id)
414422
{
415423
if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
416424
printk(VLAN_DBG "%s: VLANs not supported on %s.\n",
@@ -447,7 +455,7 @@ static int vlan_check_real_dev(struct net_device *real_dev, unsigned short vlan_
447455
return 0;
448456
}
449457

450-
static int register_vlan_dev(struct net_device *dev)
458+
int register_vlan_dev(struct net_device *dev)
451459
{
452460
struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
453461
struct net_device *real_dev = vlan->real_dev;
@@ -567,6 +575,7 @@ static int register_vlan_device(struct net_device *real_dev,
567575
VLAN_DEV_INFO(new_dev)->dent = NULL;
568576
VLAN_DEV_INFO(new_dev)->flags = VLAN_FLAG_REORDER_HDR;
569577

578+
new_dev->rtnl_link_ops = &vlan_link_ops;
570579
err = register_vlan_dev(new_dev);
571580
if (err < 0)
572581
goto out_free_newdev;

net/8021q/vlan.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,14 @@ void vlan_dev_get_realdev_name(const struct net_device *dev, char *result);
7272
void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result);
7373
void vlan_dev_set_multicast_list(struct net_device *vlan_dev);
7474

75+
int vlan_check_real_dev(struct net_device *real_dev, unsigned short vlan_id);
76+
void vlan_setup(struct net_device *dev);
77+
int register_vlan_dev(struct net_device *dev);
78+
int unregister_vlan_device(struct net_device *dev);
79+
80+
int vlan_netlink_init(void);
81+
void vlan_netlink_fini(void);
82+
83+
extern struct rtnl_link_ops vlan_link_ops;
84+
7585
#endif /* !(__BEN_VLAN_802_1Q_INC__) */

net/8021q/vlan_netlink.c

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/*
2+
* VLAN netlink control interface
3+
*
4+
* Copyright (c) 2007 Patrick McHardy <kaber@trash.net>
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU General Public License
8+
* version 2 as published by the Free Software Foundation.
9+
*/
10+
11+
#include <linux/kernel.h>
12+
#include <linux/netdevice.h>
13+
#include <linux/if_vlan.h>
14+
#include <net/netlink.h>
15+
#include <net/rtnetlink.h>
16+
#include "vlan.h"
17+
18+
19+
static const struct nla_policy vlan_policy[IFLA_VLAN_MAX + 1] = {
20+
[IFLA_VLAN_ID] = { .type = NLA_U16 },
21+
[IFLA_VLAN_FLAGS] = { .len = sizeof(struct ifla_vlan_flags) },
22+
[IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED },
23+
[IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
24+
};
25+
26+
static const struct nla_policy vlan_map_policy[IFLA_VLAN_QOS_MAX + 1] = {
27+
[IFLA_VLAN_QOS_MAPPING] = { .len = sizeof(struct ifla_vlan_qos_mapping) },
28+
};
29+
30+
31+
static inline int vlan_validate_qos_map(struct nlattr *attr)
32+
{
33+
if (!attr)
34+
return 0;
35+
return nla_validate_nested(attr, IFLA_VLAN_QOS_MAX, vlan_map_policy);
36+
}
37+
38+
static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
39+
{
40+
struct ifla_vlan_flags *flags;
41+
u16 id;
42+
int err;
43+
44+
if (!data)
45+
return -EINVAL;
46+
47+
if (data[IFLA_VLAN_ID]) {
48+
id = nla_get_u16(data[IFLA_VLAN_ID]);
49+
if (id >= VLAN_VID_MASK)
50+
return -ERANGE;
51+
}
52+
if (data[IFLA_VLAN_FLAGS]) {
53+
flags = nla_data(data[IFLA_VLAN_FLAGS]);
54+
if ((flags->flags & flags->mask) & ~VLAN_FLAG_REORDER_HDR)
55+
return -EINVAL;
56+
}
57+
58+
err = vlan_validate_qos_map(data[IFLA_VLAN_INGRESS_QOS]);
59+
if (err < 0)
60+
return err;
61+
err = vlan_validate_qos_map(data[IFLA_VLAN_EGRESS_QOS]);
62+
if (err < 0)
63+
return err;
64+
return 0;
65+
}
66+
67+
static int vlan_changelink(struct net_device *dev,
68+
struct nlattr *tb[], struct nlattr *data[])
69+
{
70+
struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
71+
struct ifla_vlan_flags *flags;
72+
struct ifla_vlan_qos_mapping *m;
73+
struct nlattr *attr;
74+
int rem;
75+
76+
if (data[IFLA_VLAN_FLAGS]) {
77+
flags = nla_data(data[IFLA_VLAN_FLAGS]);
78+
vlan->flags = (vlan->flags & ~flags->mask) |
79+
(flags->flags & flags->mask);
80+
}
81+
if (data[IFLA_VLAN_INGRESS_QOS]) {
82+
nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) {
83+
m = nla_data(attr);
84+
vlan_dev_set_ingress_priority(dev, m->to, m->from);
85+
}
86+
}
87+
if (data[IFLA_VLAN_EGRESS_QOS]) {
88+
nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) {
89+
m = nla_data(attr);
90+
vlan_dev_set_egress_priority(dev, m->from, m->to);
91+
}
92+
}
93+
return 0;
94+
}
95+
96+
static int vlan_newlink(struct net_device *dev,
97+
struct nlattr *tb[], struct nlattr *data[])
98+
{
99+
struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
100+
struct net_device *real_dev;
101+
int err;
102+
103+
if (!data[IFLA_VLAN_ID])
104+
return -EINVAL;
105+
106+
if (!tb[IFLA_LINK])
107+
return -EINVAL;
108+
real_dev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK]));
109+
if (!real_dev)
110+
return -ENODEV;
111+
112+
vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]);
113+
vlan->real_dev = real_dev;
114+
vlan->flags = VLAN_FLAG_REORDER_HDR;
115+
116+
err = vlan_check_real_dev(real_dev, vlan->vlan_id);
117+
if (err < 0)
118+
return err;
119+
120+
if (!tb[IFLA_MTU])
121+
dev->mtu = real_dev->mtu;
122+
else if (dev->mtu > real_dev->mtu)
123+
return -EINVAL;
124+
125+
err = vlan_changelink(dev, tb, data);
126+
if (err < 0)
127+
return err;
128+
129+
return register_vlan_dev(dev);
130+
}
131+
132+
static void vlan_dellink(struct net_device *dev)
133+
{
134+
unregister_vlan_device(dev);
135+
}
136+
137+
static inline size_t vlan_qos_map_size(unsigned int n)
138+
{
139+
if (n == 0)
140+
return 0;
141+
/* IFLA_VLAN_{EGRESS,INGRESS}_QOS + n * IFLA_VLAN_QOS_MAPPING */
142+
return nla_total_size(sizeof(struct nlattr)) +
143+
nla_total_size(sizeof(struct ifla_vlan_qos_mapping)) * n;
144+
}
145+
146+
static size_t vlan_get_size(const struct net_device *dev)
147+
{
148+
struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
149+
150+
return nla_total_size(2) + /* IFLA_VLAN_ID */
151+
vlan_qos_map_size(vlan->nr_ingress_mappings) +
152+
vlan_qos_map_size(vlan->nr_egress_mappings);
153+
}
154+
155+
static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
156+
{
157+
struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
158+
struct vlan_priority_tci_mapping *pm;
159+
struct ifla_vlan_flags f;
160+
struct ifla_vlan_qos_mapping m;
161+
struct nlattr *nest;
162+
unsigned int i;
163+
164+
NLA_PUT_U16(skb, IFLA_VLAN_ID, VLAN_DEV_INFO(dev)->vlan_id);
165+
if (vlan->flags) {
166+
f.flags = vlan->flags;
167+
f.mask = ~0;
168+
NLA_PUT(skb, IFLA_VLAN_FLAGS, sizeof(f), &f);
169+
}
170+
if (vlan->nr_ingress_mappings) {
171+
nest = nla_nest_start(skb, IFLA_VLAN_INGRESS_QOS);
172+
if (nest == NULL)
173+
goto nla_put_failure;
174+
175+
for (i = 0; i < ARRAY_SIZE(vlan->ingress_priority_map); i++) {
176+
if (!vlan->ingress_priority_map[i])
177+
continue;
178+
179+
m.from = i;
180+
m.to = vlan->ingress_priority_map[i];
181+
NLA_PUT(skb, IFLA_VLAN_QOS_MAPPING,
182+
sizeof(m), &m);
183+
}
184+
nla_nest_end(skb, nest);
185+
}
186+
187+
if (vlan->nr_egress_mappings) {
188+
nest = nla_nest_start(skb, IFLA_VLAN_EGRESS_QOS);
189+
if (nest == NULL)
190+
goto nla_put_failure;
191+
192+
for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
193+
for (pm = vlan->egress_priority_map[i]; pm;
194+
pm = pm->next) {
195+
if (!pm->vlan_qos)
196+
continue;
197+
198+
m.from = pm->priority;
199+
m.to = (pm->vlan_qos >> 13) & 0x7;
200+
NLA_PUT(skb, IFLA_VLAN_QOS_MAPPING,
201+
sizeof(m), &m);
202+
}
203+
}
204+
nla_nest_end(skb, nest);
205+
}
206+
return 0;
207+
208+
nla_put_failure:
209+
return -EMSGSIZE;
210+
}
211+
212+
struct rtnl_link_ops vlan_link_ops __read_mostly = {
213+
.kind = "vlan",
214+
.maxtype = IFLA_VLAN_MAX,
215+
.policy = vlan_policy,
216+
.priv_size = sizeof(struct vlan_dev_info),
217+
.setup = vlan_setup,
218+
.validate = vlan_validate,
219+
.newlink = vlan_newlink,
220+
.changelink = vlan_changelink,
221+
.dellink = vlan_dellink,
222+
.get_size = vlan_get_size,
223+
.fill_info = vlan_fill_info,
224+
};
225+
226+
int __init vlan_netlink_init(void)
227+
{
228+
return rtnl_link_register(&vlan_link_ops);
229+
}
230+
231+
void __exit vlan_netlink_fini(void)
232+
{
233+
rtnl_link_unregister(&vlan_link_ops);
234+
}
235+
236+
MODULE_ALIAS_RTNL_LINK("vlan");

0 commit comments

Comments
 (0)