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