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