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