1 /* 2 Copyright 2021 Jo-Philipp Wich <jo@mein.io> 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 /** 18 * # Routing Netlink 19 * 20 * The `rtnl` module provides functions for interacting with the routing netlink interface. 21 * 22 * Functions can be individually imported and directly accessed using the 23 * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#named_import named import} 24 * syntax: 25 * 26 * ```javascript 27 * import { error, request, listener, RTM_GETROUTE, RTM_NEWROUTE, RTM_DELROUTE, AF_INET } from 'rtnl'; 28 * 29 * // Send a netlink request 30 * let response = request(RTM_GETROUTE, 0, { family: AF_INET }); 31 * 32 * // Create a listener for route changes 33 * let routeListener = listener((msg) => { 34 * print('Received route message:', msg, '\n'); 35 * }, [RTM_NEWROUTE, RTM_DELROUTE]); 36 * ``` 37 * 38 * Alternatively, the module namespace can be imported 39 * using a wildcard import statement: 40 * 41 * ```javascript 42 * import * as rtnl from 'rtnl'; 43 * 44 * // Send a netlink request 45 * let response = rtnl.request(rtnl.RTM_GETROUTE, 0, { family: rtnl.AF_INET }); 46 * 47 * // Create a listener for route changes 48 * let listener = rtnl.listener((msg) => { 49 * print('Received route message:', msg, '\n'); 50 * }, [rtnl.RTM_NEWROUTE, rtnl.RTM_DELROUTE]); 51 * ``` 52 * 53 * Additionally, the rtnl module namespace may also be imported by invoking 54 * the `ucode` interpreter with the `-lrtnl` switch. 55 * 56 * @module rtnl 57 */ 58 59 #include <stdio.h> 60 #include <stdint.h> 61 #include <stdbool.h> 62 #include <stdarg.h> 63 #include <unistd.h> 64 #include <errno.h> 65 #include <string.h> 66 #include <limits.h> 67 #include <math.h> 68 #include <assert.h> 69 70 #include <netinet/ether.h> 71 #include <arpa/inet.h> 72 #include <netlink/msg.h> 73 #include <netlink/attr.h> 74 #include <netlink/socket.h> 75 76 #include <linux/rtnetlink.h> 77 #include <linux/if_tunnel.h> 78 #include <linux/ip6_tunnel.h> 79 #include <linux/lwtunnel.h> 80 #include <linux/mpls.h> 81 #include <linux/mpls_iptunnel.h> 82 #include <linux/seg6.h> 83 #include <linux/seg6_iptunnel.h> 84 #include <linux/seg6_hmac.h> 85 #include <linux/veth.h> 86 #include <linux/ila.h> 87 #include <linux/fib_rules.h> 88 #include <linux/if_addrlabel.h> 89 #include <linux/if_bridge.h> 90 #include <linux/netconf.h> 91 #include <linux/ipv6.h> 92 #include <linux/can/netlink.h> 93 #include <linux/can/vxcan.h> 94 95 #include <libubox/uloop.h> 96 97 #include "ucode/module.h" 98 #include "ucode/platform.h" 99 100 #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 101 102 #define err_return(code, ...) do { set_error(code, __VA_ARGS__); return NULL; } while(0) 103 104 #define NLM_F_STRICT_CHK (1 << 15) 105 106 #define RTNL_CMDS_BITMAP_SIZE DIV_ROUND_UP(__RTM_MAX, 32) 107 #define RTNL_GRPS_BITMAP_SIZE DIV_ROUND_UP(__RTNLGRP_MAX, 32) 108 109 /* Can't use net/if.h for declarations as it clashes with linux/if.h 110 * on certain musl versions. 111 * Ref: https://www.openwall.com/lists/musl/2017/04/16/1 */ 112 extern unsigned int if_nametoindex (const char *); 113 extern char *if_indextoname (unsigned int ifindex, char *ifname); 114 115 static struct { 116 int code; 117 char *msg; 118 } last_error; 119 120 __attribute__((format(printf, 2, 3))) static void 121 set_error(int errcode, const char *fmt, ...) { 122 va_list ap; 123 124 free(last_error.msg); 125 126 last_error.code = errcode; 127 last_error.msg = NULL; 128 129 if (fmt) { 130 va_start(ap, fmt); 131 xvasprintf(&last_error.msg, fmt, ap); 132 va_end(ap); 133 } 134 } 135 136 static uc_resource_type_t *listener_type; 137 static uc_value_t *listener_registry; 138 static uc_vm_t *listener_vm; 139 140 typedef struct { 141 uint32_t cmds[RTNL_CMDS_BITMAP_SIZE]; 142 size_t index; 143 } uc_nl_listener_t; 144 145 typedef struct { 146 uint8_t family; 147 uint8_t mask; 148 uint8_t alen; 149 uint8_t bitlen; 150 union { 151 struct in_addr in; 152 struct in6_addr in6; 153 struct mpls_label mpls[16]; 154 } addr; 155 } uc_nl_cidr_t; 156 157 static bool 158 uc_nl_parse_u32(uc_value_t *val, uint32_t *n) 159 { 160 uint64_t u; 161 162 u = ucv_to_unsigned(val); 163 164 if (errno != 0 || u > UINT32_MAX) 165 return false; 166 167 *n = (uint32_t)u; 168 169 return true; 170 } 171 172 static bool 173 uc_nl_parse_s32(uc_value_t *val, uint32_t *n) 174 { 175 int64_t i; 176 177 i = ucv_to_integer(val); 178 179 if (errno != 0 || i < INT32_MIN || i > INT32_MAX) 180 return false; 181 182 *n = (uint32_t)i; 183 184 return true; 185 } 186 187 static bool 188 uc_nl_parse_u64(uc_value_t *val, uint64_t *n) 189 { 190 *n = ucv_to_unsigned(val); 191 192 return (errno == 0); 193 } 194 195 static const char * 196 addr64_ntop(const void *addr, char *buf, size_t buflen) 197 { 198 const union { uint64_t u64; uint16_t u16[4]; } *a64 = addr; 199 int len; 200 201 errno = 0; 202 203 len = snprintf(buf, buflen, "%04x:%04x:%04x:%04x", 204 ntohs(a64->u16[0]), ntohs(a64->u16[1]), 205 ntohs(a64->u16[2]), ntohs(a64->u16[3])); 206 207 if ((size_t)len >= buflen) { 208 errno = ENOSPC; 209 210 return NULL; 211 } 212 213 return buf; 214 } 215 216 static int 217 addr64_pton(const char *src, void *dst) 218 { 219 union { uint64_t u64; uint16_t u16[4]; } *a64 = dst; 220 unsigned long n; 221 size_t i; 222 char *e; 223 224 for (i = 0; i < ARRAY_SIZE(a64->u16); i++) { 225 n = strtoul(src, &e, 16); 226 227 if (e == src || n > 0xffff) 228 return -1; 229 230 a64->u16[i] = htons(n); 231 232 if (*e == 0) 233 break; 234 235 if (i >= 3 || *e != ':') 236 return -1; 237 238 src += (e - src) + 1; 239 } 240 241 return 0; 242 } 243 244 static const char * 245 mpls_ntop(const void *addr, size_t addrlen, char *buf, size_t buflen) 246 { 247 const struct mpls_label *p = addr; 248 size_t remlen = buflen; 249 uint32_t entry, label; 250 char *s = buf; 251 int len; 252 253 errno = 0; 254 255 while (addrlen >= sizeof(*p)) { 256 entry = ntohl(p->entry); 257 label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT; 258 259 len = snprintf(s, remlen, "%u", label); 260 261 if ((size_t)len >= remlen) 262 break; 263 264 if (entry & MPLS_LS_S_MASK) 265 return buf; 266 267 s += len; 268 remlen -= len; 269 270 if (remlen) { 271 *s++ = '/'; 272 remlen--; 273 } 274 275 p++; 276 277 addrlen -= sizeof(*p); 278 } 279 280 errno = ENOSPC; 281 282 return NULL; 283 } 284 285 static int 286 mpls_pton(int af, const char *src, void *dst, size_t dstlen) 287 { 288 size_t max = dstlen / sizeof(struct mpls_label); 289 struct mpls_label *p = dst; 290 uint32_t label; 291 char *e; 292 293 errno = 0; 294 295 if (af != AF_MPLS) { 296 errno = EAFNOSUPPORT; 297 298 return -1; 299 } 300 301 while (max > 0) { 302 label = strtoul(src, &e, 0); 303 304 if (label >= (1 << 20)) 305 return 0; 306 307 if (e == src) 308 return 0; 309 310 p->entry = htonl(label << MPLS_LS_LABEL_SHIFT); 311 312 if (*e == 0) { 313 p->entry |= htonl(1 << MPLS_LS_S_SHIFT); 314 315 return 1; 316 } 317 318 if (*e != '/') 319 return 0; 320 321 src += (e - src) + 1; 322 max--; 323 p++; 324 } 325 326 errno = ENOSPC; 327 328 return -1; 329 } 330 331 static bool 332 uc_nl_parse_cidr(uc_vm_t *vm, uc_value_t *val, uc_nl_cidr_t *p) 333 { 334 char *s = ucv_to_string(vm, val); 335 struct in6_addr mask6 = { 0 }; 336 struct in_addr mask = { 0 }; 337 bool valid = true; 338 char *m, *e; 339 long n = 0; 340 size_t i; 341 342 if (!s) 343 return false; 344 345 m = strchr(s, '/'); 346 347 if (m) 348 *m++ = '\0'; 349 350 if (inet_pton(AF_INET6, s, &p->addr.in6) == 1) { 351 if (m) { 352 if (inet_pton(AF_INET6, m, &mask6) == 1) { 353 while (n < 128 && (mask6.s6_addr[n / 8] << (n % 8)) & 128) 354 n++; 355 } 356 else { 357 n = strtol(m, &e, 10); 358 359 if (e == m || *e || n < 0 || n > 128) 360 valid = false; 361 } 362 363 p->mask = (uint8_t)n; 364 } 365 else { 366 p->mask = 128; 367 } 368 369 p->family = AF_INET6; 370 p->alen = sizeof(mask6); 371 p->bitlen = p->alen * 8; 372 } 373 else if (strchr(s, '.') && inet_pton(AF_INET, s, &p->addr.in) == 1) { 374 if (m) { 375 if (inet_pton(AF_INET, m, &mask) == 1) { 376 mask.s_addr = ntohl(mask.s_addr); 377 378 while (n < 32 && (mask.s_addr << n) & 0x80000000) 379 n++; 380 } 381 else { 382 n = strtol(m, &e, 10); 383 384 if (e == m || *e || n < 0 || n > 32) 385 valid = false; 386 } 387 388 p->mask = (uint8_t)n; 389 } 390 else { 391 p->mask = 32; 392 } 393 394 p->family = AF_INET; 395 p->alen = sizeof(mask); 396 p->bitlen = p->alen * 8; 397 } 398 else { 399 if (m) 400 m[-1] = '/'; 401 402 if (mpls_pton(AF_MPLS, s, &p->addr.mpls, sizeof(p->addr.mpls)) == 1) { 403 p->family = AF_MPLS; 404 p->alen = 0; 405 406 for (i = 0; i < ARRAY_SIZE(p->addr.mpls); i++) { 407 p->alen += sizeof(struct mpls_label); 408 409 if (ntohl(p->addr.mpls[i].entry) & MPLS_LS_S_MASK) 410 break; 411 } 412 413 p->bitlen = p->alen * 8; 414 p->mask = p->bitlen; 415 } 416 else { 417 valid = false; 418 } 419 } 420 421 free(s); 422 423 return valid; 424 } 425 426 typedef enum { 427 DT_FLAG, 428 DT_BOOL, 429 DT_U8, 430 DT_U16, 431 DT_U32, 432 DT_S32, 433 DT_U64, 434 DT_STRING, 435 DT_NETDEV, 436 DT_LLADDR, 437 DT_INADDR, 438 DT_IN6ADDR, 439 DT_U64ADDR, 440 DT_MPLSADDR, 441 DT_ANYADDR, 442 DT_BRIDGEID, 443 DT_LINKINFO, 444 DT_MULTIPATH, 445 DT_NUMRANGE, 446 DT_AFSPEC, 447 DT_FLAGS, 448 DT_ENCAP, 449 DT_SRH, 450 DT_IPOPTS, 451 DT_U32_OR_MEMBER, 452 DT_NESTED, 453 } uc_nl_attr_datatype_t; 454 455 enum { 456 DF_NO_SET = (1 << 0), 457 DF_NO_GET = (1 << 1), 458 DF_ALLOW_NONE = (1 << 2), 459 DF_BYTESWAP = (1 << 3), 460 DF_MAX_1 = (1 << 4), 461 DF_MAX_255 = (1 << 5), 462 DF_MAX_65535 = (1 << 6), 463 DF_MAX_16777215 = (1 << 7), 464 DF_STORE_MASK = (1 << 8), 465 DF_MULTIPLE = (1 << 9), 466 DF_FLAT = (1 << 10), 467 DF_FAMILY_HINT = (1 << 11), 468 }; 469 470 typedef struct uc_nl_attr_spec { 471 size_t attr; 472 const char *key; 473 uc_nl_attr_datatype_t type; 474 uint32_t flags; 475 const void *auxdata; 476 } uc_nl_attr_spec_t; 477 478 typedef struct uc_nl_nested_spec { 479 size_t headsize; 480 size_t nattrs; 481 const uc_nl_attr_spec_t attrs[]; 482 } uc_nl_nested_spec_t; 483 484 #define SIZE(type) (void *)(uintptr_t)sizeof(struct type) 485 #define MEMBER(type, field) (void *)(uintptr_t)offsetof(struct type, field) 486 487 static const uc_nl_nested_spec_t route_cacheinfo_rta = { 488 .headsize = NLA_ALIGN(sizeof(struct rta_cacheinfo)), 489 .nattrs = 8, 490 .attrs = { 491 { RTA_UNSPEC, "clntref", DT_U32, 0, MEMBER(rta_cacheinfo, rta_clntref) }, 492 { RTA_UNSPEC, "lastuse", DT_U32, 0, MEMBER(rta_cacheinfo, rta_lastuse) }, 493 { RTA_UNSPEC, "expires", DT_S32, 0, MEMBER(rta_cacheinfo, rta_expires) }, 494 { RTA_UNSPEC, "error", DT_U32, 0, MEMBER(rta_cacheinfo, rta_error) }, 495 { RTA_UNSPEC, "used", DT_U32, 0, MEMBER(rta_cacheinfo, rta_used) }, 496 { RTA_UNSPEC, "id", DT_U32, 0, MEMBER(rta_cacheinfo, rta_id) }, 497 { RTA_UNSPEC, "ts", DT_U32, 0, MEMBER(rta_cacheinfo, rta_ts) }, 498 { RTA_UNSPEC, "tsage", DT_U32, 0, MEMBER(rta_cacheinfo, rta_tsage) }, 499 } 500 }; 501 502 static const uc_nl_nested_spec_t route_metrics_rta = { 503 .headsize = 0, 504 .nattrs = 16, 505 .attrs = { 506 { RTAX_MTU, "mtu", DT_U32, 0, NULL }, 507 { RTAX_HOPLIMIT, "hoplimit", DT_U32, DF_MAX_255, NULL }, 508 { RTAX_ADVMSS, "advmss", DT_U32, 0, NULL }, 509 { RTAX_REORDERING, "reordering", DT_U32, 0, NULL }, 510 { RTAX_RTT, "rtt", DT_U32, 0, NULL }, 511 { RTAX_WINDOW, "window", DT_U32, 0, NULL }, 512 { RTAX_CWND, "cwnd", DT_U32, 0, NULL }, 513 { RTAX_INITCWND, "initcwnd", DT_U32, 0, NULL }, 514 { RTAX_INITRWND, "initrwnd", DT_U32, 0, NULL }, 515 { RTAX_FEATURES, "ecn", DT_U32, DF_MAX_1, NULL }, 516 { RTAX_QUICKACK, "quickack", DT_U32, DF_MAX_1, NULL }, 517 { RTAX_CC_ALGO, "cc_algo", DT_STRING, 0, NULL }, 518 { RTAX_RTTVAR, "rttvar", DT_U32, 0, NULL }, 519 { RTAX_SSTHRESH, "ssthresh", DT_U32, 0, NULL }, 520 { RTAX_FASTOPEN_NO_COOKIE, "fastopen_no_cookie", DT_U32, DF_MAX_1, NULL }, 521 { RTAX_LOCK, "lock", DT_U32, 0, NULL }, 522 } 523 }; 524 525 static const uc_nl_nested_spec_t route_msg = { 526 .headsize = NLA_ALIGN(sizeof(struct rtmsg)), 527 .nattrs = 28, 528 .attrs = { 529 { RTA_UNSPEC, "family", DT_U8, 0, MEMBER(rtmsg, rtm_family) }, 530 { RTA_UNSPEC, "tos", DT_U8, 0, MEMBER(rtmsg, rtm_tos) }, 531 { RTA_UNSPEC, "protocol", DT_U8, 0, MEMBER(rtmsg, rtm_protocol) }, 532 { RTA_UNSPEC, "scope", DT_U8, 0, MEMBER(rtmsg, rtm_scope) }, 533 { RTA_UNSPEC, "type", DT_U8, 0, MEMBER(rtmsg, rtm_type) }, 534 { RTA_UNSPEC, "flags", DT_U32, 0, MEMBER(rtmsg, rtm_flags) }, 535 { RTA_SRC, "src", DT_ANYADDR, DF_STORE_MASK|DF_FAMILY_HINT, MEMBER(rtmsg, rtm_src_len) }, 536 { RTA_DST, "dst", DT_ANYADDR, DF_STORE_MASK|DF_FAMILY_HINT, MEMBER(rtmsg, rtm_dst_len) }, 537 { RTA_IIF, "iif", DT_NETDEV, 0, NULL }, 538 { RTA_OIF, "oif", DT_NETDEV, 0, NULL }, 539 { RTA_GATEWAY, "gateway", DT_ANYADDR, DF_FAMILY_HINT, NULL }, 540 { RTA_PRIORITY, "priority", DT_U32, 0, NULL }, 541 { RTA_PREFSRC, "prefsrc", DT_ANYADDR, DF_FAMILY_HINT, NULL }, 542 { RTA_METRICS, "metrics", DT_NESTED, 0, &route_metrics_rta }, 543 { RTA_MULTIPATH, "multipath", DT_MULTIPATH, 0, NULL }, 544 { RTA_FLOW, "flow", DT_U32, 0, NULL }, 545 { RTA_CACHEINFO, "cacheinfo", DT_NESTED, DF_NO_SET, &route_cacheinfo_rta }, 546 { RTA_TABLE, "table", DT_U32_OR_MEMBER, DF_MAX_255, MEMBER(rtmsg, rtm_table) }, 547 { RTA_MARK, "mark", DT_U32, 0, NULL }, 548 //RTA_MFC_STATS, 549 { RTA_PREF, "pref", DT_U8, 0, NULL }, 550 { RTA_ENCAP, "encap", DT_ENCAP, 0, NULL }, 551 { RTA_EXPIRES, "expires", DT_U32, 0, NULL }, 552 { RTA_UID, "uid", DT_U32, 0, NULL }, 553 { RTA_TTL_PROPAGATE, "ttl_propagate", DT_BOOL, 0, NULL }, 554 { RTA_IP_PROTO, "ip_proto", DT_U8, 0, NULL }, 555 { RTA_SPORT, "sport", DT_U16, DF_BYTESWAP, NULL }, 556 { RTA_DPORT, "dport", DT_U16, DF_BYTESWAP, NULL }, 557 { RTA_NH_ID, "nh_id", DT_U32, 0, NULL }, 558 } 559 }; 560 561 static const uc_nl_attr_spec_t route_encap_mpls_attrs[] = { 562 { MPLS_IPTUNNEL_DST, "dst", DT_MPLSADDR, 0, NULL }, 563 { MPLS_IPTUNNEL_TTL, "ttl", DT_U8, 0, NULL }, 564 }; 565 566 static const uc_nl_attr_spec_t route_encap_ip_attrs[] = { 567 { LWTUNNEL_IP_ID, "id", DT_U64, DF_BYTESWAP, NULL }, 568 { LWTUNNEL_IP_DST, "dst", DT_INADDR, 0, NULL }, 569 { LWTUNNEL_IP_SRC, "src", DT_INADDR, 0, NULL }, 570 { LWTUNNEL_IP_TOS, "tos", DT_U8, 0, NULL }, 571 { LWTUNNEL_IP_TTL, "ttl", DT_U8, 0, NULL }, 572 { LWTUNNEL_IP_OPTS, "opts", DT_IPOPTS, 0, NULL }, 573 { LWTUNNEL_IP_FLAGS, "flags", DT_U16, 0, NULL }, 574 }; 575 576 static const uc_nl_attr_spec_t route_encap_ila_attrs[] = { 577 { ILA_ATTR_LOCATOR, "locator", DT_U64ADDR, 0, NULL }, 578 { ILA_ATTR_CSUM_MODE, "csum_mode", DT_U8, 0, NULL }, 579 { ILA_ATTR_IDENT_TYPE, "ident_type", DT_U8, 0, NULL }, 580 { ILA_ATTR_HOOK_TYPE, "hook_type", DT_U8, 0, NULL }, 581 }; 582 583 static const uc_nl_attr_spec_t route_encap_ip6_attrs[] = { 584 { LWTUNNEL_IP6_ID, "id", DT_U64, DF_BYTESWAP, NULL }, 585 { LWTUNNEL_IP6_DST, "dst", DT_IN6ADDR, 0, NULL }, 586 { LWTUNNEL_IP6_SRC, "src", DT_IN6ADDR, 0, NULL }, 587 { LWTUNNEL_IP6_TC, "tc", DT_U32, 0, NULL }, 588 { LWTUNNEL_IP6_HOPLIMIT, "hoplimit", DT_U8, 0, NULL }, 589 { LWTUNNEL_IP6_OPTS, "opts", DT_IPOPTS, 0, NULL }, 590 { LWTUNNEL_IP6_FLAGS, "flags", DT_U16, 0, NULL }, 591 }; 592 593 static const uc_nl_attr_spec_t route_encap_seg6_attrs[] = { 594 { SEG6_IPTUNNEL_SRH, "srh", DT_SRH, 0, NULL }, 595 }; 596 597 #define IPV4_DEVCONF_ENTRY(name) ((void *)((IPV4_DEVCONF_##name - 1) * sizeof(uint32_t))) 598 599 static const uc_nl_nested_spec_t link_attrs_af_spec_inet_devconf_rta = { 600 .headsize = NLA_ALIGN(IPV4_DEVCONF_MAX * sizeof(uint32_t)), 601 .nattrs = 32, 602 .attrs = { 603 { 0, "forwarding", DT_U32, 0, IPV4_DEVCONF_ENTRY(FORWARDING) }, 604 { 0, "mc_forwarding", DT_U32, 0, IPV4_DEVCONF_ENTRY(MC_FORWARDING) }, 605 { 0, "proxy_arp", DT_U32, 0, IPV4_DEVCONF_ENTRY(PROXY_ARP) }, 606 { 0, "accept_redirects", DT_U32, 0, IPV4_DEVCONF_ENTRY(ACCEPT_REDIRECTS) }, 607 { 0, "secure_redirects", DT_U32, 0, IPV4_DEVCONF_ENTRY(SECURE_REDIRECTS) }, 608 { 0, "send_redirects", DT_U32, 0, IPV4_DEVCONF_ENTRY(SEND_REDIRECTS) }, 609 { 0, "shared_media", DT_U32, 0, IPV4_DEVCONF_ENTRY(SHARED_MEDIA) }, 610 { 0, "rp_filter", DT_U32, 0, IPV4_DEVCONF_ENTRY(RP_FILTER) }, 611 { 0, "accept_source_route", DT_U32, 0, IPV4_DEVCONF_ENTRY(ACCEPT_SOURCE_ROUTE) }, 612 { 0, "bootp_relay", DT_U32, 0, IPV4_DEVCONF_ENTRY(BOOTP_RELAY) }, 613 { 0, "log_martians", DT_U32, 0, IPV4_DEVCONF_ENTRY(LOG_MARTIANS) }, 614 { 0, "tag", DT_U32, 0, IPV4_DEVCONF_ENTRY(TAG) }, 615 { 0, "arpfilter", DT_U32, 0, IPV4_DEVCONF_ENTRY(ARPFILTER) }, 616 { 0, "medium_id", DT_U32, 0, IPV4_DEVCONF_ENTRY(MEDIUM_ID) }, 617 { 0, "noxfrm", DT_U32, 0, IPV4_DEVCONF_ENTRY(NOXFRM) }, 618 { 0, "nopolicy", DT_U32, 0, IPV4_DEVCONF_ENTRY(NOPOLICY) }, 619 { 0, "force_igmp_version", DT_U32, 0, IPV4_DEVCONF_ENTRY(FORCE_IGMP_VERSION) }, 620 { 0, "arp_announce", DT_U32, 0, IPV4_DEVCONF_ENTRY(ARP_ANNOUNCE) }, 621 { 0, "arp_ignore", DT_U32, 0, IPV4_DEVCONF_ENTRY(ARP_IGNORE) }, 622 { 0, "promote_secondaries", DT_U32, 0, IPV4_DEVCONF_ENTRY(PROMOTE_SECONDARIES) }, 623 { 0, "arp_accept", DT_U32, 0, IPV4_DEVCONF_ENTRY(ARP_ACCEPT) }, 624 { 0, "arp_notify", DT_U32, 0, IPV4_DEVCONF_ENTRY(ARP_NOTIFY) }, 625 { 0, "accept_local", DT_U32, 0, IPV4_DEVCONF_ENTRY(ACCEPT_LOCAL) }, 626 { 0, "src_vmark", DT_U32, 0, IPV4_DEVCONF_ENTRY(SRC_VMARK) }, 627 { 0, "proxy_arp_pvlan", DT_U32, 0, IPV4_DEVCONF_ENTRY(PROXY_ARP_PVLAN) }, 628 { 0, "route_localnet", DT_U32, 0, IPV4_DEVCONF_ENTRY(ROUTE_LOCALNET) }, 629 { 0, "igmpv2_unsolicited_report_interval", DT_U32, 0, IPV4_DEVCONF_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL) }, 630 { 0, "igmpv3_unsolicited_report_interval", DT_U32, 0, IPV4_DEVCONF_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL) }, 631 { 0, "ignore_routes_with_linkdown", DT_U32, 0, IPV4_DEVCONF_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN) }, 632 { 0, "drop_unicast_in_l2_multicast", DT_U32, 0, IPV4_DEVCONF_ENTRY(DROP_UNICAST_IN_L2_MULTICAST) }, 633 { 0, "drop_gratuitous_arp", DT_U32, 0, IPV4_DEVCONF_ENTRY(DROP_GRATUITOUS_ARP) }, 634 { 0, "bc_forwarding", DT_U32, 0, IPV4_DEVCONF_ENTRY(BC_FORWARDING) }, 635 } 636 }; 637 638 static const uc_nl_nested_spec_t link_attrs_af_spec_inet_rta = { 639 .headsize = 0, 640 .nattrs = 1, 641 .attrs = { 642 { IFLA_INET_CONF, "conf", DT_NESTED, 0, &link_attrs_af_spec_inet_devconf_rta }, 643 } 644 }; 645 646 #define IPV6_DEVCONF_ENTRY(name) ((void *)(DEVCONF_##name * sizeof(uint32_t))) 647 648 static const uc_nl_nested_spec_t link_attrs_af_spec_inet6_devconf_rta = { 649 .headsize = NLA_ALIGN(DEVCONF_MAX * sizeof(uint32_t)), 650 .nattrs = 53, 651 .attrs = { 652 { 0, "forwarding", DT_S32, 0, IPV6_DEVCONF_ENTRY(FORWARDING) }, 653 { 0, "hoplimit", DT_S32, 0, IPV6_DEVCONF_ENTRY(HOPLIMIT) }, 654 { 0, "mtu6", DT_S32, 0, IPV6_DEVCONF_ENTRY(MTU6) }, 655 { 0, "accept_ra", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA) }, 656 { 0, "accept_redirects", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_REDIRECTS) }, 657 { 0, "autoconf", DT_S32, 0, IPV6_DEVCONF_ENTRY(AUTOCONF) }, 658 { 0, "dad_transmits", DT_S32, 0, IPV6_DEVCONF_ENTRY(DAD_TRANSMITS) }, 659 { 0, "rtr_solicits", DT_S32, 0, IPV6_DEVCONF_ENTRY(RTR_SOLICITS) }, 660 { 0, "rtr_solicit_interval", DT_S32, 0, IPV6_DEVCONF_ENTRY(RTR_SOLICIT_INTERVAL) }, 661 { 0, "rtr_solicit_delay", DT_S32, 0, IPV6_DEVCONF_ENTRY(RTR_SOLICIT_DELAY) }, 662 { 0, "use_tempaddr", DT_S32, 0, IPV6_DEVCONF_ENTRY(USE_TEMPADDR) }, 663 { 0, "temp_valid_lft", DT_S32, 0, IPV6_DEVCONF_ENTRY(TEMP_VALID_LFT) }, 664 { 0, "temp_prefered_lft", DT_S32, 0, IPV6_DEVCONF_ENTRY(TEMP_PREFERED_LFT) }, 665 { 0, "regen_max_retry", DT_S32, 0, IPV6_DEVCONF_ENTRY(REGEN_MAX_RETRY) }, 666 { 0, "max_desync_factor", DT_S32, 0, IPV6_DEVCONF_ENTRY(MAX_DESYNC_FACTOR) }, 667 { 0, "max_addresses", DT_S32, 0, IPV6_DEVCONF_ENTRY(MAX_ADDRESSES) }, 668 { 0, "force_mld_version", DT_S32, 0, IPV6_DEVCONF_ENTRY(FORCE_MLD_VERSION) }, 669 { 0, "accept_ra_defrtr", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_DEFRTR) }, 670 { 0, "accept_ra_pinfo", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_PINFO) }, 671 { 0, "accept_ra_rtr_pref", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_RTR_PREF) }, 672 { 0, "rtr_probe_interval", DT_S32, 0, IPV6_DEVCONF_ENTRY(RTR_PROBE_INTERVAL) }, 673 { 0, "accept_ra_rt_info_max_plen", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_RT_INFO_MAX_PLEN) }, 674 { 0, "proxy_ndp", DT_S32, 0, IPV6_DEVCONF_ENTRY(PROXY_NDP) }, 675 { 0, "optimistic_dad", DT_S32, 0, IPV6_DEVCONF_ENTRY(OPTIMISTIC_DAD) }, 676 { 0, "accept_source_route", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_SOURCE_ROUTE) }, 677 { 0, "mc_forwarding", DT_S32, 0, IPV6_DEVCONF_ENTRY(MC_FORWARDING) }, 678 { 0, "disable_ipv6", DT_S32, 0, IPV6_DEVCONF_ENTRY(DISABLE_IPV6) }, 679 { 0, "accept_dad", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_DAD) }, 680 { 0, "force_tllao", DT_S32, 0, IPV6_DEVCONF_ENTRY(FORCE_TLLAO) }, 681 { 0, "ndisc_notify", DT_S32, 0, IPV6_DEVCONF_ENTRY(NDISC_NOTIFY) }, 682 { 0, "mldv1_unsolicited_report_interval", DT_S32, 0, IPV6_DEVCONF_ENTRY(MLDV1_UNSOLICITED_REPORT_INTERVAL) }, 683 { 0, "mldv2_unsolicited_report_interval", DT_S32, 0, IPV6_DEVCONF_ENTRY(MLDV2_UNSOLICITED_REPORT_INTERVAL) }, 684 { 0, "suppress_frag_ndisc", DT_S32, 0, IPV6_DEVCONF_ENTRY(SUPPRESS_FRAG_NDISC) }, 685 { 0, "accept_ra_from_local", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_FROM_LOCAL) }, 686 { 0, "use_optimistic", DT_S32, 0, IPV6_DEVCONF_ENTRY(USE_OPTIMISTIC) }, 687 { 0, "accept_ra_mtu", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_MTU) }, 688 { 0, "stable_secret", DT_S32, 0, IPV6_DEVCONF_ENTRY(STABLE_SECRET) }, 689 { 0, "use_oif_addrs_only", DT_S32, 0, IPV6_DEVCONF_ENTRY(USE_OIF_ADDRS_ONLY) }, 690 { 0, "accept_ra_min_hop_limit", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_MIN_HOP_LIMIT) }, 691 { 0, "ignore_routes_with_linkdown", DT_S32, 0, IPV6_DEVCONF_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN) }, 692 { 0, "drop_unicast_in_l2_multicast", DT_S32, 0, IPV6_DEVCONF_ENTRY(DROP_UNICAST_IN_L2_MULTICAST) }, 693 { 0, "drop_unsolicited_na", DT_S32, 0, IPV6_DEVCONF_ENTRY(DROP_UNSOLICITED_NA) }, 694 { 0, "keep_addr_on_down", DT_S32, 0, IPV6_DEVCONF_ENTRY(KEEP_ADDR_ON_DOWN) }, 695 { 0, "rtr_solicit_max_interval", DT_S32, 0, IPV6_DEVCONF_ENTRY(RTR_SOLICIT_MAX_INTERVAL) }, 696 { 0, "seg6_enabled", DT_S32, 0, IPV6_DEVCONF_ENTRY(SEG6_ENABLED) }, 697 { 0, "seg6_require_hmac", DT_S32, 0, IPV6_DEVCONF_ENTRY(SEG6_REQUIRE_HMAC) }, 698 { 0, "enhanced_dad", DT_S32, 0, IPV6_DEVCONF_ENTRY(ENHANCED_DAD) }, 699 { 0, "addr_gen_mode", DT_S32, 0, IPV6_DEVCONF_ENTRY(ADDR_GEN_MODE) }, 700 { 0, "disable_policy", DT_S32, 0, IPV6_DEVCONF_ENTRY(DISABLE_POLICY) }, 701 { 0, "accept_ra_rt_info_min_plen", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_RT_INFO_MIN_PLEN) }, 702 { 0, "ndisc_tclass", DT_S32, 0, IPV6_DEVCONF_ENTRY(NDISC_TCLASS) }, 703 { 0, "rpl_seg_enabled", DT_S32, 0, IPV6_DEVCONF_ENTRY(RPL_SEG_ENABLED) }, 704 { 0, "ra_defrtr_metric", DT_S32, 0, IPV6_DEVCONF_ENTRY(RA_DEFRTR_METRIC) }, 705 } 706 }; 707 708 static const uc_nl_nested_spec_t link_attrs_af_spec_inet6_rta = { 709 .headsize = 0, 710 .nattrs = 3, 711 .attrs = { 712 { IFLA_INET6_ADDR_GEN_MODE, "mode", DT_U8, 0, NULL }, 713 { IFLA_INET6_FLAGS, "flags", DT_U32, DF_NO_SET, NULL }, 714 { IFLA_INET6_CONF, "conf", DT_NESTED, DF_NO_SET, &link_attrs_af_spec_inet6_devconf_rta }, 715 } 716 }; 717 718 static const uc_nl_nested_spec_t link_attrs_af_spec_rta = { 719 .headsize = 0, 720 .nattrs = 2, 721 .attrs = { 722 { AF_INET, "inet", DT_NESTED, DF_NO_SET, &link_attrs_af_spec_inet_rta }, 723 { AF_INET6, "inet6", DT_NESTED, 0, &link_attrs_af_spec_inet6_rta }, 724 } 725 }; 726 727 static const uc_nl_nested_spec_t link_attrs_stats64_rta = { 728 .headsize = NLA_ALIGN(sizeof(struct rtnl_link_stats64)), 729 .nattrs = 24, 730 .attrs = { 731 { IFLA_UNSPEC, "rx_packets", DT_U64, 0, MEMBER(rtnl_link_stats64, rx_packets) }, 732 { IFLA_UNSPEC, "tx_packets", DT_U64, 0, MEMBER(rtnl_link_stats64, tx_packets) }, 733 { IFLA_UNSPEC, "rx_bytes", DT_U64, 0, MEMBER(rtnl_link_stats64, rx_bytes) }, 734 { IFLA_UNSPEC, "tx_bytes", DT_U64, 0, MEMBER(rtnl_link_stats64, tx_bytes) }, 735 { IFLA_UNSPEC, "rx_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, rx_errors) }, 736 { IFLA_UNSPEC, "tx_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, tx_errors) }, 737 { IFLA_UNSPEC, "rx_dropped", DT_U64, 0, MEMBER(rtnl_link_stats64, rx_dropped) }, 738 { IFLA_UNSPEC, "tx_dropped", DT_U64, 0, MEMBER(rtnl_link_stats64, tx_dropped) }, 739 { IFLA_UNSPEC, "multicast", DT_U64, 0, MEMBER(rtnl_link_stats64, multicast) }, 740 { IFLA_UNSPEC, "collisions", DT_U64, 0, MEMBER(rtnl_link_stats64, collisions) }, 741 { IFLA_UNSPEC, "rx_length_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, rx_length_errors) }, 742 { IFLA_UNSPEC, "rx_over_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, rx_over_errors) }, 743 { IFLA_UNSPEC, "rx_crc_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, rx_crc_errors) }, 744 { IFLA_UNSPEC, "rx_frame_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, rx_frame_errors) }, 745 { IFLA_UNSPEC, "rx_fifo_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, rx_fifo_errors) }, 746 { IFLA_UNSPEC, "rx_missed_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, rx_missed_errors) }, 747 { IFLA_UNSPEC, "tx_aborted_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, tx_aborted_errors) }, 748 { IFLA_UNSPEC, "tx_carrier_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, tx_carrier_errors) }, 749 { IFLA_UNSPEC, "tx_fifo_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, tx_fifo_errors) }, 750 { IFLA_UNSPEC, "tx_heartbeat_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, tx_heartbeat_errors) }, 751 { IFLA_UNSPEC, "tx_window_errors", DT_U64, 0, MEMBER(rtnl_link_stats64, tx_window_errors) }, 752 { IFLA_UNSPEC, "rx_compressed", DT_U64, 0, MEMBER(rtnl_link_stats64, rx_compressed) }, 753 { IFLA_UNSPEC, "tx_compressed", DT_U64, 0, MEMBER(rtnl_link_stats64, tx_compressed) }, 754 { IFLA_UNSPEC, "rx_nohandler", DT_U64, 0, MEMBER(rtnl_link_stats64, rx_nohandler) }, 755 } 756 }; 757 758 static const uc_nl_nested_spec_t link_msg = { 759 .headsize = NLA_ALIGN(sizeof(struct ifinfomsg)), 760 .nattrs = 26, 761 .attrs = { 762 { IFLA_UNSPEC, "family", DT_U8, 0, MEMBER(ifinfomsg, ifi_family) }, 763 { IFLA_UNSPEC, "type", DT_U16, 0, MEMBER(ifinfomsg, ifi_type) }, 764 { IFLA_UNSPEC, "dev", DT_NETDEV, 0, MEMBER(ifinfomsg, ifi_index) }, 765 { IFLA_UNSPEC, "flags", DT_FLAGS, 0, MEMBER(ifinfomsg, ifi_flags) }, 766 { IFLA_UNSPEC, "change", DT_FLAGS, 0, MEMBER(ifinfomsg, ifi_change) }, 767 { IFLA_ADDRESS, "address", DT_LLADDR, 0, NULL }, 768 { IFLA_BROADCAST, "broadcast", DT_LLADDR, 0, NULL }, 769 { IFLA_TXQLEN, "txqlen", DT_U32, 0, NULL }, 770 { IFLA_MTU, "mtu", DT_U32, 0, NULL }, 771 { IFLA_CARRIER, "carrier", DT_BOOL, 0, NULL }, 772 { IFLA_MASTER, "master", DT_NETDEV, DF_ALLOW_NONE, NULL }, 773 { IFLA_IFALIAS, "ifalias", DT_STRING, 0, NULL }, 774 { IFLA_LINKMODE, "linkmode", DT_U8, 0, NULL }, 775 { IFLA_OPERSTATE, "operstate", DT_U8, 0, NULL }, 776 { IFLA_NUM_TX_QUEUES, "num_tx_queues", DT_U32, 0, NULL }, 777 { IFLA_NUM_RX_QUEUES, "num_rx_queues", DT_U32, 0, NULL }, 778 { IFLA_AF_SPEC, "af_spec", DT_AFSPEC, 0, NULL }, 779 { IFLA_LINK_NETNSID, "link_netnsid", DT_U32, 0, NULL }, 780 { IFLA_TARGET_NETNSID, "target_netnsid", DT_S32, 0, NULL }, 781 { IFLA_PROTO_DOWN, "proto_down", DT_BOOL, 0, NULL }, 782 { IFLA_GROUP, "group", DT_U32, 0, NULL }, 783 { IFLA_LINK, "link", DT_NETDEV, 0, NULL }, 784 { IFLA_IFNAME, "ifname", DT_STRING, 0, NULL }, 785 { IFLA_LINKINFO, "linkinfo", DT_LINKINFO, 0, NULL }, /* XXX: DF_NO_GET ? */ 786 { IFLA_EXT_MASK, "ext_mask", DT_U32, 0, NULL }, 787 { IFLA_STATS64, "stats64", DT_NESTED, DF_NO_SET, &link_attrs_stats64_rta }, 788 /* TODO: IFLA_VFINFO_LIST */ 789 /* TODO: the following two should be straightforward, just uncomment and test */ 790 /* { IFLA_NET_NS_PID, "net_ns_pid", DT_S32, 0, NULL }, */ 791 /* { IFLA_NET_NS_FD, "net_ns_fd", DT_S32, 0, NULL }, */ 792 } 793 }; 794 795 static const uc_nl_attr_spec_t link_bareudp_attrs[] = { 796 { IFLA_BAREUDP_ETHERTYPE, "ethertype", DT_U16, 0, NULL }, 797 { IFLA_BAREUDP_MULTIPROTO_MODE, "multiproto_mode", DT_FLAG, 0, NULL }, 798 { IFLA_BAREUDP_PORT, "port", DT_U16, 0, NULL }, 799 { IFLA_BAREUDP_SRCPORT_MIN, "srcport_min", DT_U16, 0, NULL }, 800 }; 801 802 static const uc_nl_nested_spec_t link_bond_ad_info_rta = { 803 .headsize = 0, 804 .nattrs = 5, 805 .attrs = { 806 { IFLA_BOND_AD_INFO_ACTOR_KEY, "ad_info_actor_key", DT_U16, DF_NO_SET, NULL }, 807 { IFLA_BOND_AD_INFO_AGGREGATOR, "ad_info_aggregator", DT_U16, DF_NO_SET, NULL }, 808 { IFLA_BOND_AD_INFO_NUM_PORTS, "ad_info_num_ports", DT_U16, DF_NO_SET, NULL }, 809 { IFLA_BOND_AD_INFO_PARTNER_KEY, "ad_info_partner_key", DT_U16, DF_NO_SET, NULL }, 810 { IFLA_BOND_AD_INFO_PARTNER_MAC, "ad_info_partner_mac", DT_LLADDR, DF_NO_SET, NULL }, 811 } 812 }; 813 814 static const uc_nl_attr_spec_t link_bond_attrs[] = { 815 { IFLA_BOND_ACTIVE_SLAVE, "active_slave", DT_NETDEV, DF_ALLOW_NONE, NULL }, 816 { IFLA_BOND_AD_ACTOR_SYSTEM, "ad_actor_system", DT_LLADDR, 0, NULL }, 817 { IFLA_BOND_AD_ACTOR_SYS_PRIO, "ad_actor_sys_prio", DT_U16, 0, NULL }, 818 { IFLA_BOND_AD_INFO, "ad_info", DT_NESTED, DF_NO_SET, &link_bond_ad_info_rta }, 819 { IFLA_BOND_AD_LACP_RATE, "ad_lacp_rate", DT_U8, 0, NULL }, 820 { IFLA_BOND_AD_SELECT, "ad_select", DT_U8, 0, NULL }, 821 { IFLA_BOND_AD_USER_PORT_KEY, "ad_user_port_key", DT_U16, 0, NULL }, 822 { IFLA_BOND_ALL_SLAVES_ACTIVE, "all_slaves_active", DT_U8, 0, NULL }, 823 { IFLA_BOND_ARP_ALL_TARGETS, "arp_all_targets", DT_U32, 0, NULL }, 824 { IFLA_BOND_ARP_INTERVAL, "arp_interval", DT_U32, 0, NULL }, 825 { IFLA_BOND_ARP_IP_TARGET, "arp_ip_target", DT_INADDR, DF_MULTIPLE, NULL }, 826 { IFLA_BOND_ARP_VALIDATE, "arp_validate", DT_U32, 0, NULL }, 827 { IFLA_BOND_DOWNDELAY, "downdelay", DT_U32, 0, NULL }, 828 { IFLA_BOND_FAIL_OVER_MAC, "fail_over_mac", DT_U8, 0, NULL }, 829 { IFLA_BOND_LP_INTERVAL, "lp_interval", DT_U32, 0, NULL }, 830 { IFLA_BOND_MIIMON, "miimon", DT_U32, 0, NULL }, 831 { IFLA_BOND_MIN_LINKS, "min_links", DT_U32, 0, NULL }, 832 { IFLA_BOND_MODE, "mode", DT_U8, 0, NULL }, 833 { IFLA_BOND_NUM_PEER_NOTIF, "num_peer_notif", DT_U8, 0, NULL }, 834 { IFLA_BOND_PACKETS_PER_SLAVE, "packets_per_slave", DT_U32, 0, NULL }, 835 { IFLA_BOND_PRIMARY, "primary", DT_NETDEV, 0, NULL }, 836 { IFLA_BOND_PRIMARY_RESELECT, "primary_reselect", DT_U8, 0, NULL }, 837 { IFLA_BOND_RESEND_IGMP, "resend_igmp", DT_U32, 0, NULL }, 838 { IFLA_BOND_TLB_DYNAMIC_LB, "tlb_dynamic_lb", DT_U8, 0, NULL }, 839 { IFLA_BOND_UPDELAY, "updelay", DT_U32, 0, NULL }, 840 { IFLA_BOND_USE_CARRIER, "use_carrier", DT_U8, 0, NULL }, 841 { IFLA_BOND_XMIT_HASH_POLICY, "xmit_hash_policy", DT_U8, 0, NULL }, 842 }; 843 844 static const uc_nl_attr_spec_t link_bond_slave_attrs[] = { 845 { IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, "ad_actor_oper_port_state", DT_U8, DF_NO_SET, NULL }, 846 { IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, "ad_aggregator_id", DT_U16, DF_NO_SET, NULL }, 847 { IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, "ad_partner_oper_port_state", DT_U8, DF_NO_SET, NULL }, 848 { IFLA_BOND_SLAVE_LINK_FAILURE_COUNT, "link_failure_count", DT_U32, DF_NO_SET, NULL }, 849 { IFLA_BOND_SLAVE_MII_STATUS, "mii_status", DT_U8, DF_NO_SET, NULL }, 850 { IFLA_BOND_SLAVE_PERM_HWADDR, "perm_hwaddr", DT_LLADDR, DF_NO_SET, NULL }, 851 { IFLA_BOND_SLAVE_QUEUE_ID, "queue_id", DT_U16, 0, NULL }, 852 { IFLA_BOND_SLAVE_STATE, "state", DT_U8, DF_NO_SET, NULL }, 853 }; 854 855 static const uc_nl_attr_spec_t link_bridge_attrs[] = { 856 { IFLA_BR_AGEING_TIME, "ageing_time", DT_U32, 0, NULL }, 857 { IFLA_BR_BRIDGE_ID, "bridge_id", DT_BRIDGEID, DF_NO_SET, NULL }, 858 { IFLA_BR_FDB_FLUSH, "fdb_flush", DT_FLAG, DF_NO_GET, NULL }, 859 { IFLA_BR_FORWARD_DELAY, "forward_delay", DT_U32, 0, NULL }, 860 { IFLA_BR_GC_TIMER, "gc_timer", DT_U64, DF_NO_SET, NULL }, 861 { IFLA_BR_GROUP_ADDR, "group_addr", DT_LLADDR, 0, NULL }, 862 { IFLA_BR_GROUP_FWD_MASK, "group_fwd_mask", DT_U16, 0, NULL }, 863 { IFLA_BR_HELLO_TIME, "hello_time", DT_U32, 0, NULL }, 864 { IFLA_BR_HELLO_TIMER, "hello_timer", DT_U64, DF_NO_SET, NULL }, 865 { IFLA_BR_MAX_AGE, "max_age", DT_U32, 0, NULL }, 866 { IFLA_BR_MCAST_HASH_ELASTICITY, "mcast_hash_elasticity", DT_U32, 0, NULL }, 867 { IFLA_BR_MCAST_HASH_MAX, "mcast_hash_max", DT_U32, 0, NULL }, 868 { IFLA_BR_MCAST_IGMP_VERSION, "mcast_igmp_version", DT_U8, 0, NULL }, 869 { IFLA_BR_MCAST_LAST_MEMBER_CNT, "mcast_last_member_cnt", DT_U32, 0, NULL }, 870 { IFLA_BR_MCAST_LAST_MEMBER_INTVL, "mcast_last_member_intvl", DT_U64, 0, NULL }, 871 { IFLA_BR_MCAST_MEMBERSHIP_INTVL, "mcast_membership_intvl", DT_U64, 0, NULL }, 872 { IFLA_BR_MCAST_MLD_VERSION, "mcast_mld_version", DT_U8, 0, NULL }, 873 { IFLA_BR_MCAST_QUERIER, "mcast_querier", DT_U8, 0, NULL }, 874 { IFLA_BR_MCAST_QUERIER_INTVL, "mcast_querier_intvl", DT_U64, 0, NULL }, 875 { IFLA_BR_MCAST_QUERY_INTVL, "mcast_query_intvl", DT_U64, 0, NULL }, 876 { IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, "mcast_query_response_intvl", DT_U64, 0, NULL }, 877 { IFLA_BR_MCAST_QUERY_USE_IFADDR, "mcast_query_use_ifaddr", DT_U8, 0, NULL }, 878 { IFLA_BR_MCAST_ROUTER, "mcast_router", DT_U8, 0, NULL }, 879 { IFLA_BR_MCAST_SNOOPING, "mcast_snooping", DT_U8, 0, NULL }, 880 { IFLA_BR_MCAST_STARTUP_QUERY_CNT, "mcast_startup_query_cnt", DT_U32, 0, NULL }, 881 { IFLA_BR_MCAST_STARTUP_QUERY_INTVL, "mcast_startup_query_intvl", DT_U64, 0, NULL }, 882 { IFLA_BR_MCAST_STATS_ENABLED, "mcast_stats_enabled", DT_U8, 0, NULL }, 883 { IFLA_BR_NF_CALL_ARPTABLES, "nf_call_arptables", DT_U8, 0, NULL }, 884 { IFLA_BR_NF_CALL_IP6TABLES, "nf_call_ip6tables", DT_U8, 0, NULL }, 885 { IFLA_BR_NF_CALL_IPTABLES, "nf_call_iptables", DT_U8, 0, NULL }, 886 { IFLA_BR_PRIORITY, "priority", DT_U16, 0, NULL }, 887 { IFLA_BR_ROOT_ID, "root_id", DT_BRIDGEID, DF_NO_SET, NULL }, 888 { IFLA_BR_ROOT_PATH_COST, "root_path_cost", DT_U32, DF_NO_SET, NULL }, 889 { IFLA_BR_ROOT_PORT, "root_port", DT_U16, DF_NO_SET, NULL }, 890 { IFLA_BR_STP_STATE, "stp_state", DT_U32, 0, NULL }, 891 { IFLA_BR_TCN_TIMER, "tcn_timer", DT_U64, DF_NO_SET, NULL }, 892 { IFLA_BR_TOPOLOGY_CHANGE, "topology_change", DT_U8, DF_NO_SET, NULL }, 893 { IFLA_BR_TOPOLOGY_CHANGE_DETECTED, "topology_change_detected", DT_U8, DF_NO_SET, NULL }, 894 { IFLA_BR_TOPOLOGY_CHANGE_TIMER, "topology_change_timer", DT_U64, DF_NO_SET, NULL }, 895 { IFLA_BR_VLAN_DEFAULT_PVID, "vlan_default_pvid", DT_U16, 0, NULL }, 896 { IFLA_BR_VLAN_FILTERING, "vlan_filtering", DT_U8, 0, NULL }, 897 { IFLA_BR_VLAN_PROTOCOL, "vlan_protocol", DT_U16, 0, NULL }, 898 { IFLA_BR_VLAN_STATS_ENABLED, "vlan_stats_enabled", DT_U8, 0, NULL }, 899 }; 900 901 static const uc_nl_attr_spec_t link_bridge_slave_attrs[] = { 902 { IFLA_BRPORT_BACKUP_PORT, "backup_port", DT_NETDEV, 0, NULL }, 903 //{ IFLA_BRPORT_BCAST_FLOOD, "bcast-flood", DT_??, 0, NULL }, 904 { IFLA_BRPORT_BRIDGE_ID, "bridge_id", DT_BRIDGEID, DF_NO_SET, NULL }, 905 { IFLA_BRPORT_CONFIG_PENDING, "config_pending", DT_U8, DF_NO_SET, NULL }, 906 { IFLA_BRPORT_COST, "cost", DT_U32, 0, NULL }, 907 { IFLA_BRPORT_DESIGNATED_COST, "designated_cost", DT_U16, DF_NO_SET, NULL }, 908 { IFLA_BRPORT_DESIGNATED_PORT, "designated_port", DT_U16, DF_NO_SET, NULL }, 909 { IFLA_BRPORT_FAST_LEAVE, "fast_leave", DT_U8, 0, NULL }, 910 { IFLA_BRPORT_FLUSH, "flush", DT_FLAG, DF_NO_GET, NULL }, 911 { IFLA_BRPORT_FORWARD_DELAY_TIMER, "forward_delay_timer", DT_U64, DF_NO_SET, NULL }, 912 { IFLA_BRPORT_GROUP_FWD_MASK, "group_fwd_mask", DT_U16, 0, NULL }, 913 { IFLA_BRPORT_GUARD, "guard", DT_U8, 0, NULL }, 914 { IFLA_BRPORT_HOLD_TIMER, "hold_timer", DT_U64, DF_NO_SET, NULL }, 915 { IFLA_BRPORT_ID, "id", DT_U16, DF_NO_SET, NULL }, 916 { IFLA_BRPORT_ISOLATED, "isolated", DT_U8, 0, NULL }, 917 { IFLA_BRPORT_LEARNING, "learning", DT_U8, 0, NULL }, 918 { IFLA_BRPORT_LEARNING_SYNC, "learning_sync", DT_U8, 0, NULL }, 919 { IFLA_BRPORT_MCAST_FLOOD, "mcast_flood", DT_U8, 0, NULL }, 920 { IFLA_BRPORT_MCAST_TO_UCAST, "mcast_to_ucast", DT_U8, 0, NULL }, 921 { IFLA_BRPORT_MESSAGE_AGE_TIMER, "message_age_timer", DT_U64, DF_NO_SET, NULL }, 922 { IFLA_BRPORT_MODE, "mode", DT_U8, 0, NULL }, 923 { IFLA_BRPORT_MULTICAST_ROUTER, "multicast_router", DT_U8, 0, NULL }, 924 { IFLA_BRPORT_NEIGH_SUPPRESS, "neigh_suppress", DT_U8, 0, NULL }, 925 { IFLA_BRPORT_NO, "no", DT_U16, DF_NO_SET, NULL }, 926 { IFLA_BRPORT_PRIORITY, "priority", DT_U16, 0, NULL }, 927 { IFLA_BRPORT_PROTECT, "protect", DT_U8, 0, NULL }, 928 { IFLA_BRPORT_PROXYARP, "proxyarp", DT_U8, DF_NO_SET, NULL }, 929 { IFLA_BRPORT_PROXYARP_WIFI, "proxyarp_wifi", DT_U8, DF_NO_SET, NULL }, 930 { IFLA_BRPORT_ROOT_ID, "root_id", DT_BRIDGEID, DF_NO_SET, NULL }, 931 { IFLA_BRPORT_STATE, "state", DT_U8, 0, NULL }, 932 { IFLA_BRPORT_TOPOLOGY_CHANGE_ACK, "topology_change_ack", DT_U8, DF_NO_SET, NULL }, 933 { IFLA_BRPORT_UNICAST_FLOOD, "unicast_flood", DT_U8, 0, NULL }, 934 { IFLA_BRPORT_VLAN_TUNNEL, "vlan_tunnel", DT_U8, 0, NULL }, 935 }; 936 937 static const uc_nl_nested_spec_t link_can_bittiming_rta = { 938 .headsize = NLA_ALIGN(sizeof(struct can_bittiming)), 939 .nattrs = 8, 940 .attrs = { 941 { RTA_UNSPEC, "bitrate", DT_U32, 0, MEMBER(can_bittiming, bitrate) }, 942 { RTA_UNSPEC, "sample_point", DT_U32, 0, MEMBER(can_bittiming, sample_point) }, 943 { RTA_UNSPEC, "tq", DT_U32, 0, MEMBER(can_bittiming, tq) }, 944 { RTA_UNSPEC, "prop_seg", DT_U32, 0, MEMBER(can_bittiming, prop_seg) }, 945 { RTA_UNSPEC, "phase_seg1", DT_U32, 0, MEMBER(can_bittiming, phase_seg1) }, 946 { RTA_UNSPEC, "phase_seg2", DT_U32, 0, MEMBER(can_bittiming, phase_seg2) }, 947 { RTA_UNSPEC, "sjw", DT_U32, 0, MEMBER(can_bittiming, sjw) }, 948 { RTA_UNSPEC, "brp", DT_U32, 0, MEMBER(can_bittiming, brp) }, 949 } 950 }; 951 952 static const uc_nl_nested_spec_t link_can_bittiming_const_rta = { 953 .headsize = NLA_ALIGN(sizeof(struct can_bittiming_const)), 954 .nattrs = 8, 955 .attrs = { 956 { RTA_UNSPEC, "tseg1_min", DT_U32, 0, MEMBER(can_bittiming_const, tseg1_min) }, 957 { RTA_UNSPEC, "tseg1_max", DT_U32, 0, MEMBER(can_bittiming_const, tseg1_max) }, 958 { RTA_UNSPEC, "tseg2_min", DT_U32, 0, MEMBER(can_bittiming_const, tseg2_min) }, 959 { RTA_UNSPEC, "tseg2_max", DT_U32, 0, MEMBER(can_bittiming_const, tseg2_max) }, 960 { RTA_UNSPEC, "sjw_max", DT_U32, 0, MEMBER(can_bittiming_const, sjw_max) }, 961 { RTA_UNSPEC, "brp_min", DT_U32, 0, MEMBER(can_bittiming_const, brp_min) }, 962 { RTA_UNSPEC, "brp_max", DT_U32, 0, MEMBER(can_bittiming_const, brp_max) }, 963 { RTA_UNSPEC, "brp_inc", DT_U32, 0, MEMBER(can_bittiming_const, brp_inc) }, 964 } 965 }; 966 967 static const uc_nl_nested_spec_t link_can_clock_rta = { 968 .headsize = NLA_ALIGN(sizeof(struct can_clock)), 969 .nattrs = 1, 970 .attrs = { 971 { RTA_UNSPEC, "freq", DT_U32, 0, MEMBER(can_clock, freq) }, 972 } 973 }; 974 975 static const uc_nl_nested_spec_t link_can_ctrlmode_rta = { 976 .headsize = NLA_ALIGN(sizeof(struct can_ctrlmode)), 977 .nattrs = 2, 978 .attrs = { 979 { RTA_UNSPEC, "mask", DT_U32, 0, MEMBER(can_ctrlmode, mask) }, 980 { RTA_UNSPEC, "flags", DT_U32, 0, MEMBER(can_ctrlmode, flags) }, 981 } 982 }; 983 984 static const uc_nl_nested_spec_t link_can_berr_counter_rta = { 985 .headsize = NLA_ALIGN(sizeof(struct can_berr_counter)), 986 .nattrs = 2, 987 .attrs = { 988 { RTA_UNSPEC, "txerr", DT_U16, 0, MEMBER(can_berr_counter, txerr) }, 989 { RTA_UNSPEC, "rxerr", DT_U16, 0, MEMBER(can_berr_counter, rxerr) }, 990 } 991 }; 992 993 static const uc_nl_attr_spec_t link_can_attrs[] = { 994 { IFLA_CAN_BERR_COUNTER, "berr_counter", DT_NESTED, DF_NO_SET, &link_can_berr_counter_rta }, 995 { IFLA_CAN_BITTIMING, "bittiming", DT_NESTED, 0, &link_can_bittiming_rta }, 996 { IFLA_CAN_BITTIMING_CONST, "bittiming_const", DT_NESTED, DF_NO_SET, &link_can_bittiming_const_rta }, 997 { IFLA_CAN_CLOCK, "clock", DT_NESTED, DF_NO_SET, &link_can_clock_rta }, 998 { IFLA_CAN_CTRLMODE, "ctrlmode", DT_NESTED, 0, &link_can_ctrlmode_rta }, 999 { IFLA_CAN_DATA_BITTIMING, "data_bittiming", DT_NESTED, 0, &link_can_bittiming_rta }, 1000 { IFLA_CAN_DATA_BITTIMING_CONST, "data_bittiming_const", DT_NESTED, DF_NO_SET, &link_can_bittiming_const_rta }, 1001 { IFLA_CAN_RESTART, "restart", DT_U32, DF_NO_GET, NULL }, 1002 { IFLA_CAN_RESTART_MS, "restart_ms", DT_U32, 0, NULL }, 1003 { IFLA_CAN_STATE, "state", DT_U32, DF_NO_SET, NULL }, 1004 { IFLA_CAN_TERMINATION, "termination", DT_U16, 0, NULL }, 1005 }; 1006 1007 static const uc_nl_attr_spec_t link_geneve_attrs[] = { 1008 { IFLA_GENEVE_COLLECT_METADATA, "collect_metadata", DT_FLAG, DF_NO_GET, NULL }, 1009 { IFLA_GENEVE_ID, "id", DT_U32, 0, NULL }, 1010 { IFLA_GENEVE_LABEL, "label", DT_U32, 0, NULL }, 1011 { IFLA_GENEVE_PORT, "port", DT_U16, 0, NULL }, 1012 { IFLA_GENEVE_REMOTE, "remote", DT_INADDR, 0, NULL }, 1013 { IFLA_GENEVE_REMOTE6, "remote6", DT_IN6ADDR, 0, NULL }, 1014 { IFLA_GENEVE_TOS, "tos", DT_U8, 0, NULL }, 1015 { IFLA_GENEVE_TTL, "ttl", DT_U8, 0, NULL }, 1016 { IFLA_GENEVE_UDP_CSUM, "udp_csum", DT_U8, 0, NULL }, 1017 { IFLA_GENEVE_UDP_ZERO_CSUM6_RX, "udp_zero_csum6_rx", DT_U8, 0, NULL }, 1018 { IFLA_GENEVE_UDP_ZERO_CSUM6_TX, "udp_zero_csum6_tx", DT_U8, 0, NULL }, 1019 }; 1020 1021 static const uc_nl_attr_spec_t link_hsr_attrs[] = { 1022 { IFLA_HSR_MULTICAST_SPEC, "multicast_spec", DT_STRING, DF_NO_GET, NULL }, 1023 { IFLA_HSR_SEQ_NR, "seq_nr", DT_U16, DF_NO_SET, NULL }, 1024 { IFLA_HSR_SLAVE1, "slave1", DT_NETDEV, 0, NULL }, 1025 { IFLA_HSR_SLAVE2, "slave2", DT_NETDEV, 0, NULL }, 1026 { IFLA_HSR_SUPERVISION_ADDR, "supervision_addr", DT_LLADDR, DF_NO_SET, NULL }, 1027 { IFLA_HSR_VERSION, "version", DT_STRING, DF_NO_GET, NULL }, 1028 }; 1029 1030 static const uc_nl_attr_spec_t link_ipoib_attrs[] = { 1031 { IFLA_IPOIB_MODE, "mode", DT_U16, 0, NULL }, 1032 { IFLA_IPOIB_PKEY, "pkey", DT_U16, 0, NULL }, 1033 { IFLA_IPOIB_UMCAST, "umcast", DT_U16, 0, NULL }, 1034 }; 1035 1036 static const uc_nl_attr_spec_t link_ipvlan_attrs[] = { 1037 { IFLA_IPVLAN_FLAGS, "flags", DT_U16, 0, NULL }, 1038 { IFLA_IPVLAN_MODE, "mode", DT_U16, 0, NULL }, 1039 }; 1040 1041 static const uc_nl_attr_spec_t link_macvlan_attrs[] = { 1042 { IFLA_MACVLAN_FLAGS, "flags", DT_U16, 0, NULL }, 1043 { IFLA_MACVLAN_MACADDR, "macaddr", DT_LLADDR, DF_NO_GET, NULL }, 1044 { IFLA_MACVLAN_MACADDR_COUNT, "macaddr_count", DT_U32, DF_NO_SET, NULL }, 1045 { IFLA_MACVLAN_MACADDR_DATA, "macaddr_data", DT_LLADDR, DF_MULTIPLE, (void *)IFLA_MACVLAN_MACADDR }, 1046 { IFLA_MACVLAN_MACADDR_MODE, "macaddr_mode", DT_U32, DF_NO_GET, NULL }, 1047 { IFLA_MACVLAN_MODE, "mode", DT_U32, 0, NULL }, 1048 }; 1049 1050 static const uc_nl_attr_spec_t link_rmnet_attrs[] = { 1051 //{ IFLA_RMNET_FLAGS, "flags", DT_??, 0, NULL }, 1052 { IFLA_RMNET_MUX_ID, "mux_id", DT_U16, 0, NULL }, 1053 }; 1054 1055 1056 static const uc_nl_attr_spec_t link_vlan_attrs[] = { 1057 { IFLA_VLAN_EGRESS_QOS, "egress_qos_map", DT_NUMRANGE, DF_MULTIPLE, (void *)IFLA_VLAN_QOS_MAPPING }, 1058 { IFLA_VLAN_FLAGS, "flags", DT_FLAGS, 0, NULL }, 1059 { IFLA_VLAN_ID, "id", DT_U16, 0, NULL }, 1060 { IFLA_VLAN_INGRESS_QOS, "ingress_qos_map", DT_NUMRANGE, DF_MULTIPLE, (void *)IFLA_VLAN_QOS_MAPPING }, 1061 { IFLA_VLAN_PROTOCOL, "protocol", DT_U16, 0, NULL }, 1062 }; 1063 1064 static const uc_nl_attr_spec_t link_vrf_attrs[] = { 1065 { IFLA_VRF_PORT_TABLE, "port_table", DT_U32, DF_NO_SET, NULL }, 1066 { IFLA_VRF_TABLE, "table", DT_U32, 0, NULL }, 1067 }; 1068 1069 static const uc_nl_attr_spec_t link_vxcan_attrs[] = { 1070 { VXCAN_INFO_PEER, "info_peer", DT_NESTED, 0, &link_msg }, 1071 }; 1072 1073 static const uc_nl_attr_spec_t link_vxlan_attrs[] = { 1074 { IFLA_VXLAN_AGEING, "ageing", DT_U32, 0, NULL }, 1075 { IFLA_VXLAN_COLLECT_METADATA, "collect_metadata", DT_U8, 0, NULL }, 1076 { IFLA_VXLAN_GBP, "gbp", DT_FLAG, 0, NULL }, 1077 { IFLA_VXLAN_GPE, "gpe", DT_FLAG, 0, NULL }, 1078 { IFLA_VXLAN_GROUP, "group", DT_INADDR, 0, NULL }, 1079 { IFLA_VXLAN_GROUP6, "group6", DT_IN6ADDR, 0, NULL }, 1080 { IFLA_VXLAN_ID, "id", DT_U32, 0, NULL }, 1081 { IFLA_VXLAN_L2MISS, "l2miss", DT_U8, 0, NULL }, 1082 { IFLA_VXLAN_L3MISS, "l3miss", DT_U8, 0, NULL }, 1083 { IFLA_VXLAN_LABEL, "label", DT_U32, 0, NULL }, 1084 { IFLA_VXLAN_LEARNING, "learning", DT_U8, 0, NULL }, 1085 { IFLA_VXLAN_LIMIT, "limit", DT_U32, 0, NULL }, 1086 { IFLA_VXLAN_LINK, "link", DT_U32, 0, NULL }, 1087 { IFLA_VXLAN_LOCAL, "local", DT_INADDR, 0, NULL }, 1088 { IFLA_VXLAN_LOCAL6, "local6", DT_IN6ADDR, 0, NULL }, 1089 { IFLA_VXLAN_PORT, "port", DT_U16, DF_BYTESWAP, NULL }, 1090 { IFLA_VXLAN_PORT_RANGE, "port_range", DT_NUMRANGE, DF_MAX_65535|DF_BYTESWAP, NULL }, 1091 { IFLA_VXLAN_PROXY, "proxy", DT_U8, 0, NULL }, 1092 //{ IFLA_VXLAN_REMCSUM_NOPARTIAL, "remcsum-nopartial", DT_??, 0, NULL }, 1093 { IFLA_VXLAN_REMCSUM_RX, "remcsum_rx", DT_BOOL, 0, NULL }, 1094 { IFLA_VXLAN_REMCSUM_TX, "remcsum_tx", DT_BOOL, 0, NULL }, 1095 { IFLA_VXLAN_RSC, "rsc", DT_BOOL, 0, NULL }, 1096 { IFLA_VXLAN_TOS, "tos", DT_U8, 0, NULL }, 1097 { IFLA_VXLAN_TTL, "ttl", DT_U8, 0, NULL }, 1098 { IFLA_VXLAN_TTL_INHERIT, "ttl_inherit", DT_FLAG, 0, NULL }, 1099 { IFLA_VXLAN_UDP_CSUM, "udp_csum", DT_BOOL, 0, NULL }, 1100 { IFLA_VXLAN_UDP_ZERO_CSUM6_RX, "udp_zero_csum6_rx", DT_BOOL, 0, NULL }, 1101 { IFLA_VXLAN_UDP_ZERO_CSUM6_TX, "udp_zero_csum6_tx", DT_BOOL, 0, NULL }, 1102 }; 1103 1104 static const uc_nl_attr_spec_t link_gre_attrs[] = { 1105 { IFLA_GRE_COLLECT_METADATA, "collect_metadata", DT_FLAG, 0, NULL }, 1106 { IFLA_GRE_ENCAP_DPORT, "encap_dport", DT_U16, DF_BYTESWAP, NULL }, 1107 { IFLA_GRE_ENCAP_FLAGS, "encap_flags", DT_U16, 0, NULL }, 1108 { IFLA_GRE_ENCAP_LIMIT, "encap_limit", DT_U8, 0, NULL }, 1109 { IFLA_GRE_ENCAP_SPORT, "encap_sport", DT_U16, DF_BYTESWAP, NULL }, 1110 { IFLA_GRE_ENCAP_TYPE, "encap_type", DT_U16, 0, NULL }, 1111 { IFLA_GRE_ERSPAN_DIR, "erspan_dir", DT_U8, 0, NULL }, 1112 { IFLA_GRE_ERSPAN_HWID, "erspan_hwid", DT_U16, 0, NULL }, 1113 { IFLA_GRE_ERSPAN_INDEX, "erspan_index", DT_U32, 0, NULL }, 1114 { IFLA_GRE_ERSPAN_VER, "erspan_ver", DT_U8, 0, NULL }, 1115 { IFLA_GRE_FLAGS, "flags", DT_U32, 0, NULL }, 1116 { IFLA_GRE_FLOWINFO, "flowinfo", DT_U32, DF_BYTESWAP, NULL }, 1117 { IFLA_GRE_FWMARK, "fwmark", DT_U32, 0, NULL }, 1118 { IFLA_GRE_IFLAGS, "iflags", DT_U16, 0, NULL }, 1119 { IFLA_GRE_IGNORE_DF, "ignore_df", DT_BOOL, 0, NULL }, 1120 { IFLA_GRE_IKEY, "ikey", DT_U32, 0, NULL }, 1121 { IFLA_GRE_LINK, "link", DT_NETDEV, 0, NULL }, 1122 { IFLA_GRE_LOCAL, "local", DT_ANYADDR, 0, NULL }, 1123 { IFLA_GRE_OFLAGS, "oflags", DT_U16, 0, NULL }, 1124 { IFLA_GRE_OKEY, "okey", DT_U32, 0, NULL }, 1125 { IFLA_GRE_PMTUDISC, "pmtudisc", DT_BOOL, 0, NULL }, 1126 { IFLA_GRE_REMOTE, "remote", DT_ANYADDR, 0, NULL }, 1127 { IFLA_GRE_TOS, "tos", DT_U8, 0, NULL }, 1128 { IFLA_GRE_TTL, "ttl", DT_U8, 0, NULL }, 1129 }; 1130 1131 #define link_gretap_attrs link_gre_attrs 1132 #define link_erspan_attrs link_gre_attrs 1133 #define link_ip6gre_attrs link_gre_attrs 1134 #define link_ip6gretap_attrs link_gre_attrs 1135 #define link_ip6erspan_attrs link_gre_attrs 1136 1137 static const uc_nl_attr_spec_t link_ip6tnl_attrs[] = { 1138 { IFLA_IPTUN_6RD_PREFIX, "6rd_prefix", DT_IN6ADDR, 0, NULL }, 1139 { IFLA_IPTUN_6RD_PREFIXLEN, "6rd_prefixlen", DT_U16, 0, NULL }, 1140 { IFLA_IPTUN_6RD_RELAY_PREFIX, "6rd_relay_prefix", DT_INADDR, 0, NULL }, 1141 { IFLA_IPTUN_6RD_RELAY_PREFIXLEN, "6rd_relay_prefixlen", DT_U16, 0, NULL }, 1142 { IFLA_IPTUN_COLLECT_METADATA, "collect_metadata", DT_BOOL, 0, NULL }, 1143 { IFLA_IPTUN_ENCAP_DPORT, "encap_dport", DT_U16, DF_BYTESWAP, NULL }, 1144 { IFLA_IPTUN_ENCAP_FLAGS, "encap_flags", DT_U16, 0, NULL }, 1145 { IFLA_IPTUN_ENCAP_LIMIT, "encap_limit", DT_U8, 0, NULL }, 1146 { IFLA_IPTUN_ENCAP_SPORT, "encap_sport", DT_U16, DF_BYTESWAP, NULL }, 1147 { IFLA_IPTUN_ENCAP_TYPE, "encap_type", DT_U16, 0, NULL }, 1148 { IFLA_IPTUN_FLAGS, "flags", DT_U16, 0, NULL }, 1149 { IFLA_IPTUN_FLOWINFO, "flowinfo", DT_U32, DF_BYTESWAP, NULL }, 1150 { IFLA_IPTUN_FWMARK, "fwmark", DT_U32, 0, NULL }, 1151 { IFLA_IPTUN_LINK, "link", DT_NETDEV, 0, NULL }, 1152 { IFLA_IPTUN_LOCAL, "local", DT_ANYADDR, 0, NULL }, 1153 { IFLA_IPTUN_PMTUDISC, "pmtudisc", DT_BOOL, 0, NULL }, 1154 { IFLA_IPTUN_PROTO, "proto", DT_U8, 0, NULL }, 1155 { IFLA_IPTUN_REMOTE, "remote", DT_ANYADDR, 0, NULL }, 1156 { IFLA_IPTUN_TOS, "tos", DT_U8, 0, NULL }, 1157 { IFLA_IPTUN_TTL, "ttl", DT_U8, 0, NULL }, 1158 }; 1159 1160 #define link_ipip_attrs link_ip6tnl_attrs 1161 #define link_sit_attrs link_ip6tnl_attrs 1162 1163 static const uc_nl_attr_spec_t link_veth_attrs[] = { 1164 { VETH_INFO_PEER, "info_peer", DT_NESTED, 0, &link_msg }, 1165 }; 1166 1167 static const uc_nl_attr_spec_t link_vti_attrs[] = { 1168 { IFLA_VTI_FWMARK, "fwmark", DT_U32, 0, NULL }, 1169 { IFLA_VTI_IKEY, "ikey", DT_U32, 0, NULL }, 1170 { IFLA_VTI_LINK, "link", DT_U32, 0, NULL }, 1171 { IFLA_VTI_LOCAL, "local", DT_ANYADDR, 0, NULL }, 1172 { IFLA_VTI_OKEY, "okey", DT_U32, 0, NULL }, 1173 { IFLA_VTI_REMOTE, "remote", DT_ANYADDR, 0, NULL }, 1174 }; 1175 1176 #define link_vti6_attrs link_vti_attrs 1177 1178 static const uc_nl_attr_spec_t link_xfrm_attrs[] = { 1179 { IFLA_XFRM_IF_ID, "if_id", DT_U32, 0, NULL }, 1180 { IFLA_XFRM_LINK, "link", DT_NETDEV, 0, NULL }, 1181 }; 1182 1183 static const uc_nl_attr_spec_t lwtipopt_erspan_attrs[] = { 1184 { LWTUNNEL_IP_OPT_ERSPAN_VER, "ver", DT_U8, 0, NULL }, 1185 { LWTUNNEL_IP_OPT_ERSPAN_INDEX, "index", DT_U16, DF_BYTESWAP, NULL }, 1186 { LWTUNNEL_IP_OPT_ERSPAN_DIR, "dir", DT_U8, 0, NULL }, 1187 { LWTUNNEL_IP_OPT_ERSPAN_HWID, "hwid", DT_U8, 0, NULL }, 1188 }; 1189 1190 static const uc_nl_attr_spec_t lwtipopt_geneve_attrs[] = { 1191 { LWTUNNEL_IP_OPT_GENEVE_CLASS, "class", DT_U16, DF_BYTESWAP, NULL }, 1192 { LWTUNNEL_IP_OPT_GENEVE_TYPE, "type", DT_U8, 0, NULL }, 1193 { LWTUNNEL_IP_OPT_GENEVE_DATA, "data", DT_STRING, 0, NULL }, 1194 }; 1195 1196 static const uc_nl_attr_spec_t lwtipopt_vxlan_attrs[] = { 1197 { LWTUNNEL_IP_OPT_VXLAN_GBP, "gbp", DT_U32, 0, NULL }, 1198 }; 1199 1200 static const uc_nl_nested_spec_t neigh_cacheinfo_rta = { 1201 .headsize = NLA_ALIGN(sizeof(struct nda_cacheinfo)), 1202 .nattrs = 4, 1203 .attrs = { 1204 { NDA_UNSPEC, "confirmed", DT_U32, 0, MEMBER(nda_cacheinfo, ndm_confirmed) }, 1205 { NDA_UNSPEC, "used", DT_U32, 0, MEMBER(nda_cacheinfo, ndm_used) }, 1206 { NDA_UNSPEC, "updated", DT_U32, 0, MEMBER(nda_cacheinfo, ndm_updated) }, 1207 { NDA_UNSPEC, "refcnt", DT_U32, 0, MEMBER(nda_cacheinfo, ndm_refcnt) }, 1208 } 1209 }; 1210 1211 static const uc_nl_nested_spec_t neigh_msg = { 1212 .headsize = NLA_ALIGN(sizeof(struct ndmsg)), 1213 .nattrs = 16, 1214 .attrs = { 1215 { NDA_UNSPEC, "family", DT_U8, 0, MEMBER(ndmsg, ndm_family) }, 1216 { NDA_UNSPEC, "dev" /* actually ifindex, but avoid clash with NDA_IFINDEX */, DT_NETDEV, DF_ALLOW_NONE, MEMBER(ndmsg, ndm_ifindex) }, 1217 { NDA_UNSPEC, "state", DT_U16, 0, MEMBER(ndmsg, ndm_state) }, 1218 { NDA_UNSPEC, "flags", DT_U8, 0, MEMBER(ndmsg, ndm_flags) }, 1219 { NDA_UNSPEC, "type", DT_U8, 0, MEMBER(ndmsg, ndm_type) }, 1220 { NDA_CACHEINFO, "cacheinfo", DT_NESTED, DF_NO_SET, &neigh_cacheinfo_rta }, 1221 { NDA_DST, "dst", DT_ANYADDR, 0, NULL }, 1222 { NDA_IFINDEX, "ifindex", DT_NETDEV, 0, NULL }, 1223 { NDA_LINK_NETNSID, "link_netnsid", DT_U32, DF_NO_SET, NULL }, 1224 { NDA_LLADDR, "lladdr", DT_LLADDR, 0, NULL }, 1225 { NDA_MASTER, "master", DT_NETDEV, 0, NULL }, 1226 { NDA_PORT, "port", DT_U16, DF_BYTESWAP, NULL }, 1227 { NDA_PROBES, "probes", DT_U32, DF_NO_SET, NULL }, 1228 { NDA_SRC_VNI, "src_vni", DT_U32, DF_NO_SET, NULL }, 1229 { NDA_VLAN, "vlan", DT_U16, 0, NULL }, 1230 { NDA_VNI, "vni", DT_U32, DF_MAX_16777215, NULL }, 1231 } 1232 }; 1233 1234 static const uc_nl_nested_spec_t addr_cacheinfo_rta = { 1235 .headsize = NLA_ALIGN(sizeof(struct ifa_cacheinfo)), 1236 .nattrs = 4, 1237 .attrs = { 1238 { IFA_UNSPEC, "preferred", DT_U32, 0, MEMBER(ifa_cacheinfo, ifa_prefered) }, 1239 { IFA_UNSPEC, "valid", DT_U32, 0, MEMBER(ifa_cacheinfo, ifa_valid) }, 1240 { IFA_UNSPEC, "cstamp", DT_U32, 0, MEMBER(ifa_cacheinfo, cstamp) }, 1241 { IFA_UNSPEC, "tstamp", DT_U32, 0, MEMBER(ifa_cacheinfo, tstamp) }, 1242 } 1243 }; 1244 1245 static const uc_nl_nested_spec_t addr_msg = { 1246 .headsize = NLA_ALIGN(sizeof(struct ifaddrmsg)), 1247 .nattrs = 11, 1248 .attrs = { 1249 { IFA_UNSPEC, "family", DT_U8, 0, MEMBER(ifaddrmsg, ifa_family) }, 1250 { IFA_FLAGS, "flags", DT_U32_OR_MEMBER, DF_MAX_255, MEMBER(ifaddrmsg, ifa_flags) }, 1251 { IFA_UNSPEC, "scope", DT_U8, 0, MEMBER(ifaddrmsg, ifa_scope) }, 1252 { IFA_UNSPEC, "dev", DT_NETDEV, 0, MEMBER(ifaddrmsg, ifa_index) }, 1253 { IFA_ADDRESS, "address", DT_ANYADDR, DF_STORE_MASK, MEMBER(ifaddrmsg, ifa_prefixlen) }, 1254 { IFA_LOCAL, "local", DT_ANYADDR, 0, NULL }, 1255 { IFA_LABEL, "label", DT_STRING, 0, NULL }, 1256 { IFA_BROADCAST, "broadcast", DT_ANYADDR, 0, NULL }, 1257 { IFA_ANYCAST, "anycast", DT_ANYADDR, 0, NULL }, 1258 { IFA_CACHEINFO, "cacheinfo", DT_NESTED, DF_NO_SET, &addr_cacheinfo_rta }, 1259 { IFA_RT_PRIORITY, "metric", DT_U32, 0, NULL }, 1260 } 1261 }; 1262 1263 static const uc_nl_nested_spec_t rule_msg = { 1264 .headsize = NLA_ALIGN(sizeof(struct fib_rule_hdr)), 1265 .nattrs = 23, 1266 .attrs = { 1267 { FRA_UNSPEC, "family", DT_U8, 0, MEMBER(fib_rule_hdr, family) }, 1268 { FRA_UNSPEC, "tos", DT_U8, 0, MEMBER(fib_rule_hdr, tos) }, 1269 { FRA_UNSPEC, "action", DT_U8, 0, MEMBER(fib_rule_hdr, action) }, 1270 { FRA_UNSPEC, "flags", DT_U32, 0, MEMBER(fib_rule_hdr, flags) }, 1271 { FRA_PRIORITY, "priority", DT_U32, 0, NULL }, 1272 { FRA_SRC, "src", DT_ANYADDR, DF_STORE_MASK|DF_FAMILY_HINT, MEMBER(fib_rule_hdr, src_len) }, 1273 { FRA_DST, "dst", DT_ANYADDR, DF_STORE_MASK|DF_FAMILY_HINT, MEMBER(fib_rule_hdr, dst_len) }, 1274 { FRA_FWMARK, "fwmark", DT_U32, 0, NULL }, 1275 { FRA_FWMASK, "fwmask", DT_U32, 0, NULL }, 1276 { FRA_IFNAME, "iif", DT_NETDEV, 0, NULL }, 1277 { FRA_OIFNAME, "oif", DT_NETDEV, 0, NULL }, 1278 { FRA_L3MDEV, "l3mdev", DT_U8, 0, NULL }, 1279 { FRA_UID_RANGE, "uid_range", DT_NUMRANGE, 0, NULL }, 1280 { FRA_IP_PROTO, "ip_proto", DT_U8, 0, NULL }, 1281 { FRA_SPORT_RANGE, "sport_range", DT_NUMRANGE, DF_MAX_65535, NULL }, 1282 { FRA_DPORT_RANGE, "dport_range", DT_NUMRANGE, DF_MAX_65535, NULL }, 1283 { FRA_TABLE, "table", DT_U32_OR_MEMBER, DF_MAX_255, MEMBER(fib_rule_hdr, table) }, 1284 { FRA_SUPPRESS_PREFIXLEN, "suppress_prefixlen", DT_S32, 0, NULL }, 1285 { FRA_SUPPRESS_IFGROUP, "suppress_ifgroup", DT_U32, 0, NULL }, 1286 { FRA_FLOW, "flow", DT_U32, 0, NULL }, 1287 { RTA_GATEWAY, "gateway", DT_ANYADDR, DF_FAMILY_HINT, NULL }, 1288 { FRA_GOTO, "goto", DT_U32, 0, NULL }, 1289 { FRA_PROTOCOL, "protocol", DT_U8, 0, NULL }, 1290 } 1291 }; 1292 1293 #define IFAL_UNSPEC 0 1294 1295 static const uc_nl_nested_spec_t addrlabel_msg = { 1296 .headsize = NLA_ALIGN(sizeof(struct ifaddrlblmsg)), 1297 .nattrs = 6, 1298 .attrs = { 1299 { IFAL_UNSPEC, "family", DT_U8, 0, MEMBER(ifaddrlblmsg, ifal_family) }, 1300 { IFAL_UNSPEC, "flags", DT_U8, 0, MEMBER(ifaddrlblmsg, ifal_flags) }, 1301 { IFAL_UNSPEC, "dev", DT_NETDEV, 0, MEMBER(ifaddrlblmsg, ifal_index) }, 1302 { IFAL_UNSPEC, "seq", DT_U32, 0, MEMBER(ifaddrlblmsg, ifal_seq) }, 1303 { IFAL_ADDRESS, "address", DT_ANYADDR, DF_STORE_MASK, MEMBER(ifaddrlblmsg, ifal_prefixlen) }, 1304 { IFAL_LABEL, "label", DT_U32, 0, NULL }, 1305 } 1306 }; 1307 1308 static const uc_nl_nested_spec_t neightbl_params_rta = { 1309 .headsize = 0, 1310 .nattrs = 13, 1311 .attrs = { 1312 { NDTPA_IFINDEX, "dev", DT_NETDEV, 0, NULL }, 1313 { NDTPA_BASE_REACHABLE_TIME, "base_reachable_time", DT_U64, 0, NULL }, 1314 { NDTPA_RETRANS_TIME, "retrans_time", DT_U64, 0, NULL }, 1315 { NDTPA_GC_STALETIME, "gc_staletime", DT_U64, 0, NULL }, 1316 { NDTPA_DELAY_PROBE_TIME, "delay_probe_time", DT_U64, 0, NULL }, 1317 { NDTPA_QUEUE_LEN, "queue_len", DT_U32, 0, NULL }, 1318 { NDTPA_APP_PROBES, "app_probes", DT_U32, 0, NULL }, 1319 { NDTPA_UCAST_PROBES, "ucast_probes", DT_U32, 0, NULL }, 1320 { NDTPA_MCAST_PROBES, "mcast_probes", DT_U32, 0, NULL }, 1321 { NDTPA_ANYCAST_DELAY, "anycast_delay", DT_U64, 0, NULL }, 1322 { NDTPA_PROXY_DELAY, "proxy_delay", DT_U64, 0, NULL }, 1323 { NDTPA_PROXY_QLEN, "proxy_qlen", DT_U32, 0, NULL }, 1324 { NDTPA_LOCKTIME, "locktime", DT_U64, 0, NULL }, 1325 } 1326 }; 1327 1328 static const uc_nl_nested_spec_t neightbl_config_rta = { 1329 .headsize = NLA_ALIGN(sizeof(struct ndt_config)), 1330 .nattrs = 9, 1331 .attrs = { 1332 { NDTA_UNSPEC, "key_len", DT_U16, 0, MEMBER(ndt_config, ndtc_key_len) }, 1333 { NDTA_UNSPEC, "entry_size", DT_U16, 0, MEMBER(ndt_config, ndtc_entry_size) }, 1334 { NDTA_UNSPEC, "entries", DT_U32, 0, MEMBER(ndt_config, ndtc_entries) }, 1335 { NDTA_UNSPEC, "last_flush", DT_U32, 0, MEMBER(ndt_config, ndtc_last_flush) }, 1336 { NDTA_UNSPEC, "last_rand", DT_U32, 0, MEMBER(ndt_config, ndtc_last_rand) }, 1337 { NDTA_UNSPEC, "hash_rnd", DT_U32, 0, MEMBER(ndt_config, ndtc_hash_rnd) }, 1338 { NDTA_UNSPEC, "hash_mask", DT_U32, 0, MEMBER(ndt_config, ndtc_hash_mask) }, 1339 { NDTA_UNSPEC, "hash_chain_gc", DT_U32, 0, MEMBER(ndt_config, ndtc_hash_chain_gc) }, 1340 { NDTA_UNSPEC, "proxy_qlen", DT_U32, 0, MEMBER(ndt_config, ndtc_proxy_qlen) }, 1341 } 1342 }; 1343 1344 static const uc_nl_nested_spec_t neightbl_stats_rta = { 1345 .headsize = NLA_ALIGN(sizeof(struct ndt_stats)), 1346 .nattrs = 10, 1347 .attrs = { 1348 { NDTA_UNSPEC, "allocs", DT_U64, 0, MEMBER(ndt_stats, ndts_allocs) }, 1349 { NDTA_UNSPEC, "destroys", DT_U64, 0, MEMBER(ndt_stats, ndts_destroys) }, 1350 { NDTA_UNSPEC, "hash_grows", DT_U64, 0, MEMBER(ndt_stats, ndts_hash_grows) }, 1351 { NDTA_UNSPEC, "res_failed", DT_U64, 0, MEMBER(ndt_stats, ndts_res_failed) }, 1352 { NDTA_UNSPEC, "lookups", DT_U64, 0, MEMBER(ndt_stats, ndts_lookups) }, 1353 { NDTA_UNSPEC, "hits", DT_U64, 0, MEMBER(ndt_stats, ndts_hits) }, 1354 { NDTA_UNSPEC, "rcv_probes_mcast", DT_U64, 0, MEMBER(ndt_stats, ndts_rcv_probes_mcast) }, 1355 { NDTA_UNSPEC, "rcv_probes_ucast", DT_U64, 0, MEMBER(ndt_stats, ndts_rcv_probes_ucast) }, 1356 { NDTA_UNSPEC, "periodic_gc_runs", DT_U64, 0, MEMBER(ndt_stats, ndts_periodic_gc_runs) }, 1357 { NDTA_UNSPEC, "forced_gc_runs", DT_U64, 0, MEMBER(ndt_stats, ndts_forced_gc_runs) }, 1358 } 1359 }; 1360 1361 static const uc_nl_nested_spec_t neightbl_msg = { 1362 .headsize = NLA_ALIGN(sizeof(struct ndtmsg)), 1363 .nattrs = 9, 1364 .attrs = { 1365 { NDTA_UNSPEC, "family", DT_U8, 0, MEMBER(ndtmsg, ndtm_family) }, 1366 { NDTA_NAME, "name", DT_STRING, 0, NULL }, 1367 { NDTA_THRESH1, "thresh1", DT_U32, 0, NULL }, 1368 { NDTA_THRESH2, "thresh2", DT_U32, 0, NULL }, 1369 { NDTA_THRESH3, "thresh3", DT_U32, 0, NULL }, 1370 { NDTA_GC_INTERVAL, "gc_interval", DT_U64, 0, NULL }, 1371 { NDTA_PARMS, "params", DT_NESTED, 0, &neightbl_params_rta }, 1372 { NDTA_CONFIG, "config", DT_NESTED, DF_NO_SET, &neightbl_config_rta }, 1373 { NDTA_STATS, "stats", DT_NESTED, DF_NO_SET, &neightbl_stats_rta }, 1374 } 1375 }; 1376 1377 static const uc_nl_nested_spec_t netconf_msg = { 1378 .headsize = NLA_ALIGN(sizeof(struct netconfmsg)), 1379 .nattrs = 8, 1380 .attrs = { 1381 { NETCONFA_UNSPEC, "family", DT_U8, 0, MEMBER(netconfmsg, ncm_family) }, 1382 { NETCONFA_IFINDEX, "dev", DT_NETDEV, 0, NULL }, 1383 { NETCONFA_FORWARDING, "forwarding", DT_U32, DF_NO_SET, NULL }, 1384 { NETCONFA_RP_FILTER, "rp_filter", DT_U32, DF_NO_SET, NULL }, 1385 { NETCONFA_MC_FORWARDING, "mc_forwarding", DT_U32, DF_NO_SET, NULL }, 1386 { NETCONFA_PROXY_NEIGH, "proxy_neigh", DT_U32, DF_NO_SET, NULL }, 1387 { NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, "ignore_routes_with_linkdown", DT_U32, DF_NO_SET, NULL }, 1388 { NETCONFA_INPUT, "input", DT_U32, DF_NO_SET, NULL }, 1389 } 1390 }; 1391 1392 1393 static bool 1394 nla_check_len(struct nlattr *nla, size_t sz) 1395 { 1396 return (nla && nla_len(nla) >= (ssize_t)sz); 1397 } 1398 1399 static bool 1400 nla_parse_error(const uc_nl_attr_spec_t *spec, uc_vm_t *vm, uc_value_t *v, const char *msg) 1401 { 1402 char *s; 1403 1404 s = ucv_to_string(vm, v); 1405 1406 set_error(NLE_INVAL, "%s `%s` has invalid value `%s`: %s", 1407 spec->attr ? "attribute" : "field", 1408 spec->key, 1409 s, 1410 msg); 1411 1412 free(s); 1413 1414 return false; 1415 } 1416 1417 static void 1418 uc_nl_put_struct_member(char *base, const void *offset, size_t datalen, void *data) 1419 { 1420 memcpy(base + (uintptr_t)offset, data, datalen); 1421 } 1422 1423 static void 1424 uc_nl_put_struct_member_u8(char *base, const void *offset, uint8_t u8) 1425 { 1426 base[(uintptr_t)offset] = u8; 1427 } 1428 1429 static void 1430 uc_nl_put_struct_member_u16(char *base, const void *offset, uint16_t u16) 1431 { 1432 uc_nl_put_struct_member(base, offset, sizeof(u16), &u16); 1433 } 1434 1435 static void 1436 uc_nl_put_struct_member_u32(char *base, const void *offset, uint32_t u32) 1437 { 1438 uc_nl_put_struct_member(base, offset, sizeof(u32), &u32); 1439 } 1440 1441 static void * 1442 uc_nl_get_struct_member(char *base, const void *offset, size_t datalen, void *data) 1443 { 1444 memcpy(data, base + (uintptr_t)offset, datalen); 1445 1446 return data; 1447 } 1448 1449 static uint8_t 1450 uc_nl_get_struct_member_u8(char *base, const void *offset) 1451 { 1452 return (uint8_t)base[(uintptr_t)offset]; 1453 } 1454 1455 static uint16_t 1456 uc_nl_get_struct_member_u16(char *base, const void *offset) 1457 { 1458 uint16_t u16; 1459 1460 uc_nl_get_struct_member(base, offset, sizeof(u16), &u16); 1461 1462 return u16; 1463 } 1464 1465 static uint32_t 1466 uc_nl_get_struct_member_u32(char *base, const void *offset) 1467 { 1468 uint32_t u32; 1469 1470 uc_nl_get_struct_member(base, offset, sizeof(u32), &u32); 1471 1472 return u32; 1473 } 1474 1475 static uint64_t 1476 uc_nl_get_struct_member_u64(char *base, const void *offset) 1477 { 1478 uint64_t u64; 1479 1480 uc_nl_get_struct_member(base, offset, sizeof(u64), &u64); 1481 1482 return u64; 1483 } 1484 1485 static bool 1486 uc_nl_parse_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val, size_t idx); 1487 1488 static uc_value_t * 1489 uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr **tb, uc_vm_t *vm); 1490 1491 static bool 1492 uc_nl_convert_attrs(struct nl_msg *msg, void *buf, size_t buflen, size_t headsize, const uc_nl_attr_spec_t *attrs, size_t nattrs, uc_vm_t *vm, uc_value_t *obj) 1493 { 1494 size_t i, maxattr = 0, structlen = headsize; 1495 struct nlattr **tb, *nla, *nla_nest; 1496 uc_value_t *v, *arr; 1497 int rem; 1498 1499 for (i = 0; i < nattrs; i++) 1500 if (attrs[i].attr > maxattr) 1501 maxattr = attrs[i].attr; 1502 1503 tb = calloc(maxattr + 1, sizeof(struct nlattr *)); 1504 1505 if (!tb) 1506 return false; 1507 1508 if (buflen > headsize) { 1509 if (maxattr) 1510 nla_parse(tb, maxattr, buf + headsize, buflen - headsize, NULL); 1511 } 1512 else { 1513 structlen = buflen; 1514 } 1515 1516 for (i = 0; i < nattrs; i++) { 1517 if (attrs[i].attr == 0 && (uintptr_t)attrs[i].auxdata >= structlen) 1518 continue; 1519 1520 if (attrs[i].attr != 0 && !tb[attrs[i].attr]) 1521 continue; 1522 1523 if (attrs[i].flags & DF_NO_GET) 1524 continue; 1525 1526 if (attrs[i].flags & DF_MULTIPLE) { 1527 /* can't happen, but needed to nudge clang-analyzer */ 1528 if (!tb[attrs[i].attr]) 1529 continue; 1530 1531 arr = ucv_array_new(vm); 1532 nla_nest = tb[attrs[i].attr]; 1533 1534 nla_for_each_attr(nla, nla_data(nla_nest), nla_len(nla_nest), rem) { 1535 if (attrs[i].auxdata && nla_type(nla) != (intptr_t)attrs[i].auxdata) 1536 continue; 1537 1538 tb[attrs[i].attr] = nla; 1539 1540 v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, tb, vm); 1541 1542 if (!v) 1543 continue; 1544 1545 ucv_array_push(arr, v); 1546 } 1547 1548 if (!ucv_array_length(arr)) { 1549 ucv_put(arr); 1550 1551 continue; 1552 } 1553 1554 v = arr; 1555 } 1556 else { 1557 v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, tb, vm); 1558 1559 if (!v) 1560 continue; 1561 } 1562 1563 ucv_object_add(obj, attrs[i].key, v); 1564 } 1565 1566 free(tb); 1567 1568 return true; 1569 } 1570 1571 static bool 1572 uc_nl_parse_attrs(struct nl_msg *msg, char *base, const uc_nl_attr_spec_t *attrs, size_t nattrs, uc_vm_t *vm, uc_value_t *obj) 1573 { 1574 struct nlattr *nla_nest = NULL; 1575 size_t i, j, idx; 1576 uc_value_t *v; 1577 bool exists; 1578 1579 for (i = 0; i < nattrs; i++) { 1580 v = ucv_object_get(obj, attrs[i].key, &exists); 1581 1582 if (!exists) 1583 continue; 1584 1585 if (attrs[i].flags & DF_MULTIPLE) { 1586 if (!(attrs[i].flags & DF_FLAT)) 1587 nla_nest = nla_nest_start(msg, attrs[i].attr); 1588 1589 if (ucv_type(v) == UC_ARRAY) { 1590 for (j = 0; j < ucv_array_length(v); j++) { 1591 if (attrs[i].flags & DF_FLAT) 1592 idx = attrs[i].attr; 1593 else if (attrs[i].auxdata) 1594 idx = (uintptr_t)attrs[i].auxdata; 1595 else 1596 idx = j; 1597 1598 if (!uc_nl_parse_attr(&attrs[i], msg, base, vm, ucv_array_get(v, j), idx)) 1599 return false; 1600 } 1601 } 1602 else { 1603 if (attrs[i].flags & DF_FLAT) 1604 idx = attrs[i].attr; 1605 else if (attrs[i].auxdata) 1606 idx = (uintptr_t)attrs[i].auxdata; 1607 else 1608 idx = 0; 1609 1610 if (!uc_nl_parse_attr(&attrs[i], msg, base, vm, v, idx)) 1611 return false; 1612 } 1613 1614 if (nla_nest) 1615 nla_nest_end(msg, nla_nest); 1616 } 1617 else if (!uc_nl_parse_attr(&attrs[i], msg, base, vm, v, 0)) { 1618 return false; 1619 } 1620 } 1621 1622 return true; 1623 } 1624 1625 static bool 1626 uc_nl_parse_rta_nexthop(struct nl_msg *msg, uc_vm_t *vm, uc_value_t *val) 1627 { 1628 struct { uint16_t family; char addr[sizeof(struct in6_addr)]; } via; 1629 struct nlmsghdr *hdr = nlmsg_hdr(msg); 1630 struct rtmsg *rtm = NLMSG_DATA(hdr); 1631 struct nlattr *rta_gateway; 1632 struct rtnexthop *rtnh; 1633 uc_nl_cidr_t cidr = { 0 }; 1634 uc_value_t *v; 1635 uint32_t u; 1636 int aflen; 1637 char *s; 1638 1639 if (ucv_type(val) != UC_OBJECT) 1640 return false; 1641 1642 if (!uc_nl_parse_cidr(vm, ucv_object_get(val, "via", NULL), &cidr)) 1643 return false; 1644 1645 aflen = (cidr.family == AF_INET6 ? sizeof(cidr.addr.in6) : sizeof(cidr.addr.in)); 1646 1647 if (cidr.mask != (aflen * 8)) 1648 return false; 1649 1650 rta_gateway = nla_reserve(msg, RTA_GATEWAY, sizeof(*rtnh)); 1651 1652 rtnh = nla_data(rta_gateway); 1653 rtnh->rtnh_len = sizeof(*rtnh); 1654 1655 if (rtm->rtm_family == AF_UNSPEC) 1656 rtm->rtm_family = cidr.family; 1657 1658 if (cidr.family == rtm->rtm_family) { 1659 nla_put(msg, RTA_GATEWAY, aflen, &cidr.addr.in6); 1660 rtnh->rtnh_len += nla_total_size(aflen); 1661 } 1662 else { 1663 via.family = cidr.family; 1664 memcpy(via.addr, &cidr.addr.in6, aflen); 1665 nla_put(msg, RTA_VIA, sizeof(via.family) + aflen, &via); 1666 rtnh->rtnh_len += nla_total_size(sizeof(via.family) + aflen); 1667 } 1668 1669 v = ucv_object_get(val, "dev", NULL); 1670 s = ucv_string_get(v); 1671 1672 if (s) { 1673 rtnh->rtnh_ifindex = if_nametoindex(s); 1674 1675 if (rtnh->rtnh_ifindex == 0) 1676 return false; 1677 } 1678 1679 v = ucv_object_get(val, "weight", NULL); 1680 1681 if (v) { 1682 if (!uc_nl_parse_u32(v, &u) || u == 0 || u > 256) 1683 return false; 1684 1685 rtnh->rtnh_hops = u - 1; 1686 } 1687 1688 if (ucv_is_truish(ucv_object_get(val, "onlink", NULL))) 1689 rtnh->rtnh_flags |= RTNH_F_ONLINK; 1690 1691 v = ucv_object_get(val, "realm", NULL); 1692 1693 if (v) { 1694 if (!uc_nl_parse_u32(v, &u)) 1695 return false; 1696 1697 nla_put_u32(msg, RTA_FLOW, u); 1698 rtnh->rtnh_len += nla_total_size(sizeof(uint32_t)); 1699 } 1700 1701 v = ucv_object_get(val, "as", NULL); 1702 1703 if (v) { 1704 if (!uc_nl_parse_cidr(vm, v, &cidr) || cidr.family != rtm->rtm_family) 1705 return false; 1706 1707 if (cidr.mask != cidr.bitlen) 1708 return false; 1709 1710 nla_put(msg, RTA_NEWDST, cidr.alen, &cidr.addr.in6); 1711 rtnh->rtnh_len += nla_total_size(cidr.alen); 1712 } 1713 1714 /* XXX: nla_nest_end(rta_gateway) ? */ 1715 1716 return true; 1717 } 1718 1719 static bool 1720 uc_nl_parse_rta_multipath(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val) 1721 { 1722 struct nlattr *rta_multipath = nla_nest_start(msg, spec->attr); 1723 size_t i; 1724 1725 for (i = 0; i < ucv_array_length(val); i++) 1726 if (!uc_nl_parse_rta_nexthop(msg, vm, ucv_array_get(val, i))) 1727 return false; 1728 1729 nla_nest_end(msg, rta_multipath); 1730 1731 return true; 1732 } 1733 1734 static uc_value_t * 1735 uc_nl_convert_rta_encap(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm); 1736 1737 static uc_value_t * 1738 uc_nl_convert_rta_multipath(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 1739 { 1740 uc_nl_attr_spec_t encap_spec = { .attr = RTA_ENCAP }; 1741 struct rtnexthop *nh = nla_data(tb[spec->attr]); 1742 struct nlattr *multipath_tb[RTA_MAX + 1]; 1743 size_t len = nla_len(tb[spec->attr]); 1744 uc_value_t *nh_obj, *nh_arr; 1745 char buf[INET6_ADDRSTRLEN]; 1746 struct rtvia *via; 1747 int af; 1748 1749 nh_arr = ucv_array_new(vm); 1750 1751 while (len >= sizeof(*nh)) { 1752 if ((size_t)NLA_ALIGN(nh->rtnh_len) > len) 1753 break; 1754 1755 nh_obj = ucv_object_new(vm); 1756 ucv_array_push(nh_arr, nh_obj); 1757 1758 nla_parse(multipath_tb, RTA_MAX, (struct nlattr *)RTNH_DATA(nh), nh->rtnh_len - sizeof(*nh), NULL); 1759 1760 if (multipath_tb[RTA_GATEWAY]) { 1761 switch (nla_len(multipath_tb[RTA_GATEWAY])) { 1762 case 4: af = AF_INET; break; 1763 case 16: af = AF_INET6; break; 1764 default: af = AF_UNSPEC; break; 1765 } 1766 1767 if (inet_ntop(af, nla_data(multipath_tb[RTA_GATEWAY]), buf, sizeof(buf))) 1768 ucv_object_add(nh_obj, "via", ucv_string_new(buf)); 1769 } 1770 1771 if (multipath_tb[RTA_VIA]) { 1772 if (nla_len(multipath_tb[RTA_VIA]) > (ssize_t)sizeof(*via)) { 1773 via = nla_data(multipath_tb[RTA_VIA]); 1774 af = via->rtvia_family; 1775 1776 if ((af == AF_INET && 1777 nla_len(multipath_tb[RTA_VIA]) == sizeof(*via) + sizeof(struct in_addr)) || 1778 (af == AF_INET6 && 1779 nla_len(multipath_tb[RTA_VIA]) == sizeof(*via) + sizeof(struct in6_addr))) { 1780 if (inet_ntop(af, via->rtvia_addr, buf, sizeof(buf))) 1781 ucv_object_add(nh_obj, "via", ucv_string_new(buf)); 1782 } 1783 } 1784 } 1785 1786 if (if_indextoname(nh->rtnh_ifindex, buf)) 1787 ucv_object_add(nh_obj, "dev", ucv_string_new(buf)); 1788 1789 ucv_object_add(nh_obj, "weight", ucv_int64_new(nh->rtnh_hops + 1)); 1790 ucv_object_add(nh_obj, "onlink", ucv_boolean_new(nh->rtnh_flags & RTNH_F_ONLINK)); 1791 1792 if (multipath_tb[RTA_FLOW] && nla_len(multipath_tb[RTA_FLOW]) == sizeof(uint32_t)) 1793 ucv_object_add(nh_obj, "realm", ucv_int64_new(nla_get_u32(multipath_tb[RTA_FLOW]))); 1794 1795 if (multipath_tb[RTA_ENCAP]) 1796 ucv_object_add(nh_obj, "encap", 1797 uc_nl_convert_rta_encap(&encap_spec, msg, multipath_tb, vm)); 1798 1799 if (multipath_tb[RTA_NEWDST]) { 1800 switch (nla_len(multipath_tb[RTA_NEWDST])) { 1801 case 4: af = AF_INET; break; 1802 case 16: af = AF_INET6; break; 1803 default: af = AF_UNSPEC; break; 1804 } 1805 1806 if (inet_ntop(af, nla_data(multipath_tb[RTA_NEWDST]), buf, sizeof(buf))) 1807 ucv_object_add(nh_obj, "as", ucv_string_new(buf)); 1808 } 1809 1810 len -= NLA_ALIGN(nh->rtnh_len); 1811 nh = RTNH_NEXT(nh); 1812 } 1813 1814 return nh_arr; 1815 } 1816 1817 static bool 1818 parse_num(const uc_nl_attr_spec_t *spec, uc_vm_t *vm, uc_value_t *val, void *dst) 1819 { 1820 int64_t n = ucv_int64_get(val); 1821 uint32_t *u32; 1822 uint16_t *u16; 1823 uint8_t *u8; 1824 1825 if (spec->flags & DF_MAX_255) { 1826 if (n < 0 || n > 255) 1827 return nla_parse_error(spec, vm, val, "number out of range 0-255"); 1828 1829 u8 = dst; *u8 = n; 1830 } 1831 else if (spec->flags & DF_MAX_65535) { 1832 if (n < 0 || n > 65535) 1833 return nla_parse_error(spec, vm, val, "number out of range 0-65535"); 1834 1835 u16 = dst; *u16 = n; 1836 1837 if (spec->flags & DF_BYTESWAP) 1838 *u16 = htons(*u16); 1839 } 1840 else if (spec->flags & DF_MAX_16777215) { 1841 if (n < 0 || n > 16777215) 1842 return nla_parse_error(spec, vm, val, "number out of range 0-16777215"); 1843 1844 u32 = dst; *u32 = n; 1845 1846 if (spec->flags & DF_BYTESWAP) 1847 *u32 = htonl(*u32); 1848 } 1849 else { 1850 if (n < 0 || n > 4294967295) 1851 return nla_parse_error(spec, vm, val, "number out of range 0-4294967295"); 1852 1853 u32 = dst; *u32 = n; 1854 1855 if (spec->flags & DF_BYTESWAP) 1856 *u32 = htonl(*u32); 1857 } 1858 1859 return true; 1860 } 1861 1862 static bool 1863 uc_nl_parse_rta_numrange(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val) 1864 { 1865 union { 1866 struct { uint8_t low; uint8_t high; } u8; 1867 struct { uint16_t low; uint16_t high; } u16; 1868 struct { uint32_t low; uint32_t high; } u32; 1869 } ranges = { 0 }; 1870 1871 void *d1, *d2; 1872 size_t len; 1873 1874 if (ucv_array_length(val) != 2 || 1875 ucv_type(ucv_array_get(val, 0)) != UC_INTEGER || 1876 ucv_type(ucv_array_get(val, 1)) != UC_INTEGER) 1877 return nla_parse_error(spec, vm, val, "not a two-element array of numbers"); 1878 1879 if (spec->flags & DF_MAX_255) { 1880 len = sizeof(ranges.u8); 1881 d1 = &ranges.u8.low; 1882 d2 = &ranges.u8.high; 1883 } 1884 else if (spec->flags & DF_MAX_65535) { 1885 len = sizeof(ranges.u16); 1886 d1 = &ranges.u16.low; 1887 d2 = &ranges.u16.high; 1888 } 1889 else { 1890 len = sizeof(ranges.u32); 1891 d1 = &ranges.u32.low; 1892 d2 = &ranges.u32.high; 1893 } 1894 1895 if (!parse_num(spec, vm, ucv_array_get(val, 0), d1) || 1896 !parse_num(spec, vm, ucv_array_get(val, 1), d2)) 1897 return false; 1898 1899 nla_put(msg, spec->attr, len, d1); 1900 1901 return true; 1902 } 1903 1904 static uc_value_t * 1905 uc_nl_convert_rta_numrange(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 1906 { 1907 union { 1908 struct { uint8_t low; uint8_t high; } *u8; 1909 struct { uint16_t low; uint16_t high; } *u16; 1910 struct { uint32_t low; uint32_t high; } *u32; 1911 } ranges = { 0 }; 1912 1913 bool swap = (spec->flags & DF_BYTESWAP); 1914 uc_value_t *arr, *n1, *n2; 1915 1916 if (spec->flags & DF_MAX_255) { 1917 if (!nla_check_len(tb[spec->attr], sizeof(*ranges.u8))) 1918 return NULL; 1919 1920 ranges.u8 = nla_data(tb[spec->attr]); 1921 n1 = ucv_int64_new(ranges.u8->low); 1922 n2 = ucv_int64_new(ranges.u8->high); 1923 } 1924 else if (spec->flags & DF_MAX_65535) { 1925 if (!nla_check_len(tb[spec->attr], sizeof(*ranges.u16))) 1926 return NULL; 1927 1928 ranges.u16 = nla_data(tb[spec->attr]); 1929 n1 = ucv_int64_new(swap ? ntohs(ranges.u16->low) : ranges.u16->low); 1930 n2 = ucv_int64_new(swap ? ntohs(ranges.u16->high) : ranges.u16->high); 1931 } 1932 else { 1933 if (!nla_check_len(tb[spec->attr], sizeof(*ranges.u32))) 1934 return NULL; 1935 1936 ranges.u32 = nla_data(tb[spec->attr]); 1937 n1 = ucv_int64_new(swap ? ntohl(ranges.u32->low) : ranges.u32->low); 1938 n2 = ucv_int64_new(swap ? ntohl(ranges.u32->high) : ranges.u32->high); 1939 } 1940 1941 arr = ucv_array_new(vm); 1942 1943 ucv_array_push(arr, n1); 1944 ucv_array_push(arr, n2); 1945 1946 return arr; 1947 } 1948 1949 1950 #define LINK_TYPE(name) \ 1951 { #name, link_##name##_attrs, ARRAY_SIZE(link_##name##_attrs) } 1952 1953 static const struct { 1954 const char *name; 1955 const uc_nl_attr_spec_t *attrs; 1956 size_t nattrs; 1957 } link_types[] = { 1958 LINK_TYPE(bareudp), 1959 LINK_TYPE(bond), 1960 LINK_TYPE(bond_slave), 1961 LINK_TYPE(bridge), 1962 LINK_TYPE(bridge_slave), 1963 LINK_TYPE(can), 1964 LINK_TYPE(geneve), 1965 LINK_TYPE(hsr), 1966 LINK_TYPE(ipoib), 1967 LINK_TYPE(ipvlan), 1968 LINK_TYPE(macvlan), 1969 LINK_TYPE(rmnet), 1970 LINK_TYPE(vlan), 1971 LINK_TYPE(vrf), 1972 LINK_TYPE(vxcan), 1973 LINK_TYPE(vxlan), 1974 //LINK_TYPE(xdp), 1975 //LINK_TYPE(xstats), 1976 LINK_TYPE(gre), 1977 LINK_TYPE(gretap), 1978 LINK_TYPE(erspan), 1979 LINK_TYPE(ip6gre), 1980 LINK_TYPE(ip6gretap), 1981 LINK_TYPE(ip6erspan), 1982 LINK_TYPE(ip6tnl), 1983 LINK_TYPE(ipip), 1984 LINK_TYPE(sit), 1985 LINK_TYPE(veth), 1986 LINK_TYPE(vti), 1987 LINK_TYPE(vti6), 1988 LINK_TYPE(xfrm), 1989 }; 1990 1991 static bool 1992 uc_nl_parse_rta_linkinfo(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val) 1993 { 1994 const uc_nl_attr_spec_t *attrs = NULL; 1995 struct nlattr *li_nla, *info_nla; 1996 size_t i, nattrs = 0; 1997 char *kind, *p; 1998 uc_value_t *k; 1999 2000 k = ucv_object_get(val, "type", NULL); 2001 kind = ucv_string_get(k); 2002 2003 if (!kind) 2004 return nla_parse_error(spec, vm, val, "linkinfo does not specify kind"); 2005 2006 li_nla = nla_nest_start(msg, spec->attr); 2007 2008 nla_put_string(msg, IFLA_INFO_KIND, kind); 2009 2010 for (i = 0; i < ARRAY_SIZE(link_types); i++) { 2011 if (!strcmp(link_types[i].name, kind)) { 2012 attrs = link_types[i].attrs; 2013 nattrs = link_types[i].nattrs; 2014 break; 2015 } 2016 } 2017 2018 p = strchr(kind, '_'); 2019 2020 if (!p || strcmp(p, "_slave")) 2021 info_nla = nla_nest_start(msg, IFLA_INFO_DATA); 2022 else 2023 info_nla = nla_nest_start(msg, IFLA_INFO_SLAVE_DATA); 2024 2025 if (!uc_nl_parse_attrs(msg, base, attrs, nattrs, vm, val)) 2026 return false; 2027 2028 nla_nest_end(msg, info_nla); 2029 nla_nest_end(msg, li_nla); 2030 2031 return true; 2032 } 2033 2034 static uc_value_t * 2035 uc_nl_convert_rta_linkinfo_data(uc_value_t *obj, size_t attr, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 2036 { 2037 const uc_nl_attr_spec_t *attrs = NULL; 2038 size_t i, nattrs = 0; 2039 uc_value_t *v; 2040 bool rv; 2041 2042 if (!tb[attr] || nla_len(tb[attr]) < 1) 2043 return NULL; 2044 2045 v = ucv_string_new_length(nla_data(tb[attr]), nla_len(tb[attr]) - 1); 2046 2047 ucv_object_add(obj, "type", v); 2048 2049 for (i = 0; i < ARRAY_SIZE(link_types); i++) { 2050 if (!strcmp(link_types[i].name, ucv_string_get(v))) { 2051 attrs = link_types[i].attrs; 2052 nattrs = link_types[i].nattrs; 2053 break; 2054 } 2055 } 2056 2057 attr = (attr == IFLA_INFO_KIND) ? IFLA_INFO_DATA : IFLA_INFO_SLAVE_DATA; 2058 2059 if (nattrs > 0 && tb[attr]) { 2060 rv = uc_nl_convert_attrs(msg, nla_data(tb[attr]), nla_len(tb[attr]), 0, attrs, nattrs, vm, obj); 2061 2062 if (!rv) 2063 return NULL; 2064 } 2065 2066 return obj; 2067 } 2068 2069 static uc_value_t * 2070 uc_nl_convert_rta_linkinfo(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 2071 { 2072 struct nlattr *linkinfo_tb[IFLA_INFO_MAX + 1]; 2073 uc_value_t *info_obj, *slave_obj; 2074 2075 if (!tb[spec->attr]) 2076 return NULL; 2077 2078 nla_parse(linkinfo_tb, IFLA_INFO_MAX, nla_data(tb[spec->attr]), nla_len(tb[spec->attr]), NULL); 2079 2080 info_obj = ucv_object_new(vm); 2081 2082 if (linkinfo_tb[IFLA_INFO_KIND]) { 2083 if (!uc_nl_convert_rta_linkinfo_data(info_obj, IFLA_INFO_KIND, msg, linkinfo_tb, vm)) { 2084 ucv_put(info_obj); 2085 2086 return NULL; 2087 } 2088 } 2089 2090 if (linkinfo_tb[IFLA_INFO_SLAVE_KIND]) { 2091 slave_obj = ucv_object_new(vm); 2092 2093 if (!uc_nl_convert_rta_linkinfo_data(slave_obj, IFLA_INFO_SLAVE_KIND, msg, linkinfo_tb, vm)) { 2094 ucv_put(info_obj); 2095 ucv_put(slave_obj); 2096 2097 return NULL; 2098 } 2099 2100 ucv_object_add(info_obj, "slave", slave_obj); 2101 } 2102 2103 return info_obj; 2104 } 2105 2106 static uc_value_t * 2107 uc_nl_convert_rta_bridgeid(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 2108 { 2109 char buf[sizeof("ffff.ff:ff:ff:ff:ff:ff")]; 2110 struct ifla_bridge_id *id; 2111 2112 if (!nla_check_len(tb[spec->attr], sizeof(*id))) 2113 return NULL; 2114 2115 id = nla_data(tb[spec->attr]); 2116 2117 snprintf(buf, sizeof(buf), "%02x%02x.%02x:%02x:%02x:%02x:%02x:%02x", 2118 id->prio[0], id->prio[1], 2119 id->addr[0], id->addr[1], 2120 id->addr[2], id->addr[3], 2121 id->addr[4], id->addr[5]); 2122 2123 return ucv_string_new(buf); 2124 } 2125 2126 static bool 2127 uc_nl_parse_rta_srh(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val) 2128 { 2129 uc_value_t *mode, *hmac, *segs, *seg; 2130 struct seg6_iptunnel_encap *tun; 2131 struct sr6_tlv_hmac *tlv; 2132 struct ipv6_sr_hdr *srh; 2133 size_t i, nsegs, srhlen; 2134 char *s; 2135 2136 mode = ucv_object_get(val, "mode", NULL); 2137 hmac = ucv_object_get(val, "hmac", NULL); 2138 segs = ucv_object_get(val, "segs", NULL); 2139 2140 if (mode != NULL && 2141 (ucv_type(mode) != UC_INTEGER || 2142 ucv_int64_get(mode) < 0 || 2143 ucv_int64_get(mode) > UINT32_MAX)) 2144 return nla_parse_error(spec, vm, val, "srh mode not an integer in range 0-4294967295"); 2145 2146 if (hmac != NULL && 2147 (ucv_type(hmac) != UC_INTEGER || 2148 ucv_int64_get(hmac) < 0 || 2149 ucv_int64_get(hmac) > UINT32_MAX)) 2150 return nla_parse_error(spec, vm, val, "srh hmac not an integer in range 0-4294967295"); 2151 2152 if (ucv_type(segs) != UC_ARRAY || 2153 ucv_array_length(segs) == 0) 2154 return nla_parse_error(spec, vm, val, "srh segs array missing or empty"); 2155 2156 nsegs = ucv_array_length(segs); 2157 2158 if (!mode || !ucv_int64_get(mode)) 2159 nsegs++; 2160 2161 srhlen = 8 + 16 * nsegs; 2162 2163 if (hmac && ucv_int64_get(hmac)) 2164 srhlen += 40; 2165 2166 2167 tun = calloc(1, sizeof(*tun) + srhlen); 2168 2169 if (!tun) 2170 return nla_parse_error(spec, vm, val, "cannot allocate srh header"); 2171 2172 tun->mode = (int)ucv_int64_get(mode); 2173 2174 srh = tun->srh; 2175 srh->hdrlen = (srhlen >> 3) - 1; 2176 srh->type = 4; 2177 srh->segments_left = nsegs - 1; 2178 srh->first_segment = nsegs - 1; 2179 2180 if (hmac && ucv_int64_get(hmac)) 2181 srh->flags |= SR6_FLAG1_HMAC; 2182 2183 for (i = 0; i < ucv_array_length(segs); i++) { 2184 seg = ucv_array_get(segs, i); 2185 s = ucv_string_get(seg); 2186 2187 if (!s || inet_pton(AF_INET6, s, &srh->segments[--nsegs]) != 1) { 2188 free(tun); 2189 2190 return nla_parse_error(spec, vm, val, "srh segs array contains invalid IPv6 address"); 2191 } 2192 } 2193 2194 if (hmac && ucv_int64_get(hmac)) { 2195 tlv = (struct sr6_tlv_hmac *)((char *)srh + srhlen - 40); 2196 tlv->tlvhdr.type = SR6_TLV_HMAC; 2197 tlv->tlvhdr.len = 38; 2198 tlv->hmackeyid = htonl((uint32_t)ucv_int64_get(hmac)); 2199 } 2200 2201 nla_put(msg, spec->attr, sizeof(*tun) + srhlen, tun); 2202 free(tun); 2203 2204 return true; 2205 } 2206 2207 static uc_value_t * 2208 uc_nl_convert_rta_srh(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 2209 { 2210 char buf[INET6_ADDRSTRLEN], *p, *e; 2211 struct seg6_iptunnel_encap *tun; 2212 uc_value_t *tun_obj, *seg_arr; 2213 struct sr6_tlv_hmac *tlv; 2214 size_t i; 2215 2216 if (!nla_check_len(tb[spec->attr], sizeof(*tun))) 2217 return NULL; 2218 2219 tun = nla_data(tb[spec->attr]); 2220 tun_obj = ucv_object_new(vm); 2221 2222 ucv_object_add(tun_obj, "mode", ucv_int64_new(tun->mode)); 2223 2224 seg_arr = ucv_array_new(vm); 2225 2226 p = (char *)tun->srh->segments; 2227 e = (char *)tun + nla_len(tb[spec->attr]); 2228 2229 for (i = tun->srh->first_segment + 1; 2230 p + sizeof(struct in6_addr) <= e && i > 0; 2231 i--, p += sizeof(struct in6_addr)) { 2232 if (inet_ntop(AF_INET6, p, buf, sizeof(buf))) 2233 ucv_array_push(seg_arr, ucv_string_new(buf)); 2234 else 2235 ucv_array_push(seg_arr, NULL); 2236 } 2237 2238 ucv_object_add(tun_obj, "segs", seg_arr); 2239 2240 if (sr_has_hmac(tun->srh)) { 2241 i = ((tun->srh->hdrlen + 1) << 3) - 40; 2242 tlv = (struct sr6_tlv_hmac *)((char *)tun->srh + i); 2243 2244 ucv_object_add(tun_obj, "hmac", ucv_int64_new(ntohl(tlv->hmackeyid))); 2245 } 2246 2247 return tun_obj; 2248 } 2249 2250 #define ENCAP_TYPE(name, type) \ 2251 { #name, LWTUNNEL_ENCAP_##type, route_encap_##name##_attrs, ARRAY_SIZE(route_encap_##name##_attrs) } 2252 2253 static const struct { 2254 const char *name; 2255 uint16_t type; 2256 const uc_nl_attr_spec_t *attrs; 2257 size_t nattrs; 2258 } encap_types[] = { 2259 ENCAP_TYPE(mpls, MPLS), 2260 ENCAP_TYPE(ip, IP), 2261 ENCAP_TYPE(ip6, IP6), 2262 ENCAP_TYPE(ila, ILA), 2263 //ENCAP_TYPE(bpf, BPF), 2264 ENCAP_TYPE(seg6, SEG6), 2265 //ENCAP_TYPE(seg6local, SEG6_LOCAL), 2266 //ENCAP_TYPE(rpl, RPL), 2267 }; 2268 2269 static bool 2270 uc_nl_parse_rta_encap(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val) 2271 { 2272 const uc_nl_attr_spec_t *attrs = NULL; 2273 struct nlattr *enc_nla; 2274 size_t i, nattrs = 0; 2275 uint16_t ntype = 0; 2276 uc_value_t *t; 2277 char *type; 2278 2279 t = ucv_object_get(val, "type", NULL); 2280 type = ucv_string_get(t); 2281 2282 if (!type) 2283 return nla_parse_error(spec, vm, val, "encap does not specify type"); 2284 2285 for (i = 0; i < ARRAY_SIZE(encap_types); i++) { 2286 if (!strcmp(encap_types[i].name, type)) { 2287 ntype = encap_types[i].type; 2288 attrs = encap_types[i].attrs; 2289 nattrs = encap_types[i].nattrs; 2290 break; 2291 } 2292 } 2293 2294 if (!ntype) 2295 return nla_parse_error(spec, vm, val, "encap specifies unknown type"); 2296 2297 nla_put_u16(msg, RTA_ENCAP_TYPE, ntype); 2298 2299 enc_nla = nla_nest_start(msg, spec->attr); 2300 2301 if (!uc_nl_parse_attrs(msg, base, attrs, nattrs, vm, val)) 2302 return false; 2303 2304 nla_nest_end(msg, enc_nla); 2305 2306 return true; 2307 } 2308 2309 static uc_value_t * 2310 uc_nl_convert_rta_encap(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 2311 { 2312 const uc_nl_attr_spec_t *attrs = NULL; 2313 const char *name = NULL; 2314 uc_value_t *encap_obj; 2315 size_t i, nattrs = 0; 2316 bool rv; 2317 2318 if (!tb[spec->attr] || 2319 !nla_check_len(tb[RTA_ENCAP_TYPE], sizeof(uint16_t))) 2320 return NULL; 2321 2322 for (i = 0; i < ARRAY_SIZE(encap_types); i++) { 2323 if (encap_types[i].type != nla_get_u16(tb[RTA_ENCAP_TYPE])) 2324 continue; 2325 2326 name = encap_types[i].name; 2327 attrs = encap_types[i].attrs; 2328 nattrs = encap_types[i].nattrs; 2329 2330 break; 2331 } 2332 2333 if (!name) 2334 return NULL; 2335 2336 encap_obj = ucv_object_new(vm); 2337 2338 rv = uc_nl_convert_attrs(msg, 2339 nla_data(tb[spec->attr]), nla_len(tb[spec->attr]), 0, 2340 attrs, nattrs, vm, encap_obj); 2341 2342 if (!rv) { 2343 ucv_put(encap_obj); 2344 2345 return NULL; 2346 } 2347 2348 ucv_object_add(encap_obj, "type", ucv_string_new(name)); 2349 2350 return encap_obj; 2351 } 2352 2353 #define IPOPTS_TYPE(name, type, multiple) \ 2354 { #name, LWTUNNEL_IP_OPTS_##type, multiple, lwtipopt_##name##_attrs, ARRAY_SIZE(lwtipopt_##name##_attrs) } 2355 2356 static const struct { 2357 const char *name; 2358 uint16_t type; 2359 bool multiple; 2360 const uc_nl_attr_spec_t *attrs; 2361 size_t nattrs; 2362 } lwtipopt_types[] = { 2363 IPOPTS_TYPE(erspan, ERSPAN, false), 2364 IPOPTS_TYPE(geneve, GENEVE, true), 2365 IPOPTS_TYPE(vxlan, VXLAN, false), 2366 }; 2367 2368 static bool 2369 uc_nl_parse_rta_ipopts(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val) 2370 { 2371 const uc_nl_attr_spec_t *attrs = NULL; 2372 struct nlattr *opt_nla, *type_nla; 2373 bool exists, multiple = false; 2374 size_t i, j, nattrs = 0; 2375 uint16_t ntype = 0; 2376 uc_value_t *item; 2377 2378 ucv_object_foreach(val, type, v) { 2379 for (i = 0; i < ARRAY_SIZE(lwtipopt_types); i++) { 2380 if (!strcmp(lwtipopt_types[i].name, type)) { 2381 val = v; 2382 ntype = lwtipopt_types[i].type; 2383 attrs = lwtipopt_types[i].attrs; 2384 nattrs = lwtipopt_types[i].nattrs; 2385 multiple = lwtipopt_types[i].multiple; 2386 break; 2387 } 2388 } 2389 } 2390 2391 if (!ntype) 2392 return nla_parse_error(spec, vm, val, "unknown IP options type specified"); 2393 2394 opt_nla = nla_nest_start(msg, spec->attr); 2395 2396 j = 0; 2397 item = (ucv_type(val) == UC_ARRAY) ? ucv_array_get(val, j++) : val; 2398 2399 while (true) { 2400 type_nla = nla_nest_start(msg, ntype); 2401 2402 for (i = 0; i < nattrs; i++) { 2403 v = ucv_object_get(item, attrs[i].key, &exists); 2404 2405 if (!exists) 2406 continue; 2407 2408 if (!uc_nl_parse_attr(&attrs[i], msg, nla_data(type_nla), vm, v, 0)) 2409 return false; 2410 } 2411 2412 nla_nest_end(msg, type_nla); 2413 2414 if (!multiple || ucv_type(val) != UC_ARRAY || j >= ucv_array_length(val)) 2415 break; 2416 2417 item = ucv_array_get(val, j++); 2418 } 2419 2420 nla_nest_end(msg, opt_nla); 2421 2422 return true; 2423 } 2424 2425 static uc_value_t * 2426 uc_nl_convert_rta_ipopts(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 2427 { 2428 struct nlattr *opt_tb[LWTUNNEL_IP_OPTS_MAX + 1]; 2429 const uc_nl_attr_spec_t *attrs = NULL; 2430 uc_value_t *opt_obj, *type_obj; 2431 const char *name = NULL; 2432 size_t i, nattrs = 0; 2433 uint16_t type = 0; 2434 bool rv; 2435 2436 if (!tb[spec->attr] || 2437 !nla_parse(opt_tb, LWTUNNEL_IP_OPTS_MAX, nla_data(tb[spec->attr]), nla_len(tb[spec->attr]), NULL)) 2438 return NULL; 2439 2440 for (i = 0; i < ARRAY_SIZE(lwtipopt_types); i++) { 2441 if (!opt_tb[lwtipopt_types[i].type]) 2442 continue; 2443 2444 type = lwtipopt_types[i].type; 2445 name = lwtipopt_types[i].name; 2446 attrs = lwtipopt_types[i].attrs; 2447 nattrs = lwtipopt_types[i].nattrs; 2448 2449 break; 2450 } 2451 2452 if (!name) 2453 return NULL; 2454 2455 type_obj = ucv_object_new(vm); 2456 2457 rv = uc_nl_convert_attrs(msg, 2458 nla_data(opt_tb[type]), nla_len(opt_tb[type]), 0, 2459 attrs, nattrs, vm, type_obj); 2460 2461 if (!rv) { 2462 ucv_put(type_obj); 2463 2464 return NULL; 2465 } 2466 2467 opt_obj = ucv_object_new(vm); 2468 2469 ucv_object_add(opt_obj, name, type_obj); 2470 2471 return opt_obj; 2472 } 2473 2474 static bool 2475 uc_nl_parse_rta_afspec(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val) 2476 { 2477 struct rtgenmsg *rtg = nlmsg_data(nlmsg_hdr(msg)); 2478 struct bridge_vlan_info vinfo = { 0 }; 2479 uc_value_t *vlans, *vlan, *vv; 2480 struct nlattr *nla, *af_nla; 2481 uint32_t num; 2482 size_t i; 2483 2484 nla = nla_reserve(msg, spec->attr, 0); 2485 2486 ucv_object_foreach(val, type, v) { 2487 if (!strcmp(type, "bridge")) { 2488 if (rtg->rtgen_family == AF_UNSPEC) 2489 rtg->rtgen_family = AF_BRIDGE; 2490 2491 vv = ucv_object_get(v, "bridge_flags", NULL); 2492 2493 if (vv) { 2494 if (!uc_nl_parse_u32(vv, &num) || num > 0xffff) 2495 return nla_parse_error(spec, vm, vv, "field bridge.bridge_flags not an integer or out of range 0-65535"); 2496 2497 nla_put_u16(msg, IFLA_BRIDGE_FLAGS, num); 2498 } 2499 2500 vv = ucv_object_get(v, "bridge_mode", NULL); 2501 2502 if (vv) { 2503 if (!uc_nl_parse_u32(vv, &num) || num > 0xffff) 2504 return nla_parse_error(spec, vm, vv, "field bridge.bridge_mode not an integer or out of range 0-65535"); 2505 2506 nla_put_u16(msg, IFLA_BRIDGE_MODE, num); 2507 } 2508 2509 vlans = ucv_object_get(v, "bridge_vlan_info", NULL); 2510 2511 for (vlan = (ucv_type(vlans) == UC_ARRAY) ? ucv_array_get(vlans, 0) : vlans, i = 0; 2512 ucv_type(vlan) == UC_OBJECT; 2513 vlan = (ucv_type(vlans) == UC_ARRAY) ? ucv_array_get(vlans, ++i) : NULL) { 2514 2515 vinfo.vid = 0; 2516 vinfo.flags = 0; 2517 2518 vv = ucv_object_get(vlan, "flags", NULL); 2519 2520 if (vv) { 2521 if (!uc_nl_parse_u32(vv, &num) || num > 0xffff) 2522 return nla_parse_error(spec, vm, vv, "field bridge.bridge_vlan_info.flags not an integer or out of range 0-65535"); 2523 2524 vinfo.flags = num; 2525 } 2526 2527 vv = ucv_object_get(vlan, "vid", NULL); 2528 2529 if (!uc_nl_parse_u32(vv, &num) || num > 0xfff) 2530 return nla_parse_error(spec, vm, vv, "field bridge.bridge_vlan_info.vid not an integer or out of range 0-4095"); 2531 2532 vinfo.vid = num; 2533 2534 vv = ucv_object_get(vlan, "vid_end", NULL); 2535 2536 if (vv) { 2537 if (!uc_nl_parse_u32(vv, &num) || num > 0xfff) 2538 return nla_parse_error(spec, vm, vv, "field bridge.bridge_vlan_info.vid_end not an integer or out of range 0-4095"); 2539 2540 vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_END; 2541 vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN; 2542 nla_put(msg, IFLA_BRIDGE_VLAN_INFO, sizeof(vinfo), &vinfo); 2543 2544 vinfo.vid = num; 2545 vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN; 2546 vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END; 2547 nla_put(msg, IFLA_BRIDGE_VLAN_INFO, sizeof(vinfo), &vinfo); 2548 } 2549 else { 2550 vinfo.flags &= ~(BRIDGE_VLAN_INFO_RANGE_BEGIN|BRIDGE_VLAN_INFO_RANGE_END); 2551 nla_put(msg, IFLA_BRIDGE_VLAN_INFO, sizeof(vinfo), &vinfo); 2552 } 2553 } 2554 } 2555 else if (!strcmp(type, "inet")) { 2556 af_nla = nla_reserve(msg, AF_INET, link_attrs_af_spec_inet_rta.headsize); 2557 2558 if (!uc_nl_parse_attrs(msg, nla_data(af_nla), 2559 link_attrs_af_spec_inet_rta.attrs, 2560 link_attrs_af_spec_inet_rta.nattrs, 2561 vm, v)) 2562 return false; 2563 2564 nla_nest_end(msg, af_nla); 2565 } 2566 else if (!strcmp(type, "inet6")) { 2567 af_nla = nla_reserve(msg, AF_INET6, link_attrs_af_spec_inet6_rta.headsize); 2568 2569 if (!uc_nl_parse_attrs(msg, nla_data(af_nla), 2570 link_attrs_af_spec_inet6_rta.attrs, 2571 link_attrs_af_spec_inet6_rta.nattrs, 2572 vm, v)) 2573 return false; 2574 2575 nla_nest_end(msg, af_nla); 2576 } 2577 else { 2578 return nla_parse_error(spec, vm, val, "unknown address family specified"); 2579 } 2580 } 2581 2582 nla_nest_end(msg, nla); 2583 2584 return true; 2585 } 2586 2587 static uc_value_t * 2588 uc_nl_convert_rta_afspec(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 2589 { 2590 struct rtgenmsg *rtg = nlmsg_data(nlmsg_hdr(msg)); 2591 uc_value_t *obj, *bridge, *vlans = NULL, *vlan; 2592 struct bridge_vlan_info vinfo; 2593 struct nlattr *nla; 2594 uint16_t vid = 0; 2595 int rem; 2596 2597 if (!tb[spec->attr]) 2598 return NULL; 2599 2600 obj = ucv_object_new(vm); 2601 2602 if (rtg->rtgen_family == AF_BRIDGE) { 2603 bridge = ucv_object_new(vm); 2604 2605 nla_for_each_attr(nla, nla_data(tb[spec->attr]), nla_len(tb[spec->attr]), rem) { 2606 switch (nla_type(nla)) { 2607 case IFLA_BRIDGE_FLAGS: 2608 if (nla_check_len(nla, sizeof(uint16_t))) 2609 ucv_object_add(bridge, "bridge_flags", ucv_uint64_new(nla_get_u16(nla))); 2610 2611 break; 2612 2613 case IFLA_BRIDGE_MODE: 2614 if (nla_check_len(nla, sizeof(uint16_t))) 2615 ucv_object_add(bridge, "bridge_mode", ucv_uint64_new(nla_get_u16(nla))); 2616 2617 break; 2618 2619 case IFLA_BRIDGE_VLAN_INFO: 2620 if (nla_check_len(nla, sizeof(vinfo))) { 2621 memcpy(&vinfo, nla_data(nla), sizeof(vinfo)); 2622 2623 if (!(vinfo.flags & BRIDGE_VLAN_INFO_RANGE_END)) 2624 vid = vinfo.vid; 2625 2626 if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) 2627 continue; 2628 2629 if (!vlans) { 2630 vlans = ucv_array_new(vm); 2631 ucv_object_add(bridge, "bridge_vlan_info", vlans); 2632 } 2633 2634 vlan = ucv_object_new(vm); 2635 2636 ucv_object_add(vlan, "vid", ucv_uint64_new(vid)); 2637 2638 if (vid != vinfo.vid) 2639 ucv_object_add(vlan, "vid_end", ucv_uint64_new(vinfo.vid)); 2640 2641 ucv_object_add(vlan, "flags", ucv_uint64_new(vinfo.flags & ~BRIDGE_VLAN_INFO_RANGE_END)); 2642 2643 ucv_array_push(vlans, vlan); 2644 } 2645 2646 break; 2647 } 2648 } 2649 2650 ucv_object_add(obj, "bridge", bridge); 2651 } 2652 else { 2653 if (!uc_nl_convert_attrs(msg, nla_data(tb[spec->attr]), nla_len(tb[spec->attr]), 2654 link_attrs_af_spec_rta.headsize, link_attrs_af_spec_rta.attrs, 2655 link_attrs_af_spec_rta.nattrs, vm, obj)) { 2656 ucv_put(obj); 2657 2658 return NULL; 2659 } 2660 } 2661 2662 return obj; 2663 } 2664 2665 static bool 2666 uc_nl_parse_rta_u32_or_member(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val) 2667 { 2668 uint32_t u32; 2669 2670 if (!uc_nl_parse_u32(val, &u32)) 2671 return nla_parse_error(spec, vm, val, "not an integer or out of range 0-4294967295"); 2672 2673 if (spec->flags & DF_MAX_255) { 2674 if (u32 <= 255) { 2675 uc_nl_put_struct_member_u8(base, spec->auxdata, u32); 2676 2677 return true; 2678 } 2679 2680 uc_nl_put_struct_member_u8(base, spec->auxdata, 0); 2681 } 2682 else if (spec->flags & DF_MAX_65535) { 2683 if (u32 <= 65535) { 2684 uc_nl_put_struct_member_u16(base, spec->auxdata, 2685 (spec->flags & DF_BYTESWAP) ? htons((uint16_t)u32) : (uint16_t)u32); 2686 2687 return true; 2688 } 2689 2690 uc_nl_put_struct_member_u16(base, spec->auxdata, 0); 2691 } 2692 else if (spec->flags & DF_MAX_16777215) { 2693 if (u32 <= 16777215) { 2694 uc_nl_put_struct_member_u32(base, spec->auxdata, 2695 (spec->flags & DF_BYTESWAP) ? htonl(u32) : u32); 2696 2697 return true; 2698 } 2699 2700 uc_nl_put_struct_member_u32(base, spec->auxdata, 0); 2701 } 2702 2703 nla_put_u32(msg, spec->attr, 2704 (spec->flags & DF_BYTESWAP) ? htonl(u32) : u32); 2705 2706 return true; 2707 } 2708 2709 static uc_value_t * 2710 uc_nl_convert_rta_u32_or_member(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr **tb, uc_vm_t *vm) 2711 { 2712 uint32_t u32 = 0; 2713 2714 if (nla_check_len(tb[spec->attr], sizeof(uint32_t))) { 2715 if (spec->flags & DF_BYTESWAP) 2716 u32 = ntohl(nla_get_u32(tb[spec->attr])); 2717 else 2718 u32 = nla_get_u32(tb[spec->attr]); 2719 } 2720 else if (spec->flags & DF_MAX_255) { 2721 u32 = uc_nl_get_struct_member_u8(base, spec->auxdata); 2722 } 2723 else if (spec->flags & DF_MAX_65535) { 2724 if (spec->flags & DF_BYTESWAP) 2725 u32 = ntohs(uc_nl_get_struct_member_u16(base, spec->auxdata)); 2726 else 2727 u32 = uc_nl_get_struct_member_u16(base, spec->auxdata); 2728 } 2729 else if (spec->flags & DF_MAX_16777215) { 2730 if (spec->flags & DF_BYTESWAP) 2731 u32 = ntohl(uc_nl_get_struct_member_u32(base, spec->auxdata)); 2732 else 2733 u32 = uc_nl_get_struct_member_u32(base, spec->auxdata); 2734 } 2735 else { 2736 return NULL; 2737 } 2738 2739 return ucv_uint64_new(u32); 2740 } 2741 2742 static bool 2743 uc_nl_parse_rta_nested(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val) 2744 { 2745 const uc_nl_nested_spec_t *nest = spec->auxdata; 2746 struct nlattr *nested_nla; 2747 2748 nested_nla = nla_reserve(msg, spec->attr, nest->headsize); 2749 2750 if (!nested_nla) 2751 return false; 2752 2753 /* nla_reserve() only zeroes the padding, not the payload, so struct 2754 * headers would otherwise carry heap garbage into the kernel */ 2755 if (nest->headsize) 2756 memset(nla_data(nested_nla), 0, nest->headsize); 2757 2758 if (!uc_nl_parse_attrs(msg, nla_data(nested_nla), nest->attrs, nest->nattrs, vm, val)) 2759 return false; 2760 2761 nla_nest_end(msg, nested_nla); 2762 2763 return true; 2764 } 2765 2766 static uc_value_t * 2767 uc_nl_convert_rta_nested(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 2768 { 2769 const uc_nl_nested_spec_t *nest = spec->auxdata; 2770 uc_value_t *nested_obj; 2771 bool rv; 2772 2773 nested_obj = ucv_object_new(vm); 2774 2775 rv = uc_nl_convert_attrs(msg, 2776 nla_data(tb[spec->attr]), nla_len(tb[spec->attr]), nest->headsize, 2777 nest->attrs, nest->nattrs, 2778 vm, nested_obj); 2779 2780 if (!rv) { 2781 ucv_put(nested_obj); 2782 2783 return NULL; 2784 } 2785 2786 return nested_obj; 2787 } 2788 2789 2790 static bool 2791 uc_nl_parse_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val, size_t idx) 2792 { 2793 uc_nl_cidr_t cidr = { 0 }; 2794 struct ether_addr *ea; 2795 struct rtgenmsg *rtg; 2796 uint64_t u64; 2797 uint32_t u32; 2798 uint16_t u16; 2799 size_t attr; 2800 char *s; 2801 2802 if (spec->flags & DF_MULTIPLE) 2803 attr = idx; 2804 else 2805 attr = spec->attr; 2806 2807 switch (spec->type) { 2808 case DT_U8: 2809 if (!uc_nl_parse_u32(val, &u32) || u32 > 255) 2810 return nla_parse_error(spec, vm, val, "not an integer or out of range 0-255"); 2811 2812 if ((spec->flags & DF_MAX_1) && u32 > 1) 2813 return nla_parse_error(spec, vm, val, "integer must be 0 or 1"); 2814 2815 if (spec->attr == 0) 2816 uc_nl_put_struct_member_u8(base, spec->auxdata, u32); 2817 else 2818 nla_put_u8(msg, attr, u32); 2819 2820 break; 2821 2822 case DT_U16: 2823 if (!uc_nl_parse_u32(val, &u32) || u32 > 65535) 2824 return nla_parse_error(spec, vm, val, "not an integer or out of range 0-65535"); 2825 2826 u16 = (uint16_t)u32; 2827 2828 if (spec->flags & DF_BYTESWAP) 2829 u16 = htons(u16); 2830 2831 if ((spec->flags & DF_MAX_1) && u32 > 1) 2832 return nla_parse_error(spec, vm, val, "integer must be 0 or 1"); 2833 else if ((spec->flags & DF_MAX_255) && u32 > 255) 2834 return nla_parse_error(spec, vm, val, "integer out of range 0-255"); 2835 2836 if (spec->attr == 0) 2837 uc_nl_put_struct_member_u16(base, spec->auxdata, u16); 2838 else 2839 nla_put_u16(msg, attr, u16); 2840 2841 break; 2842 2843 case DT_S32: 2844 case DT_U32: 2845 if (spec->type == DT_S32 && !uc_nl_parse_s32(val, &u32)) 2846 return nla_parse_error(spec, vm, val, "not an integer or out of range -2147483648-2147483647"); 2847 else if (spec->type == DT_U32 && !uc_nl_parse_u32(val, &u32)) 2848 return nla_parse_error(spec, vm, val, "not an integer or out of range 0-4294967295"); 2849 2850 if (spec->flags & DF_BYTESWAP) 2851 u32 = htonl(u32); 2852 2853 if ((spec->flags & DF_MAX_1) && u32 > 1) 2854 return nla_parse_error(spec, vm, val, "integer must be 0 or 1"); 2855 else if ((spec->flags & DF_MAX_255) && u32 > 255) 2856 return nla_parse_error(spec, vm, val, "integer out of range 0-255"); 2857 else if ((spec->flags & DF_MAX_65535) && u32 > 65535) 2858 return nla_parse_error(spec, vm, val, "integer out of range 0-65535"); 2859 else if ((spec->flags & DF_MAX_16777215) && u32 > 16777215) 2860 return nla_parse_error(spec, vm, val, "integer out of range 0-16777215"); 2861 2862 if (spec->attr == 0) 2863 uc_nl_put_struct_member_u32(base, spec->auxdata, u32); 2864 else 2865 nla_put_u32(msg, attr, u32); 2866 2867 break; 2868 2869 case DT_U64: 2870 assert(spec->attr != 0); 2871 2872 if (!uc_nl_parse_u64(val, &u64)) 2873 return nla_parse_error(spec, vm, val, "not an integer or negative"); 2874 2875 if (spec->flags & DF_BYTESWAP) 2876 u64 = htobe64(u64); 2877 2878 nla_put_u64(msg, attr, u64); 2879 break; 2880 2881 case DT_BOOL: 2882 u32 = (uint32_t)ucv_is_truish(val); 2883 2884 if (spec->attr == 0) 2885 uc_nl_put_struct_member_u8(base, spec->auxdata, u32); 2886 else 2887 nla_put_u8(msg, attr, u32); 2888 2889 break; 2890 2891 case DT_FLAG: 2892 u32 = (uint32_t)ucv_is_truish(val); 2893 2894 if (spec->attr == 0) 2895 uc_nl_put_struct_member_u8(base, spec->auxdata, u32); 2896 else if (u32 == 1) 2897 nla_put_flag(msg, attr); 2898 2899 break; 2900 2901 case DT_STRING: 2902 assert(spec->attr != 0); 2903 2904 if (ucv_type(val) == UC_STRING) { 2905 nla_put(msg, attr, ucv_string_length(val), ucv_string_get(val)); 2906 } 2907 else { 2908 s = ucv_to_string(vm, val); 2909 2910 if (!s) 2911 return nla_parse_error(spec, vm, val, "out of memory"); 2912 2913 nla_put_string(msg, attr, s); 2914 free(s); 2915 } 2916 2917 break; 2918 2919 case DT_NETDEV: 2920 if (ucv_type(val) == UC_INTEGER) { 2921 if (ucv_int64_get(val) < 0 || 2922 ucv_int64_get(val) > UINT32_MAX) 2923 return nla_parse_error(spec, vm, val, "interface index out of range 0-4294967295"); 2924 2925 u32 = (uint32_t)ucv_int64_get(val); 2926 } 2927 else { 2928 s = ucv_to_string(vm, val); 2929 2930 if (!s) 2931 return nla_parse_error(spec, vm, val, "out of memory"); 2932 2933 u32 = if_nametoindex(s); 2934 2935 free(s); 2936 } 2937 2938 if (u32 == 0 && !(spec->flags & DF_ALLOW_NONE)) 2939 return nla_parse_error(spec, vm, val, "interface not found"); 2940 2941 if (spec->attr == 0) 2942 uc_nl_put_struct_member_u32(base, spec->auxdata, u32); 2943 else 2944 nla_put_u32(msg, attr, u32); 2945 2946 break; 2947 2948 case DT_LLADDR: 2949 assert(spec->attr != 0); 2950 2951 s = ucv_to_string(vm, val); 2952 2953 if (!s) 2954 return nla_parse_error(spec, vm, val, "out of memory"); 2955 2956 ea = ether_aton(s); 2957 2958 free(s); 2959 2960 if (!ea) 2961 return nla_parse_error(spec, vm, val, "invalid MAC address"); 2962 2963 nla_put(msg, attr, sizeof(*ea), ea); 2964 2965 break; 2966 2967 case DT_U64ADDR: 2968 assert(spec->attr != 0); 2969 2970 if (ucv_type(val) == UC_INTEGER) { 2971 u64 = ucv_uint64_get(val); 2972 } 2973 else { 2974 s = ucv_to_string(vm, val); 2975 2976 if (!s) 2977 return nla_parse_error(spec, vm, val, "out of memory"); 2978 2979 u16 = addr64_pton(s, &u64); 2980 2981 free(s); 2982 2983 if (u16 != 1) 2984 return nla_parse_error(spec, vm, val, "invalid address"); 2985 } 2986 2987 nla_put_u64(msg, attr, u64); 2988 2989 break; 2990 2991 case DT_INADDR: 2992 case DT_IN6ADDR: 2993 case DT_MPLSADDR: 2994 case DT_ANYADDR: 2995 assert(spec->attr != 0); 2996 2997 rtg = nlmsg_data(nlmsg_hdr(msg)); 2998 2999 if (!uc_nl_parse_cidr(vm, val, &cidr)) 3000 return nla_parse_error(spec, vm, val, "invalid IP address"); 3001 3002 if ((spec->type == DT_INADDR && cidr.family != AF_INET) || 3003 (spec->type == DT_IN6ADDR && cidr.family != AF_INET6) || 3004 (spec->type == DT_MPLSADDR && cidr.family != AF_MPLS)) 3005 return nla_parse_error(spec, vm, val, "wrong address family"); 3006 3007 if (spec->flags & DF_STORE_MASK) 3008 uc_nl_put_struct_member_u8(base, spec->auxdata, cidr.mask); 3009 else if (cidr.mask != cidr.bitlen) 3010 return nla_parse_error(spec, vm, val, "address range given but single address expected"); 3011 3012 nla_put(msg, attr, cidr.alen, &cidr.addr.in6); 3013 3014 if ((rtg->rtgen_family == AF_UNSPEC) && (spec->flags & DF_FAMILY_HINT)) 3015 rtg->rtgen_family = cidr.family; 3016 3017 break; 3018 3019 case DT_MULTIPATH: 3020 if (!uc_nl_parse_rta_multipath(spec, msg, base, vm, val)) 3021 return nla_parse_error(spec, vm, val, "invalid nexthop data"); 3022 3023 break; 3024 3025 case DT_NUMRANGE: 3026 if (!uc_nl_parse_rta_numrange(spec, msg, base, vm, val)) 3027 return false; 3028 3029 break; 3030 3031 case DT_FLAGS: 3032 if (ucv_array_length(val) == 2) { 3033 if (ucv_type(ucv_array_get(val, 0)) != UC_INTEGER || 3034 ucv_type(ucv_array_get(val, 1)) != UC_INTEGER) 3035 return nla_parse_error(spec, vm, val, "flag or mask value not an integer"); 3036 3037 if (!uc_nl_parse_u32(ucv_array_get(val, 0), &u32)) 3038 return nla_parse_error(spec, vm, val, "flag value not an integer or out of range 0-4294967295"); 3039 3040 memcpy(&u64, &u32, sizeof(u32)); 3041 3042 if (!uc_nl_parse_u32(ucv_array_get(val, 1), &u32)) 3043 return nla_parse_error(spec, vm, val, "mask value not an integer or out of range 0-4294967295"); 3044 3045 memcpy((char *)&u64 + sizeof(u32), &u32, sizeof(u32)); 3046 } 3047 else if (ucv_type(val) == UC_INTEGER) { 3048 if (!uc_nl_parse_u32(val, &u32)) 3049 return nla_parse_error(spec, vm, val, "flag value not an integer or out of range 0-4294967295"); 3050 3051 memcpy(&u64, &u32, sizeof(u32)); 3052 memset((char *)&u64 + sizeof(u32), 0xff, sizeof(u32)); 3053 } 3054 else { 3055 return nla_parse_error(spec, vm, val, "value neither an array of flags, mask nor an integer"); 3056 } 3057 3058 if (spec->attr == 0) 3059 uc_nl_put_struct_member(base, spec->auxdata, sizeof(u64), &u64); 3060 else 3061 nla_put_u64(msg, attr, u64); 3062 3063 break; 3064 3065 case DT_LINKINFO: 3066 if (!uc_nl_parse_rta_linkinfo(spec, msg, base, vm, val)) 3067 return false; 3068 3069 break; 3070 3071 case DT_SRH: 3072 if (!uc_nl_parse_rta_srh(spec, msg, base, vm, val)) 3073 return false; 3074 3075 break; 3076 3077 case DT_ENCAP: 3078 if (!uc_nl_parse_rta_encap(spec, msg, base, vm, val)) 3079 return false; 3080 3081 break; 3082 3083 case DT_IPOPTS: 3084 if (!uc_nl_parse_rta_ipopts(spec, msg, base, vm, val)) 3085 return false; 3086 3087 break; 3088 3089 case DT_AFSPEC: 3090 if (!uc_nl_parse_rta_afspec(spec, msg, base, vm, val)) 3091 return false; 3092 3093 break; 3094 3095 case DT_U32_OR_MEMBER: 3096 if (!uc_nl_parse_rta_u32_or_member(spec, msg, base, vm, val)) 3097 return false; 3098 3099 break; 3100 3101 case DT_NESTED: 3102 if (!uc_nl_parse_rta_nested(spec, msg, base, vm, val)) 3103 return false; 3104 3105 break; 3106 3107 default: 3108 assert(0); 3109 } 3110 3111 return true; 3112 } 3113 3114 static uc_value_t * 3115 uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr **tb, uc_vm_t *vm) 3116 { 3117 union { uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; size_t sz; } t = { 0 }; 3118 struct { uint32_t flags; uint32_t mask; } flags; 3119 char buf[sizeof(struct mpls_label) * 16]; 3120 struct nlmsghdr *hdr = nlmsg_hdr(msg); 3121 struct rtgenmsg *rtg = nlmsg_data(hdr); 3122 struct ether_addr *ea; 3123 uc_value_t *v; 3124 char *s; 3125 3126 switch (spec->type) { 3127 case DT_U8: 3128 if (spec->attr == 0) 3129 t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); 3130 else if (nla_check_len(tb[spec->attr], sizeof(t.u8))) 3131 t.u8 = nla_get_u8(tb[spec->attr]); 3132 3133 return ucv_uint64_new(t.u8); 3134 3135 case DT_U16: 3136 if (spec->attr == 0) 3137 t.u16 = uc_nl_get_struct_member_u16(base, spec->auxdata); 3138 else if (nla_check_len(tb[spec->attr], sizeof(t.u16))) 3139 t.u16 = nla_get_u16(tb[spec->attr]); 3140 3141 if (spec->flags & DF_BYTESWAP) 3142 t.u16 = ntohs(t.u16); 3143 3144 return ucv_uint64_new(t.u16); 3145 3146 case DT_U32: 3147 case DT_S32: 3148 if (spec->attr == 0) 3149 t.u32 = uc_nl_get_struct_member_u32(base, spec->auxdata); 3150 else if (nla_check_len(tb[spec->attr], sizeof(t.u32))) 3151 t.u32 = nla_get_u32(tb[spec->attr]); 3152 3153 if (spec->flags & DF_BYTESWAP) 3154 t.u32 = ntohl(t.u32); 3155 3156 if (spec->type == DT_S32) 3157 return ucv_int64_new((int32_t)t.u32); 3158 3159 return ucv_uint64_new(t.u32); 3160 3161 case DT_U64: 3162 if (spec->attr == 0) 3163 t.u64 = uc_nl_get_struct_member_u64(base, spec->auxdata); 3164 else if (nla_check_len(tb[spec->attr], sizeof(t.u64))) 3165 memcpy(&t.u64, nla_data(tb[spec->attr]), sizeof(t.u64)); 3166 3167 return ucv_uint64_new(t.u64); 3168 3169 case DT_BOOL: 3170 if (spec->attr == 0) 3171 t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); 3172 else if (nla_check_len(tb[spec->attr], sizeof(t.u8))) 3173 t.u8 = nla_get_u8(tb[spec->attr]); 3174 3175 return ucv_boolean_new(t.u8 != 0); 3176 3177 case DT_FLAG: 3178 if (spec->attr == 0) 3179 t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); 3180 else if (tb[spec->attr] != NULL) 3181 t.u8 = 1; 3182 3183 return ucv_boolean_new(t.u8 != 0); 3184 3185 case DT_STRING: 3186 assert(spec->attr != 0); 3187 3188 if (!nla_check_len(tb[spec->attr], 1)) 3189 return NULL; 3190 3191 return ucv_string_new_length( 3192 nla_data(tb[spec->attr]), nla_len(tb[spec->attr]) - 1); 3193 3194 case DT_NETDEV: 3195 if (spec->attr == 0) 3196 t.u32 = uc_nl_get_struct_member_u32(base, spec->auxdata); 3197 else if (nla_check_len(tb[spec->attr], sizeof(t.u32))) 3198 t.u32 = nla_get_u32(tb[spec->attr]); 3199 3200 if (if_indextoname(t.u32, buf)) 3201 return ucv_string_new(buf); 3202 else if (spec->flags & DF_ALLOW_NONE) 3203 return ucv_int64_new(0); 3204 3205 return NULL; 3206 3207 case DT_LLADDR: 3208 assert(spec->attr != 0); 3209 3210 if (!nla_check_len(tb[spec->attr], sizeof(*ea))) 3211 return NULL; 3212 3213 ea = nla_data(tb[spec->attr]); 3214 3215 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", 3216 ea->ether_addr_octet[0], ea->ether_addr_octet[1], 3217 ea->ether_addr_octet[2], ea->ether_addr_octet[3], 3218 ea->ether_addr_octet[4], ea->ether_addr_octet[5]); 3219 3220 return ucv_string_new(buf); 3221 3222 case DT_U64ADDR: 3223 assert(spec->attr != 0); 3224 3225 if (!nla_check_len(tb[spec->attr], sizeof(uint64_t)) || 3226 !addr64_ntop(nla_data(tb[spec->attr]), buf, sizeof(buf))) 3227 return NULL; 3228 3229 return ucv_string_new(buf); 3230 3231 case DT_INADDR: 3232 case DT_IN6ADDR: 3233 case DT_MPLSADDR: 3234 case DT_ANYADDR: 3235 assert(spec->attr != 0); 3236 3237 t.sz = (size_t)nla_len(tb[spec->attr]); 3238 3239 switch (spec->type) { 3240 case DT_INADDR: 3241 if (t.sz < sizeof(struct in_addr) || 3242 !inet_ntop(AF_INET, nla_data(tb[spec->attr]), buf, sizeof(buf))) 3243 return NULL; 3244 3245 break; 3246 3247 case DT_IN6ADDR: 3248 if (t.sz < sizeof(struct in6_addr) || 3249 !inet_ntop(AF_INET6, nla_data(tb[spec->attr]), buf, sizeof(buf))) 3250 return NULL; 3251 3252 break; 3253 3254 case DT_MPLSADDR: 3255 if (t.sz < sizeof(struct mpls_label) || 3256 !mpls_ntop(nla_data(tb[spec->attr]), t.sz, buf, sizeof(buf))) 3257 return NULL; 3258 3259 break; 3260 3261 default: 3262 switch (rtg->rtgen_family) { 3263 case AF_MPLS: 3264 if (t.sz < sizeof(struct mpls_label) || 3265 !mpls_ntop(nla_data(tb[spec->attr]), t.sz, buf, sizeof(buf))) 3266 return NULL; 3267 3268 break; 3269 3270 case AF_INET6: 3271 if (t.sz < sizeof(struct in6_addr) || 3272 !inet_ntop(AF_INET6, nla_data(tb[spec->attr]), buf, sizeof(buf))) 3273 return NULL; 3274 3275 break; 3276 3277 case AF_INET: 3278 if (t.sz < sizeof(struct in_addr) || 3279 !inet_ntop(AF_INET, nla_data(tb[spec->attr]), buf, sizeof(buf))) 3280 return NULL; 3281 3282 break; 3283 3284 default: 3285 return NULL; 3286 } 3287 3288 break; 3289 } 3290 3291 if (spec->flags & DF_STORE_MASK) { 3292 s = buf + strlen(buf); 3293 snprintf(s, buf + sizeof(buf) - s, "/%hhu", 3294 uc_nl_get_struct_member_u8(base, spec->auxdata)); 3295 } 3296 3297 return ucv_string_new(buf); 3298 3299 case DT_MULTIPATH: 3300 return uc_nl_convert_rta_multipath(spec, msg, tb, vm); 3301 3302 case DT_NUMRANGE: 3303 return uc_nl_convert_rta_numrange(spec, msg, tb, vm); 3304 3305 case DT_FLAGS: 3306 if (spec->attr == 0) 3307 uc_nl_get_struct_member(base, spec->auxdata, sizeof(flags), &flags); 3308 else if (nla_check_len(tb[spec->attr], sizeof(flags))) 3309 memcpy(&flags, nla_data(tb[spec->attr]), sizeof(flags)); 3310 else 3311 return NULL; 3312 3313 if (flags.mask == 0) 3314 return ucv_uint64_new(flags.flags); 3315 3316 v = ucv_array_new(vm); 3317 3318 ucv_array_push(v, ucv_uint64_new(flags.flags)); 3319 ucv_array_push(v, ucv_uint64_new(flags.mask)); 3320 3321 return v; 3322 3323 case DT_LINKINFO: 3324 return uc_nl_convert_rta_linkinfo(spec, msg, tb, vm); 3325 3326 case DT_BRIDGEID: 3327 return uc_nl_convert_rta_bridgeid(spec, msg, tb, vm); 3328 3329 case DT_SRH: 3330 return uc_nl_convert_rta_srh(spec, msg, tb, vm); 3331 3332 case DT_ENCAP: 3333 return uc_nl_convert_rta_encap(spec, msg, tb, vm); 3334 3335 case DT_IPOPTS: 3336 return uc_nl_convert_rta_ipopts(spec, msg, tb, vm); 3337 3338 case DT_AFSPEC: 3339 return uc_nl_convert_rta_afspec(spec, msg, tb, vm); 3340 3341 case DT_U32_OR_MEMBER: 3342 return uc_nl_convert_rta_u32_or_member(spec, msg, base, tb, vm); 3343 3344 case DT_NESTED: 3345 return uc_nl_convert_rta_nested(spec, msg, tb, vm); 3346 3347 default: 3348 assert(0); 3349 } 3350 3351 return NULL; 3352 } 3353 3354 3355 static struct nl_sock *sock = NULL; 3356 static struct { 3357 struct nl_sock *evsock; 3358 struct uloop_fd evsock_fd; 3359 uint32_t groups[RTNL_GRPS_BITMAP_SIZE]; 3360 } nl_conn; 3361 3362 typedef enum { 3363 STATE_UNREPLIED, 3364 STATE_CONTINUE, 3365 STATE_REPLIED, 3366 STATE_ERROR 3367 } reply_state_t; 3368 3369 typedef struct { 3370 reply_state_t state; 3371 uc_vm_t *vm; 3372 uc_value_t *res; 3373 int family; 3374 const uc_nl_nested_spec_t *spec; 3375 } request_state_t; 3376 3377 3378 /** 3379 * Query error information. 3380 * 3381 * Returns a string containing a description of the last occurred error or 3382 * `null` if there is no error information. 3383 * 3384 * @function module:rtnl#error 3385 * 3386 * @returns {?string} 3387 * 3388 * @example 3389 * // Trigger rtnl error 3390 * request('invalid_command', {}, {}); 3391 * 3392 * // Print error (should yield error description) 3393 * print(error(), "\n"); 3394 */ 3395 static uc_value_t * 3396 uc_nl_error(uc_vm_t *vm, size_t nargs) 3397 { 3398 uc_stringbuf_t *buf; 3399 const char *s; 3400 3401 if (last_error.code == 0) 3402 return NULL; 3403 3404 buf = ucv_stringbuf_new(); 3405 3406 if (last_error.code == NLE_FAILURE && last_error.msg) { 3407 ucv_stringbuf_addstr(buf, last_error.msg, strlen(last_error.msg)); 3408 } 3409 else { 3410 s = nl_geterror(last_error.code); 3411 3412 ucv_stringbuf_addstr(buf, s, strlen(s)); 3413 3414 if (last_error.msg) 3415 ucv_stringbuf_printf(buf, ": %s", last_error.msg); 3416 } 3417 3418 set_error(0, NULL); 3419 3420 return ucv_stringbuf_finish(buf); 3421 } 3422 3423 /* 3424 * route functions 3425 */ 3426 3427 static int 3428 cb_done(struct nl_msg *msg, void *arg) 3429 { 3430 request_state_t *s = arg; 3431 3432 s->state = STATE_REPLIED; 3433 3434 return NL_STOP; 3435 } 3436 3437 static int 3438 cb_error(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) 3439 { 3440 request_state_t *s = arg; 3441 int errnum = err->error; 3442 3443 set_error(NLE_FAILURE, "RTNETLINK answers: %s", 3444 strerror(errnum < 0 ? -errnum : errnum)); 3445 3446 s->state = STATE_ERROR; 3447 3448 return NL_STOP; 3449 } 3450 3451 static int 3452 cb_reply(struct nl_msg *msg, void *arg) 3453 { 3454 struct nlmsghdr *hdr = nlmsg_hdr(msg); 3455 request_state_t *s = arg; 3456 uc_value_t *o; 3457 bool rv; 3458 3459 if (RTM_FAM(hdr->nlmsg_type) != s->family) 3460 return NL_SKIP; 3461 3462 if (s->spec) { 3463 if (nlmsg_attrlen(hdr, 0) < (ssize_t)s->spec->headsize) 3464 return NL_SKIP; 3465 3466 o = ucv_object_new(s->vm); 3467 3468 rv = uc_nl_convert_attrs(msg, 3469 nlmsg_attrdata(hdr, 0), 3470 nlmsg_attrlen(hdr, 0), 3471 s->spec->headsize, 3472 s->spec->attrs, s->spec->nattrs, s->vm, o); 3473 3474 if (rv) { 3475 if (hdr->nlmsg_flags & NLM_F_MULTI) { 3476 if (!s->res) 3477 s->res = ucv_array_new(s->vm); 3478 3479 ucv_array_push(s->res, o); 3480 } 3481 else { 3482 s->res = o; 3483 } 3484 } 3485 else { 3486 ucv_put(o); 3487 } 3488 } 3489 3490 s->state = STATE_CONTINUE; 3491 3492 return NL_SKIP; 3493 } 3494 3495 3496 static const struct { 3497 int family; 3498 const uc_nl_nested_spec_t *spec; 3499 } rtm_families[] = { 3500 { RTM_FAM(RTM_GETLINK), &link_msg }, 3501 { RTM_FAM(RTM_GETROUTE), &route_msg }, 3502 { RTM_FAM(RTM_GETNEIGH), &neigh_msg }, 3503 { RTM_FAM(RTM_GETADDR), &addr_msg }, 3504 { RTM_FAM(RTM_GETRULE), &rule_msg }, 3505 { RTM_FAM(RTM_GETADDRLABEL), &addrlabel_msg }, 3506 { RTM_FAM(RTM_GETNEIGHTBL), &neightbl_msg }, 3507 { RTM_FAM(RTM_GETNETCONF), &netconf_msg }, 3508 }; 3509 3510 /** 3511 * Send a netlink request. 3512 * 3513 * Sends a netlink request with the specified command, flags, and payload. 3514 * 3515 * @function module:rtnl#request 3516 * 3517 * @param {string} cmd - The netlink command to send 3518 * @param {number} flags - The netlink flags for the request 3519 * @param {*} payload - The payload data for the request 3520 * 3521 * @returns {?*} - The response data or null on error 3522 * 3523 * @example 3524 * // Send a route request 3525 * let response = request('RTM_GETROUTE', 0, { family: AF_INET }); 3526 */ 3527 static uc_value_t * 3528 uc_nl_request(uc_vm_t *vm, size_t nargs) 3529 { 3530 uc_value_t *cmd = uc_fn_arg(0); 3531 uc_value_t *flags = uc_fn_arg(1); 3532 uc_value_t *payload = uc_fn_arg(2); 3533 request_state_t st = { .vm = vm }; 3534 uint16_t flagval = 0; 3535 struct nl_msg *msg; 3536 struct nl_cb *cb; 3537 socklen_t optlen; 3538 int enable, err; 3539 void *buf; 3540 size_t i; 3541 3542 if (ucv_type(cmd) != UC_INTEGER || ucv_int64_get(cmd) < 0 || 3543 (flags != NULL && ucv_type(flags) != UC_INTEGER) || 3544 (payload != NULL && ucv_type(payload) != UC_OBJECT)) 3545 err_return(NLE_INVAL, NULL); 3546 3547 if (flags) { 3548 if (ucv_int64_get(flags) < 0 || ucv_int64_get(flags) > 0xffff) 3549 err_return(NLE_INVAL, NULL); 3550 else 3551 flagval = (uint16_t)ucv_int64_get(flags); 3552 } 3553 3554 for (i = 0; i < ARRAY_SIZE(rtm_families); i++) { 3555 if (rtm_families[i].family == RTM_FAM(ucv_int64_get(cmd))) { 3556 st.spec = rtm_families[i].spec; 3557 st.family = rtm_families[i].family; 3558 break; 3559 } 3560 } 3561 3562 if (!sock) { 3563 sock = nl_socket_alloc(); 3564 3565 if (!sock) 3566 err_return(NLE_NOMEM, NULL); 3567 3568 err = nl_connect(sock, NETLINK_ROUTE); 3569 3570 if (err != 0) 3571 err_return(err, NULL); 3572 } 3573 3574 optlen = sizeof(enable); 3575 3576 if (getsockopt(sock->s_fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &enable, &optlen) < 0) 3577 enable = 0; 3578 3579 if (!!(flagval & NLM_F_STRICT_CHK) != enable) { 3580 enable = !!(flagval & NLM_F_STRICT_CHK); 3581 3582 if (setsockopt(sock->s_fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &enable, sizeof(enable)) < 0) 3583 err_return(nl_syserr2nlerr(errno), "Unable to toggle NETLINK_GET_STRICT_CHK"); 3584 } 3585 3586 msg = nlmsg_alloc_simple(ucv_int64_get(cmd), NLM_F_REQUEST | (flagval & ~NLM_F_STRICT_CHK)); 3587 3588 if (!msg) 3589 err_return(NLE_NOMEM, NULL); 3590 3591 if (st.spec) { 3592 if (st.spec->headsize) { 3593 buf = nlmsg_reserve(msg, st.spec->headsize, 0); 3594 3595 if (!buf) { 3596 nlmsg_free(msg); 3597 3598 return NULL; 3599 } 3600 3601 memset(buf, 0, st.spec->headsize); 3602 } 3603 3604 if (!uc_nl_parse_attrs(msg, NLMSG_DATA(nlmsg_hdr(msg)), st.spec->attrs, st.spec->nattrs, vm, payload)) { 3605 nlmsg_free(msg); 3606 3607 return NULL; 3608 } 3609 } 3610 3611 cb = nl_cb_alloc(NL_CB_DEFAULT); 3612 3613 if (!cb) { 3614 nlmsg_free(msg); 3615 err_return(NLE_NOMEM, NULL); 3616 } 3617 3618 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_reply, &st); 3619 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &st); 3620 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_done, &st); 3621 nl_cb_err(cb, NL_CB_CUSTOM, cb_error, &st); 3622 3623 nl_send_auto_complete(sock, msg); 3624 3625 do { 3626 err = nl_recvmsgs(sock, cb); 3627 3628 if (err && st.state != STATE_ERROR) { 3629 set_error(err, NULL); 3630 3631 st.state = STATE_ERROR; 3632 } 3633 } 3634 while (st.state < STATE_REPLIED); 3635 3636 nlmsg_free(msg); 3637 nl_cb_put(cb); 3638 3639 switch (st.state) { 3640 case STATE_REPLIED: 3641 return st.res; 3642 3643 case STATE_UNREPLIED: 3644 return ucv_boolean_new(true); 3645 3646 case STATE_ERROR: 3647 return ucv_boolean_new(false); 3648 3649 default: 3650 set_error(NLE_FAILURE, "Interrupted reply"); 3651 3652 return ucv_boolean_new(false); 3653 } 3654 } 3655 3656 static const uc_nl_nested_spec_t * 3657 uc_nl_msg_spec(int type) 3658 { 3659 switch (type) { 3660 case RTM_NEWLINK: 3661 case RTM_DELLINK: 3662 return &link_msg; 3663 case RTM_NEWROUTE: 3664 case RTM_DELROUTE: 3665 return &route_msg; 3666 case RTM_NEWNEIGH: 3667 case RTM_DELNEIGH: 3668 return &neigh_msg; 3669 case RTM_NEWADDR: 3670 case RTM_DELADDR: 3671 return &addr_msg; 3672 case RTM_NEWRULE: 3673 case RTM_DELRULE: 3674 return &rule_msg; 3675 case RTM_NEWADDRLABEL: 3676 case RTM_DELADDRLABEL: 3677 return &addrlabel_msg; 3678 case RTM_NEWNEIGHTBL: 3679 return &neightbl_msg; 3680 case RTM_NEWNETCONF: 3681 case RTM_DELNETCONF: 3682 return &netconf_msg; 3683 default: 3684 return NULL; 3685 } 3686 } 3687 3688 static void 3689 uc_nl_prepare_event(uc_vm_t *vm, uc_value_t *dest, struct nl_msg *msg) 3690 { 3691 struct nlmsghdr *hdr = nlmsg_hdr(msg); 3692 const uc_nl_nested_spec_t *spec; 3693 const uc_nl_attr_spec_t *attrs = NULL; 3694 size_t nattrs = 0, headsize = 0; 3695 uc_value_t *o; 3696 3697 spec = uc_nl_msg_spec(hdr->nlmsg_type); 3698 if (spec) { 3699 attrs = spec->attrs; 3700 nattrs = spec->nattrs; 3701 headsize = spec->headsize; 3702 } 3703 3704 o = ucv_object_new(vm); 3705 if (!uc_nl_convert_attrs(msg, nlmsg_attrdata(hdr, 0), 3706 nlmsg_attrlen(hdr, 0), headsize, attrs, nattrs, vm, o)) { 3707 ucv_put(o); 3708 return; 3709 } 3710 3711 ucv_object_add(dest, "msg", o); 3712 if (headsize) 3713 ucv_object_add(dest, "head", ucv_string_new_length(NLMSG_DATA(hdr), headsize)); 3714 } 3715 3716 static bool 3717 uc_nl_fill_cmds(uint32_t *cmd_bits, uc_value_t *cmds) 3718 { 3719 if (ucv_type(cmds) == UC_ARRAY) { 3720 for (size_t i = 0; i < ucv_array_length(cmds); i++) { 3721 int64_t n = ucv_int64_get(ucv_array_get(cmds, i)); 3722 3723 if (errno || n < 0 || n >= __RTM_MAX) 3724 return false; 3725 3726 cmd_bits[n / 32] |= (1 << (n % 32)); 3727 } 3728 } 3729 else if (ucv_type(cmds) == UC_INTEGER) { 3730 int64_t n = ucv_int64_get(cmds); 3731 3732 if (errno || n < 0 || n > 255) 3733 return false; 3734 3735 cmd_bits[n / 32] |= (1 << (n % 32)); 3736 } 3737 else if (!cmds) 3738 memset(cmd_bits, 0xff, RTNL_CMDS_BITMAP_SIZE * sizeof(*cmd_bits)); 3739 else 3740 return false; 3741 3742 return true; 3743 } 3744 3745 static int 3746 cb_listener_event(struct nl_msg *msg, void *arg) 3747 { 3748 struct nlmsghdr *hdr = nlmsg_hdr(msg); 3749 uc_vm_t *vm = listener_vm; 3750 int cmd = hdr->nlmsg_type; 3751 3752 if (!nl_conn.evsock_fd.registered || !vm) 3753 return NL_SKIP; 3754 3755 for (size_t i = 0; i < ucv_array_length(listener_registry); i += 2) { 3756 uc_value_t *this = ucv_array_get(listener_registry, i); 3757 uc_value_t *func = ucv_array_get(listener_registry, i + 1); 3758 uc_nl_listener_t *l; 3759 uc_value_t *o; 3760 3761 l = ucv_resource_data(this, "rtnl.listener"); 3762 if (!l) 3763 continue; 3764 3765 if (cmd > __RTM_MAX || !(l->cmds[cmd / 32] & (1 << (cmd % 32)))) 3766 continue; 3767 3768 if (!ucv_is_callable(func)) 3769 continue; 3770 3771 o = ucv_object_new(vm); 3772 uc_nl_prepare_event(vm, o, msg); 3773 ucv_object_add(o, "cmd", ucv_int64_new(cmd)); 3774 3775 uc_vm_stack_push(vm, ucv_get(this)); 3776 uc_vm_stack_push(vm, ucv_get(func)); 3777 uc_vm_stack_push(vm, o); 3778 3779 if (uc_vm_call(vm, true, 1) != EXCEPTION_NONE) { 3780 uloop_end(); 3781 set_error(NLE_FAILURE, "Runtime exception in callback"); 3782 3783 errno = EINVAL; 3784 3785 return NL_STOP; 3786 } 3787 3788 ucv_put(uc_vm_stack_pop(vm)); 3789 } 3790 3791 errno = 0; 3792 3793 return NL_SKIP; 3794 } 3795 3796 static void 3797 uc_nl_listener_cb(struct uloop_fd *fd, unsigned int events) 3798 { 3799 while (true) { 3800 errno = 0; 3801 3802 nl_recvmsgs_default(nl_conn.evsock); 3803 3804 if (errno != 0) 3805 break; 3806 } 3807 } 3808 3809 static void 3810 uc_nl_add_group(unsigned int idx) 3811 { 3812 if (idx >= __RTNLGRP_MAX) 3813 return; 3814 3815 if (nl_conn.groups[idx / 32] & (1 << (idx % 32))) 3816 return; 3817 3818 nl_conn.groups[idx / 32] |= (1 << (idx % 32)); 3819 nl_socket_add_membership(nl_conn.evsock, idx); 3820 } 3821 3822 static bool 3823 uc_nl_evsock_init(void) 3824 { 3825 struct uloop_fd *fd = &nl_conn.evsock_fd; 3826 struct nl_sock *sock; 3827 3828 if (nl_conn.evsock) 3829 return true; 3830 3831 sock = nl_socket_alloc(); 3832 3833 if (nl_connect(sock, NETLINK_ROUTE)) 3834 goto free; 3835 3836 fd->fd = nl_socket_get_fd(sock); 3837 fd->cb = uc_nl_listener_cb; 3838 uloop_fd_add(fd, ULOOP_READ); 3839 3840 nl_socket_set_buffer_size(sock, 1024 * 1024, 0); 3841 nl_socket_disable_seq_check(sock); 3842 nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, cb_listener_event, NULL); 3843 3844 nl_conn.evsock = sock; 3845 3846 return true; 3847 3848 free: 3849 nl_socket_free(sock); 3850 return false; 3851 } 3852 3853 /** 3854 * Represents a netlink listener resource. 3855 * 3856 * @class module:rtnl.listener 3857 * @hideconstructor 3858 * 3859 * @see {@link module:rtnl#listener|listener()} 3860 * 3861 * @example 3862 * const nlListener = listener((msg) => { 3863 * print('Received netlink message:', msg, '\n'); 3864 * }, [RTM_NEWROUTE, RTM_DELROUTE]); 3865 * 3866 * nlListener.set_commands([RTM_GETLINK, RTM_SETLINK]); 3867 * 3868 * nlListener.close(); 3869 */ 3870 3871 /** 3872 * Create a netlink listener. 3873 * 3874 * Creates a new netlink listener that will receive messages matching the specified 3875 * commands and multicast groups. 3876 * 3877 * @function module:rtnl#listener 3878 * 3879 * @param {function} callback - The callback function to invoke when a message is received 3880 * @param {Array<string>} [commands] - Array of netlink commands to listen for (optional) 3881 * @param {Array<number>} [groups] - Array of multicast groups to join (optional) 3882 * 3883 * @returns {module:rtnl.listener} - A listener object with methods to control the listener 3884 * 3885 * @example 3886 * // Create a listener for route changes 3887 * let routeListener = listener((msg) => { 3888 * print('Received route message:', msg, '\n'); 3889 * }, [RTM_NEWROUTE, RTM_DELROUTE]); 3890 */ 3891 static uc_value_t * 3892 uc_nl_listener(uc_vm_t *vm, size_t nargs) 3893 { 3894 uc_nl_listener_t *l; 3895 uc_value_t *cb_func = uc_fn_arg(0); 3896 uc_value_t *cmds = uc_fn_arg(1); 3897 uc_value_t *groups = uc_fn_arg(2); 3898 uc_value_t *rv; 3899 size_t i; 3900 3901 if (!ucv_is_callable(cb_func)) { 3902 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid callback"); 3903 return NULL; 3904 } 3905 3906 if (!uc_nl_evsock_init()) 3907 return NULL; 3908 3909 if (ucv_type(groups) == UC_ARRAY) { 3910 for (i = 0; i < ucv_array_length(groups); i++) { 3911 int64_t n = ucv_int64_get(ucv_array_get(groups, i)); 3912 3913 if (errno || n < 0 || n >= __RTNLGRP_MAX) 3914 err_return(NLE_INVAL, NULL); 3915 3916 uc_nl_add_group(n); 3917 } 3918 } else { 3919 uc_nl_add_group(RTNLGRP_LINK); 3920 } 3921 3922 for (i = 0; i < ucv_array_length(listener_registry); i += 2) { 3923 if (!ucv_array_get(listener_registry, i)) 3924 break; 3925 } 3926 3927 l = xalloc(sizeof(*l)); 3928 l->index = i; 3929 3930 if (!uc_nl_fill_cmds(l->cmds, cmds)) { 3931 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid command ID"); 3932 free(l); 3933 return NULL; 3934 } 3935 3936 rv = uc_resource_new(listener_type, l); 3937 3938 ucv_array_set(listener_registry, i, ucv_get(rv)); 3939 ucv_array_set(listener_registry, i + 1, ucv_get(cb_func)); 3940 3941 listener_vm = vm; 3942 3943 return rv; 3944 } 3945 3946 static void 3947 uc_nl_listener_free(void *arg) 3948 { 3949 uc_nl_listener_t *l = arg; 3950 3951 if (!l) 3952 return; 3953 3954 ucv_array_set(listener_registry, l->index, NULL); 3955 ucv_array_set(listener_registry, l->index + 1, NULL); 3956 free(l); 3957 } 3958 3959 /** 3960 * Set the commands for a netlink listener. 3961 * 3962 * Updates the set of netlink commands that the listener will receive. 3963 * 3964 * @function module:rtnl.listener#set_commands 3965 * 3966 * @param {Array<string>} commands - Array of netlink commands to listen for 3967 * 3968 * @returns {boolean} - true if successful, false on error 3969 * 3970 * @example 3971 * // Update listener to only receive route messages 3972 * listener.set_commands([RTM_NEWROUTE, RTM_DELROUTE]); 3973 */ 3974 static uc_value_t * 3975 uc_nl_listener_set_commands(uc_vm_t *vm, size_t nargs) 3976 { 3977 uc_nl_listener_t *l = uc_fn_thisval("rtnl.listener"); 3978 uc_value_t *cmds = uc_fn_arg(0); 3979 3980 if (!l) 3981 return NULL; 3982 3983 memset(l->cmds, 0, sizeof(l->cmds)); 3984 if (!uc_nl_fill_cmds(l->cmds, cmds)) 3985 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid command ID"); 3986 3987 return NULL; 3988 } 3989 3990 /** 3991 * Close a netlink listener. 3992 * 3993 * Closes the netlink listener and stops receiving messages. 3994 * 3995 * @function module:rtnl.listener#close 3996 * 3997 * @returns {boolean} - true if successful, false on error 3998 * 3999 * @example 4000 * // Close the listener 4001 * listener.close(); 4002 */ 4003 static uc_value_t * 4004 uc_nl_listener_close(uc_vm_t *vm, size_t nargs) 4005 { 4006 uc_nl_listener_t **lptr = uc_fn_this("rtnl.listener"); 4007 uc_nl_listener_t *l; 4008 4009 if (!lptr) 4010 return NULL; 4011 4012 l = *lptr; 4013 if (!l) 4014 return NULL; 4015 4016 *lptr = NULL; 4017 uc_nl_listener_free(l); 4018 4019 return NULL; 4020 } 4021 4022 4023 static void 4024 register_constants(uc_vm_t *vm, uc_value_t *scope) 4025 { 4026 uc_value_t *c = ucv_object_new(vm); 4027 4028 #define ADD_CONST(x) ucv_object_add(c, #x, ucv_int64_new(x)) 4029 4030 /** 4031 * @typedef 4032 * @name Netlink message flags 4033 * @property {number} NLM_F_ACK - Request for acknowledgment 4034 * @property {number} NLM_F_ACK_TLVS - Request for acknowledgment with TLVs 4035 * @property {number} NLM_F_APPEND - Append to existing list 4036 * @property {number} NLM_F_ATOMIC - Atomic operation 4037 * @property {number} NLM_F_CAPPED - Request capped 4038 * @property {number} NLM_F_CREATE - Create if not exists 4039 * @property {number} NLM_F_DUMP - Dump request 4040 * @property {number} NLM_F_DUMP_FILTERED - Dump filtered request 4041 * @property {number} NLM_F_DUMP_INTR - Dump interrupted 4042 * @property {number} NLM_F_ECHO - Echo request 4043 * @property {number} NLM_F_EXCL - Exclusive creation 4044 * @property {number} NLM_F_MATCH - Match request 4045 * @property {number} NLM_F_MULTI - Multi-part message 4046 * @property {number} NLM_F_NONREC - Non-recursive operation 4047 * @property {number} NLM_F_REPLACE - Replace existing 4048 * @property {number} NLM_F_REQUEST - Request message 4049 * @property {number} NLM_F_ROOT - Root operation 4050 * @property {number} NLM_F_STRICT_CHK - Strict checking 4051 */ 4052 ADD_CONST(NLM_F_ACK); 4053 ADD_CONST(NLM_F_ACK); 4054 ADD_CONST(NLM_F_ACK_TLVS); 4055 ADD_CONST(NLM_F_APPEND); 4056 ADD_CONST(NLM_F_ATOMIC); 4057 ADD_CONST(NLM_F_CAPPED); 4058 ADD_CONST(NLM_F_CREATE); 4059 ADD_CONST(NLM_F_DUMP); 4060 ADD_CONST(NLM_F_DUMP_FILTERED); 4061 ADD_CONST(NLM_F_DUMP_INTR); 4062 ADD_CONST(NLM_F_ECHO); 4063 ADD_CONST(NLM_F_EXCL); 4064 ADD_CONST(NLM_F_MATCH); 4065 ADD_CONST(NLM_F_MULTI); 4066 ADD_CONST(NLM_F_NONREC); 4067 ADD_CONST(NLM_F_REPLACE); 4068 ADD_CONST(NLM_F_REQUEST); 4069 ADD_CONST(NLM_F_ROOT); 4070 ADD_CONST(NLM_F_STRICT_CHK); /* custom */ 4071 4072 /** 4073 * @typedef 4074 * @name IPv6 address generation modes 4075 * @property {number} IN6_ADDR_GEN_MODE_EUI64 - EUI-64 mode 4076 * @property {number} IN6_ADDR_GEN_MODE_NONE - No mode 4077 * @property {number} IN6_ADDR_GEN_MODE_STABLE_PRIVACY - Stable privacy mode 4078 * @property {number} IN6_ADDR_GEN_MODE_RANDOM - Random mode 4079 */ 4080 ADD_CONST(IN6_ADDR_GEN_MODE_EUI64); 4081 ADD_CONST(IN6_ADDR_GEN_MODE_NONE); 4082 ADD_CONST(IN6_ADDR_GEN_MODE_STABLE_PRIVACY); 4083 ADD_CONST(IN6_ADDR_GEN_MODE_RANDOM); 4084 4085 /** 4086 * @typedef 4087 * @name MACVLAN modes 4088 * @property {number} MACVLAN_MODE_PRIVATE - Private mode 4089 * @property {number} MACVLAN_MODE_VEPA - VEPA mode 4090 * @property {number} MACVLAN_MODE_BRIDGE - Bridge mode 4091 * @property {number} MACVLAN_MODE_PASSTHRU - Pass-through mode 4092 * @property {number} MACVLAN_MODE_SOURCE - Source mode 4093 */ 4094 ADD_CONST(MACVLAN_MODE_PRIVATE); 4095 ADD_CONST(MACVLAN_MODE_VEPA); 4096 ADD_CONST(MACVLAN_MODE_BRIDGE); 4097 ADD_CONST(MACVLAN_MODE_PASSTHRU); 4098 ADD_CONST(MACVLAN_MODE_SOURCE); 4099 4100 /** 4101 * @typedef 4102 * @name MACVLAN MAC address commands 4103 * @property {number} MACVLAN_MACADDR_ADD - Add MAC address 4104 * @property {number} MACVLAN_MACADDR_DEL - Delete MAC address 4105 * @property {number} MACVLAN_MACADDR_FLUSH - Flush MAC addresses 4106 * @property {number} MACVLAN_MACADDR_SET - Set MAC address 4107 */ 4108 ADD_CONST(MACVLAN_MACADDR_ADD); 4109 ADD_CONST(MACVLAN_MACADDR_DEL); 4110 ADD_CONST(MACVLAN_MACADDR_FLUSH); 4111 ADD_CONST(MACVLAN_MACADDR_SET); 4112 4113 /** 4114 * @typedef 4115 * @name MACsec validation levels 4116 * @property {number} MACSEC_VALIDATE_DISABLED - Disabled validation 4117 * @property {number} MACSEC_VALIDATE_CHECK - Check validation 4118 * @property {number} MACSEC_VALIDATE_STRICT - Strict validation 4119 * @property {number} MACSEC_VALIDATE_MAX - Maximum validation 4120 */ 4121 ADD_CONST(MACSEC_VALIDATE_DISABLED); 4122 ADD_CONST(MACSEC_VALIDATE_CHECK); 4123 ADD_CONST(MACSEC_VALIDATE_STRICT); 4124 ADD_CONST(MACSEC_VALIDATE_MAX); 4125 4126 /** 4127 * @typedef 4128 * @name MACsec offload modes 4129 * @property {number} MACSEC_OFFLOAD_OFF - Offload off 4130 * @property {number} MACSEC_OFFLOAD_PHY - Physical offload 4131 * @property {number} MACSEC_OFFLOAD_MAC - MAC offload 4132 * @property {number} MACSEC_OFFLOAD_MAX - Maximum offload 4133 */ 4134 ADD_CONST(MACSEC_OFFLOAD_OFF); 4135 ADD_CONST(MACSEC_OFFLOAD_PHY); 4136 ADD_CONST(MACSEC_OFFLOAD_MAC); 4137 ADD_CONST(MACSEC_OFFLOAD_MAX); 4138 4139 /** 4140 * @typedef 4141 * @name IPVLAN modes 4142 * @property {number} IPVLAN_MODE_L2 - Layer 2 mode 4143 * @property {number} IPVLAN_MODE_L3 - Layer 3 mode 4144 * @property {number} IPVLAN_MODE_L3S - Layer 3 symmetric mode 4145 */ 4146 ADD_CONST(IPVLAN_MODE_L2); 4147 ADD_CONST(IPVLAN_MODE_L3); 4148 ADD_CONST(IPVLAN_MODE_L3S); 4149 4150 /** 4151 * @typedef 4152 * @name VXLAN data frame flags 4153 * @property {number} VXLAN_DF_UNSET - Data frame unset 4154 * @property {number} VXLAN_DF_SET - Data frame set 4155 * @property {number} VXLAN_DF_INHERIT - Data frame inherit 4156 * @property {number} VXLAN_DF_MAX - Maximum data frame 4157 */ 4158 ADD_CONST(VXLAN_DF_UNSET); 4159 ADD_CONST(VXLAN_DF_SET); 4160 ADD_CONST(VXLAN_DF_INHERIT); 4161 ADD_CONST(VXLAN_DF_MAX); 4162 4163 /** 4164 * @typedef 4165 * @name Geneve data frame flags 4166 * @property {number} GENEVE_DF_UNSET - Data frame unset 4167 * @property {number} GENEVE_DF_SET - Data frame set 4168 * @property {number} GENEVE_DF_INHERIT - Data frame inherit 4169 * @property {number} GENEVE_DF_MAX - Maximum data frame 4170 */ 4171 ADD_CONST(GENEVE_DF_UNSET); 4172 ADD_CONST(GENEVE_DF_SET); 4173 ADD_CONST(GENEVE_DF_INHERIT); 4174 ADD_CONST(GENEVE_DF_MAX); 4175 4176 /** 4177 * @typedef 4178 * @name GTP roles 4179 * @property {number} GTP_ROLE_GGSN - GGSN role 4180 * @property {number} GTP_ROLE_SGSN - SGSN role 4181 */ 4182 ADD_CONST(GTP_ROLE_GGSN); 4183 ADD_CONST(GTP_ROLE_SGSN); 4184 4185 /** 4186 * @typedef 4187 * @name Port request types 4188 * @property {number} PORT_REQUEST_PREASSOCIATE - Pre-associate request 4189 * @property {number} PORT_REQUEST_PREASSOCIATE_RR - Pre-associate round-robin request 4190 * @property {number} PORT_REQUEST_ASSOCIATE - Associate request 4191 * @property {number} PORT_REQUEST_DISASSOCIATE - Disassociate request 4192 */ 4193 ADD_CONST(PORT_REQUEST_PREASSOCIATE); 4194 ADD_CONST(PORT_REQUEST_PREASSOCIATE_RR); 4195 ADD_CONST(PORT_REQUEST_ASSOCIATE); 4196 ADD_CONST(PORT_REQUEST_DISASSOCIATE); 4197 4198 /** 4199 * @typedef 4200 * @name Port VDP responses 4201 * @property {number} PORT_VDP_RESPONSE_SUCCESS - Success response 4202 * @property {number} PORT_VDP_RESPONSE_INVALID_FORMAT - Invalid format response 4203 * @property {number} PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES - Insufficient resources response 4204 * @property {number} PORT_VDP_RESPONSE_UNUSED_VTID - Unused VTID response 4205 * @property {number} PORT_VDP_RESPONSE_VTID_VIOLATION - VTID violation response 4206 * @property {number} PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION - VTID version violation response 4207 * @property {number} PORT_VDP_RESPONSE_OUT_OF_SYNC - Out of sync response 4208 */ 4209 ADD_CONST(PORT_VDP_RESPONSE_SUCCESS); 4210 ADD_CONST(PORT_VDP_RESPONSE_INVALID_FORMAT); 4211 ADD_CONST(PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES); 4212 ADD_CONST(PORT_VDP_RESPONSE_UNUSED_VTID); 4213 ADD_CONST(PORT_VDP_RESPONSE_VTID_VIOLATION); 4214 ADD_CONST(PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION); 4215 ADD_CONST(PORT_VDP_RESPONSE_OUT_OF_SYNC); 4216 4217 /** 4218 * @typedef 4219 * @name Port profile responses 4220 * @property {number} PORT_PROFILE_RESPONSE_SUCCESS - Success response 4221 * @property {number} PORT_PROFILE_RESPONSE_INPROGRESS - In progress response 4222 * @property {number} PORT_PROFILE_RESPONSE_INVALID - Invalid response 4223 * @property {number} PORT_PROFILE_RESPONSE_BADSTATE - Bad state response 4224 * @property {number} PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES - Insufficient resources response 4225 * @property {number} PORT_PROFILE_RESPONSE_ERROR - Error response 4226 */ 4227 ADD_CONST(PORT_PROFILE_RESPONSE_SUCCESS); 4228 ADD_CONST(PORT_PROFILE_RESPONSE_INPROGRESS); 4229 ADD_CONST(PORT_PROFILE_RESPONSE_INVALID); 4230 ADD_CONST(PORT_PROFILE_RESPONSE_BADSTATE); 4231 ADD_CONST(PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES); 4232 ADD_CONST(PORT_PROFILE_RESPONSE_ERROR); 4233 4234 /** 4235 * @typedef 4236 * @name IPoIB modes 4237 * @property {number} IPOIB_MODE_DATAGRAM - Datagram mode 4238 * @property {number} IPOIB_MODE_CONNECTED - Connected mode 4239 */ 4240 ADD_CONST(IPOIB_MODE_DATAGRAM); 4241 ADD_CONST(IPOIB_MODE_CONNECTED); 4242 4243 /** 4244 * @typedef 4245 * @name HSR protocols 4246 * @property {number} HSR_PROTOCOL_HSR - HSR protocol 4247 * @property {number} HSR_PROTOCOL_PRP - PRP protocol 4248 */ 4249 ADD_CONST(HSR_PROTOCOL_HSR); 4250 ADD_CONST(HSR_PROTOCOL_PRP); 4251 4252 /** 4253 * @typedef 4254 * @name CAN controller modes 4255 * @description 4256 * Flag bits used in the `mask` and `flags` members of the `ctrlmode` 4257 * attribute of `can` type links. 4258 * @property {number} CAN_CTRLMODE_LOOPBACK - Loopback mode 4259 * @property {number} CAN_CTRLMODE_LISTENONLY - Listen-only mode 4260 * @property {number} CAN_CTRLMODE_3_SAMPLES - Triple sampling mode 4261 * @property {number} CAN_CTRLMODE_ONE_SHOT - One-shot mode 4262 * @property {number} CAN_CTRLMODE_BERR_REPORTING - Bus error reporting 4263 * @property {number} CAN_CTRLMODE_FD - CAN FD mode 4264 * @property {number} CAN_CTRLMODE_PRESUME_ACK - Ignore missing CAN ACKs 4265 * @property {number} CAN_CTRLMODE_FD_NON_ISO - CAN FD in non-ISO mode 4266 * @property {number} CAN_CTRLMODE_CC_LEN8_DLC - Classic CAN DLC option 4267 */ 4268 ADD_CONST(CAN_CTRLMODE_LOOPBACK); 4269 ADD_CONST(CAN_CTRLMODE_LISTENONLY); 4270 ADD_CONST(CAN_CTRLMODE_3_SAMPLES); 4271 ADD_CONST(CAN_CTRLMODE_ONE_SHOT); 4272 ADD_CONST(CAN_CTRLMODE_BERR_REPORTING); 4273 ADD_CONST(CAN_CTRLMODE_FD); 4274 ADD_CONST(CAN_CTRLMODE_PRESUME_ACK); 4275 ADD_CONST(CAN_CTRLMODE_FD_NON_ISO); 4276 #ifdef CAN_CTRLMODE_CC_LEN8_DLC 4277 ADD_CONST(CAN_CTRLMODE_CC_LEN8_DLC); 4278 #endif 4279 #ifdef CAN_CTRLMODE_TDC_AUTO 4280 ADD_CONST(CAN_CTRLMODE_TDC_AUTO); 4281 ADD_CONST(CAN_CTRLMODE_TDC_MANUAL); 4282 #endif 4283 4284 /** 4285 * @typedef 4286 * @name CAN operational states 4287 * @description 4288 * Values of the `state` attribute of `can` type links. 4289 * @property {number} CAN_STATE_ERROR_ACTIVE - RX/TX error count < 96 4290 * @property {number} CAN_STATE_ERROR_WARNING - RX/TX error count < 128 4291 * @property {number} CAN_STATE_ERROR_PASSIVE - RX/TX error count < 256 4292 * @property {number} CAN_STATE_BUS_OFF - RX/TX error count >= 256 4293 * @property {number} CAN_STATE_STOPPED - Device is stopped 4294 * @property {number} CAN_STATE_SLEEPING - Device is sleeping 4295 */ 4296 ADD_CONST(CAN_STATE_ERROR_ACTIVE); 4297 ADD_CONST(CAN_STATE_ERROR_WARNING); 4298 ADD_CONST(CAN_STATE_ERROR_PASSIVE); 4299 ADD_CONST(CAN_STATE_BUS_OFF); 4300 ADD_CONST(CAN_STATE_STOPPED); 4301 ADD_CONST(CAN_STATE_SLEEPING); 4302 4303 /** 4304 * @typedef 4305 * @name Link extended statistics types 4306 * @property {number} LINK_XSTATS_TYPE_UNSPEC - Unspecified type 4307 * @property {number} LINK_XSTATS_TYPE_BRIDGE - Bridge type 4308 * @property {number} LINK_XSTATS_TYPE_BOND - Bond type 4309 */ 4310 ADD_CONST(LINK_XSTATS_TYPE_UNSPEC); 4311 ADD_CONST(LINK_XSTATS_TYPE_BRIDGE); 4312 ADD_CONST(LINK_XSTATS_TYPE_BOND); 4313 4314 /** 4315 * @typedef 4316 * @name XDP attach types 4317 * @property {number} XDP_ATTACHED_NONE - Not attached 4318 * @property {number} XDP_ATTACHED_DRV - Driver attached 4319 * @property {number} XDP_ATTACHED_SKB - SKB attached 4320 * @property {number} XDP_ATTACHED_HW - Hardware attached 4321 * @property {number} XDP_ATTACHED_MULTI - Multi attached 4322 */ 4323 ADD_CONST(XDP_ATTACHED_NONE); 4324 ADD_CONST(XDP_ATTACHED_DRV); 4325 ADD_CONST(XDP_ATTACHED_SKB); 4326 ADD_CONST(XDP_ATTACHED_HW); 4327 ADD_CONST(XDP_ATTACHED_MULTI); 4328 4329 /** 4330 * @typedef 4331 * @name FDB notification bits 4332 * @property {number} FDB_NOTIFY_BIT - Notify bit 4333 * @property {number} FDB_NOTIFY_INACTIVE_BIT - Inactive notify bit 4334 */ 4335 4336 ADD_CONST(FDB_NOTIFY_BIT); 4337 ADD_CONST(FDB_NOTIFY_INACTIVE_BIT); 4338 4339 /** 4340 * @typedef 4341 * @name Route commands 4342 * @property {number} RTM_BASE - Base command 4343 * @property {number} RTM_NEWLINK - New link 4344 * @property {number} RTM_DELLINK - Delete link 4345 * @property {number} RTM_GETLINK - Get link 4346 * @property {number} RTM_SETLINK - Set link 4347 * @property {number} RTM_NEWADDR - New address 4348 * @property {number} RTM_DELADDR - Delete address 4349 * @property {number} RTM_GETADDR - Get address 4350 * @property {number} RTM_NEWROUTE - New route 4351 * @property {number} RTM_DELROUTE - Delete route 4352 * @property {number} RTM_GETROUTE - Get route 4353 * @property {number} RTM_NEWRULE - New rule 4354 * @property {number} RTM_DELRULE - Delete rule 4355 * @property {number} RTM_GETRULE - Get rule 4356 * @property {number} RTM_NEWQDISC - New queue discipline 4357 * @property {number} RTM_DELQDISC - Delete queue discipline 4358 * @property {number} RTM_GETQDISC - Get queue discipline 4359 * @property {number} RTM_NEWTCLASS - New traffic class 4360 * @property {number} RTM_DELTCLASS - Delete traffic class 4361 * @property {number} RTM_GETTCLASS - Get traffic class 4362 * @property {number} RTM_NEWTFILTER - New traffic filter 4363 * @property {number} RTM_DELTFILTER - Delete traffic filter 4364 * @property {number} RTM_GETTFILTER - Get traffic filter 4365 * @property {number} RTM_NEWACTION - New action 4366 * @property {number} RTM_DELACTION - Delete action 4367 * @property {number} RTM_GETACTION - Get action 4368 * @property {number} RTM_NEWPREFIX - New prefix 4369 * @property {number} RTM_GETMULTICAST - Get multicast 4370 * @property {number} RTM_GETANYCAST - Get anycast 4371 * @property {number} RTM_NEWNEIGHTBL - New neighbor table 4372 * @property {number} RTM_GETNEIGHTBL - Get neighbor table 4373 * @property {number} RTM_SETNEIGHTBL - Set neighbor table 4374 * @property {number} RTM_NEWNDUSEROPT - New neighbor user option 4375 * @property {number} RTM_NEWADDRLABEL - New address label 4376 * @property {number} RTM_DELADDRLABEL - Delete address label 4377 * @property {number} RTM_GETADDRLABEL - Get address label 4378 * @property {number} RTM_GETDCB - Get DCB 4379 * @property {number} RTM_SETDCB - Set DCB 4380 * @property {number} RTM_NEWNETCONF - New network configuration 4381 * @property {number} RTM_DELNETCONF - Delete network configuration 4382 * @property {number} RTM_GETNETCONF - Get network configuration 4383 * @property {number} RTM_NEWMDB - New multicast database 4384 * @property {number} RTM_DELMDB - Delete multicast database 4385 * @property {number} RTM_GETMDB - Get multicast database 4386 * @property {number} RTM_NEWNSID - New network namespace ID 4387 * @property {number} RTM_DELNSID - Delete network namespace ID 4388 * @property {number} RTM_GETNSID - Get network namespace ID 4389 * @property {number} RTM_NEWSTATS - New statistics 4390 * @property {number} RTM_GETSTATS - Get statistics 4391 * @property {number} RTM_NEWCACHEREPORT - New cache report 4392 * @property {number} RTM_NEWCHAIN - New chain 4393 * @property {number} RTM_DELCHAIN - Delete chain 4394 * @property {number} RTM_GETCHAIN - Get chain 4395 * @property {number} RTM_NEWNEXTHOP - New next hop 4396 * @property {number} RTM_DELNEXTHOP - Delete next hop 4397 * @property {number} RTM_GETNEXTHOP - Get next hop 4398 * @property {number} RTM_NEWLINKPROP - New link property 4399 * @property {number} RTM_DELLINKPROP - Delete link property 4400 * @property {number} RTM_GETLINKPROP - Get link property 4401 * @property {number} RTM_NEWVLAN - New VLAN 4402 * @property {number} RTM_DELVLAN - Delete VLAN 4403 * @property {number} RTM_GETVLAN - Get VLAN 4404 */ 4405 ADD_CONST(RTM_BASE); 4406 ADD_CONST(RTM_NEWLINK); 4407 ADD_CONST(RTM_DELLINK); 4408 ADD_CONST(RTM_GETLINK); 4409 ADD_CONST(RTM_SETLINK); 4410 ADD_CONST(RTM_NEWADDR); 4411 ADD_CONST(RTM_DELADDR); 4412 ADD_CONST(RTM_GETADDR); 4413 ADD_CONST(RTM_NEWROUTE); 4414 ADD_CONST(RTM_DELROUTE); 4415 ADD_CONST(RTM_GETROUTE); 4416 ADD_CONST(RTM_NEWNEIGH); 4417 ADD_CONST(RTM_DELNEIGH); 4418 ADD_CONST(RTM_GETNEIGH); 4419 ADD_CONST(RTM_NEWRULE); 4420 ADD_CONST(RTM_DELRULE); 4421 ADD_CONST(RTM_GETRULE); 4422 ADD_CONST(RTM_NEWQDISC); 4423 ADD_CONST(RTM_DELQDISC); 4424 ADD_CONST(RTM_GETQDISC); 4425 ADD_CONST(RTM_NEWTCLASS); 4426 ADD_CONST(RTM_DELTCLASS); 4427 ADD_CONST(RTM_GETTCLASS); 4428 ADD_CONST(RTM_NEWTFILTER); 4429 ADD_CONST(RTM_DELTFILTER); 4430 ADD_CONST(RTM_GETTFILTER); 4431 ADD_CONST(RTM_NEWACTION); 4432 ADD_CONST(RTM_DELACTION); 4433 ADD_CONST(RTM_GETACTION); 4434 ADD_CONST(RTM_NEWPREFIX); 4435 ADD_CONST(RTM_GETMULTICAST); 4436 ADD_CONST(RTM_GETANYCAST); 4437 ADD_CONST(RTM_NEWNEIGHTBL); 4438 ADD_CONST(RTM_GETNEIGHTBL); 4439 ADD_CONST(RTM_SETNEIGHTBL); 4440 ADD_CONST(RTM_NEWNDUSEROPT); 4441 ADD_CONST(RTM_NEWADDRLABEL); 4442 ADD_CONST(RTM_DELADDRLABEL); 4443 ADD_CONST(RTM_GETADDRLABEL); 4444 ADD_CONST(RTM_GETDCB); 4445 ADD_CONST(RTM_SETDCB); 4446 ADD_CONST(RTM_NEWNETCONF); 4447 ADD_CONST(RTM_DELNETCONF); 4448 ADD_CONST(RTM_GETNETCONF); 4449 ADD_CONST(RTM_NEWMDB); 4450 ADD_CONST(RTM_DELMDB); 4451 ADD_CONST(RTM_GETMDB); 4452 ADD_CONST(RTM_NEWNSID); 4453 ADD_CONST(RTM_DELNSID); 4454 ADD_CONST(RTM_GETNSID); 4455 ADD_CONST(RTM_NEWSTATS); 4456 ADD_CONST(RTM_GETSTATS); 4457 ADD_CONST(RTM_NEWCACHEREPORT); 4458 ADD_CONST(RTM_NEWCHAIN); 4459 ADD_CONST(RTM_DELCHAIN); 4460 ADD_CONST(RTM_GETCHAIN); 4461 ADD_CONST(RTM_NEWNEXTHOP); 4462 ADD_CONST(RTM_DELNEXTHOP); 4463 ADD_CONST(RTM_GETNEXTHOP); 4464 ADD_CONST(RTM_NEWLINKPROP); 4465 ADD_CONST(RTM_DELLINKPROP); 4466 ADD_CONST(RTM_GETLINKPROP); 4467 ADD_CONST(RTM_NEWVLAN); 4468 ADD_CONST(RTM_DELVLAN); 4469 ADD_CONST(RTM_GETVLAN); 4470 4471 /** 4472 * @typedef 4473 * @name Route types 4474 * @property {number} RTN_UNSPEC - Unspecified route 4475 * @property {number} RTN_UNICAST - Unicast route 4476 * @property {number} RTN_LOCAL - Local route 4477 * @property {number} RTN_BROADCAST - Broadcast route 4478 * @property {number} RTN_ANYCAST - Anycast route 4479 * @property {number} RTN_MULTICAST - Multicast route 4480 * @property {number} RTN_BLACKHOLE - Blackhole route 4481 * @property {number} RTN_UNREACHABLE - Unreachable route 4482 * @property {number} RTN_PROHIBIT - Prohibited route 4483 * @property {number} RTN_THROW - Throw route 4484 * @property {number} RTN_NAT - NAT route 4485 * @property {number} RTN_XRESOLVE - External resolve route 4486 */ 4487 ADD_CONST(RTN_UNSPEC); 4488 ADD_CONST(RTN_UNICAST); 4489 ADD_CONST(RTN_LOCAL); 4490 ADD_CONST(RTN_BROADCAST); 4491 ADD_CONST(RTN_ANYCAST); 4492 ADD_CONST(RTN_MULTICAST); 4493 ADD_CONST(RTN_BLACKHOLE); 4494 ADD_CONST(RTN_UNREACHABLE); 4495 ADD_CONST(RTN_PROHIBIT); 4496 ADD_CONST(RTN_THROW); 4497 ADD_CONST(RTN_NAT); 4498 ADD_CONST(RTN_XRESOLVE); 4499 4500 /** 4501 * @typedef 4502 * @name Route scopes 4503 * @property {number} RT_SCOPE_UNIVERSE - Universe scope 4504 * @property {number} RT_SCOPE_SITE - Site scope 4505 * @property {number} RT_SCOPE_LINK - Link scope 4506 * @property {number} RT_SCOPE_HOST - Host scope 4507 * @property {number} RT_SCOPE_NOWHERE - Nowhere scope 4508 */ 4509 ADD_CONST(RT_SCOPE_UNIVERSE); 4510 ADD_CONST(RT_SCOPE_SITE); 4511 ADD_CONST(RT_SCOPE_LINK); 4512 ADD_CONST(RT_SCOPE_HOST); 4513 ADD_CONST(RT_SCOPE_NOWHERE); 4514 4515 /** 4516 * @typedef 4517 * @name Route tables 4518 * @property {number} RT_TABLE_UNSPEC - Unspecified table 4519 * @property {number} RT_TABLE_COMPAT - Compatibility table 4520 * @property {number} RT_TABLE_DEFAULT - Default table 4521 * @property {number} RT_TABLE_MAIN - Main table 4522 * @property {number} RT_TABLE_LOCAL - Local table 4523 * @property {number} RT_TABLE_MAX - Maximum table 4524 */ 4525 ADD_CONST(RT_TABLE_UNSPEC); 4526 ADD_CONST(RT_TABLE_COMPAT); 4527 ADD_CONST(RT_TABLE_DEFAULT); 4528 ADD_CONST(RT_TABLE_MAIN); 4529 ADD_CONST(RT_TABLE_LOCAL); 4530 ADD_CONST(RT_TABLE_MAX); 4531 4532 /** 4533 * @typedef 4534 * @name Route metrics 4535 * @property {number} RTAX_MTU - Maximum transmission unit 4536 * @property {number} RTAX_HOPLIMIT - Hop limit 4537 * @property {number} RTAX_ADVMSS - Advertised MSS 4538 * @property {number} RTAX_REORDERING - Reordering 4539 * @property {number} RTAX_RTT - Round trip time 4540 * @property {number} RTAX_WINDOW - Window size 4541 * @property {number} RTAX_CWND - Congestion window 4542 * @property {number} RTAX_INITCWND - Initial congestion window 4543 * @property {number} RTAX_INITRWND - Initial receive window 4544 * @property {number} RTAX_FEATURES - Features 4545 * @property {number} RTAX_QUICKACK - Quick acknowledgment 4546 * @property {number} RTAX_CC_ALGO - Congestion control algorithm 4547 * @property {number} RTAX_RTTVAR - RTT variance 4548 * @property {number} RTAX_SSTHRESH - Slow start threshold 4549 * @property {number} RTAX_FASTOPEN_NO_COOKIE - Fast open no cookie 4550 */ 4551 /* required to construct RTAX_LOCK */ 4552 ADD_CONST(RTAX_MTU); 4553 ADD_CONST(RTAX_HOPLIMIT); 4554 ADD_CONST(RTAX_ADVMSS); 4555 ADD_CONST(RTAX_REORDERING); 4556 ADD_CONST(RTAX_RTT); 4557 ADD_CONST(RTAX_WINDOW); 4558 ADD_CONST(RTAX_CWND); 4559 ADD_CONST(RTAX_INITCWND); 4560 ADD_CONST(RTAX_INITRWND); 4561 ADD_CONST(RTAX_FEATURES); 4562 ADD_CONST(RTAX_QUICKACK); 4563 ADD_CONST(RTAX_CC_ALGO); 4564 ADD_CONST(RTAX_RTTVAR); 4565 ADD_CONST(RTAX_SSTHRESH); 4566 ADD_CONST(RTAX_FASTOPEN_NO_COOKIE); 4567 4568 /** 4569 * @typedef 4570 * @name Prefix types 4571 * @property {number} PREFIX_UNSPEC - Unspecified prefix 4572 * @property {number} PREFIX_ADDRESS - Address prefix 4573 * @property {number} PREFIX_CACHEINFO - Cache info prefix 4574 */ 4575 ADD_CONST(PREFIX_UNSPEC); 4576 ADD_CONST(PREFIX_ADDRESS); 4577 ADD_CONST(PREFIX_CACHEINFO); 4578 4579 /** 4580 * @typedef 4581 * @name Neighbor discovery user option types 4582 * @property {number} NDUSEROPT_UNSPEC - Unspecified option 4583 * @property {number} NDUSEROPT_SRCADDR - Source address option 4584 */ 4585 ADD_CONST(NDUSEROPT_UNSPEC); 4586 ADD_CONST(NDUSEROPT_SRCADDR); 4587 4588 /** 4589 * @typedef 4590 * @name Multicast groups 4591 * @property {number} RTNLGRP_NONE - No group 4592 * @property {number} RTNLGRP_LINK - Link group 4593 * @property {number} RTNLGRP_NOTIFY - Notify group 4594 * @property {number} RTNLGRP_NEIGH - Neighbor group 4595 * @property {number} RTNLGRP_TC - Traffic control group 4596 * @property {number} RTNLGRP_IPV4_IFADDR - IPv4 interface address group 4597 * @property {number} RTNLGRP_IPV4_MROUTE - IPv4 multicast route group 4598 * @property {number} RTNLGRP_IPV4_ROUTE - IPv4 route group 4599 * @property {number} RTNLGRP_IPV4_RULE - IPv4 rule group 4600 * @property {number} RTNLGRP_IPV6_IFADDR - IPv6 interface address group 4601 * @property {number} RTNLGRP_IPV6_MROUTE - IPv6 multicast route group 4602 * @property {number} RTNLGRP_IPV6_ROUTE - IPv6 route group 4603 * @property {number} RTNLGRP_IPV6_IFINFO - IPv6 interface info group 4604 * @property {number} RTNLGRP_DECnet_IFADDR - DECnet interface address group 4605 * @property {number} RTNLGRP_NOP2 - No operation 2 4606 * @property {number} RTNLGRP_DECnet_ROUTE - DECnet route group 4607 * @property {number} RTNLGRP_DECnet_RULE - DECnet rule group 4608 * @property {number} RTNLGRP_NOP4 - No operation 4 4609 * @property {number} RTNLGRP_IPV6_PREFIX - IPv6 prefix group 4610 * @property {number} RTNLGRP_IPV6_RULE - IPv6 rule group 4611 * @property {number} RTNLGRP_ND_USEROPT - Neighbor discovery user option group 4612 * @property {number} RTNLGRP_PHONET_IFADDR - Phonet interface address group 4613 * @property {number} RTNLGRP_PHONET_ROUTE - Phonet route group 4614 * @property {number} RTNLGRP_DCB - Data Center Bridging group 4615 * @property {number} RTNLGRP_IPV4_NETCONF - IPv4 network configuration group 4616 * @property {number} RTNLGRP_IPV6_NETCONF - IPv6 network configuration group 4617 * @property {number} RTNLGRP_MDB - Multicast database group 4618 * @property {number} RTNLGRP_MPLS_ROUTE - MPLS route group 4619 * @property {number} RTNLGRP_NSID - Network namespace ID group 4620 * @property {number} RTNLGRP_MPLS_NETCONF - MPLS network configuration group 4621 * @property {number} RTNLGRP_IPV4_MROUTE_R - IPv4 multicast route reverse group 4622 * @property {number} RTNLGRP_IPV6_MROUTE_R - IPv6 multicast route reverse group 4623 * @property {number} RTNLGRP_NEXTHOP - Next hop group 4624 * @property {number} RTNLGRP_BRVLAN - Bridge VLAN group 4625 */ 4626 ADD_CONST(RTNLGRP_NONE); 4627 ADD_CONST(RTNLGRP_LINK); 4628 ADD_CONST(RTNLGRP_NOTIFY); 4629 ADD_CONST(RTNLGRP_NEIGH); 4630 ADD_CONST(RTNLGRP_TC); 4631 ADD_CONST(RTNLGRP_IPV4_IFADDR); 4632 ADD_CONST(RTNLGRP_IPV4_MROUTE); 4633 ADD_CONST(RTNLGRP_IPV4_ROUTE); 4634 ADD_CONST(RTNLGRP_IPV4_RULE); 4635 ADD_CONST(RTNLGRP_IPV6_IFADDR); 4636 ADD_CONST(RTNLGRP_IPV6_MROUTE); 4637 ADD_CONST(RTNLGRP_IPV6_ROUTE); 4638 ADD_CONST(RTNLGRP_IPV6_IFINFO); 4639 ADD_CONST(RTNLGRP_DECnet_IFADDR); 4640 ADD_CONST(RTNLGRP_NOP2); 4641 ADD_CONST(RTNLGRP_DECnet_ROUTE); 4642 ADD_CONST(RTNLGRP_DECnet_RULE); 4643 ADD_CONST(RTNLGRP_NOP4); 4644 ADD_CONST(RTNLGRP_IPV6_PREFIX); 4645 ADD_CONST(RTNLGRP_IPV6_RULE); 4646 ADD_CONST(RTNLGRP_ND_USEROPT); 4647 ADD_CONST(RTNLGRP_PHONET_IFADDR); 4648 ADD_CONST(RTNLGRP_PHONET_ROUTE); 4649 ADD_CONST(RTNLGRP_DCB); 4650 ADD_CONST(RTNLGRP_IPV4_NETCONF); 4651 ADD_CONST(RTNLGRP_IPV6_NETCONF); 4652 ADD_CONST(RTNLGRP_MDB); 4653 ADD_CONST(RTNLGRP_MPLS_ROUTE); 4654 ADD_CONST(RTNLGRP_NSID); 4655 ADD_CONST(RTNLGRP_MPLS_NETCONF); 4656 ADD_CONST(RTNLGRP_IPV4_MROUTE_R); 4657 ADD_CONST(RTNLGRP_IPV6_MROUTE_R); 4658 ADD_CONST(RTNLGRP_NEXTHOP); 4659 ADD_CONST(RTNLGRP_BRVLAN); 4660 4661 /** 4662 * @typedef 4663 * @name Route flags 4664 * @property {number} RTM_F_CLONED - Cloned route 4665 * @property {number} RTM_F_EQUALIZE - Equalize route 4666 * @property {number} RTM_F_FIB_MATCH - FIB match 4667 * @property {number} RTM_F_LOOKUP_TABLE - Lookup table 4668 * @property {number} RTM_F_NOTIFY - Notify 4669 * @property {number} RTM_F_PREFIX - Prefix 4670 */ 4671 ADD_CONST(RTM_F_CLONED); 4672 ADD_CONST(RTM_F_EQUALIZE); 4673 ADD_CONST(RTM_F_FIB_MATCH); 4674 ADD_CONST(RTM_F_LOOKUP_TABLE); 4675 ADD_CONST(RTM_F_NOTIFY); 4676 ADD_CONST(RTM_F_PREFIX); 4677 4678 /** 4679 * @typedef 4680 * @name Address families 4681 * @property {number} AF_UNSPEC - Unspecified address family 4682 * @property {number} AF_INET - IPv4 address family 4683 * @property {number} AF_INET6 - IPv6 address family 4684 * @property {number} AF_MPLS - MPLS address family 4685 * @property {number} AF_BRIDGE - Bridge address family 4686 */ 4687 ADD_CONST(AF_UNSPEC); 4688 ADD_CONST(AF_INET); 4689 ADD_CONST(AF_INET6); 4690 ADD_CONST(AF_MPLS); 4691 ADD_CONST(AF_BRIDGE); 4692 4693 /** 4694 * @typedef 4695 * @name Generic Routing Encapsulation flags 4696 * @property {number} GRE_CSUM - Checksum flag 4697 * @property {number} GRE_ROUTING - Routing flag 4698 * @property {number} GRE_KEY - Key flag 4699 * @property {number} GRE_SEQ - Sequence flag 4700 * @property {number} GRE_STRICT - Strict flag 4701 * @property {number} GRE_REC - Record flag 4702 * @property {number} GRE_ACK - Acknowledgment flag 4703 */ 4704 ADD_CONST(GRE_CSUM); 4705 ADD_CONST(GRE_ROUTING); 4706 ADD_CONST(GRE_KEY); 4707 ADD_CONST(GRE_SEQ); 4708 ADD_CONST(GRE_STRICT); 4709 ADD_CONST(GRE_REC); 4710 ADD_CONST(GRE_ACK); 4711 4712 /** 4713 * @typedef 4714 * @name Tunnel encapsulation types 4715 * @property {number} TUNNEL_ENCAP_NONE - No encapsulation 4716 * @property {number} TUNNEL_ENCAP_FOU - Foo over UDP 4717 * @property {number} TUNNEL_ENCAP_GUE - Generic UDP Encapsulation 4718 * @property {number} TUNNEL_ENCAP_MPLS - MPLS encapsulation 4719 */ 4720 ADD_CONST(TUNNEL_ENCAP_NONE); 4721 ADD_CONST(TUNNEL_ENCAP_FOU); 4722 ADD_CONST(TUNNEL_ENCAP_GUE); 4723 ADD_CONST(TUNNEL_ENCAP_MPLS); 4724 4725 /** 4726 * @typedef 4727 * @name Tunnel encapsulation flags 4728 * @property {number} TUNNEL_ENCAP_FLAG_CSUM - Checksum flag 4729 * @property {number} TUNNEL_ENCAP_FLAG_CSUM6 - IPv6 checksum flag 4730 * @property {number} TUNNEL_ENCAP_FLAG_REMCSUM - Remote checksum flag 4731 */ 4732 ADD_CONST(TUNNEL_ENCAP_FLAG_CSUM); 4733 ADD_CONST(TUNNEL_ENCAP_FLAG_CSUM6); 4734 ADD_CONST(TUNNEL_ENCAP_FLAG_REMCSUM); 4735 4736 /** 4737 * @typedef 4738 * @name IPv6 tunnel flags 4739 * @property {number} IP6_TNL_F_ALLOW_LOCAL_REMOTE - Allow local remote 4740 * @property {number} IP6_TNL_F_IGN_ENCAP_LIMIT - Ignore encapsulation limit 4741 * @property {number} IP6_TNL_F_MIP6_DEV - Mobile IPv6 device 4742 * @property {number} IP6_TNL_F_RCV_DSCP_COPY - Receive DSCP copy 4743 * @property {number} IP6_TNL_F_USE_ORIG_FLOWLABEL - Use original flow label 4744 * @property {number} IP6_TNL_F_USE_ORIG_FWMARK - Use original firewall mark 4745 * @property {number} IP6_TNL_F_USE_ORIG_TCLASS - Use original traffic class 4746 */ 4747 ADD_CONST(IP6_TNL_F_ALLOW_LOCAL_REMOTE); 4748 ADD_CONST(IP6_TNL_F_IGN_ENCAP_LIMIT); 4749 ADD_CONST(IP6_TNL_F_MIP6_DEV); 4750 ADD_CONST(IP6_TNL_F_RCV_DSCP_COPY); 4751 ADD_CONST(IP6_TNL_F_USE_ORIG_FLOWLABEL); 4752 ADD_CONST(IP6_TNL_F_USE_ORIG_FWMARK); 4753 ADD_CONST(IP6_TNL_F_USE_ORIG_TCLASS); 4754 4755 /** 4756 * @typedef 4757 * @name Interface flags 4758 * @property {number} NTF_EXT_LEARNED - Externally learned 4759 * @property {number} NTF_MASTER - Master interface 4760 * @property {number} NTF_OFFLOADED - Offloaded 4761 * @property {number} NTF_PROXY - Proxy 4762 * @property {number} NTF_ROUTER - Router 4763 * @property {number} NTF_SELF - Self 4764 * @property {number} NTF_STICKY - Sticky 4765 * @property {number} NTF_USE - Use 4766 */ 4767 ADD_CONST(NTF_EXT_LEARNED); 4768 ADD_CONST(NTF_MASTER); 4769 ADD_CONST(NTF_OFFLOADED); 4770 ADD_CONST(NTF_PROXY); 4771 ADD_CONST(NTF_ROUTER); 4772 ADD_CONST(NTF_SELF); 4773 ADD_CONST(NTF_STICKY); 4774 ADD_CONST(NTF_USE); 4775 4776 /** 4777 * @typedef 4778 * @name Neighbor states 4779 * @property {number} NUD_DELAY - Delay state 4780 * @property {number} NUD_FAILED - Failed state 4781 * @property {number} NUD_INCOMPLETE - Incomplete state 4782 * @property {number} NUD_NOARP - No ARP 4783 * @property {number} NUD_NONE - No state 4784 * @property {number} NUD_PERMANENT - Permanent state 4785 * @property {number} NUD_PROBE - Probe state 4786 * @property {number} NUD_REACHABLE - Reachable state 4787 * @property {number} NUD_STALE - Stale state 4788 */ 4789 ADD_CONST(NUD_DELAY); 4790 ADD_CONST(NUD_FAILED); 4791 ADD_CONST(NUD_INCOMPLETE); 4792 ADD_CONST(NUD_NOARP); 4793 ADD_CONST(NUD_NONE); 4794 ADD_CONST(NUD_PERMANENT); 4795 ADD_CONST(NUD_PROBE); 4796 ADD_CONST(NUD_REACHABLE); 4797 ADD_CONST(NUD_STALE); 4798 4799 /** 4800 * @typedef 4801 * @name Address flags 4802 * @property {number} IFA_F_DADFAILED - DAD failed 4803 * @property {number} IFA_F_DEPRECATED - Deprecated 4804 * @property {number} IFA_F_HOMEADDRESS - Home address 4805 * @property {number} IFA_F_MANAGETEMPADDR - Manage temporary address 4806 * @property {number} IFA_F_MCAUTOJOIN - Multicast auto join 4807 * @property {number} IFA_F_NODAD - No DAD 4808 * @property {number} IFA_F_NOPREFIXROUTE - No prefix route 4809 * @property {number} IFA_F_OPTIMISTIC - Optimistic 4810 * @property {number} IFA_F_PERMANENT - Permanent 4811 * @property {number} IFA_F_SECONDARY - Secondary 4812 * @property {number} IFA_F_STABLE_PRIVACY - Stable privacy 4813 * @property {number} IFA_F_TEMPORARY - Temporary 4814 * @property {number} IFA_F_TENTATIVE - Tentative 4815 */ 4816 ADD_CONST(IFA_F_DADFAILED); 4817 ADD_CONST(IFA_F_DEPRECATED); 4818 ADD_CONST(IFA_F_HOMEADDRESS); 4819 ADD_CONST(IFA_F_MANAGETEMPADDR); 4820 ADD_CONST(IFA_F_MCAUTOJOIN); 4821 ADD_CONST(IFA_F_NODAD); 4822 ADD_CONST(IFA_F_NOPREFIXROUTE); 4823 ADD_CONST(IFA_F_OPTIMISTIC); 4824 ADD_CONST(IFA_F_PERMANENT); 4825 ADD_CONST(IFA_F_SECONDARY); 4826 ADD_CONST(IFA_F_STABLE_PRIVACY); 4827 ADD_CONST(IFA_F_TEMPORARY); 4828 ADD_CONST(IFA_F_TENTATIVE); 4829 4830 /** 4831 * @typedef 4832 * @name FIB rule flags 4833 * @property {number} FIB_RULE_PERMANENT - Permanent rule 4834 * @property {number} FIB_RULE_INVERT - Invert rule 4835 * @property {number} FIB_RULE_UNRESOLVED - Unresolved rule 4836 * @property {number} FIB_RULE_IIF_DETACHED - Interface detached 4837 * @property {number} FIB_RULE_DEV_DETACHED - Device detached 4838 * @property {number} FIB_RULE_OIF_DETACHED - Output interface detached 4839 */ 4840 ADD_CONST(FIB_RULE_PERMANENT); 4841 ADD_CONST(FIB_RULE_INVERT); 4842 ADD_CONST(FIB_RULE_UNRESOLVED); 4843 ADD_CONST(FIB_RULE_IIF_DETACHED); 4844 ADD_CONST(FIB_RULE_DEV_DETACHED); 4845 ADD_CONST(FIB_RULE_OIF_DETACHED); 4846 4847 /** 4848 * @typedef 4849 * @name FIB rule actions 4850 * @property {number} FR_ACT_TO_TBL - To table action 4851 * @property {number} FR_ACT_GOTO - Goto action 4852 * @property {number} FR_ACT_NOP - No operation action 4853 * @property {number} FR_ACT_BLACKHOLE - Blackhole action 4854 * @property {number} FR_ACT_UNREACHABLE - Unreachable action 4855 * @property {number} FR_ACT_PROHIBIT - Prohibit action 4856 */ 4857 ADD_CONST(FR_ACT_TO_TBL); 4858 ADD_CONST(FR_ACT_GOTO); 4859 ADD_CONST(FR_ACT_NOP); 4860 ADD_CONST(FR_ACT_BLACKHOLE); 4861 ADD_CONST(FR_ACT_UNREACHABLE); 4862 ADD_CONST(FR_ACT_PROHIBIT); 4863 4864 /** 4865 * @typedef 4866 * @name Network configuration indices 4867 * @property {number} NETCONFA_IFINDEX_ALL - All interfaces 4868 * @property {number} NETCONFA_IFINDEX_DEFAULT - Default interface 4869 */ 4870 ADD_CONST(NETCONFA_IFINDEX_ALL); 4871 ADD_CONST(NETCONFA_IFINDEX_DEFAULT); 4872 4873 /** 4874 * @typedef 4875 * @name Bridge flags 4876 * @property {number} BRIDGE_FLAGS_MASTER - Master flag 4877 * @property {number} BRIDGE_FLAGS_SELF - Self flag 4878 */ 4879 ADD_CONST(BRIDGE_FLAGS_MASTER); 4880 ADD_CONST(BRIDGE_FLAGS_SELF); 4881 4882 /** 4883 * @typedef 4884 * @name Bridge modes 4885 * @property {number} BRIDGE_MODE_VEB - Virtual Ethernet Bridge mode 4886 * @property {number} BRIDGE_MODE_VEPA - Virtual Ethernet Port Aggregator mode 4887 * @property {number} BRIDGE_MODE_UNDEF - Undefined mode 4888 * @property {number} BRIDGE_MODE_UNSPEC - Unspecified mode 4889 * @property {number} BRIDGE_MODE_HAIRPIN - Hairpin mode 4890 */ 4891 ADD_CONST(BRIDGE_MODE_VEB); 4892 ADD_CONST(BRIDGE_MODE_VEPA); 4893 ADD_CONST(BRIDGE_MODE_UNDEF); 4894 ADD_CONST(BRIDGE_MODE_UNSPEC); 4895 ADD_CONST(BRIDGE_MODE_HAIRPIN); 4896 4897 /** 4898 * @typedef 4899 * @name Bridge VLAN information flags 4900 * @property {number} BRIDGE_VLAN_INFO_MASTER - Master VLAN info 4901 * @property {number} BRIDGE_VLAN_INFO_PVID - Primary VLAN ID 4902 * @property {number} BRIDGE_VLAN_INFO_UNTAGGED - Untagged VLAN 4903 * @property {number} BRIDGE_VLAN_INFO_RANGE_BEGIN - Range begin 4904 * @property {number} BRIDGE_VLAN_INFO_RANGE_END - Range end 4905 * @property {number} BRIDGE_VLAN_INFO_BRENTRY - Bridge entry 4906 */ 4907 ADD_CONST(BRIDGE_VLAN_INFO_MASTER); 4908 ADD_CONST(BRIDGE_VLAN_INFO_PVID); 4909 ADD_CONST(BRIDGE_VLAN_INFO_UNTAGGED); 4910 ADD_CONST(BRIDGE_VLAN_INFO_RANGE_BEGIN); 4911 ADD_CONST(BRIDGE_VLAN_INFO_RANGE_END); 4912 ADD_CONST(BRIDGE_VLAN_INFO_BRENTRY); 4913 4914 ucv_object_add(scope, "const", c); 4915 }; 4916 4917 static const uc_function_list_t global_fns[] = { 4918 { "error", uc_nl_error }, 4919 { "request", uc_nl_request }, 4920 { "listener", uc_nl_listener }, 4921 }; 4922 4923 static const uc_function_list_t listener_fns[] = { 4924 { "set_commands", uc_nl_listener_set_commands }, 4925 { "close", uc_nl_listener_close }, 4926 }; 4927 4928 void uc_module_init(uc_vm_t *vm, uc_value_t *scope) 4929 { 4930 uc_function_list_register(scope, global_fns); 4931 4932 listener_type = uc_type_declare(vm, "rtnl.listener", listener_fns, uc_nl_listener_free); 4933 listener_registry = ucv_array_new(vm); 4934 4935 uc_vm_registry_set(vm, "rtnl.registry", listener_registry); 4936 4937 register_constants(vm, scope); 4938 } 4939
This page was automatically generated by LXR 0.3.1. • OpenWrt