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