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 if (ucv_type(val) == UC_STRING) { 2778 nla_put(msg, attr, ucv_string_length(val), ucv_string_get(val)); 2779 } 2780 else { 2781 s = ucv_to_string(vm, val); 2782 2783 if (!s) 2784 return nla_parse_error(spec, vm, val, "out of memory"); 2785 2786 nla_put_string(msg, attr, s); 2787 free(s); 2788 } 2789 2790 break; 2791 2792 case DT_NETDEV: 2793 if (ucv_type(val) == UC_INTEGER) { 2794 if (ucv_int64_get(val) < 0 || 2795 ucv_int64_get(val) > UINT32_MAX) 2796 return nla_parse_error(spec, vm, val, "interface index out of range 0-4294967295"); 2797 2798 u32 = (uint32_t)ucv_int64_get(val); 2799 } 2800 else { 2801 s = ucv_to_string(vm, val); 2802 2803 if (!s) 2804 return nla_parse_error(spec, vm, val, "out of memory"); 2805 2806 u32 = if_nametoindex(s); 2807 2808 free(s); 2809 } 2810 2811 if (u32 == 0 && !(spec->flags & DF_ALLOW_NONE)) 2812 return nla_parse_error(spec, vm, val, "interface not found"); 2813 2814 if (spec->attr == 0) 2815 uc_nl_put_struct_member_u32(base, spec->auxdata, u32); 2816 else 2817 nla_put_u32(msg, attr, u32); 2818 2819 break; 2820 2821 case DT_LLADDR: 2822 assert(spec->attr != 0); 2823 2824 s = ucv_to_string(vm, val); 2825 2826 if (!s) 2827 return nla_parse_error(spec, vm, val, "out of memory"); 2828 2829 ea = ether_aton(s); 2830 2831 free(s); 2832 2833 if (!ea) 2834 return nla_parse_error(spec, vm, val, "invalid MAC address"); 2835 2836 nla_put(msg, attr, sizeof(*ea), ea); 2837 2838 break; 2839 2840 case DT_U64ADDR: 2841 assert(spec->attr != 0); 2842 2843 if (ucv_type(val) == UC_INTEGER) { 2844 u64 = ucv_uint64_get(val); 2845 } 2846 else { 2847 s = ucv_to_string(vm, val); 2848 2849 if (!s) 2850 return nla_parse_error(spec, vm, val, "out of memory"); 2851 2852 u16 = addr64_pton(s, &u64); 2853 2854 free(s); 2855 2856 if (u16 != 1) 2857 return nla_parse_error(spec, vm, val, "invalid address"); 2858 } 2859 2860 nla_put_u64(msg, attr, u64); 2861 2862 break; 2863 2864 case DT_INADDR: 2865 case DT_IN6ADDR: 2866 case DT_MPLSADDR: 2867 case DT_ANYADDR: 2868 assert(spec->attr != 0); 2869 2870 rtg = nlmsg_data(nlmsg_hdr(msg)); 2871 2872 if (!uc_nl_parse_cidr(vm, val, &cidr)) 2873 return nla_parse_error(spec, vm, val, "invalid IP address"); 2874 2875 if ((spec->type == DT_INADDR && cidr.family != AF_INET) || 2876 (spec->type == DT_IN6ADDR && cidr.family != AF_INET6) || 2877 (spec->type == DT_MPLSADDR && cidr.family != AF_MPLS)) 2878 return nla_parse_error(spec, vm, val, "wrong address family"); 2879 2880 if (spec->flags & DF_STORE_MASK) 2881 uc_nl_put_struct_member_u8(base, spec->auxdata, cidr.mask); 2882 else if (cidr.mask != cidr.bitlen) 2883 return nla_parse_error(spec, vm, val, "address range given but single address expected"); 2884 2885 nla_put(msg, attr, cidr.alen, &cidr.addr.in6); 2886 2887 if ((rtg->rtgen_family == AF_UNSPEC) && (spec->flags & DF_FAMILY_HINT)) 2888 rtg->rtgen_family = cidr.family; 2889 2890 break; 2891 2892 case DT_MULTIPATH: 2893 if (!uc_nl_parse_rta_multipath(spec, msg, base, vm, val)) 2894 return nla_parse_error(spec, vm, val, "invalid nexthop data"); 2895 2896 break; 2897 2898 case DT_NUMRANGE: 2899 if (!uc_nl_parse_rta_numrange(spec, msg, base, vm, val)) 2900 return false; 2901 2902 break; 2903 2904 case DT_FLAGS: 2905 if (ucv_array_length(val) == 2) { 2906 if (ucv_type(ucv_array_get(val, 0)) != UC_INTEGER || 2907 ucv_type(ucv_array_get(val, 1)) != UC_INTEGER) 2908 return nla_parse_error(spec, vm, val, "flag or mask value not an integer"); 2909 2910 if (!uc_nl_parse_u32(ucv_array_get(val, 0), &u32)) 2911 return nla_parse_error(spec, vm, val, "flag value not an integer or out of range 0-4294967295"); 2912 2913 memcpy(&u64, &u32, sizeof(u32)); 2914 2915 if (!uc_nl_parse_u32(ucv_array_get(val, 1), &u32)) 2916 return nla_parse_error(spec, vm, val, "mask value not an integer or out of range 0-4294967295"); 2917 2918 memcpy((char *)&u64 + sizeof(u32), &u32, sizeof(u32)); 2919 } 2920 else if (ucv_type(val) == UC_INTEGER) { 2921 if (!uc_nl_parse_u32(val, &u32)) 2922 return nla_parse_error(spec, vm, val, "flag value not an integer or out of range 0-4294967295"); 2923 2924 memcpy(&u64, &u32, sizeof(u32)); 2925 memset((char *)&u64 + sizeof(u32), 0xff, sizeof(u32)); 2926 } 2927 else { 2928 return nla_parse_error(spec, vm, val, "value neither an array of flags, mask nor an integer"); 2929 } 2930 2931 if (spec->attr == 0) 2932 uc_nl_put_struct_member(base, spec->auxdata, sizeof(u64), &u64); 2933 else 2934 nla_put_u64(msg, attr, u64); 2935 2936 break; 2937 2938 case DT_LINKINFO: 2939 if (!uc_nl_parse_rta_linkinfo(spec, msg, base, vm, val)) 2940 return false; 2941 2942 break; 2943 2944 case DT_SRH: 2945 if (!uc_nl_parse_rta_srh(spec, msg, base, vm, val)) 2946 return false; 2947 2948 break; 2949 2950 case DT_ENCAP: 2951 if (!uc_nl_parse_rta_encap(spec, msg, base, vm, val)) 2952 return false; 2953 2954 break; 2955 2956 case DT_IPOPTS: 2957 if (!uc_nl_parse_rta_ipopts(spec, msg, base, vm, val)) 2958 return false; 2959 2960 break; 2961 2962 case DT_AFSPEC: 2963 if (!uc_nl_parse_rta_afspec(spec, msg, base, vm, val)) 2964 return false; 2965 2966 break; 2967 2968 case DT_U32_OR_MEMBER: 2969 if (!uc_nl_parse_rta_u32_or_member(spec, msg, base, vm, val)) 2970 return false; 2971 2972 break; 2973 2974 case DT_NESTED: 2975 if (!uc_nl_parse_rta_nested(spec, msg, base, vm, val)) 2976 return false; 2977 2978 break; 2979 2980 default: 2981 assert(0); 2982 } 2983 2984 return true; 2985 } 2986 2987 static uc_value_t * 2988 uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr **tb, uc_vm_t *vm) 2989 { 2990 union { uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; size_t sz; } t = { 0 }; 2991 struct { uint32_t flags; uint32_t mask; } flags; 2992 char buf[sizeof(struct mpls_label) * 16]; 2993 struct nlmsghdr *hdr = nlmsg_hdr(msg); 2994 struct rtgenmsg *rtg = nlmsg_data(hdr); 2995 struct ether_addr *ea; 2996 uc_value_t *v; 2997 char *s; 2998 2999 switch (spec->type) { 3000 case DT_U8: 3001 if (spec->attr == 0) 3002 t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); 3003 else if (nla_check_len(tb[spec->attr], sizeof(t.u8))) 3004 t.u8 = nla_get_u8(tb[spec->attr]); 3005 3006 return ucv_uint64_new(t.u8); 3007 3008 case DT_U16: 3009 if (spec->attr == 0) 3010 t.u16 = uc_nl_get_struct_member_u16(base, spec->auxdata); 3011 else if (nla_check_len(tb[spec->attr], sizeof(t.u16))) 3012 t.u16 = nla_get_u16(tb[spec->attr]); 3013 3014 if (spec->flags & DF_BYTESWAP) 3015 t.u16 = ntohs(t.u16); 3016 3017 return ucv_uint64_new(t.u16); 3018 3019 case DT_U32: 3020 case DT_S32: 3021 if (spec->attr == 0) 3022 t.u32 = uc_nl_get_struct_member_u32(base, spec->auxdata); 3023 else if (nla_check_len(tb[spec->attr], sizeof(t.u32))) 3024 t.u32 = nla_get_u32(tb[spec->attr]); 3025 3026 if (spec->flags & DF_BYTESWAP) 3027 t.u32 = ntohl(t.u32); 3028 3029 if (spec->type == DT_S32) 3030 return ucv_int64_new((int32_t)t.u32); 3031 3032 return ucv_uint64_new(t.u32); 3033 3034 case DT_U64: 3035 if (spec->attr == 0) 3036 t.u64 = uc_nl_get_struct_member_u64(base, spec->auxdata); 3037 else if (nla_check_len(tb[spec->attr], sizeof(t.u64))) 3038 memcpy(&t.u64, nla_data(tb[spec->attr]), sizeof(t.u64)); 3039 3040 return ucv_uint64_new(t.u64); 3041 3042 case DT_BOOL: 3043 if (spec->attr == 0) 3044 t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); 3045 else if (nla_check_len(tb[spec->attr], sizeof(t.u8))) 3046 t.u8 = nla_get_u8(tb[spec->attr]); 3047 3048 return ucv_boolean_new(t.u8 != 0); 3049 3050 case DT_FLAG: 3051 if (spec->attr == 0) 3052 t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); 3053 else if (tb[spec->attr] != NULL) 3054 t.u8 = 1; 3055 3056 return ucv_boolean_new(t.u8 != 0); 3057 3058 case DT_STRING: 3059 assert(spec->attr != 0); 3060 3061 if (!nla_check_len(tb[spec->attr], 1)) 3062 return NULL; 3063 3064 return ucv_string_new_length( 3065 nla_data(tb[spec->attr]), nla_len(tb[spec->attr]) - 1); 3066 3067 case DT_NETDEV: 3068 if (spec->attr == 0) 3069 t.u32 = uc_nl_get_struct_member_u32(base, spec->auxdata); 3070 else if (nla_check_len(tb[spec->attr], sizeof(t.u32))) 3071 t.u32 = nla_get_u32(tb[spec->attr]); 3072 3073 if (if_indextoname(t.u32, buf)) 3074 return ucv_string_new(buf); 3075 else if (spec->flags & DF_ALLOW_NONE) 3076 return ucv_int64_new(0); 3077 3078 return NULL; 3079 3080 case DT_LLADDR: 3081 assert(spec->attr != 0); 3082 3083 if (!nla_check_len(tb[spec->attr], sizeof(*ea))) 3084 return NULL; 3085 3086 ea = nla_data(tb[spec->attr]); 3087 3088 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", 3089 ea->ether_addr_octet[0], ea->ether_addr_octet[1], 3090 ea->ether_addr_octet[2], ea->ether_addr_octet[3], 3091 ea->ether_addr_octet[4], ea->ether_addr_octet[5]); 3092 3093 return ucv_string_new(buf); 3094 3095 case DT_U64ADDR: 3096 assert(spec->attr != 0); 3097 3098 if (!nla_check_len(tb[spec->attr], sizeof(uint64_t)) || 3099 !addr64_ntop(nla_data(tb[spec->attr]), buf, sizeof(buf))) 3100 return NULL; 3101 3102 return ucv_string_new(buf); 3103 3104 case DT_INADDR: 3105 case DT_IN6ADDR: 3106 case DT_MPLSADDR: 3107 case DT_ANYADDR: 3108 assert(spec->attr != 0); 3109 3110 t.sz = (size_t)nla_len(tb[spec->attr]); 3111 3112 switch (spec->type) { 3113 case DT_INADDR: 3114 if (t.sz < sizeof(struct in_addr) || 3115 !inet_ntop(AF_INET, nla_data(tb[spec->attr]), buf, sizeof(buf))) 3116 return NULL; 3117 3118 break; 3119 3120 case DT_IN6ADDR: 3121 if (t.sz < sizeof(struct in6_addr) || 3122 !inet_ntop(AF_INET6, nla_data(tb[spec->attr]), buf, sizeof(buf))) 3123 return NULL; 3124 3125 break; 3126 3127 case DT_MPLSADDR: 3128 if (t.sz < sizeof(struct mpls_label) || 3129 !mpls_ntop(nla_data(tb[spec->attr]), t.sz, buf, sizeof(buf))) 3130 return NULL; 3131 3132 break; 3133 3134 default: 3135 switch (rtg->rtgen_family) { 3136 case AF_MPLS: 3137 if (t.sz < sizeof(struct mpls_label) || 3138 !mpls_ntop(nla_data(tb[spec->attr]), t.sz, buf, sizeof(buf))) 3139 return NULL; 3140 3141 break; 3142 3143 case AF_INET6: 3144 if (t.sz < sizeof(struct in6_addr) || 3145 !inet_ntop(AF_INET6, nla_data(tb[spec->attr]), buf, sizeof(buf))) 3146 return NULL; 3147 3148 break; 3149 3150 case AF_INET: 3151 if (t.sz < sizeof(struct in_addr) || 3152 !inet_ntop(AF_INET, nla_data(tb[spec->attr]), buf, sizeof(buf))) 3153 return NULL; 3154 3155 break; 3156 3157 default: 3158 return NULL; 3159 } 3160 3161 break; 3162 } 3163 3164 if (spec->flags & DF_STORE_MASK) { 3165 s = buf + strlen(buf); 3166 snprintf(s, buf + sizeof(buf) - s, "/%hhu", 3167 uc_nl_get_struct_member_u8(base, spec->auxdata)); 3168 } 3169 3170 return ucv_string_new(buf); 3171 3172 case DT_MULTIPATH: 3173 return uc_nl_convert_rta_multipath(spec, msg, tb, vm); 3174 3175 case DT_NUMRANGE: 3176 return uc_nl_convert_rta_numrange(spec, msg, tb, vm); 3177 3178 case DT_FLAGS: 3179 if (spec->attr == 0) 3180 uc_nl_get_struct_member(base, spec->auxdata, sizeof(flags), &flags); 3181 else if (nla_check_len(tb[spec->attr], sizeof(flags))) 3182 memcpy(&flags, nla_data(tb[spec->attr]), sizeof(flags)); 3183 else 3184 return NULL; 3185 3186 if (flags.mask == 0) 3187 return ucv_uint64_new(flags.flags); 3188 3189 v = ucv_array_new(vm); 3190 3191 ucv_array_push(v, ucv_uint64_new(flags.flags)); 3192 ucv_array_push(v, ucv_uint64_new(flags.mask)); 3193 3194 return v; 3195 3196 case DT_LINKINFO: 3197 return uc_nl_convert_rta_linkinfo(spec, msg, tb, vm); 3198 3199 case DT_BRIDGEID: 3200 return uc_nl_convert_rta_bridgeid(spec, msg, tb, vm); 3201 3202 case DT_SRH: 3203 return uc_nl_convert_rta_srh(spec, msg, tb, vm); 3204 3205 case DT_ENCAP: 3206 return uc_nl_convert_rta_encap(spec, msg, tb, vm); 3207 3208 case DT_IPOPTS: 3209 return uc_nl_convert_rta_ipopts(spec, msg, tb, vm); 3210 3211 case DT_AFSPEC: 3212 return uc_nl_convert_rta_afspec(spec, msg, tb, vm); 3213 3214 case DT_U32_OR_MEMBER: 3215 return uc_nl_convert_rta_u32_or_member(spec, msg, base, tb, vm); 3216 3217 case DT_NESTED: 3218 return uc_nl_convert_rta_nested(spec, msg, tb, vm); 3219 3220 default: 3221 assert(0); 3222 } 3223 3224 return NULL; 3225 } 3226 3227 3228 static struct nl_sock *sock = NULL; 3229 static struct { 3230 struct nl_sock *evsock; 3231 struct uloop_fd evsock_fd; 3232 uint32_t groups[RTNL_GRPS_BITMAP_SIZE]; 3233 } nl_conn; 3234 3235 typedef enum { 3236 STATE_UNREPLIED, 3237 STATE_CONTINUE, 3238 STATE_REPLIED, 3239 STATE_ERROR 3240 } reply_state_t; 3241 3242 typedef struct { 3243 reply_state_t state; 3244 uc_vm_t *vm; 3245 uc_value_t *res; 3246 int family; 3247 const uc_nl_nested_spec_t *spec; 3248 } request_state_t; 3249 3250 3251 static uc_value_t * 3252 uc_nl_error(uc_vm_t *vm, size_t nargs) 3253 { 3254 uc_stringbuf_t *buf; 3255 const char *s; 3256 3257 if (last_error.code == 0) 3258 return NULL; 3259 3260 buf = ucv_stringbuf_new(); 3261 3262 if (last_error.code == NLE_FAILURE && last_error.msg) { 3263 ucv_stringbuf_addstr(buf, last_error.msg, strlen(last_error.msg)); 3264 } 3265 else { 3266 s = nl_geterror(last_error.code); 3267 3268 ucv_stringbuf_addstr(buf, s, strlen(s)); 3269 3270 if (last_error.msg) 3271 ucv_stringbuf_printf(buf, ": %s", last_error.msg); 3272 } 3273 3274 set_error(0, NULL); 3275 3276 return ucv_stringbuf_finish(buf); 3277 } 3278 3279 /* 3280 * route functions 3281 */ 3282 3283 static int 3284 cb_done(struct nl_msg *msg, void *arg) 3285 { 3286 request_state_t *s = arg; 3287 3288 s->state = STATE_REPLIED; 3289 3290 return NL_STOP; 3291 } 3292 3293 static int 3294 cb_error(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) 3295 { 3296 request_state_t *s = arg; 3297 int errnum = err->error; 3298 3299 set_error(NLE_FAILURE, "RTNETLINK answers: %s", 3300 strerror(errnum < 0 ? -errnum : errnum)); 3301 3302 s->state = STATE_ERROR; 3303 3304 return NL_STOP; 3305 } 3306 3307 static int 3308 cb_reply(struct nl_msg *msg, void *arg) 3309 { 3310 struct nlmsghdr *hdr = nlmsg_hdr(msg); 3311 request_state_t *s = arg; 3312 uc_value_t *o; 3313 bool rv; 3314 3315 if (RTM_FAM(hdr->nlmsg_type) != s->family) 3316 return NL_SKIP; 3317 3318 if (s->spec) { 3319 if (nlmsg_attrlen(hdr, 0) < (ssize_t)s->spec->headsize) 3320 return NL_SKIP; 3321 3322 o = ucv_object_new(s->vm); 3323 3324 rv = uc_nl_convert_attrs(msg, 3325 nlmsg_attrdata(hdr, 0), 3326 nlmsg_attrlen(hdr, 0), 3327 s->spec->headsize, 3328 s->spec->attrs, s->spec->nattrs, s->vm, o); 3329 3330 if (rv) { 3331 if (hdr->nlmsg_flags & NLM_F_MULTI) { 3332 if (!s->res) 3333 s->res = ucv_array_new(s->vm); 3334 3335 ucv_array_push(s->res, o); 3336 } 3337 else { 3338 s->res = o; 3339 } 3340 } 3341 else { 3342 ucv_put(o); 3343 } 3344 } 3345 3346 s->state = STATE_CONTINUE; 3347 3348 return NL_SKIP; 3349 } 3350 3351 3352 static const struct { 3353 int family; 3354 const uc_nl_nested_spec_t *spec; 3355 } rtm_families[] = { 3356 { RTM_FAM(RTM_GETLINK), &link_msg }, 3357 { RTM_FAM(RTM_GETROUTE), &route_msg }, 3358 { RTM_FAM(RTM_GETNEIGH), &neigh_msg }, 3359 { RTM_FAM(RTM_GETADDR), &addr_msg }, 3360 { RTM_FAM(RTM_GETRULE), &rule_msg }, 3361 { RTM_FAM(RTM_GETADDRLABEL), &addrlabel_msg }, 3362 { RTM_FAM(RTM_GETNEIGHTBL), &neightbl_msg }, 3363 { RTM_FAM(RTM_GETNETCONF), &netconf_msg }, 3364 }; 3365 3366 static uc_value_t * 3367 uc_nl_request(uc_vm_t *vm, size_t nargs) 3368 { 3369 uc_value_t *cmd = uc_fn_arg(0); 3370 uc_value_t *flags = uc_fn_arg(1); 3371 uc_value_t *payload = uc_fn_arg(2); 3372 request_state_t st = { .vm = vm }; 3373 uint16_t flagval = 0; 3374 struct nl_msg *msg; 3375 struct nl_cb *cb; 3376 socklen_t optlen; 3377 int enable, err; 3378 void *buf; 3379 size_t i; 3380 3381 if (ucv_type(cmd) != UC_INTEGER || ucv_int64_get(cmd) < 0 || 3382 (flags != NULL && ucv_type(flags) != UC_INTEGER) || 3383 (payload != NULL && ucv_type(payload) != UC_OBJECT)) 3384 err_return(NLE_INVAL, NULL); 3385 3386 if (flags) { 3387 if (ucv_int64_get(flags) < 0 || ucv_int64_get(flags) > 0xffff) 3388 err_return(NLE_INVAL, NULL); 3389 else 3390 flagval = (uint16_t)ucv_int64_get(flags); 3391 } 3392 3393 for (i = 0; i < ARRAY_SIZE(rtm_families); i++) { 3394 if (rtm_families[i].family == RTM_FAM(ucv_int64_get(cmd))) { 3395 st.spec = rtm_families[i].spec; 3396 st.family = rtm_families[i].family; 3397 break; 3398 } 3399 } 3400 3401 if (!sock) { 3402 sock = nl_socket_alloc(); 3403 3404 if (!sock) 3405 err_return(NLE_NOMEM, NULL); 3406 3407 err = nl_connect(sock, NETLINK_ROUTE); 3408 3409 if (err != 0) 3410 err_return(err, NULL); 3411 } 3412 3413 optlen = sizeof(enable); 3414 3415 if (getsockopt(sock->s_fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &enable, &optlen) < 0) 3416 enable = 0; 3417 3418 if (!!(flagval & NLM_F_STRICT_CHK) != enable) { 3419 enable = !!(flagval & NLM_F_STRICT_CHK); 3420 3421 if (setsockopt(sock->s_fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &enable, sizeof(enable)) < 0) 3422 err_return(nl_syserr2nlerr(errno), "Unable to toggle NETLINK_GET_STRICT_CHK"); 3423 } 3424 3425 msg = nlmsg_alloc_simple(ucv_int64_get(cmd), NLM_F_REQUEST | (flagval & ~NLM_F_STRICT_CHK)); 3426 3427 if (!msg) 3428 err_return(NLE_NOMEM, NULL); 3429 3430 if (st.spec) { 3431 if (st.spec->headsize) { 3432 buf = nlmsg_reserve(msg, st.spec->headsize, 0); 3433 3434 if (!buf) { 3435 nlmsg_free(msg); 3436 3437 return NULL; 3438 } 3439 3440 memset(buf, 0, st.spec->headsize); 3441 } 3442 3443 if (!uc_nl_parse_attrs(msg, NLMSG_DATA(nlmsg_hdr(msg)), st.spec->attrs, st.spec->nattrs, vm, payload)) { 3444 nlmsg_free(msg); 3445 3446 return NULL; 3447 } 3448 } 3449 3450 cb = nl_cb_alloc(NL_CB_DEFAULT); 3451 3452 if (!cb) { 3453 nlmsg_free(msg); 3454 err_return(NLE_NOMEM, NULL); 3455 } 3456 3457 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_reply, &st); 3458 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &st); 3459 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_done, &st); 3460 nl_cb_err(cb, NL_CB_CUSTOM, cb_error, &st); 3461 3462 nl_send_auto_complete(sock, msg); 3463 3464 do { 3465 err = nl_recvmsgs(sock, cb); 3466 3467 if (err && st.state != STATE_ERROR) { 3468 set_error(err, NULL); 3469 3470 st.state = STATE_ERROR; 3471 } 3472 } 3473 while (st.state < STATE_REPLIED); 3474 3475 nlmsg_free(msg); 3476 nl_cb_put(cb); 3477 3478 switch (st.state) { 3479 case STATE_REPLIED: 3480 return st.res; 3481 3482 case STATE_UNREPLIED: 3483 return ucv_boolean_new(true); 3484 3485 case STATE_ERROR: 3486 return ucv_boolean_new(false); 3487 3488 default: 3489 set_error(NLE_FAILURE, "Interrupted reply"); 3490 3491 return ucv_boolean_new(false); 3492 } 3493 } 3494 3495 static const uc_nl_nested_spec_t * 3496 uc_nl_msg_spec(int type) 3497 { 3498 switch (type) { 3499 case RTM_NEWLINK: 3500 case RTM_DELLINK: 3501 return &link_msg; 3502 case RTM_NEWROUTE: 3503 case RTM_DELROUTE: 3504 return &route_msg; 3505 case RTM_NEWNEIGH: 3506 case RTM_DELNEIGH: 3507 return &neigh_msg; 3508 case RTM_NEWADDR: 3509 case RTM_DELADDR: 3510 return &addr_msg; 3511 case RTM_NEWRULE: 3512 case RTM_DELRULE: 3513 return &rule_msg; 3514 case RTM_NEWADDRLABEL: 3515 case RTM_DELADDRLABEL: 3516 return &addrlabel_msg; 3517 case RTM_NEWNEIGHTBL: 3518 return &neightbl_msg; 3519 case RTM_NEWNETCONF: 3520 case RTM_DELNETCONF: 3521 return &netconf_msg; 3522 default: 3523 return NULL; 3524 } 3525 } 3526 3527 static void 3528 uc_nl_prepare_event(uc_vm_t *vm, uc_value_t *dest, struct nl_msg *msg) 3529 { 3530 struct nlmsghdr *hdr = nlmsg_hdr(msg); 3531 const uc_nl_nested_spec_t *spec; 3532 const uc_nl_attr_spec_t *attrs = NULL; 3533 size_t nattrs = 0, headsize = 0; 3534 uc_value_t *o; 3535 3536 spec = uc_nl_msg_spec(hdr->nlmsg_type); 3537 if (spec) { 3538 attrs = spec->attrs; 3539 nattrs = spec->nattrs; 3540 headsize = spec->headsize; 3541 } 3542 3543 o = ucv_object_new(vm); 3544 if (!uc_nl_convert_attrs(msg, nlmsg_attrdata(hdr, 0), 3545 nlmsg_attrlen(hdr, 0), headsize, attrs, nattrs, vm, o)) { 3546 ucv_put(o); 3547 return; 3548 } 3549 3550 ucv_object_add(dest, "msg", o); 3551 if (headsize) 3552 ucv_object_add(dest, "head", ucv_string_new_length(NLMSG_DATA(hdr), headsize)); 3553 } 3554 3555 static bool 3556 uc_nl_fill_cmds(uint32_t *cmd_bits, uc_value_t *cmds) 3557 { 3558 if (ucv_type(cmds) == UC_ARRAY) { 3559 for (size_t i = 0; i < ucv_array_length(cmds); i++) { 3560 int64_t n = ucv_int64_get(ucv_array_get(cmds, i)); 3561 3562 if (errno || n < 0 || n >= __RTM_MAX) 3563 return false; 3564 3565 cmd_bits[n / 32] |= (1 << (n % 32)); 3566 } 3567 } 3568 else if (ucv_type(cmds) == UC_INTEGER) { 3569 int64_t n = ucv_int64_get(cmds); 3570 3571 if (errno || n < 0 || n > 255) 3572 return false; 3573 3574 cmd_bits[n / 32] |= (1 << (n % 32)); 3575 } 3576 else if (!cmds) 3577 memset(cmd_bits, 0xff, RTNL_CMDS_BITMAP_SIZE * sizeof(*cmd_bits)); 3578 else 3579 return false; 3580 3581 return true; 3582 } 3583 3584 static int 3585 cb_listener_event(struct nl_msg *msg, void *arg) 3586 { 3587 struct nlmsghdr *hdr = nlmsg_hdr(msg); 3588 uc_vm_t *vm = listener_vm; 3589 int cmd = hdr->nlmsg_type; 3590 3591 if (!nl_conn.evsock_fd.registered || !vm) 3592 return NL_SKIP; 3593 3594 for (size_t i = 0; i < ucv_array_length(listener_registry); i += 2) { 3595 uc_value_t *this = ucv_array_get(listener_registry, i); 3596 uc_value_t *func = ucv_array_get(listener_registry, i + 1); 3597 uc_nl_listener_t *l; 3598 uc_value_t *o; 3599 3600 l = ucv_resource_data(this, "rtnl.listener"); 3601 if (!l) 3602 continue; 3603 3604 if (cmd > __RTM_MAX || !(l->cmds[cmd / 32] & (1 << (cmd % 32)))) 3605 continue; 3606 3607 if (!ucv_is_callable(func)) 3608 continue; 3609 3610 o = ucv_object_new(vm); 3611 uc_nl_prepare_event(vm, o, msg); 3612 ucv_object_add(o, "cmd", ucv_int64_new(cmd)); 3613 3614 uc_vm_stack_push(vm, ucv_get(this)); 3615 uc_vm_stack_push(vm, ucv_get(func)); 3616 uc_vm_stack_push(vm, o); 3617 3618 if (uc_vm_call(vm, true, 1) != EXCEPTION_NONE) { 3619 uloop_end(); 3620 set_error(NLE_FAILURE, "Runtime exception in callback"); 3621 3622 errno = EINVAL; 3623 3624 return NL_STOP; 3625 } 3626 3627 ucv_put(uc_vm_stack_pop(vm)); 3628 } 3629 3630 errno = 0; 3631 3632 return NL_SKIP; 3633 } 3634 3635 static void 3636 uc_nl_listener_cb(struct uloop_fd *fd, unsigned int events) 3637 { 3638 while (true) { 3639 errno = 0; 3640 3641 nl_recvmsgs_default(nl_conn.evsock); 3642 3643 if (errno != 0) 3644 break; 3645 } 3646 } 3647 3648 static void 3649 uc_nl_add_group(unsigned int idx) 3650 { 3651 if (idx >= __RTNLGRP_MAX) 3652 return; 3653 3654 if (nl_conn.groups[idx / 32] & (1 << (idx % 32))) 3655 return; 3656 3657 nl_conn.groups[idx / 32] |= (1 << (idx % 32)); 3658 nl_socket_add_membership(nl_conn.evsock, idx); 3659 } 3660 3661 static bool 3662 uc_nl_evsock_init(void) 3663 { 3664 struct uloop_fd *fd = &nl_conn.evsock_fd; 3665 struct nl_sock *sock; 3666 3667 if (nl_conn.evsock) 3668 return true; 3669 3670 sock = nl_socket_alloc(); 3671 3672 if (nl_connect(sock, NETLINK_ROUTE)) 3673 goto free; 3674 3675 fd->fd = nl_socket_get_fd(sock); 3676 fd->cb = uc_nl_listener_cb; 3677 uloop_fd_add(fd, ULOOP_READ); 3678 3679 nl_socket_set_buffer_size(sock, 1024 * 1024, 0); 3680 nl_socket_disable_seq_check(sock); 3681 nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, cb_listener_event, NULL); 3682 3683 nl_conn.evsock = sock; 3684 3685 return true; 3686 3687 free: 3688 nl_socket_free(sock); 3689 return false; 3690 } 3691 3692 static uc_value_t * 3693 uc_nl_listener(uc_vm_t *vm, size_t nargs) 3694 { 3695 uc_nl_listener_t *l; 3696 uc_value_t *cb_func = uc_fn_arg(0); 3697 uc_value_t *cmds = uc_fn_arg(1); 3698 uc_value_t *groups = uc_fn_arg(2); 3699 uc_value_t *rv; 3700 size_t i; 3701 3702 if (!ucv_is_callable(cb_func)) { 3703 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid callback"); 3704 return NULL; 3705 } 3706 3707 if (!uc_nl_evsock_init()) 3708 return NULL; 3709 3710 if (ucv_type(groups) == UC_ARRAY) { 3711 for (i = 0; i < ucv_array_length(groups); i++) { 3712 int64_t n = ucv_int64_get(ucv_array_get(groups, i)); 3713 3714 if (errno || n < 0 || n >= __RTNLGRP_MAX) 3715 err_return(NLE_INVAL, NULL); 3716 3717 uc_nl_add_group(n); 3718 } 3719 } else { 3720 uc_nl_add_group(RTNLGRP_LINK); 3721 } 3722 3723 for (i = 0; i < ucv_array_length(listener_registry); i += 2) { 3724 if (!ucv_array_get(listener_registry, i)) 3725 break; 3726 } 3727 3728 l = xalloc(sizeof(*l)); 3729 l->index = i; 3730 3731 if (!uc_nl_fill_cmds(l->cmds, cmds)) { 3732 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid command ID"); 3733 free(l); 3734 return NULL; 3735 } 3736 3737 rv = uc_resource_new(listener_type, l); 3738 3739 ucv_array_set(listener_registry, i, ucv_get(rv)); 3740 ucv_array_set(listener_registry, i + 1, ucv_get(cb_func)); 3741 3742 listener_vm = vm; 3743 3744 return rv; 3745 } 3746 3747 static void 3748 uc_nl_listener_free(void *arg) 3749 { 3750 uc_nl_listener_t *l = arg; 3751 3752 ucv_array_set(listener_registry, l->index, NULL); 3753 ucv_array_set(listener_registry, l->index + 1, NULL); 3754 free(l); 3755 } 3756 3757 static uc_value_t * 3758 uc_nl_listener_set_commands(uc_vm_t *vm, size_t nargs) 3759 { 3760 uc_nl_listener_t *l = uc_fn_thisval("rtnl.listener"); 3761 uc_value_t *cmds = uc_fn_arg(0); 3762 3763 if (!l) 3764 return NULL; 3765 3766 memset(l->cmds, 0, sizeof(l->cmds)); 3767 if (!uc_nl_fill_cmds(l->cmds, cmds)) 3768 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid command ID"); 3769 3770 return NULL; 3771 } 3772 3773 static uc_value_t * 3774 uc_nl_listener_close(uc_vm_t *vm, size_t nargs) 3775 { 3776 uc_nl_listener_t **lptr = uc_fn_this("rtnl.listener"); 3777 uc_nl_listener_t *l; 3778 3779 if (!lptr) 3780 return NULL; 3781 3782 l = *lptr; 3783 if (!l) 3784 return NULL; 3785 3786 *lptr = NULL; 3787 uc_nl_listener_free(l); 3788 3789 return NULL; 3790 } 3791 3792 3793 static void 3794 register_constants(uc_vm_t *vm, uc_value_t *scope) 3795 { 3796 uc_value_t *c = ucv_object_new(vm); 3797 3798 #define ADD_CONST(x) ucv_object_add(c, #x, ucv_int64_new(x)) 3799 3800 ADD_CONST(NLM_F_ACK); 3801 ADD_CONST(NLM_F_ACK_TLVS); 3802 ADD_CONST(NLM_F_APPEND); 3803 ADD_CONST(NLM_F_ATOMIC); 3804 ADD_CONST(NLM_F_CAPPED); 3805 ADD_CONST(NLM_F_CREATE); 3806 ADD_CONST(NLM_F_DUMP); 3807 ADD_CONST(NLM_F_DUMP_FILTERED); 3808 ADD_CONST(NLM_F_DUMP_INTR); 3809 ADD_CONST(NLM_F_ECHO); 3810 ADD_CONST(NLM_F_EXCL); 3811 ADD_CONST(NLM_F_MATCH); 3812 ADD_CONST(NLM_F_MULTI); 3813 ADD_CONST(NLM_F_NONREC); 3814 ADD_CONST(NLM_F_REPLACE); 3815 ADD_CONST(NLM_F_REQUEST); 3816 ADD_CONST(NLM_F_ROOT); 3817 ADD_CONST(NLM_F_STRICT_CHK); /* custom */ 3818 3819 ADD_CONST(IN6_ADDR_GEN_MODE_EUI64); 3820 ADD_CONST(IN6_ADDR_GEN_MODE_NONE); 3821 ADD_CONST(IN6_ADDR_GEN_MODE_STABLE_PRIVACY); 3822 ADD_CONST(IN6_ADDR_GEN_MODE_RANDOM); 3823 3824 ADD_CONST(BRIDGE_MODE_UNSPEC); 3825 ADD_CONST(BRIDGE_MODE_HAIRPIN); 3826 3827 ADD_CONST(MACVLAN_MODE_PRIVATE); 3828 ADD_CONST(MACVLAN_MODE_VEPA); 3829 ADD_CONST(MACVLAN_MODE_BRIDGE); 3830 ADD_CONST(MACVLAN_MODE_PASSTHRU); 3831 ADD_CONST(MACVLAN_MODE_SOURCE); 3832 3833 ADD_CONST(MACVLAN_MACADDR_ADD); 3834 ADD_CONST(MACVLAN_MACADDR_DEL); 3835 ADD_CONST(MACVLAN_MACADDR_FLUSH); 3836 ADD_CONST(MACVLAN_MACADDR_SET); 3837 3838 ADD_CONST(MACSEC_VALIDATE_DISABLED); 3839 ADD_CONST(MACSEC_VALIDATE_CHECK); 3840 ADD_CONST(MACSEC_VALIDATE_STRICT); 3841 ADD_CONST(MACSEC_VALIDATE_MAX); 3842 3843 ADD_CONST(MACSEC_OFFLOAD_OFF); 3844 ADD_CONST(MACSEC_OFFLOAD_PHY); 3845 ADD_CONST(MACSEC_OFFLOAD_MAC); 3846 ADD_CONST(MACSEC_OFFLOAD_MAX); 3847 3848 ADD_CONST(IPVLAN_MODE_L2); 3849 ADD_CONST(IPVLAN_MODE_L3); 3850 ADD_CONST(IPVLAN_MODE_L3S); 3851 3852 ADD_CONST(VXLAN_DF_UNSET); 3853 ADD_CONST(VXLAN_DF_SET); 3854 ADD_CONST(VXLAN_DF_INHERIT); 3855 ADD_CONST(VXLAN_DF_MAX); 3856 3857 ADD_CONST(GENEVE_DF_UNSET); 3858 ADD_CONST(GENEVE_DF_SET); 3859 ADD_CONST(GENEVE_DF_INHERIT); 3860 ADD_CONST(GENEVE_DF_MAX); 3861 3862 ADD_CONST(GTP_ROLE_GGSN); 3863 ADD_CONST(GTP_ROLE_SGSN); 3864 3865 ADD_CONST(PORT_REQUEST_PREASSOCIATE); 3866 ADD_CONST(PORT_REQUEST_PREASSOCIATE_RR); 3867 ADD_CONST(PORT_REQUEST_ASSOCIATE); 3868 ADD_CONST(PORT_REQUEST_DISASSOCIATE); 3869 3870 ADD_CONST(PORT_VDP_RESPONSE_SUCCESS); 3871 ADD_CONST(PORT_VDP_RESPONSE_INVALID_FORMAT); 3872 ADD_CONST(PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES); 3873 ADD_CONST(PORT_VDP_RESPONSE_UNUSED_VTID); 3874 ADD_CONST(PORT_VDP_RESPONSE_VTID_VIOLATION); 3875 ADD_CONST(PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION); 3876 ADD_CONST(PORT_VDP_RESPONSE_OUT_OF_SYNC); 3877 ADD_CONST(PORT_PROFILE_RESPONSE_SUCCESS); 3878 ADD_CONST(PORT_PROFILE_RESPONSE_INPROGRESS); 3879 ADD_CONST(PORT_PROFILE_RESPONSE_INVALID); 3880 ADD_CONST(PORT_PROFILE_RESPONSE_BADSTATE); 3881 ADD_CONST(PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES); 3882 ADD_CONST(PORT_PROFILE_RESPONSE_ERROR); 3883 3884 ADD_CONST(IPOIB_MODE_DATAGRAM); 3885 ADD_CONST(IPOIB_MODE_CONNECTED); 3886 3887 ADD_CONST(HSR_PROTOCOL_HSR); 3888 ADD_CONST(HSR_PROTOCOL_PRP); 3889 3890 ADD_CONST(LINK_XSTATS_TYPE_UNSPEC); 3891 ADD_CONST(LINK_XSTATS_TYPE_BRIDGE); 3892 ADD_CONST(LINK_XSTATS_TYPE_BOND); 3893 3894 ADD_CONST(XDP_ATTACHED_NONE); 3895 ADD_CONST(XDP_ATTACHED_DRV); 3896 ADD_CONST(XDP_ATTACHED_SKB); 3897 ADD_CONST(XDP_ATTACHED_HW); 3898 ADD_CONST(XDP_ATTACHED_MULTI); 3899 3900 ADD_CONST(FDB_NOTIFY_BIT); 3901 ADD_CONST(FDB_NOTIFY_INACTIVE_BIT); 3902 3903 ADD_CONST(RTM_BASE); 3904 ADD_CONST(RTM_NEWLINK); 3905 ADD_CONST(RTM_DELLINK); 3906 ADD_CONST(RTM_GETLINK); 3907 ADD_CONST(RTM_SETLINK); 3908 ADD_CONST(RTM_NEWADDR); 3909 ADD_CONST(RTM_DELADDR); 3910 ADD_CONST(RTM_GETADDR); 3911 ADD_CONST(RTM_NEWROUTE); 3912 ADD_CONST(RTM_DELROUTE); 3913 ADD_CONST(RTM_GETROUTE); 3914 ADD_CONST(RTM_NEWNEIGH); 3915 ADD_CONST(RTM_DELNEIGH); 3916 ADD_CONST(RTM_GETNEIGH); 3917 ADD_CONST(RTM_NEWRULE); 3918 ADD_CONST(RTM_DELRULE); 3919 ADD_CONST(RTM_GETRULE); 3920 ADD_CONST(RTM_NEWQDISC); 3921 ADD_CONST(RTM_DELQDISC); 3922 ADD_CONST(RTM_GETQDISC); 3923 ADD_CONST(RTM_NEWTCLASS); 3924 ADD_CONST(RTM_DELTCLASS); 3925 ADD_CONST(RTM_GETTCLASS); 3926 ADD_CONST(RTM_NEWTFILTER); 3927 ADD_CONST(RTM_DELTFILTER); 3928 ADD_CONST(RTM_GETTFILTER); 3929 ADD_CONST(RTM_NEWACTION); 3930 ADD_CONST(RTM_DELACTION); 3931 ADD_CONST(RTM_GETACTION); 3932 ADD_CONST(RTM_NEWPREFIX); 3933 ADD_CONST(RTM_GETMULTICAST); 3934 ADD_CONST(RTM_GETANYCAST); 3935 ADD_CONST(RTM_NEWNEIGHTBL); 3936 ADD_CONST(RTM_GETNEIGHTBL); 3937 ADD_CONST(RTM_SETNEIGHTBL); 3938 ADD_CONST(RTM_NEWNDUSEROPT); 3939 ADD_CONST(RTM_NEWADDRLABEL); 3940 ADD_CONST(RTM_DELADDRLABEL); 3941 ADD_CONST(RTM_GETADDRLABEL); 3942 ADD_CONST(RTM_GETDCB); 3943 ADD_CONST(RTM_SETDCB); 3944 ADD_CONST(RTM_NEWNETCONF); 3945 ADD_CONST(RTM_DELNETCONF); 3946 ADD_CONST(RTM_GETNETCONF); 3947 ADD_CONST(RTM_NEWMDB); 3948 ADD_CONST(RTM_DELMDB); 3949 ADD_CONST(RTM_GETMDB); 3950 ADD_CONST(RTM_NEWNSID); 3951 ADD_CONST(RTM_DELNSID); 3952 ADD_CONST(RTM_GETNSID); 3953 ADD_CONST(RTM_NEWSTATS); 3954 ADD_CONST(RTM_GETSTATS); 3955 ADD_CONST(RTM_NEWCACHEREPORT); 3956 ADD_CONST(RTM_NEWCHAIN); 3957 ADD_CONST(RTM_DELCHAIN); 3958 ADD_CONST(RTM_GETCHAIN); 3959 ADD_CONST(RTM_NEWNEXTHOP); 3960 ADD_CONST(RTM_DELNEXTHOP); 3961 ADD_CONST(RTM_GETNEXTHOP); 3962 ADD_CONST(RTM_NEWLINKPROP); 3963 ADD_CONST(RTM_DELLINKPROP); 3964 ADD_CONST(RTM_GETLINKPROP); 3965 ADD_CONST(RTM_NEWVLAN); 3966 ADD_CONST(RTM_DELVLAN); 3967 ADD_CONST(RTM_GETVLAN); 3968 3969 ADD_CONST(RTN_UNSPEC); 3970 ADD_CONST(RTN_UNICAST); 3971 ADD_CONST(RTN_LOCAL); 3972 ADD_CONST(RTN_BROADCAST); 3973 ADD_CONST(RTN_ANYCAST); 3974 ADD_CONST(RTN_MULTICAST); 3975 ADD_CONST(RTN_BLACKHOLE); 3976 ADD_CONST(RTN_UNREACHABLE); 3977 ADD_CONST(RTN_PROHIBIT); 3978 ADD_CONST(RTN_THROW); 3979 ADD_CONST(RTN_NAT); 3980 ADD_CONST(RTN_XRESOLVE); 3981 3982 ADD_CONST(RT_SCOPE_UNIVERSE); 3983 ADD_CONST(RT_SCOPE_SITE); 3984 ADD_CONST(RT_SCOPE_LINK); 3985 ADD_CONST(RT_SCOPE_HOST); 3986 ADD_CONST(RT_SCOPE_NOWHERE); 3987 3988 ADD_CONST(RT_TABLE_UNSPEC); 3989 ADD_CONST(RT_TABLE_COMPAT); 3990 ADD_CONST(RT_TABLE_DEFAULT); 3991 ADD_CONST(RT_TABLE_MAIN); 3992 ADD_CONST(RT_TABLE_LOCAL); 3993 ADD_CONST(RT_TABLE_MAX); 3994 3995 /* required to construct RTAX_LOCK */ 3996 ADD_CONST(RTAX_MTU); 3997 ADD_CONST(RTAX_HOPLIMIT); 3998 ADD_CONST(RTAX_ADVMSS); 3999 ADD_CONST(RTAX_REORDERING); 4000 ADD_CONST(RTAX_RTT); 4001 ADD_CONST(RTAX_WINDOW); 4002 ADD_CONST(RTAX_CWND); 4003 ADD_CONST(RTAX_INITCWND); 4004 ADD_CONST(RTAX_INITRWND); 4005 ADD_CONST(RTAX_FEATURES); 4006 ADD_CONST(RTAX_QUICKACK); 4007 ADD_CONST(RTAX_CC_ALGO); 4008 ADD_CONST(RTAX_RTTVAR); 4009 ADD_CONST(RTAX_SSTHRESH); 4010 ADD_CONST(RTAX_FASTOPEN_NO_COOKIE); 4011 4012 ADD_CONST(PREFIX_UNSPEC); 4013 ADD_CONST(PREFIX_ADDRESS); 4014 ADD_CONST(PREFIX_CACHEINFO); 4015 4016 ADD_CONST(NDUSEROPT_UNSPEC); 4017 ADD_CONST(NDUSEROPT_SRCADDR); 4018 4019 ADD_CONST(RTNLGRP_NONE); 4020 ADD_CONST(RTNLGRP_LINK); 4021 ADD_CONST(RTNLGRP_NOTIFY); 4022 ADD_CONST(RTNLGRP_NEIGH); 4023 ADD_CONST(RTNLGRP_TC); 4024 ADD_CONST(RTNLGRP_IPV4_IFADDR); 4025 ADD_CONST(RTNLGRP_IPV4_MROUTE); 4026 ADD_CONST(RTNLGRP_IPV4_ROUTE); 4027 ADD_CONST(RTNLGRP_IPV4_RULE); 4028 ADD_CONST(RTNLGRP_IPV6_IFADDR); 4029 ADD_CONST(RTNLGRP_IPV6_MROUTE); 4030 ADD_CONST(RTNLGRP_IPV6_ROUTE); 4031 ADD_CONST(RTNLGRP_IPV6_IFINFO); 4032 ADD_CONST(RTNLGRP_DECnet_IFADDR); 4033 ADD_CONST(RTNLGRP_NOP2); 4034 ADD_CONST(RTNLGRP_DECnet_ROUTE); 4035 ADD_CONST(RTNLGRP_DECnet_RULE); 4036 ADD_CONST(RTNLGRP_NOP4); 4037 ADD_CONST(RTNLGRP_IPV6_PREFIX); 4038 ADD_CONST(RTNLGRP_IPV6_RULE); 4039 ADD_CONST(RTNLGRP_ND_USEROPT); 4040 ADD_CONST(RTNLGRP_PHONET_IFADDR); 4041 ADD_CONST(RTNLGRP_PHONET_ROUTE); 4042 ADD_CONST(RTNLGRP_DCB); 4043 ADD_CONST(RTNLGRP_IPV4_NETCONF); 4044 ADD_CONST(RTNLGRP_IPV6_NETCONF); 4045 ADD_CONST(RTNLGRP_MDB); 4046 ADD_CONST(RTNLGRP_MPLS_ROUTE); 4047 ADD_CONST(RTNLGRP_NSID); 4048 ADD_CONST(RTNLGRP_MPLS_NETCONF); 4049 ADD_CONST(RTNLGRP_IPV4_MROUTE_R); 4050 ADD_CONST(RTNLGRP_IPV6_MROUTE_R); 4051 ADD_CONST(RTNLGRP_NEXTHOP); 4052 ADD_CONST(RTNLGRP_BRVLAN); 4053 4054 ADD_CONST(RTM_F_CLONED); 4055 ADD_CONST(RTM_F_EQUALIZE); 4056 ADD_CONST(RTM_F_FIB_MATCH); 4057 ADD_CONST(RTM_F_LOOKUP_TABLE); 4058 ADD_CONST(RTM_F_NOTIFY); 4059 ADD_CONST(RTM_F_PREFIX); 4060 4061 ADD_CONST(AF_UNSPEC); 4062 ADD_CONST(AF_INET); 4063 ADD_CONST(AF_INET6); 4064 ADD_CONST(AF_MPLS); 4065 ADD_CONST(AF_BRIDGE); 4066 4067 ADD_CONST(GRE_CSUM); 4068 ADD_CONST(GRE_ROUTING); 4069 ADD_CONST(GRE_KEY); 4070 ADD_CONST(GRE_SEQ); 4071 ADD_CONST(GRE_STRICT); 4072 ADD_CONST(GRE_REC); 4073 ADD_CONST(GRE_ACK); 4074 4075 ADD_CONST(TUNNEL_ENCAP_NONE); 4076 ADD_CONST(TUNNEL_ENCAP_FOU); 4077 ADD_CONST(TUNNEL_ENCAP_GUE); 4078 ADD_CONST(TUNNEL_ENCAP_MPLS); 4079 4080 ADD_CONST(TUNNEL_ENCAP_FLAG_CSUM); 4081 ADD_CONST(TUNNEL_ENCAP_FLAG_CSUM6); 4082 ADD_CONST(TUNNEL_ENCAP_FLAG_REMCSUM); 4083 4084 ADD_CONST(IP6_TNL_F_ALLOW_LOCAL_REMOTE); 4085 ADD_CONST(IP6_TNL_F_IGN_ENCAP_LIMIT); 4086 ADD_CONST(IP6_TNL_F_MIP6_DEV); 4087 ADD_CONST(IP6_TNL_F_RCV_DSCP_COPY); 4088 ADD_CONST(IP6_TNL_F_USE_ORIG_FLOWLABEL); 4089 ADD_CONST(IP6_TNL_F_USE_ORIG_FWMARK); 4090 ADD_CONST(IP6_TNL_F_USE_ORIG_TCLASS); 4091 4092 ADD_CONST(NTF_EXT_LEARNED); 4093 ADD_CONST(NTF_MASTER); 4094 ADD_CONST(NTF_OFFLOADED); 4095 ADD_CONST(NTF_PROXY); 4096 ADD_CONST(NTF_ROUTER); 4097 ADD_CONST(NTF_SELF); 4098 ADD_CONST(NTF_STICKY); 4099 ADD_CONST(NTF_USE); 4100 4101 ADD_CONST(NUD_DELAY); 4102 ADD_CONST(NUD_FAILED); 4103 ADD_CONST(NUD_INCOMPLETE); 4104 ADD_CONST(NUD_NOARP); 4105 ADD_CONST(NUD_NONE); 4106 ADD_CONST(NUD_PERMANENT); 4107 ADD_CONST(NUD_PROBE); 4108 ADD_CONST(NUD_REACHABLE); 4109 ADD_CONST(NUD_STALE); 4110 4111 ADD_CONST(IFA_F_DADFAILED); 4112 ADD_CONST(IFA_F_DEPRECATED); 4113 ADD_CONST(IFA_F_HOMEADDRESS); 4114 ADD_CONST(IFA_F_MANAGETEMPADDR); 4115 ADD_CONST(IFA_F_MCAUTOJOIN); 4116 ADD_CONST(IFA_F_NODAD); 4117 ADD_CONST(IFA_F_NOPREFIXROUTE); 4118 ADD_CONST(IFA_F_OPTIMISTIC); 4119 ADD_CONST(IFA_F_PERMANENT); 4120 ADD_CONST(IFA_F_SECONDARY); 4121 ADD_CONST(IFA_F_STABLE_PRIVACY); 4122 ADD_CONST(IFA_F_TEMPORARY); 4123 ADD_CONST(IFA_F_TENTATIVE); 4124 4125 ADD_CONST(FIB_RULE_PERMANENT); 4126 ADD_CONST(FIB_RULE_INVERT); 4127 ADD_CONST(FIB_RULE_UNRESOLVED); 4128 ADD_CONST(FIB_RULE_IIF_DETACHED); 4129 ADD_CONST(FIB_RULE_DEV_DETACHED); 4130 ADD_CONST(FIB_RULE_OIF_DETACHED); 4131 4132 ADD_CONST(FR_ACT_TO_TBL); 4133 ADD_CONST(FR_ACT_GOTO); 4134 ADD_CONST(FR_ACT_NOP); 4135 ADD_CONST(FR_ACT_BLACKHOLE); 4136 ADD_CONST(FR_ACT_UNREACHABLE); 4137 ADD_CONST(FR_ACT_PROHIBIT); 4138 4139 ADD_CONST(NETCONFA_IFINDEX_ALL); 4140 ADD_CONST(NETCONFA_IFINDEX_DEFAULT); 4141 4142 ADD_CONST(BRIDGE_FLAGS_MASTER); 4143 ADD_CONST(BRIDGE_FLAGS_SELF); 4144 4145 ADD_CONST(BRIDGE_MODE_VEB); 4146 ADD_CONST(BRIDGE_MODE_VEPA); 4147 ADD_CONST(BRIDGE_MODE_UNDEF); 4148 4149 ADD_CONST(BRIDGE_VLAN_INFO_MASTER); 4150 ADD_CONST(BRIDGE_VLAN_INFO_PVID); 4151 ADD_CONST(BRIDGE_VLAN_INFO_UNTAGGED); 4152 ADD_CONST(BRIDGE_VLAN_INFO_RANGE_BEGIN); 4153 ADD_CONST(BRIDGE_VLAN_INFO_RANGE_END); 4154 ADD_CONST(BRIDGE_VLAN_INFO_BRENTRY); 4155 4156 ucv_object_add(scope, "const", c); 4157 }; 4158 4159 static const uc_function_list_t global_fns[] = { 4160 { "error", uc_nl_error }, 4161 { "request", uc_nl_request }, 4162 { "listener", uc_nl_listener }, 4163 }; 4164 4165 static const uc_function_list_t listener_fns[] = { 4166 { "set_commands", uc_nl_listener_set_commands }, 4167 { "close", uc_nl_listener_close }, 4168 }; 4169 4170 void uc_module_init(uc_vm_t *vm, uc_value_t *scope) 4171 { 4172 uc_function_list_register(scope, global_fns); 4173 4174 listener_type = uc_type_declare(vm, "rtnl.listener", listener_fns, uc_nl_listener_free); 4175 listener_registry = ucv_array_new(vm); 4176 4177 uc_vm_registry_set(vm, "rtnl.registry", listener_registry); 4178 4179 register_constants(vm, scope); 4180 } 4181
This page was automatically generated by LXR 0.3.1. • OpenWrt