2 * lib/route/link/vlan.c VLAN Link Info
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation version 2.1
9 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
20 #include <netlink-local.h>
21 #include <netlink/netlink.h>
22 #include <netlink/attr.h>
23 #include <netlink/utils.h>
24 #include <netlink/object.h>
25 #include <netlink/route/rtnl.h>
26 #include <netlink/route/link/info-api.h>
27 #include <netlink/route/link/vlan.h>
29 #include <linux/if_vlan.h>
32 #define VLAN_HAS_ID (1<<0)
33 #define VLAN_HAS_FLAGS (1<<1)
34 #define VLAN_HAS_INGRESS_QOS (1<<2)
35 #define VLAN_HAS_EGRESS_QOS (1<<3)
41 uint32_t vi_flags_mask;
42 uint32_t vi_ingress_qos[VLAN_PRIO_MAX+1];
44 uint32_t vi_egress_size;
45 struct vlan_map * vi_egress_qos;
50 static struct trans_tbl vlan_flags[] = {
51 __ADD(VLAN_FLAG_REORDER_HDR, reorder_hdr)
54 char *rtnl_link_vlan_flags2str(int flags, char *buf, size_t len)
56 return __flags2str(flags, buf, len, vlan_flags, ARRAY_SIZE(vlan_flags));
59 int rtnl_link_vlan_str2flags(const char *name)
61 return __str2flags(name, vlan_flags, ARRAY_SIZE(vlan_flags));
64 static struct nla_policy vlan_policy[IFLA_VLAN_MAX+1] = {
65 [IFLA_VLAN_ID] = { .type = NLA_U16 },
66 [IFLA_VLAN_FLAGS] = { .minlen = sizeof(struct ifla_vlan_flags) },
67 [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
68 [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED },
71 static int vlan_alloc(struct rtnl_link *link)
75 if ((vi = calloc(1, sizeof(*vi))) == NULL)
83 static int vlan_parse(struct rtnl_link *link, struct nlattr *data,
84 struct nlattr *xstats)
86 struct nlattr *tb[IFLA_VLAN_MAX+1];
90 NL_DBG(3, "Parsing VLAN link info");
92 if ((err = nla_parse_nested(tb, IFLA_VLAN_MAX, data, vlan_policy)) < 0)
95 if ((err = vlan_alloc(link)) < 0)
100 if (tb[IFLA_VLAN_ID]) {
101 vi->vi_vlan_id = nla_get_u16(tb[IFLA_VLAN_ID]);
102 vi->vi_mask |= VLAN_HAS_ID;
105 if (tb[IFLA_VLAN_FLAGS]) {
106 struct ifla_vlan_flags flags;
107 nla_memcpy(&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags));
109 vi->vi_flags = flags.flags;
110 vi->vi_mask |= VLAN_HAS_FLAGS;
113 if (tb[IFLA_VLAN_INGRESS_QOS]) {
114 struct ifla_vlan_qos_mapping *map;
118 memset(vi->vi_ingress_qos, 0, sizeof(vi->vi_ingress_qos));
120 nla_for_each_nested(nla, tb[IFLA_VLAN_INGRESS_QOS], remaining) {
121 if (nla_len(nla) < sizeof(*map))
125 if (map->from < 0 || map->from > VLAN_PRIO_MAX) {
129 vi->vi_ingress_qos[map->from] = map->to;
132 vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
135 if (tb[IFLA_VLAN_EGRESS_QOS]) {
136 struct ifla_vlan_qos_mapping *map;
138 int remaining, i = 0;
140 nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
141 if (nla_len(nla) < sizeof(*map))
146 /* align to have a little reserve */
147 vi->vi_egress_size = (i + 32) & ~31;
148 vi->vi_egress_qos = calloc(vi->vi_egress_size, sizeof(*map));
149 if (vi->vi_egress_qos == NULL)
153 nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
155 NL_DBG(4, "Assigning egress qos mapping %d\n", i);
156 vi->vi_egress_qos[i].vm_from = map->from;
157 vi->vi_egress_qos[i++].vm_to = map->to;
161 vi->vi_mask |= VLAN_HAS_EGRESS_QOS;
169 static void vlan_free(struct rtnl_link *link)
171 struct vlan_info *vi = link->l_info;
174 free(vi->vi_egress_qos);
175 vi->vi_egress_qos = NULL;
182 static void vlan_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
184 struct vlan_info *vi = link->l_info;
186 nl_dump(p, "vlan-id %d", vi->vi_vlan_id);
189 static void vlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
191 struct vlan_info *vi = link->l_info;
195 rtnl_link_vlan_flags2str(vi->vi_flags, buf, sizeof(buf));
196 nl_dump_line(p, " vlan-info id %d <%s>\n", vi->vi_vlan_id, buf);
198 if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) {
200 " ingress vlan prio -> qos/socket prio mapping:\n");
201 for (i = 0, printed = 0; i <= VLAN_PRIO_MAX; i++) {
202 if (vi->vi_ingress_qos[i]) {
204 nl_dump_line(p, " ");
205 nl_dump(p, "%x -> %#08x, ",
206 i, vi->vi_ingress_qos[i]);
207 if (printed++ == 3) {
214 if (printed > 0 && printed != 4)
218 if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
220 " egress qos/socket prio -> vlan prio mapping:\n");
221 for (i = 0, printed = 0; i < vi->vi_negress; i++) {
223 nl_dump_line(p, " ");
224 nl_dump(p, "%#08x -> %x, ",
225 vi->vi_egress_qos[i].vm_from,
226 vi->vi_egress_qos[i].vm_to);
227 if (printed++ == 3) {
233 if (printed > 0 && printed != 4)
238 static int vlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
240 struct vlan_info *vdst, *vsrc = src->l_info;
244 if ((err = rtnl_link_set_info_type(dst, "vlan")) < 0)
248 vdst->vi_egress_qos = calloc(vsrc->vi_egress_size,
249 sizeof(struct vlan_map));
250 if (!vdst->vi_egress_qos)
253 memcpy(vdst->vi_egress_qos, vsrc->vi_egress_qos,
254 vsrc->vi_egress_size * sizeof(struct vlan_map));
259 static int vlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
261 struct vlan_info *vi = link->l_info;
264 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
267 if (vi->vi_mask & VLAN_HAS_ID)
268 NLA_PUT_U16(msg, IFLA_VLAN_ID, vi->vi_vlan_id);
270 if (vi->vi_mask & VLAN_HAS_FLAGS) {
271 struct ifla_vlan_flags flags = {
272 .flags = vi->vi_flags,
273 .mask = vi->vi_flags_mask,
276 NLA_PUT(msg, IFLA_VLAN_FLAGS, sizeof(flags), &flags);
279 if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) {
280 struct ifla_vlan_qos_mapping map;
284 if (!(qos = nla_nest_start(msg, IFLA_VLAN_INGRESS_QOS)))
285 goto nla_put_failure;
287 for (i = 0; i <= VLAN_PRIO_MAX; i++) {
288 if (vi->vi_ingress_qos[i]) {
290 map.to = vi->vi_ingress_qos[i];
292 NLA_PUT(msg, i, sizeof(map), &map);
296 nla_nest_end(msg, qos);
299 if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
300 struct ifla_vlan_qos_mapping map;
304 if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS)))
305 goto nla_put_failure;
307 for (i = 0; i < vi->vi_negress; i++) {
308 map.from = vi->vi_egress_qos[i].vm_from;
309 map.to = vi->vi_egress_qos[i].vm_to;
311 NLA_PUT(msg, i, sizeof(map), &map);
314 nla_nest_end(msg, qos);
317 nla_nest_end(msg, data);
324 static struct rtnl_link_info_ops vlan_info_ops = {
326 .io_alloc = vlan_alloc,
327 .io_parse = vlan_parse,
329 [NL_DUMP_LINE] = vlan_dump_line,
330 [NL_DUMP_DETAILS] = vlan_dump_details,
332 .io_clone = vlan_clone,
333 .io_put_attrs = vlan_put_attrs,
334 .io_free = vlan_free,
337 int rtnl_link_vlan_set_id(struct rtnl_link *link, int id)
339 struct vlan_info *vi = link->l_info;
341 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
342 return -NLE_OPNOTSUPP;
345 vi->vi_mask |= VLAN_HAS_ID;
350 int rtnl_link_vlan_get_id(struct rtnl_link *link)
352 struct vlan_info *vi = link->l_info;
354 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
355 return -NLE_OPNOTSUPP;
357 if (vi->vi_mask & VLAN_HAS_ID)
358 return vi->vi_vlan_id;
363 int rtnl_link_vlan_set_flags(struct rtnl_link *link, unsigned int flags)
365 struct vlan_info *vi = link->l_info;
367 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
368 return -NLE_OPNOTSUPP;
370 vi->vi_flags_mask |= flags;
371 vi->vi_flags |= flags;
372 vi->vi_mask |= VLAN_HAS_FLAGS;
377 int rtnl_link_vlan_unset_flags(struct rtnl_link *link, unsigned int flags)
379 struct vlan_info *vi = link->l_info;
381 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
382 return -NLE_OPNOTSUPP;
384 vi->vi_flags_mask |= flags;
385 vi->vi_flags &= ~flags;
386 vi->vi_mask |= VLAN_HAS_FLAGS;
391 unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *link)
393 struct vlan_info *vi = link->l_info;
395 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
396 return -NLE_OPNOTSUPP;
401 int rtnl_link_vlan_set_ingress_map(struct rtnl_link *link, int from,
404 struct vlan_info *vi = link->l_info;
406 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
407 return -NLE_OPNOTSUPP;
409 if (from < 0 || from > VLAN_PRIO_MAX)
412 vi->vi_ingress_qos[from] = to;
413 vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
418 uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *link)
420 struct vlan_info *vi = link->l_info;
422 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
425 if (vi->vi_mask & VLAN_HAS_INGRESS_QOS)
426 return vi->vi_ingress_qos;
431 int rtnl_link_vlan_set_egress_map(struct rtnl_link *link, uint32_t from, int to)
433 struct vlan_info *vi = link->l_info;
435 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
436 return -NLE_OPNOTSUPP;
438 if (to < 0 || to > VLAN_PRIO_MAX)
441 if (vi->vi_negress >= vi->vi_egress_size) {
442 int new_size = vi->vi_egress_size + 32;
445 ptr = realloc(vi->vi_egress_qos, new_size);
449 vi->vi_egress_qos = ptr;
450 vi->vi_egress_size = new_size;
453 vi->vi_egress_qos[vi->vi_negress].vm_from = from;
454 vi->vi_egress_qos[vi->vi_negress].vm_to = to;
456 vi->vi_mask |= VLAN_HAS_EGRESS_QOS;
461 struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *link,
464 struct vlan_info *vi = link->l_info;
466 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
472 if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
473 *negress = vi->vi_negress;
474 return vi->vi_egress_qos;
481 static void __init vlan_init(void)
483 rtnl_link_register_info(&vlan_info_ops);
486 static void __exit vlan_exit(void)
488 rtnl_link_unregister_info(&vlan_info_ops);