00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <netlink-local.h>
00021 #include <netlink/netlink.h>
00022 #include <netlink/attr.h>
00023 #include <netlink/utils.h>
00024 #include <netlink/object.h>
00025 #include <netlink/route/rtnl.h>
00026 #include <netlink/route/link/info-api.h>
00027 #include <netlink/route/link/vlan.h>
00028
00029 #include <linux/if_vlan.h>
00030
00031
00032 #define VLAN_HAS_ID (1<<0)
00033 #define VLAN_HAS_FLAGS (1<<1)
00034 #define VLAN_HAS_INGRESS_QOS (1<<2)
00035 #define VLAN_HAS_EGRESS_QOS (1<<3)
00036
00037 struct vlan_info
00038 {
00039 uint16_t vi_vlan_id;
00040 uint32_t vi_flags;
00041 uint32_t vi_flags_mask;
00042 uint32_t vi_ingress_qos[VLAN_PRIO_MAX+1];
00043 uint32_t vi_negress;
00044 uint32_t vi_egress_size;
00045 struct vlan_map * vi_egress_qos;
00046 uint32_t vi_mask;
00047 };
00048
00049
00050 static struct trans_tbl vlan_flags[] = {
00051 __ADD(VLAN_FLAG_REORDER_HDR, reorder_hdr)
00052 };
00053
00054 char *rtnl_link_vlan_flags2str(int flags, char *buf, size_t len)
00055 {
00056 return __flags2str(flags, buf, len, vlan_flags, ARRAY_SIZE(vlan_flags));
00057 }
00058
00059 int rtnl_link_vlan_str2flags(const char *name)
00060 {
00061 return __str2flags(name, vlan_flags, ARRAY_SIZE(vlan_flags));
00062 }
00063
00064 static struct nla_policy vlan_policy[IFLA_VLAN_MAX+1] = {
00065 [IFLA_VLAN_ID] = { .type = NLA_U16 },
00066 [IFLA_VLAN_FLAGS] = { .minlen = sizeof(struct ifla_vlan_flags) },
00067 [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
00068 [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED },
00069 };
00070
00071 static int vlan_alloc(struct rtnl_link *link)
00072 {
00073 struct vlan_info *vi;
00074
00075 if ((vi = calloc(1, sizeof(*vi))) == NULL)
00076 return nl_errno(ENOMEM);
00077
00078 link->l_info = vi;
00079
00080 return 0;
00081 }
00082
00083 static int vlan_parse(struct rtnl_link *link, struct nlattr *data,
00084 struct nlattr *xstats)
00085 {
00086 struct nlattr *tb[IFLA_VLAN_MAX+1];
00087 struct vlan_info *vi;
00088 int err;
00089
00090 NL_DBG(3, "Parsing VLAN link info");
00091
00092 if ((err = nla_parse_nested(tb, IFLA_VLAN_MAX, data, vlan_policy)) < 0)
00093 goto errout;
00094
00095 if ((err = vlan_alloc(link)) < 0)
00096 goto errout;
00097
00098 vi = link->l_info;
00099
00100 if (tb[IFLA_VLAN_ID]) {
00101 vi->vi_vlan_id = nla_get_u16(tb[IFLA_VLAN_ID]);
00102 vi->vi_mask |= VLAN_HAS_ID;
00103 }
00104
00105 if (tb[IFLA_VLAN_FLAGS]) {
00106 struct ifla_vlan_flags flags;
00107 nla_memcpy(&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags));
00108
00109 vi->vi_flags = flags.flags;
00110 vi->vi_mask |= VLAN_HAS_FLAGS;
00111 }
00112
00113 if (tb[IFLA_VLAN_INGRESS_QOS]) {
00114 struct ifla_vlan_qos_mapping *map;
00115 struct nlattr *nla;
00116 int remaining;
00117
00118 memset(vi->vi_ingress_qos, 0, sizeof(vi->vi_ingress_qos));
00119
00120 nla_for_each_nested(nla, tb[IFLA_VLAN_INGRESS_QOS], remaining) {
00121 if (nla_len(nla) < sizeof(*map))
00122 return nl_error(EINVAL, "Malformed mapping");
00123
00124 map = nla_data(nla);
00125 if (map->from < 0 || map->from > VLAN_PRIO_MAX) {
00126 return nl_error(EINVAL, "VLAN prio %d out of "
00127 "range", map->from);
00128 }
00129
00130 vi->vi_ingress_qos[map->from] = map->to;
00131 }
00132
00133 vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
00134 }
00135
00136 if (tb[IFLA_VLAN_EGRESS_QOS]) {
00137 struct ifla_vlan_qos_mapping *map;
00138 struct nlattr *nla;
00139 int remaining, i = 0;
00140
00141 nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
00142 if (nla_len(nla) < sizeof(*map))
00143 return nl_error(EINVAL, "Malformed mapping");
00144 i++;
00145 }
00146
00147
00148 vi->vi_egress_size = (i + 32) & ~31;
00149 vi->vi_egress_qos = calloc(vi->vi_egress_size, sizeof(*map));
00150 if (vi->vi_egress_qos == NULL)
00151 return nl_errno(ENOMEM);
00152
00153 i = 0;
00154 nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
00155 map = nla_data(nla);
00156 NL_DBG(4, "Assigning egress qos mapping %d\n", i);
00157 vi->vi_egress_qos[i].vm_from = map->from;
00158 vi->vi_egress_qos[i++].vm_to = map->to;
00159 }
00160
00161 vi->vi_negress = i;
00162 vi->vi_mask |= VLAN_HAS_EGRESS_QOS;
00163 }
00164
00165 err = 0;
00166 errout:
00167 return err;
00168 }
00169
00170 static void vlan_free(struct rtnl_link *link)
00171 {
00172 struct vlan_info *vi = link->l_info;
00173
00174 if (vi) {
00175 free(vi->vi_egress_qos);
00176 vi->vi_egress_qos = NULL;
00177 }
00178
00179 free(vi);
00180 link->l_info = NULL;
00181 }
00182
00183 static int vlan_dump_brief(struct rtnl_link *link, struct nl_dump_params *p,
00184 int line)
00185 {
00186 struct vlan_info *vi = link->l_info;
00187
00188 dp_dump(p, "vlan-id %d", vi->vi_vlan_id);
00189
00190 return line;
00191 }
00192
00193 static int vlan_dump_full(struct rtnl_link *link, struct nl_dump_params *p,
00194 int line)
00195 {
00196 struct vlan_info *vi = link->l_info;
00197 int i, printed;
00198 char buf[64];
00199
00200 rtnl_link_vlan_flags2str(vi->vi_flags, buf, sizeof(buf));
00201 dp_dump_line(p, line++, " vlan-info id %d <%s>\n",
00202 vi->vi_vlan_id, buf);
00203
00204 if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) {
00205 dp_dump_line(p, line++,
00206 " ingress vlan prio -> qos/socket prio mapping:\n");
00207 for (i = 0, printed = 0; i <= VLAN_PRIO_MAX; i++) {
00208 if (vi->vi_ingress_qos[i]) {
00209 if (printed == 0) {
00210 dp_new_line(p, line);
00211 dp_dump(p, " ");
00212 }
00213 dp_dump(p, "%x -> %#08x, ",
00214 i, vi->vi_ingress_qos[i]);
00215 if (printed++ == 3) {
00216 dp_dump(p, "\n");
00217 printed = 0;
00218 }
00219 }
00220 }
00221
00222 if (printed > 0 && printed != 4)
00223 dp_dump(p, "\n");
00224 }
00225
00226 if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
00227 dp_dump_line(p, line++,
00228 " egress qos/socket prio -> vlan prio mapping:\n");
00229 for (i = 0, printed = 0; i < vi->vi_negress; i++) {
00230 if (printed == 0) {
00231 dp_new_line(p, line);
00232 dp_dump(p, " ");
00233 }
00234 dp_dump(p, "%#08x -> %x, ",
00235 vi->vi_egress_qos[i].vm_from,
00236 vi->vi_egress_qos[i].vm_to);
00237 if (printed++ == 3) {
00238 dp_dump(p, "\n");
00239 printed = 0;
00240 }
00241 }
00242
00243 if (printed > 0 && printed != 4)
00244 dp_dump(p, "\n");
00245 }
00246
00247 return line;
00248 }
00249
00250 static int vlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
00251 {
00252 struct vlan_info *vdst, *vsrc = src->l_info;
00253 int err;
00254
00255 dst->l_info = NULL;
00256 if ((err = rtnl_link_set_info_type(dst, "vlan")) < 0)
00257 return err;
00258 vdst = dst->l_info;
00259
00260 vdst->vi_egress_qos = calloc(vsrc->vi_egress_size,
00261 sizeof(struct vlan_map));
00262 if (!vdst->vi_egress_qos)
00263 return nl_errno(ENOMEM);
00264
00265 memcpy(vdst->vi_egress_qos, vsrc->vi_egress_qos,
00266 vsrc->vi_egress_size * sizeof(struct vlan_map));
00267
00268 return 0;
00269 }
00270
00271 static int vlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
00272 {
00273 struct vlan_info *vi = link->l_info;
00274 struct nlattr *data;
00275
00276 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
00277 return nl_errno(ENOBUFS);
00278
00279 if (vi->vi_mask & VLAN_HAS_ID)
00280 NLA_PUT_U16(msg, IFLA_VLAN_ID, vi->vi_vlan_id);
00281
00282 if (vi->vi_mask & VLAN_HAS_FLAGS) {
00283 struct ifla_vlan_flags flags = {
00284 .flags = vi->vi_flags,
00285 .mask = vi->vi_flags_mask,
00286 };
00287
00288 NLA_PUT(msg, IFLA_VLAN_FLAGS, sizeof(flags), &flags);
00289 }
00290
00291 if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) {
00292 struct ifla_vlan_qos_mapping map;
00293 struct nlattr *qos;
00294 int i;
00295
00296 if (!(qos = nla_nest_start(msg, IFLA_VLAN_INGRESS_QOS)))
00297 goto nla_put_failure;
00298
00299 for (i = 0; i <= VLAN_PRIO_MAX; i++) {
00300 if (vi->vi_ingress_qos[i]) {
00301 map.from = i;
00302 map.to = vi->vi_ingress_qos[i];
00303
00304 NLA_PUT(msg, i, sizeof(map), &map);
00305 }
00306 }
00307
00308 nla_nest_end(msg, qos);
00309 }
00310
00311 if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
00312 struct ifla_vlan_qos_mapping map;
00313 struct nlattr *qos;
00314 int i;
00315
00316 if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS)))
00317 goto nla_put_failure;
00318
00319 for (i = 0; i < vi->vi_negress; i++) {
00320 map.from = vi->vi_egress_qos[i].vm_from;
00321 map.to = vi->vi_egress_qos[i].vm_to;
00322
00323 NLA_PUT(msg, i, sizeof(map), &map);
00324 }
00325
00326 nla_nest_end(msg, qos);
00327 }
00328
00329 nla_nest_end(msg, data);
00330
00331 nla_put_failure:
00332
00333 return 0;
00334 }
00335
00336 static struct rtnl_link_info_ops vlan_info_ops = {
00337 .io_name = "vlan",
00338 .io_alloc = vlan_alloc,
00339 .io_parse = vlan_parse,
00340 .io_dump[NL_DUMP_BRIEF] = vlan_dump_brief,
00341 .io_dump[NL_DUMP_FULL] = vlan_dump_full,
00342 .io_clone = vlan_clone,
00343 .io_put_attrs = vlan_put_attrs,
00344 .io_free = vlan_free,
00345 };
00346
00347 int rtnl_link_vlan_set_id(struct rtnl_link *link, int id)
00348 {
00349 struct vlan_info *vi = link->l_info;
00350
00351 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
00352 return nl_error(EOPNOTSUPP, "Not a VLAN link");
00353
00354 vi->vi_vlan_id = id;
00355 vi->vi_mask |= VLAN_HAS_ID;
00356
00357 return 0;
00358 }
00359
00360 int rtnl_link_vlan_get_id(struct rtnl_link *link)
00361 {
00362 struct vlan_info *vi = link->l_info;
00363
00364 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
00365 return nl_error(EOPNOTSUPP, "Not a VLAN link");
00366
00367 if (vi->vi_mask & VLAN_HAS_ID)
00368 return vi->vi_vlan_id;
00369 else
00370 return 0;
00371 }
00372
00373 int rtnl_link_vlan_set_flags(struct rtnl_link *link, unsigned int flags)
00374 {
00375 struct vlan_info *vi = link->l_info;
00376
00377 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
00378 return nl_error(EOPNOTSUPP, "Not a VLAN link");
00379
00380 vi->vi_flags_mask |= flags;
00381 vi->vi_flags |= flags;
00382 vi->vi_mask |= VLAN_HAS_FLAGS;
00383
00384 return 0;
00385 }
00386
00387 int rtnl_link_vlan_unset_flags(struct rtnl_link *link, unsigned int flags)
00388 {
00389 struct vlan_info *vi = link->l_info;
00390
00391 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
00392 return nl_error(EOPNOTSUPP, "Not a VLAN link");
00393
00394 vi->vi_flags_mask |= flags;
00395 vi->vi_flags &= ~flags;
00396 vi->vi_mask |= VLAN_HAS_FLAGS;
00397
00398 return 0;
00399 }
00400
00401 unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *link)
00402 {
00403 struct vlan_info *vi = link->l_info;
00404
00405 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
00406 return nl_error(EOPNOTSUPP, "Not a VLAN link");
00407
00408 return vi->vi_flags;
00409 }
00410
00411 int rtnl_link_vlan_set_ingress_map(struct rtnl_link *link, int from,
00412 uint32_t to)
00413 {
00414 struct vlan_info *vi = link->l_info;
00415
00416 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
00417 return nl_error(EOPNOTSUPP, "Not a VLAN link");
00418
00419 if (from < 0 || from > VLAN_PRIO_MAX)
00420 return nl_error(EINVAL, "Invalid vlan prio 0..%d",
00421 VLAN_PRIO_MAX);
00422
00423 vi->vi_ingress_qos[from] = to;
00424 vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
00425
00426 return 0;
00427 }
00428
00429 uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *link)
00430 {
00431 struct vlan_info *vi = link->l_info;
00432
00433 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) {
00434 nl_error(EOPNOTSUPP, "Not a VLAN link");
00435 return NULL;
00436 }
00437
00438 if (vi->vi_mask & VLAN_HAS_INGRESS_QOS)
00439 return vi->vi_ingress_qos;
00440 else
00441 return NULL;
00442 }
00443
00444 int rtnl_link_vlan_set_egress_map(struct rtnl_link *link, uint32_t from, int to)
00445 {
00446 struct vlan_info *vi = link->l_info;
00447
00448 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
00449 return nl_error(EOPNOTSUPP, "Not a VLAN link");
00450
00451 if (to < 0 || to > VLAN_PRIO_MAX)
00452 return nl_error(EINVAL, "Invalid vlan prio 0..%d",
00453 VLAN_PRIO_MAX);
00454
00455 if (vi->vi_negress >= vi->vi_egress_size) {
00456 int new_size = vi->vi_egress_size + 32;
00457 void *ptr;
00458
00459 ptr = realloc(vi->vi_egress_qos, new_size);
00460 if (!ptr)
00461 return nl_errno(ENOMEM);
00462
00463 vi->vi_egress_qos = ptr;
00464 vi->vi_egress_size = new_size;
00465 }
00466
00467 vi->vi_egress_qos[vi->vi_negress].vm_from = from;
00468 vi->vi_egress_qos[vi->vi_negress].vm_to = to;
00469 vi->vi_negress++;
00470 vi->vi_mask |= VLAN_HAS_EGRESS_QOS;
00471
00472 return 0;
00473 }
00474
00475 struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *link,
00476 int *negress)
00477 {
00478 struct vlan_info *vi = link->l_info;
00479
00480 if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) {
00481 nl_error(EOPNOTSUPP, "Not a VLAN link");
00482 return NULL;
00483 }
00484
00485 if (negress == NULL) {
00486 nl_error(EINVAL, "Require pointer to store negress");
00487 return NULL;
00488 }
00489
00490 if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
00491 *negress = vi->vi_negress;
00492 return vi->vi_egress_qos;
00493 } else {
00494 *negress = 0;
00495 return NULL;
00496 }
00497 }
00498
00499 static void __init vlan_init(void)
00500 {
00501 rtnl_link_register_info(&vlan_info_ops);
00502 }
00503
00504 static void __exit vlan_exit(void)
00505 {
00506 rtnl_link_unregister_info(&vlan_info_ops);
00507 }
00508
00509