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