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