summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt11
-rw-r--r--include/linux/const.h36
-rw-r--r--include/linux/fib_rules.h90
-rw-r--r--include/linux/hdlc/ioctl.h94
-rw-r--r--include/linux/if.h296
-rw-r--r--include/linux/if_addr.h70
-rw-r--r--include/linux/if_addrlabel.h33
-rw-r--r--include/linux/if_bridge.h739
-rw-r--r--include/linux/if_ether.h173
-rw-r--r--include/linux/if_link.h1251
-rw-r--r--include/linux/if_macsec.h192
-rw-r--r--include/linux/if_tunnel.h183
-rw-r--r--include/linux/ila.h68
-rw-r--r--include/linux/in6.h301
-rw-r--r--include/linux/ip.h177
-rw-r--r--include/linux/ip6_tunnel.h56
-rw-r--r--include/linux/ipv6.h197
-rw-r--r--include/linux/lwtunnel.h113
-rw-r--r--include/linux/mpls.h77
-rw-r--r--include/linux/mpls_iptunnel.h31
-rw-r--r--include/linux/neighbour.h199
-rw-r--r--include/linux/netconf.h30
-rw-r--r--include/linux/netlink.h355
-rw-r--r--include/linux/rtnetlink.h800
-rw-r--r--include/linux/seg6.h55
-rw-r--r--include/linux/seg6_hmac.h23
-rw-r--r--include/linux/seg6_iptunnel.h40
-rw-r--r--include/linux/socket.h29
-rw-r--r--include/linux/types.h50
-rw-r--r--include/linux/veth.h13
-rw-r--r--lib/rtnl.c3653
31 files changed, 9435 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7f8171d..935df68 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,6 +17,7 @@ OPTION(FS_SUPPORT "Filesystem plugin support" ON)
OPTION(MATH_SUPPORT "Math plugin support" ON)
OPTION(UBUS_SUPPORT "Ubus plugin support" ON)
OPTION(UCI_SUPPORT "UCI plugin support" ON)
+OPTION(RTNL_SUPPORT "Route Netlink plugin support" ON)
OPTION(LEGACY_SUPPORT "Support deprecated syntax features" ON)
@@ -114,6 +115,16 @@ IF(UCI_SUPPORT)
TARGET_LINK_LIBRARIES(uci_lib ${uci} ${ubox})
ENDIF()
+IF(RTNL_SUPPORT)
+ FIND_LIBRARY(nl NAMES nl-tiny)
+ FIND_PATH(nl_include_dir NAMES netlink/msg.h PATH_SUFFIXES libnl-tiny)
+ INCLUDE_DIRECTORIES(${nl_include_dir})
+ SET(LIBRARIES ${LIBRARIES} rtnl_lib)
+ ADD_LIBRARY(rtnl_lib MODULE lib/rtnl.c)
+ SET_TARGET_PROPERTIES(rtnl_lib PROPERTIES OUTPUT_NAME rtnl PREFIX "")
+ TARGET_LINK_LIBRARIES(rtnl_lib ${nl})
+ENDIF()
+
IF(UNIT_TESTING)
ENABLE_TESTING()
ADD_DEFINITIONS(-DUNIT_TESTING)
diff --git a/include/linux/const.h b/include/linux/const.h
new file mode 100644
index 0000000..5e48987
--- /dev/null
+++ b/include/linux/const.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* const.h: Macros for dealing with constants. */
+
+#ifndef _LINUX_CONST_H
+#define _LINUX_CONST_H
+
+/* Some constant macros are used in both assembler and
+ * C code. Therefore we cannot annotate them always with
+ * 'UL' and other type specifiers unilaterally. We
+ * use the following macros to deal with this.
+ *
+ * Similarly, _AT() will cast an expression with a type in C, but
+ * leave it unchanged in asm.
+ */
+
+#ifdef __ASSEMBLY__
+#define _AC(X,Y) X
+#define _AT(T,X) X
+#else
+#define __AC(X,Y) (X##Y)
+#define _AC(X,Y) __AC(X,Y)
+#define _AT(T,X) ((T)(X))
+#endif
+
+#define _UL(x) (_AC(x, UL))
+#define _ULL(x) (_AC(x, ULL))
+
+#define _BITUL(x) (_UL(1) << (x))
+#define _BITULL(x) (_ULL(1) << (x))
+
+#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
+#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
+
+#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+
+#endif /* _LINUX_CONST_H */
diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h
new file mode 100644
index 0000000..232df14
--- /dev/null
+++ b/include/linux/fib_rules.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_FIB_RULES_H
+#define __LINUX_FIB_RULES_H
+
+#include <linux/types.h>
+#include <linux/rtnetlink.h>
+
+/* rule is permanent, and cannot be deleted */
+#define FIB_RULE_PERMANENT 0x00000001
+#define FIB_RULE_INVERT 0x00000002
+#define FIB_RULE_UNRESOLVED 0x00000004
+#define FIB_RULE_IIF_DETACHED 0x00000008
+#define FIB_RULE_DEV_DETACHED FIB_RULE_IIF_DETACHED
+#define FIB_RULE_OIF_DETACHED 0x00000010
+
+/* try to find source address in routing lookups */
+#define FIB_RULE_FIND_SADDR 0x00010000
+
+struct fib_rule_hdr {
+ __u8 family;
+ __u8 dst_len;
+ __u8 src_len;
+ __u8 tos;
+
+ __u8 table;
+ __u8 res1; /* reserved */
+ __u8 res2; /* reserved */
+ __u8 action;
+
+ __u32 flags;
+};
+
+struct fib_rule_uid_range {
+ __u32 start;
+ __u32 end;
+};
+
+struct fib_rule_port_range {
+ __u16 start;
+ __u16 end;
+};
+
+enum {
+ FRA_UNSPEC,
+ FRA_DST, /* destination address */
+ FRA_SRC, /* source address */
+ FRA_IIFNAME, /* interface name */
+#define FRA_IFNAME FRA_IIFNAME
+ FRA_GOTO, /* target to jump to (FR_ACT_GOTO) */
+ FRA_UNUSED2,
+ FRA_PRIORITY, /* priority/preference */
+ FRA_UNUSED3,
+ FRA_UNUSED4,
+ FRA_UNUSED5,
+ FRA_FWMARK, /* mark */
+ FRA_FLOW, /* flow/class id */
+ FRA_TUN_ID,
+ FRA_SUPPRESS_IFGROUP,
+ FRA_SUPPRESS_PREFIXLEN,
+ FRA_TABLE, /* Extended table id */
+ FRA_FWMASK, /* mask for netfilter mark */
+ FRA_OIFNAME,
+ FRA_PAD,
+ FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
+ FRA_UID_RANGE, /* UID range */
+ FRA_PROTOCOL, /* Originator of the rule */
+ FRA_IP_PROTO, /* ip proto */
+ FRA_SPORT_RANGE, /* sport */
+ FRA_DPORT_RANGE, /* dport */
+ __FRA_MAX
+};
+
+#define FRA_MAX (__FRA_MAX - 1)
+
+enum {
+ FR_ACT_UNSPEC,
+ FR_ACT_TO_TBL, /* Pass to fixed table */
+ FR_ACT_GOTO, /* Jump to another rule */
+ FR_ACT_NOP, /* No operation */
+ FR_ACT_RES3,
+ FR_ACT_RES4,
+ FR_ACT_BLACKHOLE, /* Drop without notification */
+ FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */
+ FR_ACT_PROHIBIT, /* Drop with EACCES */
+ __FR_ACT_MAX,
+};
+
+#define FR_ACT_MAX (__FR_ACT_MAX - 1)
+
+#endif
diff --git a/include/linux/hdlc/ioctl.h b/include/linux/hdlc/ioctl.h
new file mode 100644
index 0000000..b06341a
--- /dev/null
+++ b/include/linux/hdlc/ioctl.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __HDLC_IOCTL_H__
+#define __HDLC_IOCTL_H__
+
+
+#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */
+
+#define CLOCK_DEFAULT 0 /* Default setting */
+#define CLOCK_EXT 1 /* External TX and RX clock - DTE */
+#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */
+#define CLOCK_TXINT 3 /* Internal TX and external RX clock */
+#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */
+
+
+#define ENCODING_DEFAULT 0 /* Default setting */
+#define ENCODING_NRZ 1
+#define ENCODING_NRZI 2
+#define ENCODING_FM_MARK 3
+#define ENCODING_FM_SPACE 4
+#define ENCODING_MANCHESTER 5
+
+
+#define PARITY_DEFAULT 0 /* Default setting */
+#define PARITY_NONE 1 /* No parity */
+#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */
+#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */
+#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */
+#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */
+#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */
+#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */
+
+#define LMI_DEFAULT 0 /* Default setting */
+#define LMI_NONE 1 /* No LMI, all PVCs are static */
+#define LMI_ANSI 2 /* ANSI Annex D */
+#define LMI_CCITT 3 /* ITU-T Annex A */
+#define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+ unsigned int clock_rate; /* bits per second */
+ unsigned int clock_type; /* internal, external, TX-internal etc. */
+ unsigned short loopback;
+} sync_serial_settings; /* V.35, V.24, X.21 */
+
+typedef struct {
+ unsigned int clock_rate; /* bits per second */
+ unsigned int clock_type; /* internal, external, TX-internal etc. */
+ unsigned short loopback;
+ unsigned int slot_map;
+} te1_settings; /* T1, E1 */
+
+typedef struct {
+ unsigned short encoding;
+ unsigned short parity;
+} raw_hdlc_proto;
+
+typedef struct {
+ unsigned int t391;
+ unsigned int t392;
+ unsigned int n391;
+ unsigned int n392;
+ unsigned int n393;
+ unsigned short lmi;
+ unsigned short dce; /* 1 for DCE (network side) operation */
+} fr_proto;
+
+typedef struct {
+ unsigned int dlci;
+} fr_proto_pvc; /* for creating/deleting FR PVCs */
+
+typedef struct {
+ unsigned int dlci;
+ char master[IFNAMSIZ]; /* Name of master FRAD device */
+}fr_proto_pvc_info; /* for returning PVC information only */
+
+typedef struct {
+ unsigned int interval;
+ unsigned int timeout;
+} cisco_proto;
+
+typedef struct {
+ unsigned short dce; /* 1 for DCE (network side) operation */
+ unsigned int modulo; /* modulo (8 = basic / 128 = extended) */
+ unsigned int window; /* frame window size */
+ unsigned int t1; /* timeout t1 */
+ unsigned int t2; /* timeout t2 */
+ unsigned int n2; /* frame retry counter */
+} x25_hdlc_proto;
+
+/* PPP doesn't need any info now - supply length = 0 to ioctl */
+
+#endif /* __ASSEMBLY__ */
+#endif /* __HDLC_IOCTL_H__ */
diff --git a/include/linux/if.h b/include/linux/if.h
new file mode 100644
index 0000000..b287b2a
--- /dev/null
+++ b/include/linux/if.h
@@ -0,0 +1,296 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the INET interface module.
+ *
+ * Version: @(#)if.h 1.0.2 04/18/93
+ *
+ * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988
+ * Ross Biro
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_H
+#define _LINUX_IF_H
+
+#include <linux/libc-compat.h> /* for compatibility with glibc */
+#include <linux/types.h> /* for "__kernel_caddr_t" et al */
+#include <linux/socket.h> /* for "struct sockaddr" et al */
+ /* for "__user" et al */
+
+#include <sys/socket.h> /* for struct sockaddr. */
+
+#if __UAPI_DEF_IF_IFNAMSIZ
+#define IFNAMSIZ 16
+#endif /* __UAPI_DEF_IF_IFNAMSIZ */
+#define IFALIASZ 256
+#define ALTIFNAMSIZ 128
+#include <linux/hdlc/ioctl.h>
+
+/* For glibc compatibility. An empty enum does not compile. */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || \
+ __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0
+/**
+ * enum net_device_flags - &struct net_device flags
+ *
+ * These are the &struct net_device flags, they can be set by drivers, the
+ * kernel and some can be triggered by userspace. Userspace can query and
+ * set these flags using userspace utilities but there is also a sysfs
+ * entry available for all dev flags which can be queried and set. These flags
+ * are shared for all types of net_devices. The sysfs entries are available
+ * via /sys/class/net/<dev>/flags. Flags which can be toggled through sysfs
+ * are annotated below, note that only a few flags can be toggled and some
+ * other flags are always preserved from the original net_device flags
+ * even if you try to set them via sysfs. Flags which are always preserved
+ * are kept under the flag grouping @IFF_VOLATILE. Flags which are __volatile__
+ * are annotated below as such.
+ *
+ * You should have a pretty good reason to be extending these flags.
+ *
+ * @IFF_UP: interface is up. Can be toggled through sysfs.
+ * @IFF_BROADCAST: broadcast address valid. Volatile.
+ * @IFF_DEBUG: turn on debugging. Can be toggled through sysfs.
+ * @IFF_LOOPBACK: is a loopback net. Volatile.
+ * @IFF_POINTOPOINT: interface is has p-p link. Volatile.
+ * @IFF_NOTRAILERS: avoid use of trailers. Can be toggled through sysfs.
+ * Volatile.
+ * @IFF_RUNNING: interface RFC2863 OPER_UP. Volatile.
+ * @IFF_NOARP: no ARP protocol. Can be toggled through sysfs. Volatile.
+ * @IFF_PROMISC: receive all packets. Can be toggled through sysfs.
+ * @IFF_ALLMULTI: receive all multicast packets. Can be toggled through
+ * sysfs.
+ * @IFF_MASTER: master of a load balancer. Volatile.
+ * @IFF_SLAVE: slave of a load balancer. Volatile.
+ * @IFF_MULTICAST: Supports multicast. Can be toggled through sysfs.
+ * @IFF_PORTSEL: can set media type. Can be toggled through sysfs.
+ * @IFF_AUTOMEDIA: auto media select active. Can be toggled through sysfs.
+ * @IFF_DYNAMIC: dialup device with changing addresses. Can be toggled
+ * through sysfs.
+ * @IFF_LOWER_UP: driver signals L1 up. Volatile.
+ * @IFF_DORMANT: driver signals dormant. Volatile.
+ * @IFF_ECHO: echo sent packets. Volatile.
+ */
+enum net_device_flags {
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS
+ IFF_UP = 1<<0, /* sysfs */
+ IFF_BROADCAST = 1<<1, /* __volatile__ */
+ IFF_DEBUG = 1<<2, /* sysfs */
+ IFF_LOOPBACK = 1<<3, /* __volatile__ */
+ IFF_POINTOPOINT = 1<<4, /* __volatile__ */
+ IFF_NOTRAILERS = 1<<5, /* sysfs */
+ IFF_RUNNING = 1<<6, /* __volatile__ */
+ IFF_NOARP = 1<<7, /* sysfs */
+ IFF_PROMISC = 1<<8, /* sysfs */
+ IFF_ALLMULTI = 1<<9, /* sysfs */
+ IFF_MASTER = 1<<10, /* __volatile__ */
+ IFF_SLAVE = 1<<11, /* __volatile__ */
+ IFF_MULTICAST = 1<<12, /* sysfs */
+ IFF_PORTSEL = 1<<13, /* sysfs */
+ IFF_AUTOMEDIA = 1<<14, /* sysfs */
+ IFF_DYNAMIC = 1<<15, /* sysfs */
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
+ IFF_LOWER_UP = 1<<16, /* __volatile__ */
+ IFF_DORMANT = 1<<17, /* __volatile__ */
+ IFF_ECHO = 1<<18, /* __volatile__ */
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
+};
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */
+
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS
+#define IFF_UP IFF_UP
+#define IFF_BROADCAST IFF_BROADCAST
+#define IFF_DEBUG IFF_DEBUG
+#define IFF_LOOPBACK IFF_LOOPBACK
+#define IFF_POINTOPOINT IFF_POINTOPOINT
+#define IFF_NOTRAILERS IFF_NOTRAILERS
+#define IFF_RUNNING IFF_RUNNING
+#define IFF_NOARP IFF_NOARP
+#define IFF_PROMISC IFF_PROMISC
+#define IFF_ALLMULTI IFF_ALLMULTI
+#define IFF_MASTER IFF_MASTER
+#define IFF_SLAVE IFF_SLAVE
+#define IFF_MULTICAST IFF_MULTICAST
+#define IFF_PORTSEL IFF_PORTSEL
+#define IFF_AUTOMEDIA IFF_AUTOMEDIA
+#define IFF_DYNAMIC IFF_DYNAMIC
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */
+
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
+#define IFF_LOWER_UP IFF_LOWER_UP
+#define IFF_DORMANT IFF_DORMANT
+#define IFF_ECHO IFF_ECHO
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
+
+#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
+ IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
+
+#define IF_GET_IFACE 0x0001 /* for querying only */
+#define IF_GET_PROTO 0x0002
+
+/* For definitions see hdlc.h */
+#define IF_IFACE_V35 0x1000 /* V.35 serial interface */
+#define IF_IFACE_V24 0x1001 /* V.24 serial interface */
+#define IF_IFACE_X21 0x1002 /* X.21 serial interface */
+#define IF_IFACE_T1 0x1003 /* T1 telco serial interface */
+#define IF_IFACE_E1 0x1004 /* E1 telco serial interface */
+#define IF_IFACE_SYNC_SERIAL 0x1005 /* can't be set by software */
+#define IF_IFACE_X21D 0x1006 /* X.21 Dual Clocking (FarSite) */
+
+/* For definitions see hdlc.h */
+#define IF_PROTO_HDLC 0x2000 /* raw HDLC protocol */
+#define IF_PROTO_PPP 0x2001 /* PPP protocol */
+#define IF_PROTO_CISCO 0x2002 /* Cisco HDLC protocol */
+#define IF_PROTO_FR 0x2003 /* Frame Relay protocol */
+#define IF_PROTO_FR_ADD_PVC 0x2004 /* Create FR PVC */
+#define IF_PROTO_FR_DEL_PVC 0x2005 /* Delete FR PVC */
+#define IF_PROTO_X25 0x2006 /* X.25 */
+#define IF_PROTO_HDLC_ETH 0x2007 /* raw HDLC, Ethernet emulation */
+#define IF_PROTO_FR_ADD_ETH_PVC 0x2008 /* Create FR Ethernet-bridged PVC */
+#define IF_PROTO_FR_DEL_ETH_PVC 0x2009 /* Delete FR Ethernet-bridged PVC */
+#define IF_PROTO_FR_PVC 0x200A /* for reading PVC status */
+#define IF_PROTO_FR_ETH_PVC 0x200B
+#define IF_PROTO_RAW 0x200C /* RAW Socket */
+
+/* RFC 2863 operational status */
+enum {
+ IF_OPER_UNKNOWN,
+ IF_OPER_NOTPRESENT,
+ IF_OPER_DOWN,
+ IF_OPER_LOWERLAYERDOWN,
+ IF_OPER_TESTING,
+ IF_OPER_DORMANT,
+ IF_OPER_UP,
+};
+
+/* link modes */
+enum {
+ IF_LINK_MODE_DEFAULT,
+ IF_LINK_MODE_DORMANT, /* limit upward transition to dormant */
+ IF_LINK_MODE_TESTING, /* limit upward transition to testing */
+};
+
+/*
+ * Device mapping structure. I'd just gone off and designed a
+ * beautiful scheme using only loadable modules with arguments
+ * for driver options and along come the PCMCIA people 8)
+ *
+ * Ah well. The get() side of this is good for WDSETUP, and it'll
+ * be handy for debugging things. The set side is fine for now and
+ * being very small might be worth keeping for clean configuration.
+ */
+
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_IFMAP
+struct ifmap {
+ unsigned long mem_start;
+ unsigned long mem_end;
+ unsigned short base_addr;
+ unsigned char irq;
+ unsigned char dma;
+ unsigned char port;
+ /* 3 bytes spare */
+};
+#endif /* __UAPI_DEF_IF_IFMAP */
+
+struct if_settings {
+ unsigned int type; /* Type of physical device or protocol */
+ unsigned int size; /* Size of the data allocated by the caller */
+ union {
+ /* {atm/eth/dsl}_settings anyone ? */
+ raw_hdlc_proto *raw_hdlc;
+ cisco_proto *cisco;
+ fr_proto *fr;
+ fr_proto_pvc *fr_pvc;
+ fr_proto_pvc_info *fr_pvc_info;
+ x25_hdlc_proto *x25;
+
+ /* interface settings */
+ sync_serial_settings *sync;
+ te1_settings *te1;
+ } ifs_ifsu;
+};
+
+/*
+ * Interface request structure used for socket
+ * ioctl's. All interface ioctl's must have parameter
+ * definitions which begin with ifr_name. The
+ * remainder may be interface specific.
+ */
+
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_IFREQ
+struct ifreq {
+#define IFHWADDRLEN 6
+ union
+ {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ } ifr_ifrn;
+
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_dstaddr;
+ struct sockaddr ifru_broadaddr;
+ struct sockaddr ifru_netmask;
+ struct sockaddr ifru_hwaddr;
+ short ifru_flags;
+ int ifru_ivalue;
+ int ifru_mtu;
+ struct ifmap ifru_map;
+ char ifru_slave[IFNAMSIZ]; /* Just fits the size */
+ char ifru_newname[IFNAMSIZ];
+ void * ifru_data;
+ struct if_settings ifru_settings;
+ } ifr_ifru;
+};
+#endif /* __UAPI_DEF_IF_IFREQ */
+
+#define ifr_name ifr_ifrn.ifrn_name /* interface name */
+#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
+#define ifr_addr ifr_ifru.ifru_addr /* address */
+#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
+#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
+#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
+#define ifr_flags ifr_ifru.ifru_flags /* flags */
+#define ifr_metric ifr_ifru.ifru_ivalue /* metric */
+#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
+#define ifr_map ifr_ifru.ifru_map /* device map */
+#define ifr_slave ifr_ifru.ifru_slave /* slave device */
+#define ifr_data ifr_ifru.ifru_data /* for use by interface */
+#define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */
+#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
+#define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */
+#define ifr_newname ifr_ifru.ifru_newname /* New name */
+#define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/
+
+/*
+ * Structure used in SIOCGIFCONF request.
+ * Used to retrieve interface configuration
+ * for machine (useful for programs which
+ * must know all networks accessible).
+ */
+
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_IFCONF
+struct ifconf {
+ int ifc_len; /* size of buffer */
+ union {
+ char *ifcu_buf;
+ struct ifreq *ifcu_req;
+ } ifc_ifcu;
+};
+#endif /* __UAPI_DEF_IF_IFCONF */
+
+#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
+#define ifc_req ifc_ifcu.ifcu_req /* array of structures */
+
+#endif /* _LINUX_IF_H */
diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
new file mode 100644
index 0000000..c4dd87f
--- /dev/null
+++ b/include/linux/if_addr.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_IF_ADDR_H
+#define __LINUX_IF_ADDR_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct ifaddrmsg {
+ __u8 ifa_family;
+ __u8 ifa_prefixlen; /* The prefix length */
+ __u8 ifa_flags; /* Flags */
+ __u8 ifa_scope; /* Address scope */
+ __u32 ifa_index; /* Link index */
+};
+
+/*
+ * Important comment:
+ * IFA_ADDRESS is prefix address, rather than local interface address.
+ * It makes no difference for normally configured broadcast interfaces,
+ * but for point-to-point IFA_ADDRESS is DESTINATION address,
+ * local address is supplied in IFA_LOCAL attribute.
+ *
+ * IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags.
+ * If present, the value from struct ifaddrmsg will be ignored.
+ */
+enum {
+ IFA_UNSPEC,
+ IFA_ADDRESS,
+ IFA_LOCAL,
+ IFA_LABEL,
+ IFA_BROADCAST,
+ IFA_ANYCAST,
+ IFA_CACHEINFO,
+ IFA_MULTICAST,
+ IFA_FLAGS,
+ IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */
+ IFA_TARGET_NETNSID,
+ __IFA_MAX,
+};
+
+#define IFA_MAX (__IFA_MAX - 1)
+
+/* ifa_flags */
+#define IFA_F_SECONDARY 0x01
+#define IFA_F_TEMPORARY IFA_F_SECONDARY
+
+#define IFA_F_NODAD 0x02
+#define IFA_F_OPTIMISTIC 0x04
+#define IFA_F_DADFAILED 0x08
+#define IFA_F_HOMEADDRESS 0x10
+#define IFA_F_DEPRECATED 0x20
+#define IFA_F_TENTATIVE 0x40
+#define IFA_F_PERMANENT 0x80
+#define IFA_F_MANAGETEMPADDR 0x100
+#define IFA_F_NOPREFIXROUTE 0x200
+#define IFA_F_MCAUTOJOIN 0x400
+#define IFA_F_STABLE_PRIVACY 0x800
+
+struct ifa_cacheinfo {
+ __u32 ifa_prefered;
+ __u32 ifa_valid;
+ __u32 cstamp; /* created timestamp, hundredths of seconds */
+ __u32 tstamp; /* updated timestamp, hundredths of seconds */
+};
+
+/* backwards compatibility for userspace */
+#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+
+#endif
diff --git a/include/linux/if_addrlabel.h b/include/linux/if_addrlabel.h
new file mode 100644
index 0000000..d1f5974
--- /dev/null
+++ b/include/linux/if_addrlabel.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * if_addrlabel.h - netlink interface for address labels
+ *
+ * Copyright (C)2007 USAGI/WIDE Project, All Rights Reserved.
+ *
+ * Authors:
+ * YOSHIFUJI Hideaki @ USAGI/WIDE <yoshfuji@linux-ipv6.org>
+ */
+
+#ifndef __LINUX_IF_ADDRLABEL_H
+#define __LINUX_IF_ADDRLABEL_H
+
+#include <linux/types.h>
+
+struct ifaddrlblmsg {
+ __u8 ifal_family; /* Address family */
+ __u8 __ifal_reserved; /* Reserved */
+ __u8 ifal_prefixlen; /* Prefix length */
+ __u8 ifal_flags; /* Flags */
+ __u32 ifal_index; /* Link index */
+ __u32 ifal_seq; /* sequence number */
+};
+
+enum {
+ IFAL_ADDRESS = 1,
+ IFAL_LABEL = 2,
+ __IFAL_MAX
+};
+
+#define IFAL_MAX (__IFAL_MAX - 1)
+
+#endif
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
new file mode 100644
index 0000000..fee6e45
--- /dev/null
+++ b/include/linux/if_bridge.h
@@ -0,0 +1,739 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Linux ethernet bridge
+ *
+ * Authors:
+ * Lennert Buytenhek <buytenh@gnu.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IF_BRIDGE_H
+#define _LINUX_IF_BRIDGE_H
+
+#include <linux/types.h>
+#include <linux/if_ether.h>
+#include <linux/in6.h>
+
+#define SYSFS_BRIDGE_ATTR "bridge"
+#define SYSFS_BRIDGE_FDB "brforward"
+#define SYSFS_BRIDGE_PORT_SUBDIR "brif"
+#define SYSFS_BRIDGE_PORT_ATTR "brport"
+#define SYSFS_BRIDGE_PORT_LINK "bridge"
+
+#define BRCTL_VERSION 1
+
+#define BRCTL_GET_VERSION 0
+#define BRCTL_GET_BRIDGES 1
+#define BRCTL_ADD_BRIDGE 2
+#define BRCTL_DEL_BRIDGE 3
+#define BRCTL_ADD_IF 4
+#define BRCTL_DEL_IF 5
+#define BRCTL_GET_BRIDGE_INFO 6
+#define BRCTL_GET_PORT_LIST 7
+#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8
+#define BRCTL_SET_BRIDGE_HELLO_TIME 9
+#define BRCTL_SET_BRIDGE_MAX_AGE 10
+#define BRCTL_SET_AGEING_TIME 11
+#define BRCTL_SET_GC_INTERVAL 12
+#define BRCTL_GET_PORT_INFO 13
+#define BRCTL_SET_BRIDGE_STP_STATE 14
+#define BRCTL_SET_BRIDGE_PRIORITY 15
+#define BRCTL_SET_PORT_PRIORITY 16
+#define BRCTL_SET_PATH_COST 17
+#define BRCTL_GET_FDB_ENTRIES 18
+
+#define BR_STATE_DISABLED 0
+#define BR_STATE_LISTENING 1
+#define BR_STATE_LEARNING 2
+#define BR_STATE_FORWARDING 3
+#define BR_STATE_BLOCKING 4
+
+struct __bridge_info {
+ __u64 designated_root;
+ __u64 bridge_id;
+ __u32 root_path_cost;
+ __u32 max_age;
+ __u32 hello_time;
+ __u32 forward_delay;
+ __u32 bridge_max_age;
+ __u32 bridge_hello_time;
+ __u32 bridge_forward_delay;
+ __u8 topology_change;
+ __u8 topology_change_detected;
+ __u8 root_port;
+ __u8 stp_enabled;
+ __u32 ageing_time;
+ __u32 gc_interval;
+ __u32 hello_timer_value;
+ __u32 tcn_timer_value;
+ __u32 topology_change_timer_value;
+ __u32 gc_timer_value;
+};
+
+struct __port_info {
+ __u64 designated_root;
+ __u64 designated_bridge;
+ __u16 port_id;
+ __u16 designated_port;
+ __u32 path_cost;
+ __u32 designated_cost;
+ __u8 state;
+ __u8 top_change_ack;
+ __u8 config_pending;
+ __u8 unused0;
+ __u32 message_age_timer_value;
+ __u32 forward_delay_timer_value;
+ __u32 hold_timer_value;
+};
+
+struct __fdb_entry {
+ __u8 mac_addr[ETH_ALEN];
+ __u8 port_no;
+ __u8 is_local;
+ __u32 ageing_timer_value;
+ __u8 port_hi;
+ __u8 pad0;
+ __u16 unused;
+};
+
+/* Bridge Flags */
+#define BRIDGE_FLAGS_MASTER 1 /* Bridge command to/from master */
+#define BRIDGE_FLAGS_SELF 2 /* Bridge command to/from lowerdev */
+
+#define BRIDGE_MODE_VEB 0 /* Default loopback mode */
+#define BRIDGE_MODE_VEPA 1 /* 802.1Qbg defined VEPA mode */
+#define BRIDGE_MODE_UNDEF 0xFFFF /* mode undefined */
+
+/* Bridge management nested attributes
+ * [IFLA_AF_SPEC] = {
+ * [IFLA_BRIDGE_FLAGS]
+ * [IFLA_BRIDGE_MODE]
+ * [IFLA_BRIDGE_VLAN_INFO]
+ * }
+ */
+enum {
+ IFLA_BRIDGE_FLAGS,
+ IFLA_BRIDGE_MODE,
+ IFLA_BRIDGE_VLAN_INFO,
+ IFLA_BRIDGE_VLAN_TUNNEL_INFO,
+ IFLA_BRIDGE_MRP,
+ IFLA_BRIDGE_CFM,
+ __IFLA_BRIDGE_MAX,
+};
+#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
+
+#define BRIDGE_VLAN_INFO_MASTER (1<<0) /* Operate on Bridge device as well */
+#define BRIDGE_VLAN_INFO_PVID (1<<1) /* VLAN is PVID, ingress untagged */
+#define BRIDGE_VLAN_INFO_UNTAGGED (1<<2) /* VLAN egresses untagged */
+#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */
+#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */
+#define BRIDGE_VLAN_INFO_BRENTRY (1<<5) /* Global bridge VLAN entry */
+#define BRIDGE_VLAN_INFO_ONLY_OPTS (1<<6) /* Skip create/delete/flags */
+
+struct bridge_vlan_info {
+ __u16 flags;
+ __u16 vid;
+};
+
+enum {
+ IFLA_BRIDGE_VLAN_TUNNEL_UNSPEC,
+ IFLA_BRIDGE_VLAN_TUNNEL_ID,
+ IFLA_BRIDGE_VLAN_TUNNEL_VID,
+ IFLA_BRIDGE_VLAN_TUNNEL_FLAGS,
+ __IFLA_BRIDGE_VLAN_TUNNEL_MAX,
+};
+
+#define IFLA_BRIDGE_VLAN_TUNNEL_MAX (__IFLA_BRIDGE_VLAN_TUNNEL_MAX - 1)
+
+struct bridge_vlan_xstats {
+ __u64 rx_bytes;
+ __u64 rx_packets;
+ __u64 tx_bytes;
+ __u64 tx_packets;
+ __u16 vid;
+ __u16 flags;
+ __u32 pad2;
+};
+
+enum {
+ IFLA_BRIDGE_MRP_UNSPEC,
+ IFLA_BRIDGE_MRP_INSTANCE,
+ IFLA_BRIDGE_MRP_PORT_STATE,
+ IFLA_BRIDGE_MRP_PORT_ROLE,
+ IFLA_BRIDGE_MRP_RING_STATE,
+ IFLA_BRIDGE_MRP_RING_ROLE,
+ IFLA_BRIDGE_MRP_START_TEST,
+ IFLA_BRIDGE_MRP_INFO,
+ IFLA_BRIDGE_MRP_IN_ROLE,
+ IFLA_BRIDGE_MRP_IN_STATE,
+ IFLA_BRIDGE_MRP_START_IN_TEST,
+ __IFLA_BRIDGE_MRP_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_MAX (__IFLA_BRIDGE_MRP_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_INSTANCE_UNSPEC,
+ IFLA_BRIDGE_MRP_INSTANCE_RING_ID,
+ IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX,
+ IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX,
+ IFLA_BRIDGE_MRP_INSTANCE_PRIO,
+ __IFLA_BRIDGE_MRP_INSTANCE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_INSTANCE_MAX (__IFLA_BRIDGE_MRP_INSTANCE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_PORT_STATE_UNSPEC,
+ IFLA_BRIDGE_MRP_PORT_STATE_STATE,
+ __IFLA_BRIDGE_MRP_PORT_STATE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_PORT_STATE_MAX (__IFLA_BRIDGE_MRP_PORT_STATE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_PORT_ROLE_UNSPEC,
+ IFLA_BRIDGE_MRP_PORT_ROLE_ROLE,
+ __IFLA_BRIDGE_MRP_PORT_ROLE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_PORT_ROLE_MAX (__IFLA_BRIDGE_MRP_PORT_ROLE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_RING_STATE_UNSPEC,
+ IFLA_BRIDGE_MRP_RING_STATE_RING_ID,
+ IFLA_BRIDGE_MRP_RING_STATE_STATE,
+ __IFLA_BRIDGE_MRP_RING_STATE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_RING_STATE_MAX (__IFLA_BRIDGE_MRP_RING_STATE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_RING_ROLE_UNSPEC,
+ IFLA_BRIDGE_MRP_RING_ROLE_RING_ID,
+ IFLA_BRIDGE_MRP_RING_ROLE_ROLE,
+ __IFLA_BRIDGE_MRP_RING_ROLE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_RING_ROLE_MAX (__IFLA_BRIDGE_MRP_RING_ROLE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_START_TEST_UNSPEC,
+ IFLA_BRIDGE_MRP_START_TEST_RING_ID,
+ IFLA_BRIDGE_MRP_START_TEST_INTERVAL,
+ IFLA_BRIDGE_MRP_START_TEST_MAX_MISS,
+ IFLA_BRIDGE_MRP_START_TEST_PERIOD,
+ IFLA_BRIDGE_MRP_START_TEST_MONITOR,
+ __IFLA_BRIDGE_MRP_START_TEST_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_START_TEST_MAX (__IFLA_BRIDGE_MRP_START_TEST_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_INFO_UNSPEC,
+ IFLA_BRIDGE_MRP_INFO_RING_ID,
+ IFLA_BRIDGE_MRP_INFO_P_IFINDEX,
+ IFLA_BRIDGE_MRP_INFO_S_IFINDEX,
+ IFLA_BRIDGE_MRP_INFO_PRIO,
+ IFLA_BRIDGE_MRP_INFO_RING_STATE,
+ IFLA_BRIDGE_MRP_INFO_RING_ROLE,
+ IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL,
+ IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS,
+ IFLA_BRIDGE_MRP_INFO_TEST_MONITOR,
+ IFLA_BRIDGE_MRP_INFO_I_IFINDEX,
+ IFLA_BRIDGE_MRP_INFO_IN_STATE,
+ IFLA_BRIDGE_MRP_INFO_IN_ROLE,
+ IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL,
+ IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS,
+ __IFLA_BRIDGE_MRP_INFO_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_INFO_MAX (__IFLA_BRIDGE_MRP_INFO_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_IN_STATE_UNSPEC,
+ IFLA_BRIDGE_MRP_IN_STATE_IN_ID,
+ IFLA_BRIDGE_MRP_IN_STATE_STATE,
+ __IFLA_BRIDGE_MRP_IN_STATE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_IN_STATE_MAX (__IFLA_BRIDGE_MRP_IN_STATE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC,
+ IFLA_BRIDGE_MRP_IN_ROLE_RING_ID,
+ IFLA_BRIDGE_MRP_IN_ROLE_IN_ID,
+ IFLA_BRIDGE_MRP_IN_ROLE_ROLE,
+ IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX,
+ __IFLA_BRIDGE_MRP_IN_ROLE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_IN_ROLE_MAX (__IFLA_BRIDGE_MRP_IN_ROLE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC,
+ IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID,
+ IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL,
+ IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS,
+ IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD,
+ __IFLA_BRIDGE_MRP_START_IN_TEST_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_START_IN_TEST_MAX (__IFLA_BRIDGE_MRP_START_IN_TEST_MAX - 1)
+
+struct br_mrp_instance {
+ __u32 ring_id;
+ __u32 p_ifindex;
+ __u32 s_ifindex;
+ __u16 prio;
+};
+
+struct br_mrp_ring_state {
+ __u32 ring_id;
+ __u32 ring_state;
+};
+
+struct br_mrp_ring_role {
+ __u32 ring_id;
+ __u32 ring_role;
+};
+
+struct br_mrp_start_test {
+ __u32 ring_id;
+ __u32 interval;
+ __u32 max_miss;
+ __u32 period;
+ __u32 monitor;
+};
+
+struct br_mrp_in_state {
+ __u32 in_state;
+ __u16 in_id;
+};
+
+struct br_mrp_in_role {
+ __u32 ring_id;
+ __u32 in_role;
+ __u32 i_ifindex;
+ __u16 in_id;
+};
+
+struct br_mrp_start_in_test {
+ __u32 interval;
+ __u32 max_miss;
+ __u32 period;
+ __u16 in_id;
+};
+
+enum {
+ IFLA_BRIDGE_CFM_UNSPEC,
+ IFLA_BRIDGE_CFM_MEP_CREATE,
+ IFLA_BRIDGE_CFM_MEP_DELETE,
+ IFLA_BRIDGE_CFM_MEP_CONFIG,
+ IFLA_BRIDGE_CFM_CC_CONFIG,
+ IFLA_BRIDGE_CFM_CC_PEER_MEP_ADD,
+ IFLA_BRIDGE_CFM_CC_PEER_MEP_REMOVE,
+ IFLA_BRIDGE_CFM_CC_RDI,
+ IFLA_BRIDGE_CFM_CC_CCM_TX,
+ IFLA_BRIDGE_CFM_MEP_CREATE_INFO,
+ IFLA_BRIDGE_CFM_MEP_CONFIG_INFO,
+ IFLA_BRIDGE_CFM_CC_CONFIG_INFO,
+ IFLA_BRIDGE_CFM_CC_RDI_INFO,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_INFO,
+ IFLA_BRIDGE_CFM_CC_PEER_MEP_INFO,
+ IFLA_BRIDGE_CFM_MEP_STATUS_INFO,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_INFO,
+ __IFLA_BRIDGE_CFM_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_MAX (__IFLA_BRIDGE_CFM_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_MEP_CREATE_UNSPEC,
+ IFLA_BRIDGE_CFM_MEP_CREATE_INSTANCE,
+ IFLA_BRIDGE_CFM_MEP_CREATE_DOMAIN,
+ IFLA_BRIDGE_CFM_MEP_CREATE_DIRECTION,
+ IFLA_BRIDGE_CFM_MEP_CREATE_IFINDEX,
+ __IFLA_BRIDGE_CFM_MEP_CREATE_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_MEP_CREATE_MAX (__IFLA_BRIDGE_CFM_MEP_CREATE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_MEP_DELETE_UNSPEC,
+ IFLA_BRIDGE_CFM_MEP_DELETE_INSTANCE,
+ __IFLA_BRIDGE_CFM_MEP_DELETE_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_MEP_DELETE_MAX (__IFLA_BRIDGE_CFM_MEP_DELETE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_MEP_CONFIG_UNSPEC,
+ IFLA_BRIDGE_CFM_MEP_CONFIG_INSTANCE,
+ IFLA_BRIDGE_CFM_MEP_CONFIG_UNICAST_MAC,
+ IFLA_BRIDGE_CFM_MEP_CONFIG_MDLEVEL,
+ IFLA_BRIDGE_CFM_MEP_CONFIG_MEPID,
+ __IFLA_BRIDGE_CFM_MEP_CONFIG_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_MEP_CONFIG_MAX (__IFLA_BRIDGE_CFM_MEP_CONFIG_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_CC_CONFIG_UNSPEC,
+ IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE,
+ IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE,
+ IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL,
+ IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID,
+ __IFLA_BRIDGE_CFM_CC_CONFIG_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_CC_CONFIG_MAX (__IFLA_BRIDGE_CFM_CC_CONFIG_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_CC_PEER_MEP_UNSPEC,
+ IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE,
+ IFLA_BRIDGE_CFM_CC_PEER_MEPID,
+ __IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX (__IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_CC_RDI_UNSPEC,
+ IFLA_BRIDGE_CFM_CC_RDI_INSTANCE,
+ IFLA_BRIDGE_CFM_CC_RDI_RDI,
+ __IFLA_BRIDGE_CFM_CC_RDI_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_CC_RDI_MAX (__IFLA_BRIDGE_CFM_CC_RDI_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_CC_CCM_TX_UNSPEC,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_INSTANCE,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_DMAC,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_SEQ_NO_UPDATE,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_PERIOD,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV_VALUE,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV_VALUE,
+ __IFLA_BRIDGE_CFM_CC_CCM_TX_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_CC_CCM_TX_MAX (__IFLA_BRIDGE_CFM_CC_CCM_TX_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_MEP_STATUS_UNSPEC,
+ IFLA_BRIDGE_CFM_MEP_STATUS_INSTANCE,
+ IFLA_BRIDGE_CFM_MEP_STATUS_OPCODE_UNEXP_SEEN,
+ IFLA_BRIDGE_CFM_MEP_STATUS_VERSION_UNEXP_SEEN,
+ IFLA_BRIDGE_CFM_MEP_STATUS_RX_LEVEL_LOW_SEEN,
+ __IFLA_BRIDGE_CFM_MEP_STATUS_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_MEP_STATUS_MAX (__IFLA_BRIDGE_CFM_MEP_STATUS_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_UNSPEC,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_INSTANCE,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_PEER_MEPID,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_CCM_DEFECT,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_RDI,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_PORT_TLV_VALUE,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_IF_TLV_VALUE,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_SEEN,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_TLV_SEEN,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_SEQ_UNEXP_SEEN,
+ __IFLA_BRIDGE_CFM_CC_PEER_STATUS_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_CC_PEER_STATUS_MAX (__IFLA_BRIDGE_CFM_CC_PEER_STATUS_MAX - 1)
+
+struct bridge_stp_xstats {
+ __u64 transition_blk;
+ __u64 transition_fwd;
+ __u64 rx_bpdu;
+ __u64 tx_bpdu;
+ __u64 rx_tcn;
+ __u64 tx_tcn;
+};
+
+/* Bridge vlan RTM header */
+struct br_vlan_msg {
+ __u8 family;
+ __u8 reserved1;
+ __u16 reserved2;
+ __u32 ifindex;
+};
+
+enum {
+ BRIDGE_VLANDB_DUMP_UNSPEC,
+ BRIDGE_VLANDB_DUMP_FLAGS,
+ __BRIDGE_VLANDB_DUMP_MAX,
+};
+#define BRIDGE_VLANDB_DUMP_MAX (__BRIDGE_VLANDB_DUMP_MAX - 1)
+
+/* flags used in BRIDGE_VLANDB_DUMP_FLAGS attribute to affect dumps */
+#define BRIDGE_VLANDB_DUMPF_STATS (1 << 0) /* Include stats in the dump */
+
+/* Bridge vlan RTM attributes
+ * [BRIDGE_VLANDB_ENTRY] = {
+ * [BRIDGE_VLANDB_ENTRY_INFO]
+ * ...
+ * }
+ */
+enum {
+ BRIDGE_VLANDB_UNSPEC,
+ BRIDGE_VLANDB_ENTRY,
+ __BRIDGE_VLANDB_MAX,
+};
+#define BRIDGE_VLANDB_MAX (__BRIDGE_VLANDB_MAX - 1)
+
+enum {
+ BRIDGE_VLANDB_ENTRY_UNSPEC,
+ BRIDGE_VLANDB_ENTRY_INFO,
+ BRIDGE_VLANDB_ENTRY_RANGE,
+ BRIDGE_VLANDB_ENTRY_STATE,
+ BRIDGE_VLANDB_ENTRY_TUNNEL_INFO,
+ BRIDGE_VLANDB_ENTRY_STATS,
+ __BRIDGE_VLANDB_ENTRY_MAX,
+};
+#define BRIDGE_VLANDB_ENTRY_MAX (__BRIDGE_VLANDB_ENTRY_MAX - 1)
+
+/* [BRIDGE_VLANDB_ENTRY] = {
+ * [BRIDGE_VLANDB_ENTRY_TUNNEL_INFO] = {
+ * [BRIDGE_VLANDB_TINFO_ID]
+ * ...
+ * }
+ * }
+ */
+enum {
+ BRIDGE_VLANDB_TINFO_UNSPEC,
+ BRIDGE_VLANDB_TINFO_ID,
+ BRIDGE_VLANDB_TINFO_CMD,
+ __BRIDGE_VLANDB_TINFO_MAX,
+};
+#define BRIDGE_VLANDB_TINFO_MAX (__BRIDGE_VLANDB_TINFO_MAX - 1)
+
+/* [BRIDGE_VLANDB_ENTRY] = {
+ * [BRIDGE_VLANDB_ENTRY_STATS] = {
+ * [BRIDGE_VLANDB_STATS_RX_BYTES]
+ * ...
+ * }
+ * ...
+ * }
+ */
+enum {
+ BRIDGE_VLANDB_STATS_UNSPEC,
+ BRIDGE_VLANDB_STATS_RX_BYTES,
+ BRIDGE_VLANDB_STATS_RX_PACKETS,
+ BRIDGE_VLANDB_STATS_TX_BYTES,
+ BRIDGE_VLANDB_STATS_TX_PACKETS,
+ BRIDGE_VLANDB_STATS_PAD,
+ __BRIDGE_VLANDB_STATS_MAX,
+};
+#define BRIDGE_VLANDB_STATS_MAX (__BRIDGE_VLANDB_STATS_MAX - 1)
+
+/* Bridge multicast database attributes
+ * [MDBA_MDB] = {
+ * [MDBA_MDB_ENTRY] = {
+ * [MDBA_MDB_ENTRY_INFO] {
+ * struct br_mdb_entry
+ * [MDBA_MDB_EATTR attributes]
+ * }
+ * }
+ * }
+ * [MDBA_ROUTER] = {
+ * [MDBA_ROUTER_PORT] = {
+ * u32 ifindex
+ * [MDBA_ROUTER_PATTR attributes]
+ * }
+ * }
+ */
+enum {
+ MDBA_UNSPEC,
+ MDBA_MDB,
+ MDBA_ROUTER,
+ __MDBA_MAX,
+};
+#define MDBA_MAX (__MDBA_MAX - 1)
+
+enum {
+ MDBA_MDB_UNSPEC,
+ MDBA_MDB_ENTRY,
+ __MDBA_MDB_MAX,
+};
+#define MDBA_MDB_MAX (__MDBA_MDB_MAX - 1)
+
+enum {
+ MDBA_MDB_ENTRY_UNSPEC,
+ MDBA_MDB_ENTRY_INFO,
+ __MDBA_MDB_ENTRY_MAX,
+};
+#define MDBA_MDB_ENTRY_MAX (__MDBA_MDB_ENTRY_MAX - 1)
+
+/* per mdb entry additional attributes */
+enum {
+ MDBA_MDB_EATTR_UNSPEC,
+ MDBA_MDB_EATTR_TIMER,
+ MDBA_MDB_EATTR_SRC_LIST,
+ MDBA_MDB_EATTR_GROUP_MODE,
+ MDBA_MDB_EATTR_SOURCE,
+ MDBA_MDB_EATTR_RTPROT,
+ __MDBA_MDB_EATTR_MAX
+};
+#define MDBA_MDB_EATTR_MAX (__MDBA_MDB_EATTR_MAX - 1)
+
+/* per mdb entry source */
+enum {
+ MDBA_MDB_SRCLIST_UNSPEC,
+ MDBA_MDB_SRCLIST_ENTRY,
+ __MDBA_MDB_SRCLIST_MAX
+};
+#define MDBA_MDB_SRCLIST_MAX (__MDBA_MDB_SRCLIST_MAX - 1)
+
+/* per mdb entry per source attributes
+ * these are embedded in MDBA_MDB_SRCLIST_ENTRY
+ */
+enum {
+ MDBA_MDB_SRCATTR_UNSPEC,
+ MDBA_MDB_SRCATTR_ADDRESS,
+ MDBA_MDB_SRCATTR_TIMER,
+ __MDBA_MDB_SRCATTR_MAX
+};
+#define MDBA_MDB_SRCATTR_MAX (__MDBA_MDB_SRCATTR_MAX - 1)
+
+/* multicast router types */
+enum {
+ MDB_RTR_TYPE_DISABLED,
+ MDB_RTR_TYPE_TEMP_QUERY,
+ MDB_RTR_TYPE_PERM,
+ MDB_RTR_TYPE_TEMP
+};
+
+enum {
+ MDBA_ROUTER_UNSPEC,
+ MDBA_ROUTER_PORT,
+ __MDBA_ROUTER_MAX,
+};
+#define MDBA_ROUTER_MAX (__MDBA_ROUTER_MAX - 1)
+
+/* router port attributes */
+enum {
+ MDBA_ROUTER_PATTR_UNSPEC,
+ MDBA_ROUTER_PATTR_TIMER,
+ MDBA_ROUTER_PATTR_TYPE,
+ __MDBA_ROUTER_PATTR_MAX
+};
+#define MDBA_ROUTER_PATTR_MAX (__MDBA_ROUTER_PATTR_MAX - 1)
+
+struct br_port_msg {
+ __u8 family;
+ __u32 ifindex;
+};
+
+struct br_mdb_entry {
+ __u32 ifindex;
+#define MDB_TEMPORARY 0
+#define MDB_PERMANENT 1
+ __u8 state;
+#define MDB_FLAGS_OFFLOAD (1 << 0)
+#define MDB_FLAGS_FAST_LEAVE (1 << 1)
+#define MDB_FLAGS_STAR_EXCL (1 << 2)
+#define MDB_FLAGS_BLOCKED (1 << 3)
+ __u8 flags;
+ __u16 vid;
+ struct {
+ union {
+ __be32 ip4;
+ struct in6_addr ip6;
+ unsigned char mac_addr[ETH_ALEN];
+ } u;
+ __be16 proto;
+ } addr;
+};
+
+enum {
+ MDBA_SET_ENTRY_UNSPEC,
+ MDBA_SET_ENTRY,
+ MDBA_SET_ENTRY_ATTRS,
+ __MDBA_SET_ENTRY_MAX,
+};
+#define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1)
+
+/* [MDBA_SET_ENTRY_ATTRS] = {
+ * [MDBE_ATTR_xxx]
+ * ...
+ * }
+ */
+enum {
+ MDBE_ATTR_UNSPEC,
+ MDBE_ATTR_SOURCE,
+ __MDBE_ATTR_MAX,
+};
+#define MDBE_ATTR_MAX (__MDBE_ATTR_MAX - 1)
+
+/* Embedded inside LINK_XSTATS_TYPE_BRIDGE */
+enum {
+ BRIDGE_XSTATS_UNSPEC,
+ BRIDGE_XSTATS_VLAN,
+ BRIDGE_XSTATS_MCAST,
+ BRIDGE_XSTATS_PAD,
+ BRIDGE_XSTATS_STP,
+ __BRIDGE_XSTATS_MAX
+};
+#define BRIDGE_XSTATS_MAX (__BRIDGE_XSTATS_MAX - 1)
+
+enum {
+ BR_MCAST_DIR_RX,
+ BR_MCAST_DIR_TX,
+ BR_MCAST_DIR_SIZE
+};
+
+/* IGMP/MLD statistics */
+struct br_mcast_stats {
+ __u64 igmp_v1queries[BR_MCAST_DIR_SIZE];
+ __u64 igmp_v2queries[BR_MCAST_DIR_SIZE];
+ __u64 igmp_v3queries[BR_MCAST_DIR_SIZE];
+ __u64 igmp_leaves[BR_MCAST_DIR_SIZE];
+ __u64 igmp_v1reports[BR_MCAST_DIR_SIZE];
+ __u64 igmp_v2reports[BR_MCAST_DIR_SIZE];
+ __u64 igmp_v3reports[BR_MCAST_DIR_SIZE];
+ __u64 igmp_parse_errors;
+
+ __u64 mld_v1queries[BR_MCAST_DIR_SIZE];
+ __u64 mld_v2queries[BR_MCAST_DIR_SIZE];
+ __u64 mld_leaves[BR_MCAST_DIR_SIZE];
+ __u64 mld_v1reports[BR_MCAST_DIR_SIZE];
+ __u64 mld_v2reports[BR_MCAST_DIR_SIZE];
+ __u64 mld_parse_errors;
+
+ __u64 mcast_bytes[BR_MCAST_DIR_SIZE];
+ __u64 mcast_packets[BR_MCAST_DIR_SIZE];
+};
+
+/* bridge boolean options
+ * BR_BOOLOPT_NO_LL_LEARN - disable learning from link-local packets
+ *
+ * IMPORTANT: if adding a new option do not forget to handle
+ * it in br_boolopt_toggle/get and bridge sysfs
+ */
+enum br_boolopt_id {
+ BR_BOOLOPT_NO_LL_LEARN,
+ BR_BOOLOPT_MAX
+};
+
+/* struct br_boolopt_multi - change multiple bridge boolean options
+ *
+ * @optval: new option values (bit per option)
+ * @optmask: options to change (bit per option)
+ */
+struct br_boolopt_multi {
+ __u32 optval;
+ __u32 optmask;
+};
+#endif /* _LINUX_IF_BRIDGE_H */
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
new file mode 100644
index 0000000..8e6f2c3
--- /dev/null
+++ b/include/linux/if_ether.h
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the Ethernet IEEE 802.3 interface.
+ *
+ * Version: @(#)if_ether.h 1.0.1a 02/08/94
+ *
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Donald Becker, <becker@super.org>
+ * Alan Cox, <alan@lxorguk.ukuu.org.uk>
+ * Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IF_ETHER_H
+#define _LINUX_IF_ETHER_H
+
+#include <linux/types.h>
+
+/*
+ * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
+ * and FCS/CRC (frame check sequence).
+ */
+
+#define ETH_ALEN 6 /* Octets in one ethernet addr */
+#define ETH_TLEN 2 /* Octets in ethernet type field */
+#define ETH_HLEN 14 /* Total octets in header. */
+#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN 1500 /* Max. octets in payload */
+#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
+#define ETH_FCS_LEN 4 /* Octets in the FCS */
+
+#define ETH_MIN_MTU 68 /* Min IPv4 MTU per RFC791 */
+#define ETH_MAX_MTU 0xFFFFU /* 65535, same as IP_MAX_MTU */
+
+/*
+ * These are the defined Ethernet Protocol ID's.
+ */
+
+#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
+#define ETH_P_PUP 0x0200 /* Xerox PUP packet */
+#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */
+#define ETH_P_TSN 0x22F0 /* TSN (IEEE 1722) packet */
+#define ETH_P_ERSPAN2 0x22EB /* ERSPAN version 2 (type III) */
+#define ETH_P_IP 0x0800 /* Internet Protocol packet */
+#define ETH_P_X25 0x0805 /* CCITT X.25 */
+#define ETH_P_ARP 0x0806 /* Address Resolution packet */
+#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */
+#define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP Addr Trans packet */
+#define ETH_P_BATMAN 0x4305 /* B.A.T.M.A.N.-Advanced packet [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_DEC 0x6000 /* DEC Assigned proto */
+#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */
+#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */
+#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */
+#define ETH_P_LAT 0x6004 /* DEC LAT */
+#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */
+#define ETH_P_CUST 0x6006 /* DEC Customer use */
+#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */
+#define ETH_P_TEB 0x6558 /* Trans Ether Bridging */
+#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */
+#define ETH_P_ATALK 0x809B /* Appletalk DDP */
+#define ETH_P_AARP 0x80F3 /* Appletalk AARP */
+#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
+#define ETH_P_ERSPAN 0x88BE /* ERSPAN type II */
+#define ETH_P_IPX 0x8137 /* IPX over DIX */
+#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
+#define ETH_P_PAUSE 0x8808 /* IEEE Pause frames. See 802.3 31B */
+#define ETH_P_SLOW 0x8809 /* Slow Protocol. See 802.3ad 43B */
+#define ETH_P_WCCP 0x883E /* Web-cache coordination protocol
+ * defined in draft-wilson-wrec-wccp-v2-00.txt */
+#define ETH_P_MPLS_UC 0x8847 /* MPLS Unicast traffic */
+#define ETH_P_MPLS_MC 0x8848 /* MPLS Multicast traffic */
+#define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */
+#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */
+#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */
+#define ETH_P_LINK_CTL 0x886c /* HPNA, wlan link local tunnel */
+#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport
+ * over Ethernet
+ */
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#define ETH_P_AOE 0x88A2 /* ATA over Ethernet */
+#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
+#define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */
+#define ETH_P_PREAUTH 0x88C7 /* 802.11 Preauthentication */
+#define ETH_P_TIPC 0x88CA /* TIPC */
+#define ETH_P_LLDP 0x88CC /* Link Layer Discovery Protocol */
+#define ETH_P_MRP 0x88E3 /* Media Redundancy Protocol */
+#define ETH_P_MACSEC 0x88E5 /* 802.1ae MACsec */
+#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */
+#define ETH_P_MVRP 0x88F5 /* 802.1Q MVRP */
+#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */
+#define ETH_P_NCSI 0x88F8 /* NCSI protocol */
+#define ETH_P_PRP 0x88FB /* IEC 62439-3 PRP/HSRv0 */
+#define ETH_P_CFM 0x8902 /* Connectivity Fault Management */
+#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */
+#define ETH_P_IBOE 0x8915 /* Infiniband over Ethernet */
+#define ETH_P_TDLS 0x890D /* TDLS */
+#define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */
+#define ETH_P_80221 0x8917 /* IEEE 802.21 Media Independent Handover Protocol */
+#define ETH_P_HSR 0x892F /* IEC 62439-3 HSRv1 */
+#define ETH_P_NSH 0x894F /* Network Service Header */
+#define ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */
+#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_DSA_8021Q 0xDADB /* Fake VLAN Header for DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_IFE 0xED3E /* ForCES inter-FE LFB type */
+#define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */
+
+#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is less than this value
+ * then the frame is Ethernet II. Else it is 802.3 */
+
+/*
+ * Non DIX types. Won't clash for 1500 types.
+ */
+
+#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
+#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
+#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
+#define ETH_P_802_2 0x0004 /* 802.2 frames */
+#define ETH_P_SNAP 0x0005 /* Internal only */
+#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */
+#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/
+#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */
+#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
+#define ETH_P_CAN 0x000C /* CAN: Controller Area Network */
+#define ETH_P_CANFD 0x000D /* CANFD: CAN flexible data rate*/
+#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
+#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */
+#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
+#define ETH_P_CONTROL 0x0016 /* Card specific control frames */
+#define ETH_P_IRDA 0x0017 /* Linux-IrDA */
+#define ETH_P_ECONET 0x0018 /* Acorn Econet */
+#define ETH_P_HDLC 0x0019 /* HDLC frames */
+#define ETH_P_ARCNET 0x001A /* 1A for ArcNet :-) */
+#define ETH_P_DSA 0x001B /* Distributed Switch Arch. */
+#define ETH_P_TRAILER 0x001C /* Trailer switch tagging */
+#define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */
+#define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */
+#define ETH_P_CAIF 0x00F7 /* ST-Ericsson CAIF protocol */
+#define ETH_P_XDSA 0x00F8 /* Multiplexed DSA protocol */
+#define ETH_P_MAP 0x00F9 /* Qualcomm multiplexing and
+ * aggregation protocol
+ */
+
+/*
+ * This is an Ethernet frame header.
+ */
+
+/* allow libcs like musl to deactivate this, glibc does not implement this. */
+#ifndef __UAPI_DEF_ETHHDR
+#define __UAPI_DEF_ETHHDR 1
+#endif
+
+#if __UAPI_DEF_ETHHDR
+struct ethhdr {
+ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
+ unsigned char h_source[ETH_ALEN]; /* source ether addr */
+ __be16 h_proto; /* packet type ID field */
+} __attribute__((packed));
+#endif
+
+
+#endif /* _LINUX_IF_ETHER_H */
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
new file mode 100644
index 0000000..5019337
--- /dev/null
+++ b/include/linux/if_link.h
@@ -0,0 +1,1251 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_IF_LINK_H
+#define _LINUX_IF_LINK_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+/* This struct should be in sync with struct rtnl_link_stats64 */
+struct rtnl_link_stats {
+ __u32 rx_packets;
+ __u32 tx_packets;
+ __u32 rx_bytes;
+ __u32 tx_bytes;
+ __u32 rx_errors;
+ __u32 tx_errors;
+ __u32 rx_dropped;
+ __u32 tx_dropped;
+ __u32 multicast;
+ __u32 collisions;
+ /* detailed rx_errors: */
+ __u32 rx_length_errors;
+ __u32 rx_over_errors;
+ __u32 rx_crc_errors;
+ __u32 rx_frame_errors;
+ __u32 rx_fifo_errors;
+ __u32 rx_missed_errors;
+
+ /* detailed tx_errors */
+ __u32 tx_aborted_errors;
+ __u32 tx_carrier_errors;
+ __u32 tx_fifo_errors;
+ __u32 tx_heartbeat_errors;
+ __u32 tx_window_errors;
+
+ /* for cslip etc */
+ __u32 rx_compressed;
+ __u32 tx_compressed;
+
+ __u32 rx_nohandler;
+};
+
+/**
+ * struct rtnl_link_stats64 - The main device statistics structure.
+ *
+ * @rx_packets: Number of good packets received by the interface.
+ * For hardware interfaces counts all good packets received from the device
+ * by the host, including packets which host had to drop at various stages
+ * of processing (even in the driver).
+ *
+ * @tx_packets: Number of packets successfully transmitted.
+ * For hardware interfaces counts packets which host was able to successfully
+ * hand over to the device, which does not necessarily mean that packets
+ * had been successfully transmitted out of the device, only that device
+ * acknowledged it copied them out of host memory.
+ *
+ * @rx_bytes: Number of good received bytes, corresponding to @rx_packets.
+ *
+ * For IEEE 802.3 devices should count the length of Ethernet Frames
+ * excluding the FCS.
+ *
+ * @tx_bytes: Number of good transmitted bytes, corresponding to @tx_packets.
+ *
+ * For IEEE 802.3 devices should count the length of Ethernet Frames
+ * excluding the FCS.
+ *
+ * @rx_errors: Total number of bad packets received on this network device.
+ * This counter must include events counted by @rx_length_errors,
+ * @rx_crc_errors, @rx_frame_errors and other errors not otherwise
+ * counted.
+ *
+ * @tx_errors: Total number of transmit problems.
+ * This counter must include events counter by @tx_aborted_errors,
+ * @tx_carrier_errors, @tx_fifo_errors, @tx_heartbeat_errors,
+ * @tx_window_errors and other errors not otherwise counted.
+ *
+ * @rx_dropped: Number of packets received but not processed,
+ * e.g. due to lack of resources or unsupported protocol.
+ * For hardware interfaces this counter may include packets discarded
+ * due to L2 address filtering but should not include packets dropped
+ * by the device due to buffer exhaustion which are counted separately in
+ * @rx_missed_errors (since procfs folds those two counters together).
+ *
+ * @tx_dropped: Number of packets dropped on their way to transmission,
+ * e.g. due to lack of resources.
+ *
+ * @multicast: Multicast packets received.
+ * For hardware interfaces this statistic is commonly calculated
+ * at the device level (unlike @rx_packets) and therefore may include
+ * packets which did not reach the host.
+ *
+ * For IEEE 802.3 devices this counter may be equivalent to:
+ *
+ * - 30.3.1.1.21 aMulticastFramesReceivedOK
+ *
+ * @collisions: Number of collisions during packet transmissions.
+ *
+ * @rx_length_errors: Number of packets dropped due to invalid length.
+ * Part of aggregate "frame" errors in `/proc/net/dev`.
+ *
+ * For IEEE 802.3 devices this counter should be equivalent to a sum
+ * of the following attributes:
+ *
+ * - 30.3.1.1.23 aInRangeLengthErrors
+ * - 30.3.1.1.24 aOutOfRangeLengthField
+ * - 30.3.1.1.25 aFrameTooLongErrors
+ *
+ * @rx_over_errors: Receiver FIFO overflow event counter.
+ *
+ * Historically the count of overflow events. Such events may be
+ * reported in the receive descriptors or via interrupts, and may
+ * not correspond one-to-one with dropped packets.
+ *
+ * The recommended interpretation for high speed interfaces is -
+ * number of packets dropped because they did not fit into buffers
+ * provided by the host, e.g. packets larger than MTU or next buffer
+ * in the ring was not available for a scatter transfer.
+ *
+ * Part of aggregate "frame" errors in `/proc/net/dev`.
+ *
+ * This statistics was historically used interchangeably with
+ * @rx_fifo_errors.
+ *
+ * This statistic corresponds to hardware events and is not commonly used
+ * on software devices.
+ *
+ * @rx_crc_errors: Number of packets received with a CRC error.
+ * Part of aggregate "frame" errors in `/proc/net/dev`.
+ *
+ * For IEEE 802.3 devices this counter must be equivalent to:
+ *
+ * - 30.3.1.1.6 aFrameCheckSequenceErrors
+ *
+ * @rx_frame_errors: Receiver frame alignment errors.
+ * Part of aggregate "frame" errors in `/proc/net/dev`.
+ *
+ * For IEEE 802.3 devices this counter should be equivalent to:
+ *
+ * - 30.3.1.1.7 aAlignmentErrors
+ *
+ * @rx_fifo_errors: Receiver FIFO error counter.
+ *
+ * Historically the count of overflow events. Those events may be
+ * reported in the receive descriptors or via interrupts, and may
+ * not correspond one-to-one with dropped packets.
+ *
+ * This statistics was used interchangeably with @rx_over_errors.
+ * Not recommended for use in drivers for high speed interfaces.
+ *
+ * This statistic is used on software devices, e.g. to count software
+ * packet queue overflow (can) or sequencing errors (GRE).
+ *
+ * @rx_missed_errors: Count of packets missed by the host.
+ * Folded into the "drop" counter in `/proc/net/dev`.
+ *
+ * Counts number of packets dropped by the device due to lack
+ * of buffer space. This usually indicates that the host interface
+ * is slower than the network interface, or host is not keeping up
+ * with the receive packet rate.
+ *
+ * This statistic corresponds to hardware events and is not used
+ * on software devices.
+ *
+ * @tx_aborted_errors:
+ * Part of aggregate "carrier" errors in `/proc/net/dev`.
+ * For IEEE 802.3 devices capable of half-duplex operation this counter
+ * must be equivalent to:
+ *
+ * - 30.3.1.1.11 aFramesAbortedDueToXSColls
+ *
+ * High speed interfaces may use this counter as a general device
+ * discard counter.
+ *
+ * @tx_carrier_errors: Number of frame transmission errors due to loss
+ * of carrier during transmission.
+ * Part of aggregate "carrier" errors in `/proc/net/dev`.
+ *
+ * For IEEE 802.3 devices this counter must be equivalent to:
+ *
+ * - 30.3.1.1.13 aCarrierSenseErrors
+ *
+ * @tx_fifo_errors: Number of frame transmission errors due to device
+ * FIFO underrun / underflow. This condition occurs when the device
+ * begins transmission of a frame but is unable to deliver the
+ * entire frame to the transmitter in time for transmission.
+ * Part of aggregate "carrier" errors in `/proc/net/dev`.
+ *
+ * @tx_heartbeat_errors: Number of Heartbeat / SQE Test errors for
+ * old half-duplex Ethernet.
+ * Part of aggregate "carrier" errors in `/proc/net/dev`.
+ *
+ * For IEEE 802.3 devices possibly equivalent to:
+ *
+ * - 30.3.2.1.4 aSQETestErrors
+ *
+ * @tx_window_errors: Number of frame transmission errors due
+ * to late collisions (for Ethernet - after the first 64B of transmission).
+ * Part of aggregate "carrier" errors in `/proc/net/dev`.
+ *
+ * For IEEE 802.3 devices this counter must be equivalent to:
+ *
+ * - 30.3.1.1.10 aLateCollisions
+ *
+ * @rx_compressed: Number of correctly received compressed packets.
+ * This counters is only meaningful for interfaces which support
+ * packet compression (e.g. CSLIP, PPP).
+ *
+ * @tx_compressed: Number of transmitted compressed packets.
+ * This counters is only meaningful for interfaces which support
+ * packet compression (e.g. CSLIP, PPP).
+ *
+ * @rx_nohandler: Number of packets received on the interface
+ * but dropped by the networking stack because the device is
+ * not designated to receive packets (e.g. backup link in a bond).
+ */
+struct rtnl_link_stats64 {
+ __u64 rx_packets;
+ __u64 tx_packets;
+ __u64 rx_bytes;
+ __u64 tx_bytes;
+ __u64 rx_errors;
+ __u64 tx_errors;
+ __u64 rx_dropped;
+ __u64 tx_dropped;
+ __u64 multicast;
+ __u64 collisions;
+
+ /* detailed rx_errors: */
+ __u64 rx_length_errors;
+ __u64 rx_over_errors;
+ __u64 rx_crc_errors;
+ __u64 rx_frame_errors;
+ __u64 rx_fifo_errors;
+ __u64 rx_missed_errors;
+
+ /* detailed tx_errors */
+ __u64 tx_aborted_errors;
+ __u64 tx_carrier_errors;
+ __u64 tx_fifo_errors;
+ __u64 tx_heartbeat_errors;
+ __u64 tx_window_errors;
+
+ /* for cslip etc */
+ __u64 rx_compressed;
+ __u64 tx_compressed;
+ __u64 rx_nohandler;
+};
+
+/* The struct should be in sync with struct ifmap */
+struct rtnl_link_ifmap {
+ __u64 mem_start;
+ __u64 mem_end;
+ __u64 base_addr;
+ __u16 irq;
+ __u8 dma;
+ __u8 port;
+};
+
+/*
+ * IFLA_AF_SPEC
+ * Contains nested attributes for address family specific attributes.
+ * Each address family may create a attribute with the address family
+ * number as type and create its own attribute structure in it.
+ *
+ * Example:
+ * [IFLA_AF_SPEC] = {
+ * [AF_INET] = {
+ * [IFLA_INET_CONF] = ...,
+ * },
+ * [AF_INET6] = {
+ * [IFLA_INET6_FLAGS] = ...,
+ * [IFLA_INET6_CONF] = ...,
+ * }
+ * }
+ */
+
+enum {
+ IFLA_UNSPEC,
+ IFLA_ADDRESS,
+ IFLA_BROADCAST,
+ IFLA_IFNAME,
+ IFLA_MTU,
+ IFLA_LINK,
+ IFLA_QDISC,
+ IFLA_STATS,
+ IFLA_COST,
+#define IFLA_COST IFLA_COST
+ IFLA_PRIORITY,
+#define IFLA_PRIORITY IFLA_PRIORITY
+ IFLA_MASTER,
+#define IFLA_MASTER IFLA_MASTER
+ IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */
+#define IFLA_WIRELESS IFLA_WIRELESS
+ IFLA_PROTINFO, /* Protocol specific information for a link */
+#define IFLA_PROTINFO IFLA_PROTINFO
+ IFLA_TXQLEN,
+#define IFLA_TXQLEN IFLA_TXQLEN
+ IFLA_MAP,
+#define IFLA_MAP IFLA_MAP
+ IFLA_WEIGHT,
+#define IFLA_WEIGHT IFLA_WEIGHT
+ IFLA_OPERSTATE,
+ IFLA_LINKMODE,
+ IFLA_LINKINFO,
+#define IFLA_LINKINFO IFLA_LINKINFO
+ IFLA_NET_NS_PID,
+ IFLA_IFALIAS,
+ IFLA_NUM_VF, /* Number of VFs if device is SR-IOV PF */
+ IFLA_VFINFO_LIST,
+ IFLA_STATS64,
+ IFLA_VF_PORTS,
+ IFLA_PORT_SELF,
+ IFLA_AF_SPEC,
+ IFLA_GROUP, /* Group the device belongs to */
+ IFLA_NET_NS_FD,
+ IFLA_EXT_MASK, /* Extended info mask, VFs, etc */
+ IFLA_PROMISCUITY, /* Promiscuity count: > 0 means acts PROMISC */
+#define IFLA_PROMISCUITY IFLA_PROMISCUITY
+ IFLA_NUM_TX_QUEUES,
+ IFLA_NUM_RX_QUEUES,
+ IFLA_CARRIER,
+ IFLA_PHYS_PORT_ID,
+ IFLA_CARRIER_CHANGES,
+ IFLA_PHYS_SWITCH_ID,
+ IFLA_LINK_NETNSID,
+ IFLA_PHYS_PORT_NAME,
+ IFLA_PROTO_DOWN,
+ IFLA_GSO_MAX_SEGS,
+ IFLA_GSO_MAX_SIZE,
+ IFLA_PAD,
+ IFLA_XDP,
+ IFLA_EVENT,
+ IFLA_NEW_NETNSID,
+ IFLA_IF_NETNSID,
+ IFLA_TARGET_NETNSID = IFLA_IF_NETNSID, /* new alias */
+ IFLA_CARRIER_UP_COUNT,
+ IFLA_CARRIER_DOWN_COUNT,
+ IFLA_NEW_IFINDEX,
+ IFLA_MIN_MTU,
+ IFLA_MAX_MTU,
+ IFLA_PROP_LIST,
+ IFLA_ALT_IFNAME, /* Alternative ifname */
+ IFLA_PERM_ADDRESS,
+ IFLA_PROTO_DOWN_REASON,
+ __IFLA_MAX
+};
+
+
+#define IFLA_MAX (__IFLA_MAX - 1)
+
+enum {
+ IFLA_PROTO_DOWN_REASON_UNSPEC,
+ IFLA_PROTO_DOWN_REASON_MASK, /* u32, mask for reason bits */
+ IFLA_PROTO_DOWN_REASON_VALUE, /* u32, reason bit value */
+
+ __IFLA_PROTO_DOWN_REASON_CNT,
+ IFLA_PROTO_DOWN_REASON_MAX = __IFLA_PROTO_DOWN_REASON_CNT - 1
+};
+
+/* backwards compatibility for userspace */
+#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+
+enum {
+ IFLA_INET_UNSPEC,
+ IFLA_INET_CONF,
+ __IFLA_INET_MAX,
+};
+
+#define IFLA_INET_MAX (__IFLA_INET_MAX - 1)
+
+/* ifi_flags.
+
+ IFF_* flags.
+
+ The only change is:
+ IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
+ more not changeable by user. They describe link media
+ characteristics and set by device driver.
+
+ Comments:
+ - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
+ - If neither of these three flags are set;
+ the interface is NBMA.
+
+ - IFF_MULTICAST does not mean anything special:
+ multicasts can be used on all not-NBMA links.
+ IFF_MULTICAST means that this media uses special encapsulation
+ for multicast frames. Apparently, all IFF_POINTOPOINT and
+ IFF_BROADCAST devices are able to use multicasts too.
+ */
+
+/* IFLA_LINK.
+ For usual devices it is equal ifi_index.
+ If it is a "virtual interface" (f.e. tunnel), ifi_link
+ can point to real physical interface (f.e. for bandwidth calculations),
+ or maybe 0, what means, that real media is unknown (usual
+ for IPIP tunnels, when route to endpoint is allowed to change)
+ */
+
+/* Subtype attributes for IFLA_PROTINFO */
+enum {
+ IFLA_INET6_UNSPEC,
+ IFLA_INET6_FLAGS, /* link flags */
+ IFLA_INET6_CONF, /* sysctl parameters */
+ IFLA_INET6_STATS, /* statistics */
+ IFLA_INET6_MCAST, /* MC things. What of them? */
+ IFLA_INET6_CACHEINFO, /* time values and max reasm size */
+ IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */
+ IFLA_INET6_TOKEN, /* device token */
+ IFLA_INET6_ADDR_GEN_MODE, /* implicit address generator mode */
+ __IFLA_INET6_MAX
+};
+
+#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
+
+enum in6_addr_gen_mode {
+ IN6_ADDR_GEN_MODE_EUI64,
+ IN6_ADDR_GEN_MODE_NONE,
+ IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
+ IN6_ADDR_GEN_MODE_RANDOM,
+};
+
+/* Bridge section */
+
+enum {
+ IFLA_BR_UNSPEC,
+ IFLA_BR_FORWARD_DELAY,
+ IFLA_BR_HELLO_TIME,
+ IFLA_BR_MAX_AGE,
+ IFLA_BR_AGEING_TIME,
+ IFLA_BR_STP_STATE,
+ IFLA_BR_PRIORITY,
+ IFLA_BR_VLAN_FILTERING,
+ IFLA_BR_VLAN_PROTOCOL,
+ IFLA_BR_GROUP_FWD_MASK,
+ IFLA_BR_ROOT_ID,
+ IFLA_BR_BRIDGE_ID,
+ IFLA_BR_ROOT_PORT,
+ IFLA_BR_ROOT_PATH_COST,
+ IFLA_BR_TOPOLOGY_CHANGE,
+ IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
+ IFLA_BR_HELLO_TIMER,
+ IFLA_BR_TCN_TIMER,
+ IFLA_BR_TOPOLOGY_CHANGE_TIMER,
+ IFLA_BR_GC_TIMER,
+ IFLA_BR_GROUP_ADDR,
+ IFLA_BR_FDB_FLUSH,
+ IFLA_BR_MCAST_ROUTER,
+ IFLA_BR_MCAST_SNOOPING,
+ IFLA_BR_MCAST_QUERY_USE_IFADDR,
+ IFLA_BR_MCAST_QUERIER,
+ IFLA_BR_MCAST_HASH_ELASTICITY,
+ IFLA_BR_MCAST_HASH_MAX,
+ IFLA_BR_MCAST_LAST_MEMBER_CNT,
+ IFLA_BR_MCAST_STARTUP_QUERY_CNT,
+ IFLA_BR_MCAST_LAST_MEMBER_INTVL,
+ IFLA_BR_MCAST_MEMBERSHIP_INTVL,
+ IFLA_BR_MCAST_QUERIER_INTVL,
+ IFLA_BR_MCAST_QUERY_INTVL,
+ IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
+ IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
+ IFLA_BR_NF_CALL_IPTABLES,
+ IFLA_BR_NF_CALL_IP6TABLES,
+ IFLA_BR_NF_CALL_ARPTABLES,
+ IFLA_BR_VLAN_DEFAULT_PVID,
+ IFLA_BR_PAD,
+ IFLA_BR_VLAN_STATS_ENABLED,
+ IFLA_BR_MCAST_STATS_ENABLED,
+ IFLA_BR_MCAST_IGMP_VERSION,
+ IFLA_BR_MCAST_MLD_VERSION,
+ IFLA_BR_VLAN_STATS_PER_PORT,
+ IFLA_BR_MULTI_BOOLOPT,
+ __IFLA_BR_MAX,
+};
+
+#define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
+
+struct ifla_bridge_id {
+ __u8 prio[2];
+ __u8 addr[6]; /* ETH_ALEN */
+};
+
+enum {
+ BRIDGE_MODE_UNSPEC,
+ BRIDGE_MODE_HAIRPIN,
+};
+
+enum {
+ IFLA_BRPORT_UNSPEC,
+ IFLA_BRPORT_STATE, /* Spanning tree state */
+ IFLA_BRPORT_PRIORITY, /* " priority */
+ IFLA_BRPORT_COST, /* " cost */
+ IFLA_BRPORT_MODE, /* mode (hairpin) */
+ IFLA_BRPORT_GUARD, /* bpdu guard */
+ IFLA_BRPORT_PROTECT, /* root port protection */
+ IFLA_BRPORT_FAST_LEAVE, /* multicast fast leave */
+ IFLA_BRPORT_LEARNING, /* mac learning */
+ IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */
+ IFLA_BRPORT_PROXYARP, /* proxy ARP */
+ IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */
+ IFLA_BRPORT_PROXYARP_WIFI, /* proxy ARP for Wi-Fi */
+ IFLA_BRPORT_ROOT_ID, /* designated root */
+ IFLA_BRPORT_BRIDGE_ID, /* designated bridge */
+ IFLA_BRPORT_DESIGNATED_PORT,
+ IFLA_BRPORT_DESIGNATED_COST,
+ IFLA_BRPORT_ID,
+ IFLA_BRPORT_NO,
+ IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
+ IFLA_BRPORT_CONFIG_PENDING,
+ IFLA_BRPORT_MESSAGE_AGE_TIMER,
+ IFLA_BRPORT_FORWARD_DELAY_TIMER,
+ IFLA_BRPORT_HOLD_TIMER,
+ IFLA_BRPORT_FLUSH,
+ IFLA_BRPORT_MULTICAST_ROUTER,
+ IFLA_BRPORT_PAD,
+ IFLA_BRPORT_MCAST_FLOOD,
+ IFLA_BRPORT_MCAST_TO_UCAST,
+ IFLA_BRPORT_VLAN_TUNNEL,
+ IFLA_BRPORT_BCAST_FLOOD,
+ IFLA_BRPORT_GROUP_FWD_MASK,
+ IFLA_BRPORT_NEIGH_SUPPRESS,
+ IFLA_BRPORT_ISOLATED,
+ IFLA_BRPORT_BACKUP_PORT,
+ IFLA_BRPORT_MRP_RING_OPEN,
+ IFLA_BRPORT_MRP_IN_OPEN,
+ IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT,
+ IFLA_BRPORT_MCAST_EHT_HOSTS_CNT,
+ __IFLA_BRPORT_MAX
+};
+#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
+
+struct ifla_cacheinfo {
+ __u32 max_reasm_len;
+ __u32 tstamp; /* ipv6InterfaceTable updated timestamp */
+ __u32 reachable_time;
+ __u32 retrans_time;
+};
+
+enum {
+ IFLA_INFO_UNSPEC,
+ IFLA_INFO_KIND,
+ IFLA_INFO_DATA,
+ IFLA_INFO_XSTATS,
+ IFLA_INFO_SLAVE_KIND,
+ IFLA_INFO_SLAVE_DATA,
+ __IFLA_INFO_MAX,
+};
+
+#define IFLA_INFO_MAX (__IFLA_INFO_MAX - 1)
+
+/* VLAN section */
+
+enum {
+ IFLA_VLAN_UNSPEC,
+ IFLA_VLAN_ID,
+ IFLA_VLAN_FLAGS,
+ IFLA_VLAN_EGRESS_QOS,
+ IFLA_VLAN_INGRESS_QOS,
+ IFLA_VLAN_PROTOCOL,
+ __IFLA_VLAN_MAX,
+};
+
+#define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1)
+
+struct ifla_vlan_flags {
+ __u32 flags;
+ __u32 mask;
+};
+
+enum {
+ IFLA_VLAN_QOS_UNSPEC,
+ IFLA_VLAN_QOS_MAPPING,
+ __IFLA_VLAN_QOS_MAX
+};
+
+#define IFLA_VLAN_QOS_MAX (__IFLA_VLAN_QOS_MAX - 1)
+
+struct ifla_vlan_qos_mapping {
+ __u32 from;
+ __u32 to;
+};
+
+/* MACVLAN section */
+enum {
+ IFLA_MACVLAN_UNSPEC,
+ IFLA_MACVLAN_MODE,
+ IFLA_MACVLAN_FLAGS,
+ IFLA_MACVLAN_MACADDR_MODE,
+ IFLA_MACVLAN_MACADDR,
+ IFLA_MACVLAN_MACADDR_DATA,
+ IFLA_MACVLAN_MACADDR_COUNT,
+ IFLA_MACVLAN_BC_QUEUE_LEN,
+ IFLA_MACVLAN_BC_QUEUE_LEN_USED,
+ __IFLA_MACVLAN_MAX,
+};
+
+#define IFLA_MACVLAN_MAX (__IFLA_MACVLAN_MAX - 1)
+
+enum macvlan_mode {
+ MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */
+ MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */
+ MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */
+ MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */
+ MACVLAN_MODE_SOURCE = 16,/* use source MAC address list to assign */
+};
+
+enum macvlan_macaddr_mode {
+ MACVLAN_MACADDR_ADD,
+ MACVLAN_MACADDR_DEL,
+ MACVLAN_MACADDR_FLUSH,
+ MACVLAN_MACADDR_SET,
+};
+
+#define MACVLAN_FLAG_NOPROMISC 1
+
+/* VRF section */
+enum {
+ IFLA_VRF_UNSPEC,
+ IFLA_VRF_TABLE,
+ __IFLA_VRF_MAX
+};
+
+#define IFLA_VRF_MAX (__IFLA_VRF_MAX - 1)
+
+enum {
+ IFLA_VRF_PORT_UNSPEC,
+ IFLA_VRF_PORT_TABLE,
+ __IFLA_VRF_PORT_MAX
+};
+
+#define IFLA_VRF_PORT_MAX (__IFLA_VRF_PORT_MAX - 1)
+
+/* MACSEC section */
+enum {
+ IFLA_MACSEC_UNSPEC,
+ IFLA_MACSEC_SCI,
+ IFLA_MACSEC_PORT,
+ IFLA_MACSEC_ICV_LEN,
+ IFLA_MACSEC_CIPHER_SUITE,
+ IFLA_MACSEC_WINDOW,
+ IFLA_MACSEC_ENCODING_SA,
+ IFLA_MACSEC_ENCRYPT,
+ IFLA_MACSEC_PROTECT,
+ IFLA_MACSEC_INC_SCI,
+ IFLA_MACSEC_ES,
+ IFLA_MACSEC_SCB,
+ IFLA_MACSEC_REPLAY_PROTECT,
+ IFLA_MACSEC_VALIDATION,
+ IFLA_MACSEC_PAD,
+ IFLA_MACSEC_OFFLOAD,
+ __IFLA_MACSEC_MAX,
+};
+
+#define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1)
+
+/* XFRM section */
+enum {
+ IFLA_XFRM_UNSPEC,
+ IFLA_XFRM_LINK,
+ IFLA_XFRM_IF_ID,
+ __IFLA_XFRM_MAX
+};
+
+#define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1)
+
+enum macsec_validation_type {
+ MACSEC_VALIDATE_DISABLED = 0,
+ MACSEC_VALIDATE_CHECK = 1,
+ MACSEC_VALIDATE_STRICT = 2,
+ __MACSEC_VALIDATE_END,
+ MACSEC_VALIDATE_MAX = __MACSEC_VALIDATE_END - 1,
+};
+
+enum macsec_offload {
+ MACSEC_OFFLOAD_OFF = 0,
+ MACSEC_OFFLOAD_PHY = 1,
+ MACSEC_OFFLOAD_MAC = 2,
+ __MACSEC_OFFLOAD_END,
+ MACSEC_OFFLOAD_MAX = __MACSEC_OFFLOAD_END - 1,
+};
+
+/* IPVLAN section */
+enum {
+ IFLA_IPVLAN_UNSPEC,
+ IFLA_IPVLAN_MODE,
+ IFLA_IPVLAN_FLAGS,
+ __IFLA_IPVLAN_MAX
+};
+
+#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1)
+
+enum ipvlan_mode {
+ IPVLAN_MODE_L2 = 0,
+ IPVLAN_MODE_L3,
+ IPVLAN_MODE_L3S,
+ IPVLAN_MODE_MAX
+};
+
+#define IPVLAN_F_PRIVATE 0x01
+#define IPVLAN_F_VEPA 0x02
+
+/* VXLAN section */
+enum {
+ IFLA_VXLAN_UNSPEC,
+ IFLA_VXLAN_ID,
+ IFLA_VXLAN_GROUP, /* group or remote address */
+ IFLA_VXLAN_LINK,
+ IFLA_VXLAN_LOCAL,
+ IFLA_VXLAN_TTL,
+ IFLA_VXLAN_TOS,
+ IFLA_VXLAN_LEARNING,
+ IFLA_VXLAN_AGEING,
+ IFLA_VXLAN_LIMIT,
+ IFLA_VXLAN_PORT_RANGE, /* source port */
+ IFLA_VXLAN_PROXY,
+ IFLA_VXLAN_RSC,
+ IFLA_VXLAN_L2MISS,
+ IFLA_VXLAN_L3MISS,
+ IFLA_VXLAN_PORT, /* destination port */
+ IFLA_VXLAN_GROUP6,
+ IFLA_VXLAN_LOCAL6,
+ IFLA_VXLAN_UDP_CSUM,
+ IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
+ IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
+ IFLA_VXLAN_REMCSUM_TX,
+ IFLA_VXLAN_REMCSUM_RX,
+ IFLA_VXLAN_GBP,
+ IFLA_VXLAN_REMCSUM_NOPARTIAL,
+ IFLA_VXLAN_COLLECT_METADATA,
+ IFLA_VXLAN_LABEL,
+ IFLA_VXLAN_GPE,
+ IFLA_VXLAN_TTL_INHERIT,
+ IFLA_VXLAN_DF,
+ __IFLA_VXLAN_MAX
+};
+#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
+
+struct ifla_vxlan_port_range {
+ __be16 low;
+ __be16 high;
+};
+
+enum ifla_vxlan_df {
+ VXLAN_DF_UNSET = 0,
+ VXLAN_DF_SET,
+ VXLAN_DF_INHERIT,
+ __VXLAN_DF_END,
+ VXLAN_DF_MAX = __VXLAN_DF_END - 1,
+};
+
+/* GENEVE section */
+enum {
+ IFLA_GENEVE_UNSPEC,
+ IFLA_GENEVE_ID,
+ IFLA_GENEVE_REMOTE,
+ IFLA_GENEVE_TTL,
+ IFLA_GENEVE_TOS,
+ IFLA_GENEVE_PORT, /* destination port */
+ IFLA_GENEVE_COLLECT_METADATA,
+ IFLA_GENEVE_REMOTE6,
+ IFLA_GENEVE_UDP_CSUM,
+ IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
+ IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
+ IFLA_GENEVE_LABEL,
+ IFLA_GENEVE_TTL_INHERIT,
+ IFLA_GENEVE_DF,
+ __IFLA_GENEVE_MAX
+};
+#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
+
+enum ifla_geneve_df {
+ GENEVE_DF_UNSET = 0,
+ GENEVE_DF_SET,
+ GENEVE_DF_INHERIT,
+ __GENEVE_DF_END,
+ GENEVE_DF_MAX = __GENEVE_DF_END - 1,
+};
+
+/* Bareudp section */
+enum {
+ IFLA_BAREUDP_UNSPEC,
+ IFLA_BAREUDP_PORT,
+ IFLA_BAREUDP_ETHERTYPE,
+ IFLA_BAREUDP_SRCPORT_MIN,
+ IFLA_BAREUDP_MULTIPROTO_MODE,
+ __IFLA_BAREUDP_MAX
+};
+
+#define IFLA_BAREUDP_MAX (__IFLA_BAREUDP_MAX - 1)
+
+/* PPP section */
+enum {
+ IFLA_PPP_UNSPEC,
+ IFLA_PPP_DEV_FD,
+ __IFLA_PPP_MAX
+};
+#define IFLA_PPP_MAX (__IFLA_PPP_MAX - 1)
+
+/* GTP section */
+
+enum ifla_gtp_role {
+ GTP_ROLE_GGSN = 0,
+ GTP_ROLE_SGSN,
+};
+
+enum {
+ IFLA_GTP_UNSPEC,
+ IFLA_GTP_FD0,
+ IFLA_GTP_FD1,
+ IFLA_GTP_PDP_HASHSIZE,
+ IFLA_GTP_ROLE,
+ __IFLA_GTP_MAX,
+};
+#define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)
+
+/* Bonding section */
+
+enum {
+ IFLA_BOND_UNSPEC,
+ IFLA_BOND_MODE,
+ IFLA_BOND_ACTIVE_SLAVE,
+ IFLA_BOND_MIIMON,
+ IFLA_BOND_UPDELAY,
+ IFLA_BOND_DOWNDELAY,
+ IFLA_BOND_USE_CARRIER,
+ IFLA_BOND_ARP_INTERVAL,
+ IFLA_BOND_ARP_IP_TARGET,
+ IFLA_BOND_ARP_VALIDATE,
+ IFLA_BOND_ARP_ALL_TARGETS,
+ IFLA_BOND_PRIMARY,
+ IFLA_BOND_PRIMARY_RESELECT,
+ IFLA_BOND_FAIL_OVER_MAC,
+ IFLA_BOND_XMIT_HASH_POLICY,
+ IFLA_BOND_RESEND_IGMP,
+ IFLA_BOND_NUM_PEER_NOTIF,
+ IFLA_BOND_ALL_SLAVES_ACTIVE,
+ IFLA_BOND_MIN_LINKS,
+ IFLA_BOND_LP_INTERVAL,
+ IFLA_BOND_PACKETS_PER_SLAVE,
+ IFLA_BOND_AD_LACP_RATE,
+ IFLA_BOND_AD_SELECT,
+ IFLA_BOND_AD_INFO,
+ IFLA_BOND_AD_ACTOR_SYS_PRIO,
+ IFLA_BOND_AD_USER_PORT_KEY,
+ IFLA_BOND_AD_ACTOR_SYSTEM,
+ IFLA_BOND_TLB_DYNAMIC_LB,
+ IFLA_BOND_PEER_NOTIF_DELAY,
+ __IFLA_BOND_MAX,
+};
+
+#define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1)
+
+enum {
+ IFLA_BOND_AD_INFO_UNSPEC,
+ IFLA_BOND_AD_INFO_AGGREGATOR,
+ IFLA_BOND_AD_INFO_NUM_PORTS,
+ IFLA_BOND_AD_INFO_ACTOR_KEY,
+ IFLA_BOND_AD_INFO_PARTNER_KEY,
+ IFLA_BOND_AD_INFO_PARTNER_MAC,
+ __IFLA_BOND_AD_INFO_MAX,
+};
+
+#define IFLA_BOND_AD_INFO_MAX (__IFLA_BOND_AD_INFO_MAX - 1)
+
+enum {
+ IFLA_BOND_SLAVE_UNSPEC,
+ IFLA_BOND_SLAVE_STATE,
+ IFLA_BOND_SLAVE_MII_STATUS,
+ IFLA_BOND_SLAVE_LINK_FAILURE_COUNT,
+ IFLA_BOND_SLAVE_PERM_HWADDR,
+ IFLA_BOND_SLAVE_QUEUE_ID,
+ IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
+ IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
+ IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
+ __IFLA_BOND_SLAVE_MAX,
+};
+
+#define IFLA_BOND_SLAVE_MAX (__IFLA_BOND_SLAVE_MAX - 1)
+
+/* SR-IOV virtual function management section */
+
+enum {
+ IFLA_VF_INFO_UNSPEC,
+ IFLA_VF_INFO,
+ __IFLA_VF_INFO_MAX,
+};
+
+#define IFLA_VF_INFO_MAX (__IFLA_VF_INFO_MAX - 1)
+
+enum {
+ IFLA_VF_UNSPEC,
+ IFLA_VF_MAC, /* Hardware queue specific attributes */
+ IFLA_VF_VLAN, /* VLAN ID and QoS */
+ IFLA_VF_TX_RATE, /* Max TX Bandwidth Allocation */
+ IFLA_VF_SPOOFCHK, /* Spoof Checking on/off switch */
+ IFLA_VF_LINK_STATE, /* link state enable/disable/auto switch */
+ IFLA_VF_RATE, /* Min and Max TX Bandwidth Allocation */
+ IFLA_VF_RSS_QUERY_EN, /* RSS Redirection Table and Hash Key query
+ * on/off switch
+ */
+ IFLA_VF_STATS, /* network device statistics */
+ IFLA_VF_TRUST, /* Trust VF */
+ IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */
+ IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */
+ IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */
+ IFLA_VF_BROADCAST, /* VF broadcast */
+ __IFLA_VF_MAX,
+};
+
+#define IFLA_VF_MAX (__IFLA_VF_MAX - 1)
+
+struct ifla_vf_mac {
+ __u32 vf;
+ __u8 mac[32]; /* MAX_ADDR_LEN */
+};
+
+struct ifla_vf_broadcast {
+ __u8 broadcast[32];
+};
+
+struct ifla_vf_vlan {
+ __u32 vf;
+ __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
+ __u32 qos;
+};
+
+enum {
+ IFLA_VF_VLAN_INFO_UNSPEC,
+ IFLA_VF_VLAN_INFO, /* VLAN ID, QoS and VLAN protocol */
+ __IFLA_VF_VLAN_INFO_MAX,
+};
+
+#define IFLA_VF_VLAN_INFO_MAX (__IFLA_VF_VLAN_INFO_MAX - 1)
+#define MAX_VLAN_LIST_LEN 1
+
+struct ifla_vf_vlan_info {
+ __u32 vf;
+ __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
+ __u32 qos;
+ __be16 vlan_proto; /* VLAN protocol either 802.1Q or 802.1ad */
+};
+
+struct ifla_vf_tx_rate {
+ __u32 vf;
+ __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
+};
+
+struct ifla_vf_rate {
+ __u32 vf;
+ __u32 min_tx_rate; /* Min Bandwidth in Mbps */
+ __u32 max_tx_rate; /* Max Bandwidth in Mbps */
+};
+
+struct ifla_vf_spoofchk {
+ __u32 vf;
+ __u32 setting;
+};
+
+struct ifla_vf_guid {
+ __u32 vf;
+ __u64 guid;
+};
+
+enum {
+ IFLA_VF_LINK_STATE_AUTO, /* link state of the uplink */
+ IFLA_VF_LINK_STATE_ENABLE, /* link always up */
+ IFLA_VF_LINK_STATE_DISABLE, /* link always down */
+ __IFLA_VF_LINK_STATE_MAX,
+};
+
+struct ifla_vf_link_state {
+ __u32 vf;
+ __u32 link_state;
+};
+
+struct ifla_vf_rss_query_en {
+ __u32 vf;
+ __u32 setting;
+};
+
+enum {
+ IFLA_VF_STATS_RX_PACKETS,
+ IFLA_VF_STATS_TX_PACKETS,
+ IFLA_VF_STATS_RX_BYTES,
+ IFLA_VF_STATS_TX_BYTES,
+ IFLA_VF_STATS_BROADCAST,
+ IFLA_VF_STATS_MULTICAST,
+ IFLA_VF_STATS_PAD,
+ IFLA_VF_STATS_RX_DROPPED,
+ IFLA_VF_STATS_TX_DROPPED,
+ __IFLA_VF_STATS_MAX,
+};
+
+#define IFLA_VF_STATS_MAX (__IFLA_VF_STATS_MAX - 1)
+
+struct ifla_vf_trust {
+ __u32 vf;
+ __u32 setting;
+};
+
+/* VF ports management section
+ *
+ * Nested layout of set/get msg is:
+ *
+ * [IFLA_NUM_VF]
+ * [IFLA_VF_PORTS]
+ * [IFLA_VF_PORT]
+ * [IFLA_PORT_*], ...
+ * [IFLA_VF_PORT]
+ * [IFLA_PORT_*], ...
+ * ...
+ * [IFLA_PORT_SELF]
+ * [IFLA_PORT_*], ...
+ */
+
+enum {
+ IFLA_VF_PORT_UNSPEC,
+ IFLA_VF_PORT, /* nest */
+ __IFLA_VF_PORT_MAX,
+};
+
+#define IFLA_VF_PORT_MAX (__IFLA_VF_PORT_MAX - 1)
+
+enum {
+ IFLA_PORT_UNSPEC,
+ IFLA_PORT_VF, /* __u32 */
+ IFLA_PORT_PROFILE, /* string */
+ IFLA_PORT_VSI_TYPE, /* 802.1Qbg (pre-)standard VDP */
+ IFLA_PORT_INSTANCE_UUID, /* binary UUID */
+ IFLA_PORT_HOST_UUID, /* binary UUID */
+ IFLA_PORT_REQUEST, /* __u8 */
+ IFLA_PORT_RESPONSE, /* __u16, output only */
+ __IFLA_PORT_MAX,
+};
+
+#define IFLA_PORT_MAX (__IFLA_PORT_MAX - 1)
+
+#define PORT_PROFILE_MAX 40
+#define PORT_UUID_MAX 16
+#define PORT_SELF_VF -1
+
+enum {
+ PORT_REQUEST_PREASSOCIATE = 0,
+ PORT_REQUEST_PREASSOCIATE_RR,
+ PORT_REQUEST_ASSOCIATE,
+ PORT_REQUEST_DISASSOCIATE,
+};
+
+enum {
+ PORT_VDP_RESPONSE_SUCCESS = 0,
+ PORT_VDP_RESPONSE_INVALID_FORMAT,
+ PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES,
+ PORT_VDP_RESPONSE_UNUSED_VTID,
+ PORT_VDP_RESPONSE_VTID_VIOLATION,
+ PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION,
+ PORT_VDP_RESPONSE_OUT_OF_SYNC,
+ /* 0x08-0xFF reserved for future VDP use */
+ PORT_PROFILE_RESPONSE_SUCCESS = 0x100,
+ PORT_PROFILE_RESPONSE_INPROGRESS,
+ PORT_PROFILE_RESPONSE_INVALID,
+ PORT_PROFILE_RESPONSE_BADSTATE,
+ PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES,
+ PORT_PROFILE_RESPONSE_ERROR,
+};
+
+struct ifla_port_vsi {
+ __u8 vsi_mgr_id;
+ __u8 vsi_type_id[3];
+ __u8 vsi_type_version;
+ __u8 pad[3];
+};
+
+
+/* IPoIB section */
+
+enum {
+ IFLA_IPOIB_UNSPEC,
+ IFLA_IPOIB_PKEY,
+ IFLA_IPOIB_MODE,
+ IFLA_IPOIB_UMCAST,
+ __IFLA_IPOIB_MAX
+};
+
+enum {
+ IPOIB_MODE_DATAGRAM = 0, /* using unreliable datagram QPs */
+ IPOIB_MODE_CONNECTED = 1, /* using connected QPs */
+};
+
+#define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1)
+
+
+/* HSR/PRP section, both uses same interface */
+
+/* Different redundancy protocols for hsr device */
+enum {
+ HSR_PROTOCOL_HSR,
+ HSR_PROTOCOL_PRP,
+ HSR_PROTOCOL_MAX,
+};
+
+enum {
+ IFLA_HSR_UNSPEC,
+ IFLA_HSR_SLAVE1,
+ IFLA_HSR_SLAVE2,
+ IFLA_HSR_MULTICAST_SPEC, /* Last byte of supervision addr */
+ IFLA_HSR_SUPERVISION_ADDR, /* Supervision frame multicast addr */
+ IFLA_HSR_SEQ_NR,
+ IFLA_HSR_VERSION, /* HSR version */
+ IFLA_HSR_PROTOCOL, /* Indicate different protocol than
+ * HSR. For example PRP.
+ */
+ __IFLA_HSR_MAX,
+};
+
+#define IFLA_HSR_MAX (__IFLA_HSR_MAX - 1)
+
+/* STATS section */
+
+struct if_stats_msg {
+ __u8 family;
+ __u8 pad1;
+ __u16 pad2;
+ __u32 ifindex;
+ __u32 filter_mask;
+};
+
+/* A stats attribute can be netdev specific or a global stat.
+ * For netdev stats, lets use the prefix IFLA_STATS_LINK_*
+ */
+enum {
+ IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */
+ IFLA_STATS_LINK_64,
+ IFLA_STATS_LINK_XSTATS,
+ IFLA_STATS_LINK_XSTATS_SLAVE,
+ IFLA_STATS_LINK_OFFLOAD_XSTATS,
+ IFLA_STATS_AF_SPEC,
+ __IFLA_STATS_MAX,
+};
+
+#define IFLA_STATS_MAX (__IFLA_STATS_MAX - 1)
+
+#define IFLA_STATS_FILTER_BIT(ATTR) (1 << (ATTR - 1))
+
+/* These are embedded into IFLA_STATS_LINK_XSTATS:
+ * [IFLA_STATS_LINK_XSTATS]
+ * -> [LINK_XSTATS_TYPE_xxx]
+ * -> [rtnl link type specific attributes]
+ */
+enum {
+ LINK_XSTATS_TYPE_UNSPEC,
+ LINK_XSTATS_TYPE_BRIDGE,
+ LINK_XSTATS_TYPE_BOND,
+ __LINK_XSTATS_TYPE_MAX
+};
+#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1)
+
+/* These are stats embedded into IFLA_STATS_LINK_OFFLOAD_XSTATS */
+enum {
+ IFLA_OFFLOAD_XSTATS_UNSPEC,
+ IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */
+ __IFLA_OFFLOAD_XSTATS_MAX
+};
+#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1)
+
+/* XDP section */
+
+#define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0)
+#define XDP_FLAGS_SKB_MODE (1U << 1)
+#define XDP_FLAGS_DRV_MODE (1U << 2)
+#define XDP_FLAGS_HW_MODE (1U << 3)
+#define XDP_FLAGS_REPLACE (1U << 4)
+#define XDP_FLAGS_MODES (XDP_FLAGS_SKB_MODE | \
+ XDP_FLAGS_DRV_MODE | \
+ XDP_FLAGS_HW_MODE)
+#define XDP_FLAGS_MASK (XDP_FLAGS_UPDATE_IF_NOEXIST | \
+ XDP_FLAGS_MODES | XDP_FLAGS_REPLACE)
+
+/* These are stored into IFLA_XDP_ATTACHED on dump. */
+enum {
+ XDP_ATTACHED_NONE = 0,
+ XDP_ATTACHED_DRV,
+ XDP_ATTACHED_SKB,
+ XDP_ATTACHED_HW,
+ XDP_ATTACHED_MULTI,
+};
+
+enum {
+ IFLA_XDP_UNSPEC,
+ IFLA_XDP_FD,
+ IFLA_XDP_ATTACHED,
+ IFLA_XDP_FLAGS,
+ IFLA_XDP_PROG_ID,
+ IFLA_XDP_DRV_PROG_ID,
+ IFLA_XDP_SKB_PROG_ID,
+ IFLA_XDP_HW_PROG_ID,
+ IFLA_XDP_EXPECTED_FD,
+ __IFLA_XDP_MAX,
+};
+
+#define IFLA_XDP_MAX (__IFLA_XDP_MAX - 1)
+
+enum {
+ IFLA_EVENT_NONE,
+ IFLA_EVENT_REBOOT, /* internal reset / reboot */
+ IFLA_EVENT_FEATURES, /* change in offload features */
+ IFLA_EVENT_BONDING_FAILOVER, /* change in active slave */
+ IFLA_EVENT_NOTIFY_PEERS, /* re-sent grat. arp/ndisc */
+ IFLA_EVENT_IGMP_RESEND, /* re-sent IGMP JOIN */
+ IFLA_EVENT_BONDING_OPTIONS, /* change in bonding options */
+};
+
+/* tun section */
+
+enum {
+ IFLA_TUN_UNSPEC,
+ IFLA_TUN_OWNER,
+ IFLA_TUN_GROUP,
+ IFLA_TUN_TYPE,
+ IFLA_TUN_PI,
+ IFLA_TUN_VNET_HDR,
+ IFLA_TUN_PERSIST,
+ IFLA_TUN_MULTI_QUEUE,
+ IFLA_TUN_NUM_QUEUES,
+ IFLA_TUN_NUM_DISABLED_QUEUES,
+ __IFLA_TUN_MAX,
+};
+
+#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1)
+
+/* rmnet section */
+
+#define RMNET_FLAGS_INGRESS_DEAGGREGATION (1U << 0)
+#define RMNET_FLAGS_INGRESS_MAP_COMMANDS (1U << 1)
+#define RMNET_FLAGS_INGRESS_MAP_CKSUMV4 (1U << 2)
+#define RMNET_FLAGS_EGRESS_MAP_CKSUMV4 (1U << 3)
+
+enum {
+ IFLA_RMNET_UNSPEC,
+ IFLA_RMNET_MUX_ID,
+ IFLA_RMNET_FLAGS,
+ __IFLA_RMNET_MAX,
+};
+
+#define IFLA_RMNET_MAX (__IFLA_RMNET_MAX - 1)
+
+struct ifla_rmnet_flags {
+ __u32 flags;
+ __u32 mask;
+};
+
+#endif /* _LINUX_IF_LINK_H */
diff --git a/include/linux/if_macsec.h b/include/linux/if_macsec.h
new file mode 100644
index 0000000..eee31ce
--- /dev/null
+++ b/include/linux/if_macsec.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * include/uapi/linux/if_macsec.h - MACsec device
+ *
+ * Copyright (c) 2015 Sabrina Dubroca <sd@queasysnail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _MACSEC_H
+#define _MACSEC_H
+
+#include <linux/types.h>
+
+#define MACSEC_GENL_NAME "macsec"
+#define MACSEC_GENL_VERSION 1
+
+#define MACSEC_MAX_KEY_LEN 128
+
+#define MACSEC_KEYID_LEN 16
+
+/* cipher IDs as per IEEE802.1AE-2018 (Table 14-1) */
+#define MACSEC_CIPHER_ID_GCM_AES_128 0x0080C20001000001ULL
+#define MACSEC_CIPHER_ID_GCM_AES_256 0x0080C20001000002ULL
+#define MACSEC_CIPHER_ID_GCM_AES_XPN_128 0x0080C20001000003ULL
+#define MACSEC_CIPHER_ID_GCM_AES_XPN_256 0x0080C20001000004ULL
+
+/* deprecated cipher ID for GCM-AES-128 */
+#define MACSEC_DEFAULT_CIPHER_ID 0x0080020001000001ULL
+#define MACSEC_DEFAULT_CIPHER_ALT MACSEC_CIPHER_ID_GCM_AES_128
+
+#define MACSEC_MIN_ICV_LEN 8
+#define MACSEC_MAX_ICV_LEN 32
+/* upper limit for ICV length as recommended by IEEE802.1AE-2006 */
+#define MACSEC_STD_ICV_LEN 16
+
+enum macsec_attrs {
+ MACSEC_ATTR_UNSPEC,
+ MACSEC_ATTR_IFINDEX, /* u32, ifindex of the MACsec netdevice */
+ MACSEC_ATTR_RXSC_CONFIG, /* config, nested macsec_rxsc_attrs */
+ MACSEC_ATTR_SA_CONFIG, /* config, nested macsec_sa_attrs */
+ MACSEC_ATTR_SECY, /* dump, nested macsec_secy_attrs */
+ MACSEC_ATTR_TXSA_LIST, /* dump, nested, macsec_sa_attrs for each TXSA */
+ MACSEC_ATTR_RXSC_LIST, /* dump, nested, macsec_rxsc_attrs for each RXSC */
+ MACSEC_ATTR_TXSC_STATS, /* dump, nested, macsec_txsc_stats_attr */
+ MACSEC_ATTR_SECY_STATS, /* dump, nested, macsec_secy_stats_attr */
+ MACSEC_ATTR_OFFLOAD, /* config, nested, macsec_offload_attrs */
+ __MACSEC_ATTR_END,
+ NUM_MACSEC_ATTR = __MACSEC_ATTR_END,
+ MACSEC_ATTR_MAX = __MACSEC_ATTR_END - 1,
+};
+
+enum macsec_secy_attrs {
+ MACSEC_SECY_ATTR_UNSPEC,
+ MACSEC_SECY_ATTR_SCI,
+ MACSEC_SECY_ATTR_ENCODING_SA,
+ MACSEC_SECY_ATTR_WINDOW,
+ MACSEC_SECY_ATTR_CIPHER_SUITE,
+ MACSEC_SECY_ATTR_ICV_LEN,
+ MACSEC_SECY_ATTR_PROTECT,
+ MACSEC_SECY_ATTR_REPLAY,
+ MACSEC_SECY_ATTR_OPER,
+ MACSEC_SECY_ATTR_VALIDATE,
+ MACSEC_SECY_ATTR_ENCRYPT,
+ MACSEC_SECY_ATTR_INC_SCI,
+ MACSEC_SECY_ATTR_ES,
+ MACSEC_SECY_ATTR_SCB,
+ MACSEC_SECY_ATTR_PAD,
+ __MACSEC_SECY_ATTR_END,
+ NUM_MACSEC_SECY_ATTR = __MACSEC_SECY_ATTR_END,
+ MACSEC_SECY_ATTR_MAX = __MACSEC_SECY_ATTR_END - 1,
+};
+
+enum macsec_rxsc_attrs {
+ MACSEC_RXSC_ATTR_UNSPEC,
+ MACSEC_RXSC_ATTR_SCI, /* config/dump, u64 */
+ MACSEC_RXSC_ATTR_ACTIVE, /* config/dump, u8 0..1 */
+ MACSEC_RXSC_ATTR_SA_LIST, /* dump, nested */
+ MACSEC_RXSC_ATTR_STATS, /* dump, nested, macsec_rxsc_stats_attr */
+ MACSEC_RXSC_ATTR_PAD,
+ __MACSEC_RXSC_ATTR_END,
+ NUM_MACSEC_RXSC_ATTR = __MACSEC_RXSC_ATTR_END,
+ MACSEC_RXSC_ATTR_MAX = __MACSEC_RXSC_ATTR_END - 1,
+};
+
+enum macsec_sa_attrs {
+ MACSEC_SA_ATTR_UNSPEC,
+ MACSEC_SA_ATTR_AN, /* config/dump, u8 0..3 */
+ MACSEC_SA_ATTR_ACTIVE, /* config/dump, u8 0..1 */
+ MACSEC_SA_ATTR_PN, /* config/dump, u32/u64 (u64 if XPN) */
+ MACSEC_SA_ATTR_KEY, /* config, data */
+ MACSEC_SA_ATTR_KEYID, /* config/dump, 128-bit */
+ MACSEC_SA_ATTR_STATS, /* dump, nested, macsec_sa_stats_attr */
+ MACSEC_SA_ATTR_PAD,
+ MACSEC_SA_ATTR_SSCI, /* config/dump, u32 - XPN only */
+ MACSEC_SA_ATTR_SALT, /* config, 96-bit - XPN only */
+ __MACSEC_SA_ATTR_END,
+ NUM_MACSEC_SA_ATTR = __MACSEC_SA_ATTR_END,
+ MACSEC_SA_ATTR_MAX = __MACSEC_SA_ATTR_END - 1,
+};
+
+enum macsec_offload_attrs {
+ MACSEC_OFFLOAD_ATTR_UNSPEC,
+ MACSEC_OFFLOAD_ATTR_TYPE, /* config/dump, u8 0..2 */
+ MACSEC_OFFLOAD_ATTR_PAD,
+ __MACSEC_OFFLOAD_ATTR_END,
+ NUM_MACSEC_OFFLOAD_ATTR = __MACSEC_OFFLOAD_ATTR_END,
+ MACSEC_OFFLOAD_ATTR_MAX = __MACSEC_OFFLOAD_ATTR_END - 1,
+};
+
+enum macsec_nl_commands {
+ MACSEC_CMD_GET_TXSC,
+ MACSEC_CMD_ADD_RXSC,
+ MACSEC_CMD_DEL_RXSC,
+ MACSEC_CMD_UPD_RXSC,
+ MACSEC_CMD_ADD_TXSA,
+ MACSEC_CMD_DEL_TXSA,
+ MACSEC_CMD_UPD_TXSA,
+ MACSEC_CMD_ADD_RXSA,
+ MACSEC_CMD_DEL_RXSA,
+ MACSEC_CMD_UPD_RXSA,
+ MACSEC_CMD_UPD_OFFLOAD,
+};
+
+/* u64 per-RXSC stats */
+enum macsec_rxsc_stats_attr {
+ MACSEC_RXSC_STATS_ATTR_UNSPEC,
+ MACSEC_RXSC_STATS_ATTR_IN_OCTETS_VALIDATED,
+ MACSEC_RXSC_STATS_ATTR_IN_OCTETS_DECRYPTED,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNCHECKED,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_DELAYED,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_OK,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_INVALID,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_LATE,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_VALID,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_USING_SA,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNUSED_SA,
+ MACSEC_RXSC_STATS_ATTR_PAD,
+ __MACSEC_RXSC_STATS_ATTR_END,
+ NUM_MACSEC_RXSC_STATS_ATTR = __MACSEC_RXSC_STATS_ATTR_END,
+ MACSEC_RXSC_STATS_ATTR_MAX = __MACSEC_RXSC_STATS_ATTR_END - 1,
+};
+
+/* u32 per-{RX,TX}SA stats */
+enum macsec_sa_stats_attr {
+ MACSEC_SA_STATS_ATTR_UNSPEC,
+ MACSEC_SA_STATS_ATTR_IN_PKTS_OK,
+ MACSEC_SA_STATS_ATTR_IN_PKTS_INVALID,
+ MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_VALID,
+ MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_USING_SA,
+ MACSEC_SA_STATS_ATTR_IN_PKTS_UNUSED_SA,
+ MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED,
+ MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED,
+ __MACSEC_SA_STATS_ATTR_END,
+ NUM_MACSEC_SA_STATS_ATTR = __MACSEC_SA_STATS_ATTR_END,
+ MACSEC_SA_STATS_ATTR_MAX = __MACSEC_SA_STATS_ATTR_END - 1,
+};
+
+/* u64 per-TXSC stats */
+enum macsec_txsc_stats_attr {
+ MACSEC_TXSC_STATS_ATTR_UNSPEC,
+ MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED,
+ MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED,
+ MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED,
+ MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED,
+ MACSEC_TXSC_STATS_ATTR_PAD,
+ __MACSEC_TXSC_STATS_ATTR_END,
+ NUM_MACSEC_TXSC_STATS_ATTR = __MACSEC_TXSC_STATS_ATTR_END,
+ MACSEC_TXSC_STATS_ATTR_MAX = __MACSEC_TXSC_STATS_ATTR_END - 1,
+};
+
+/* u64 per-SecY stats */
+enum macsec_secy_stats_attr {
+ MACSEC_SECY_STATS_ATTR_UNSPEC,
+ MACSEC_SECY_STATS_ATTR_OUT_PKTS_UNTAGGED,
+ MACSEC_SECY_STATS_ATTR_IN_PKTS_UNTAGGED,
+ MACSEC_SECY_STATS_ATTR_OUT_PKTS_TOO_LONG,
+ MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_TAG,
+ MACSEC_SECY_STATS_ATTR_IN_PKTS_BAD_TAG,
+ MACSEC_SECY_STATS_ATTR_IN_PKTS_UNKNOWN_SCI,
+ MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_SCI,
+ MACSEC_SECY_STATS_ATTR_IN_PKTS_OVERRUN,
+ MACSEC_SECY_STATS_ATTR_PAD,
+ __MACSEC_SECY_STATS_ATTR_END,
+ NUM_MACSEC_SECY_STATS_ATTR = __MACSEC_SECY_STATS_ATTR_END,
+ MACSEC_SECY_STATS_ATTR_MAX = __MACSEC_SECY_STATS_ATTR_END - 1,
+};
+
+#endif /* _MACSEC_H */
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
new file mode 100644
index 0000000..c7f0a5e
--- /dev/null
+++ b/include/linux/if_tunnel.h
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _IF_TUNNEL_H_
+#define _IF_TUNNEL_H_
+
+#include <linux/types.h>
+#include <linux/if.h>
+#include <linux/ip.h>
+#include <linux/in6.h>
+#include <asm/byteorder.h>
+
+
+#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0)
+#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1)
+#define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2)
+#define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3)
+#define SIOCGETPRL (SIOCDEVPRIVATE + 4)
+#define SIOCADDPRL (SIOCDEVPRIVATE + 5)
+#define SIOCDELPRL (SIOCDEVPRIVATE + 6)
+#define SIOCCHGPRL (SIOCDEVPRIVATE + 7)
+#define SIOCGET6RD (SIOCDEVPRIVATE + 8)
+#define SIOCADD6RD (SIOCDEVPRIVATE + 9)
+#define SIOCDEL6RD (SIOCDEVPRIVATE + 10)
+#define SIOCCHG6RD (SIOCDEVPRIVATE + 11)
+
+#define GRE_CSUM __cpu_to_be16(0x8000)
+#define GRE_ROUTING __cpu_to_be16(0x4000)
+#define GRE_KEY __cpu_to_be16(0x2000)
+#define GRE_SEQ __cpu_to_be16(0x1000)
+#define GRE_STRICT __cpu_to_be16(0x0800)
+#define GRE_REC __cpu_to_be16(0x0700)
+#define GRE_ACK __cpu_to_be16(0x0080)
+#define GRE_FLAGS __cpu_to_be16(0x0078)
+#define GRE_VERSION __cpu_to_be16(0x0007)
+
+#define GRE_IS_CSUM(f) ((f) & GRE_CSUM)
+#define GRE_IS_ROUTING(f) ((f) & GRE_ROUTING)
+#define GRE_IS_KEY(f) ((f) & GRE_KEY)
+#define GRE_IS_SEQ(f) ((f) & GRE_SEQ)
+#define GRE_IS_STRICT(f) ((f) & GRE_STRICT)
+#define GRE_IS_REC(f) ((f) & GRE_REC)
+#define GRE_IS_ACK(f) ((f) & GRE_ACK)
+
+#define GRE_VERSION_0 __cpu_to_be16(0x0000)
+#define GRE_VERSION_1 __cpu_to_be16(0x0001)
+#define GRE_PROTO_PPP __cpu_to_be16(0x880b)
+#define GRE_PPTP_KEY_MASK __cpu_to_be32(0xffff)
+
+struct ip_tunnel_parm {
+ char name[IFNAMSIZ];
+ int link;
+ __be16 i_flags;
+ __be16 o_flags;
+ __be32 i_key;
+ __be32 o_key;
+ struct iphdr iph;
+};
+
+enum {
+ IFLA_IPTUN_UNSPEC,
+ IFLA_IPTUN_LINK,
+ IFLA_IPTUN_LOCAL,
+ IFLA_IPTUN_REMOTE,
+ IFLA_IPTUN_TTL,
+ IFLA_IPTUN_TOS,
+ IFLA_IPTUN_ENCAP_LIMIT,
+ IFLA_IPTUN_FLOWINFO,
+ IFLA_IPTUN_FLAGS,
+ IFLA_IPTUN_PROTO,
+ IFLA_IPTUN_PMTUDISC,
+ IFLA_IPTUN_6RD_PREFIX,
+ IFLA_IPTUN_6RD_RELAY_PREFIX,
+ IFLA_IPTUN_6RD_PREFIXLEN,
+ IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
+ IFLA_IPTUN_ENCAP_TYPE,
+ IFLA_IPTUN_ENCAP_FLAGS,
+ IFLA_IPTUN_ENCAP_SPORT,
+ IFLA_IPTUN_ENCAP_DPORT,
+ IFLA_IPTUN_COLLECT_METADATA,
+ IFLA_IPTUN_FWMARK,
+ __IFLA_IPTUN_MAX,
+};
+#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
+
+enum tunnel_encap_types {
+ TUNNEL_ENCAP_NONE,
+ TUNNEL_ENCAP_FOU,
+ TUNNEL_ENCAP_GUE,
+ TUNNEL_ENCAP_MPLS,
+};
+
+#define TUNNEL_ENCAP_FLAG_CSUM (1<<0)
+#define TUNNEL_ENCAP_FLAG_CSUM6 (1<<1)
+#define TUNNEL_ENCAP_FLAG_REMCSUM (1<<2)
+
+/* SIT-mode i_flags */
+#define SIT_ISATAP 0x0001
+
+struct ip_tunnel_prl {
+ __be32 addr;
+ __u16 flags;
+ __u16 __reserved;
+ __u32 datalen;
+ __u32 __reserved2;
+ /* data follows */
+};
+
+/* PRL flags */
+#define PRL_DEFAULT 0x0001
+
+struct ip_tunnel_6rd {
+ struct in6_addr prefix;
+ __be32 relay_prefix;
+ __u16 prefixlen;
+ __u16 relay_prefixlen;
+};
+
+enum {
+ IFLA_GRE_UNSPEC,
+ IFLA_GRE_LINK,
+ IFLA_GRE_IFLAGS,
+ IFLA_GRE_OFLAGS,
+ IFLA_GRE_IKEY,
+ IFLA_GRE_OKEY,
+ IFLA_GRE_LOCAL,
+ IFLA_GRE_REMOTE,
+ IFLA_GRE_TTL,
+ IFLA_GRE_TOS,
+ IFLA_GRE_PMTUDISC,
+ IFLA_GRE_ENCAP_LIMIT,
+ IFLA_GRE_FLOWINFO,
+ IFLA_GRE_FLAGS,
+ IFLA_GRE_ENCAP_TYPE,
+ IFLA_GRE_ENCAP_FLAGS,
+ IFLA_GRE_ENCAP_SPORT,
+ IFLA_GRE_ENCAP_DPORT,
+ IFLA_GRE_COLLECT_METADATA,
+ IFLA_GRE_IGNORE_DF,
+ IFLA_GRE_FWMARK,
+ IFLA_GRE_ERSPAN_INDEX,
+ IFLA_GRE_ERSPAN_VER,
+ IFLA_GRE_ERSPAN_DIR,
+ IFLA_GRE_ERSPAN_HWID,
+ __IFLA_GRE_MAX,
+};
+
+#define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1)
+
+/* VTI-mode i_flags */
+#define VTI_ISVTI ((__be16)0x0001)
+
+enum {
+ IFLA_VTI_UNSPEC,
+ IFLA_VTI_LINK,
+ IFLA_VTI_IKEY,
+ IFLA_VTI_OKEY,
+ IFLA_VTI_LOCAL,
+ IFLA_VTI_REMOTE,
+ IFLA_VTI_FWMARK,
+ __IFLA_VTI_MAX,
+};
+
+#define IFLA_VTI_MAX (__IFLA_VTI_MAX - 1)
+
+#define TUNNEL_CSUM __cpu_to_be16(0x01)
+#define TUNNEL_ROUTING __cpu_to_be16(0x02)
+#define TUNNEL_KEY __cpu_to_be16(0x04)
+#define TUNNEL_SEQ __cpu_to_be16(0x08)
+#define TUNNEL_STRICT __cpu_to_be16(0x10)
+#define TUNNEL_REC __cpu_to_be16(0x20)
+#define TUNNEL_VERSION __cpu_to_be16(0x40)
+#define TUNNEL_NO_KEY __cpu_to_be16(0x80)
+#define TUNNEL_DONT_FRAGMENT __cpu_to_be16(0x0100)
+#define TUNNEL_OAM __cpu_to_be16(0x0200)
+#define TUNNEL_CRIT_OPT __cpu_to_be16(0x0400)
+#define TUNNEL_GENEVE_OPT __cpu_to_be16(0x0800)
+#define TUNNEL_VXLAN_OPT __cpu_to_be16(0x1000)
+#define TUNNEL_NOCACHE __cpu_to_be16(0x2000)
+#define TUNNEL_ERSPAN_OPT __cpu_to_be16(0x4000)
+
+#define TUNNEL_OPTIONS_PRESENT \
+ (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT | TUNNEL_ERSPAN_OPT)
+
+#endif /* _IF_TUNNEL_H_ */
diff --git a/include/linux/ila.h b/include/linux/ila.h
new file mode 100644
index 0000000..6a6c97c
--- /dev/null
+++ b/include/linux/ila.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* ila.h - ILA Interface */
+
+#ifndef _LINUX_ILA_H
+#define _LINUX_ILA_H
+
+/* NETLINK_GENERIC related info */
+#define ILA_GENL_NAME "ila"
+#define ILA_GENL_VERSION 0x1
+
+enum {
+ ILA_ATTR_UNSPEC,
+ ILA_ATTR_LOCATOR, /* u64 */
+ ILA_ATTR_IDENTIFIER, /* u64 */
+ ILA_ATTR_LOCATOR_MATCH, /* u64 */
+ ILA_ATTR_IFINDEX, /* s32 */
+ ILA_ATTR_DIR, /* u32 */
+ ILA_ATTR_PAD,
+ ILA_ATTR_CSUM_MODE, /* u8 */
+ ILA_ATTR_IDENT_TYPE, /* u8 */
+ ILA_ATTR_HOOK_TYPE, /* u8 */
+
+ __ILA_ATTR_MAX,
+};
+
+#define ILA_ATTR_MAX (__ILA_ATTR_MAX - 1)
+
+enum {
+ ILA_CMD_UNSPEC,
+ ILA_CMD_ADD,
+ ILA_CMD_DEL,
+ ILA_CMD_GET,
+ ILA_CMD_FLUSH,
+
+ __ILA_CMD_MAX,
+};
+
+#define ILA_CMD_MAX (__ILA_CMD_MAX - 1)
+
+#define ILA_DIR_IN (1 << 0)
+#define ILA_DIR_OUT (1 << 1)
+
+enum {
+ ILA_CSUM_ADJUST_TRANSPORT,
+ ILA_CSUM_NEUTRAL_MAP,
+ ILA_CSUM_NO_ACTION,
+ ILA_CSUM_NEUTRAL_MAP_AUTO,
+};
+
+enum {
+ ILA_ATYPE_IID = 0,
+ ILA_ATYPE_LUID,
+ ILA_ATYPE_VIRT_V4,
+ ILA_ATYPE_VIRT_UNI_V6,
+ ILA_ATYPE_VIRT_MULTI_V6,
+ ILA_ATYPE_NONLOCAL_ADDR,
+ ILA_ATYPE_RSVD_1,
+ ILA_ATYPE_RSVD_2,
+
+ ILA_ATYPE_USE_FORMAT = 32, /* Get type from type field in identifier */
+};
+
+enum {
+ ILA_HOOK_ROUTE_OUTPUT,
+ ILA_HOOK_ROUTE_INPUT,
+};
+
+#endif /* _LINUX_ILA_H */
diff --git a/include/linux/in6.h b/include/linux/in6.h
new file mode 100644
index 0000000..7e3a58e
--- /dev/null
+++ b/include/linux/in6.h
@@ -0,0 +1,301 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Types and definitions for AF_INET6
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * Sources:
+ * IPv6 Program Interfaces for BSD Systems
+ * <draft-ietf-ipngwg-bsd-api-05.txt>
+ *
+ * Advanced Sockets API for IPv6
+ * <draft-stevens-advanced-api-00.txt>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IN6_H
+#define _LINUX_IN6_H
+
+#include <linux/types.h>
+#include <linux/libc-compat.h>
+
+/*
+ * IPv6 address structure
+ */
+
+#if __UAPI_DEF_IN6_ADDR
+struct in6_addr {
+ union {
+ __u8 u6_addr8[16];
+#if __UAPI_DEF_IN6_ADDR_ALT
+ __be16 u6_addr16[8];
+ __be32 u6_addr32[4];
+#endif
+ } in6_u;
+#define s6_addr in6_u.u6_addr8
+#if __UAPI_DEF_IN6_ADDR_ALT
+#define s6_addr16 in6_u.u6_addr16
+#define s6_addr32 in6_u.u6_addr32
+#endif
+};
+#endif /* __UAPI_DEF_IN6_ADDR */
+
+#if __UAPI_DEF_SOCKADDR_IN6
+struct sockaddr_in6 {
+ unsigned short int sin6_family; /* AF_INET6 */
+ __be16 sin6_port; /* Transport layer port # */
+ __be32 sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ __u32 sin6_scope_id; /* scope id (new in RFC2553) */
+};
+#endif /* __UAPI_DEF_SOCKADDR_IN6 */
+
+#if __UAPI_DEF_IPV6_MREQ
+struct ipv6_mreq {
+ /* IPv6 multicast address of group */
+ struct in6_addr ipv6mr_multiaddr;
+
+ /* local IPv6 address of interface */
+ int ipv6mr_ifindex;
+};
+#endif /* __UAPI_DEF_IVP6_MREQ */
+
+#define ipv6mr_acaddr ipv6mr_multiaddr
+
+struct in6_flowlabel_req {
+ struct in6_addr flr_dst;
+ __be32 flr_label;
+ __u8 flr_action;
+ __u8 flr_share;
+ __u16 flr_flags;
+ __u16 flr_expires;
+ __u16 flr_linger;
+ __u32 __flr_pad;
+ /* Options in format of IPV6_PKTOPTIONS */
+};
+
+#define IPV6_FL_A_GET 0
+#define IPV6_FL_A_PUT 1
+#define IPV6_FL_A_RENEW 2
+
+#define IPV6_FL_F_CREATE 1
+#define IPV6_FL_F_EXCL 2
+#define IPV6_FL_F_REFLECT 4
+#define IPV6_FL_F_REMOTE 8
+
+#define IPV6_FL_S_NONE 0
+#define IPV6_FL_S_EXCL 1
+#define IPV6_FL_S_PROCESS 2
+#define IPV6_FL_S_USER 3
+#define IPV6_FL_S_ANY 255
+
+
+/*
+ * Bitmask constant declarations to help applications select out the
+ * flow label and priority fields.
+ *
+ * Note that this are in host byte order while the flowinfo field of
+ * sockaddr_in6 is in network byte order.
+ */
+
+#define IPV6_FLOWINFO_FLOWLABEL 0x000fffff
+#define IPV6_FLOWINFO_PRIORITY 0x0ff00000
+
+/* These definitions are obsolete */
+#define IPV6_PRIORITY_UNCHARACTERIZED 0x0000
+#define IPV6_PRIORITY_FILLER 0x0100
+#define IPV6_PRIORITY_UNATTENDED 0x0200
+#define IPV6_PRIORITY_RESERVED1 0x0300
+#define IPV6_PRIORITY_BULK 0x0400
+#define IPV6_PRIORITY_RESERVED2 0x0500
+#define IPV6_PRIORITY_INTERACTIVE 0x0600
+#define IPV6_PRIORITY_CONTROL 0x0700
+#define IPV6_PRIORITY_8 0x0800
+#define IPV6_PRIORITY_9 0x0900
+#define IPV6_PRIORITY_10 0x0a00
+#define IPV6_PRIORITY_11 0x0b00
+#define IPV6_PRIORITY_12 0x0c00
+#define IPV6_PRIORITY_13 0x0d00
+#define IPV6_PRIORITY_14 0x0e00
+#define IPV6_PRIORITY_15 0x0f00
+
+/*
+ * IPV6 extension headers
+ */
+#if __UAPI_DEF_IPPROTO_V6
+#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */
+#define IPPROTO_ROUTING 43 /* IPv6 routing header */
+#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */
+#define IPPROTO_ICMPV6 58 /* ICMPv6 */
+#define IPPROTO_NONE 59 /* IPv6 no next header */
+#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */
+#define IPPROTO_MH 135 /* IPv6 mobility header */
+#endif /* __UAPI_DEF_IPPROTO_V6 */
+
+/*
+ * IPv6 TLV options.
+ */
+#define IPV6_TLV_PAD1 0
+#define IPV6_TLV_PADN 1
+#define IPV6_TLV_ROUTERALERT 5
+#define IPV6_TLV_CALIPSO 7 /* RFC 5570 */
+#define IPV6_TLV_JUMBO 194
+#define IPV6_TLV_HAO 201 /* home address option */
+
+/*
+ * IPV6 socket options
+ */
+#if __UAPI_DEF_IPV6_OPTIONS
+#define IPV6_ADDRFORM 1
+#define IPV6_2292PKTINFO 2
+#define IPV6_2292HOPOPTS 3
+#define IPV6_2292DSTOPTS 4
+#define IPV6_2292RTHDR 5
+#define IPV6_2292PKTOPTIONS 6
+#define IPV6_CHECKSUM 7
+#define IPV6_2292HOPLIMIT 8
+#define IPV6_NEXTHOP 9
+#define IPV6_AUTHHDR 10 /* obsolete */
+#define IPV6_FLOWINFO 11
+
+#define IPV6_UNICAST_HOPS 16
+#define IPV6_MULTICAST_IF 17
+#define IPV6_MULTICAST_HOPS 18
+#define IPV6_MULTICAST_LOOP 19
+#define IPV6_ADD_MEMBERSHIP 20
+#define IPV6_DROP_MEMBERSHIP 21
+#define IPV6_ROUTER_ALERT 22
+#define IPV6_MTU_DISCOVER 23
+#define IPV6_MTU 24
+#define IPV6_RECVERR 25
+#define IPV6_V6ONLY 26
+#define IPV6_JOIN_ANYCAST 27
+#define IPV6_LEAVE_ANYCAST 28
+#define IPV6_MULTICAST_ALL 29
+#define IPV6_ROUTER_ALERT_ISOLATE 30
+#define IPV6_RECVERR_RFC4884 31
+
+/* IPV6_MTU_DISCOVER values */
+#define IPV6_PMTUDISC_DONT 0
+#define IPV6_PMTUDISC_WANT 1
+#define IPV6_PMTUDISC_DO 2
+#define IPV6_PMTUDISC_PROBE 3
+/* same as IPV6_PMTUDISC_PROBE, provided for symetry with IPv4
+ * also see comments on IP_PMTUDISC_INTERFACE
+ */
+#define IPV6_PMTUDISC_INTERFACE 4
+/* weaker version of IPV6_PMTUDISC_INTERFACE, which allows packets to
+ * get fragmented if they exceed the interface mtu
+ */
+#define IPV6_PMTUDISC_OMIT 5
+
+/* Flowlabel */
+#define IPV6_FLOWLABEL_MGR 32
+#define IPV6_FLOWINFO_SEND 33
+
+#define IPV6_IPSEC_POLICY 34
+#define IPV6_XFRM_POLICY 35
+#define IPV6_HDRINCL 36
+#endif
+
+/*
+ * Multicast:
+ * Following socket options are shared between IPv4 and IPv6.
+ *
+ * MCAST_JOIN_GROUP 42
+ * MCAST_BLOCK_SOURCE 43
+ * MCAST_UNBLOCK_SOURCE 44
+ * MCAST_LEAVE_GROUP 45
+ * MCAST_JOIN_SOURCE_GROUP 46
+ * MCAST_LEAVE_SOURCE_GROUP 47
+ * MCAST_MSFILTER 48
+ */
+
+/*
+ * Advanced API (RFC3542) (1)
+ *
+ * Note: IPV6_RECVRTHDRDSTOPTS does not exist. see net/ipv6/datagram.c.
+ */
+
+#define IPV6_RECVPKTINFO 49
+#define IPV6_PKTINFO 50
+#define IPV6_RECVHOPLIMIT 51
+#define IPV6_HOPLIMIT 52
+#define IPV6_RECVHOPOPTS 53
+#define IPV6_HOPOPTS 54
+#define IPV6_RTHDRDSTOPTS 55
+#define IPV6_RECVRTHDR 56
+#define IPV6_RTHDR 57
+#define IPV6_RECVDSTOPTS 58
+#define IPV6_DSTOPTS 59
+#define IPV6_RECVPATHMTU 60
+#define IPV6_PATHMTU 61
+#define IPV6_DONTFRAG 62
+#if 0 /* not yet */
+#define IPV6_USE_MIN_MTU 63
+#endif
+
+/*
+ * Netfilter (1)
+ *
+ * Following socket options are used in ip6_tables;
+ * see include/linux/netfilter_ipv6/ip6_tables.h.
+ *
+ * IP6T_SO_SET_REPLACE / IP6T_SO_GET_INFO 64
+ * IP6T_SO_SET_ADD_COUNTERS / IP6T_SO_GET_ENTRIES 65
+ */
+
+/*
+ * Advanced API (RFC3542) (2)
+ */
+#define IPV6_RECVTCLASS 66
+#define IPV6_TCLASS 67
+
+/*
+ * Netfilter (2)
+ *
+ * Following socket options are used in ip6_tables;
+ * see include/linux/netfilter_ipv6/ip6_tables.h.
+ *
+ * IP6T_SO_GET_REVISION_MATCH 68
+ * IP6T_SO_GET_REVISION_TARGET 69
+ * IP6T_SO_ORIGINAL_DST 80
+ */
+
+#define IPV6_AUTOFLOWLABEL 70
+/* RFC5014: Source address selection */
+#define IPV6_ADDR_PREFERENCES 72
+
+#define IPV6_PREFER_SRC_TMP 0x0001
+#define IPV6_PREFER_SRC_PUBLIC 0x0002
+#define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100
+#define IPV6_PREFER_SRC_COA 0x0004
+#define IPV6_PREFER_SRC_HOME 0x0400
+#define IPV6_PREFER_SRC_CGA 0x0008
+#define IPV6_PREFER_SRC_NONCGA 0x0800
+
+/* RFC5082: Generalized Ttl Security Mechanism */
+#define IPV6_MINHOPCOUNT 73
+
+#define IPV6_ORIGDSTADDR 74
+#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR
+#define IPV6_TRANSPARENT 75
+#define IPV6_UNICAST_IF 76
+#define IPV6_RECVFRAGSIZE 77
+#define IPV6_FREEBIND 78
+
+/*
+ * Multicast Routing:
+ * see include/uapi/linux/mroute6.h.
+ *
+ * MRT6_BASE 200
+ * ...
+ * MRT6_MAX
+ */
+#endif /* _LINUX_IN6_H */
diff --git a/include/linux/ip.h b/include/linux/ip.h
new file mode 100644
index 0000000..f4ecd2f
--- /dev/null
+++ b/include/linux/ip.h
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the IP protocol.
+ *
+ * Version: @(#)ip.h 1.0.2 04/28/93
+ *
+ * Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IP_H
+#define _LINUX_IP_H
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define IPTOS_TOS_MASK 0x1E
+#define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK)
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_RELIABILITY 0x04
+#define IPTOS_MINCOST 0x02
+
+#define IPTOS_PREC_MASK 0xE0
+#define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK)
+#define IPTOS_PREC_NETCONTROL 0xe0
+#define IPTOS_PREC_INTERNETCONTROL 0xc0
+#define IPTOS_PREC_CRITIC_ECP 0xa0
+#define IPTOS_PREC_FLASHOVERRIDE 0x80
+#define IPTOS_PREC_FLASH 0x60
+#define IPTOS_PREC_IMMEDIATE 0x40
+#define IPTOS_PREC_PRIORITY 0x20
+#define IPTOS_PREC_ROUTINE 0x00
+
+
+/* IP options */
+#define IPOPT_COPY 0x80
+#define IPOPT_CLASS_MASK 0x60
+#define IPOPT_NUMBER_MASK 0x1f
+
+#define IPOPT_COPIED(o) ((o)&IPOPT_COPY)
+#define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK)
+#define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK)
+
+#define IPOPT_CONTROL 0x00
+#define IPOPT_RESERVED1 0x20
+#define IPOPT_MEASUREMENT 0x40
+#define IPOPT_RESERVED2 0x60
+
+#define IPOPT_END (0 |IPOPT_CONTROL)
+#define IPOPT_NOOP (1 |IPOPT_CONTROL)
+#define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY)
+#define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY)
+#define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT)
+#define IPOPT_CIPSO (6 |IPOPT_CONTROL|IPOPT_COPY)
+#define IPOPT_RR (7 |IPOPT_CONTROL)
+#define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY)
+#define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY)
+#define IPOPT_RA (20|IPOPT_CONTROL|IPOPT_COPY)
+
+#define IPVERSION 4
+#define MAXTTL 255
+#define IPDEFTTL 64
+
+#define IPOPT_OPTVAL 0
+#define IPOPT_OLEN 1
+#define IPOPT_OFFSET 2
+#define IPOPT_MINOFF 4
+#define MAX_IPOPTLEN 40
+#define IPOPT_NOP IPOPT_NOOP
+#define IPOPT_EOL IPOPT_END
+#define IPOPT_TS IPOPT_TIMESTAMP
+
+#define IPOPT_TS_TSONLY 0 /* timestamps only */
+#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
+#define IPOPT_TS_PRESPEC 3 /* specified modules only */
+
+#define IPV4_BEET_PHMAXLEN 8
+
+struct iphdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 ihl:4,
+ version:4;
+#elif defined (__BIG_ENDIAN_BITFIELD)
+ __u8 version:4,
+ ihl:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u8 tos;
+ __be16 tot_len;
+ __be16 id;
+ __be16 frag_off;
+ __u8 ttl;
+ __u8 protocol;
+ __sum16 check;
+ __be32 saddr;
+ __be32 daddr;
+ /*The options start here. */
+};
+
+
+struct ip_auth_hdr {
+ __u8 nexthdr;
+ __u8 hdrlen; /* This one is measured in 32 bit units! */
+ __be16 reserved;
+ __be32 spi;
+ __be32 seq_no; /* Sequence number */
+ __u8 auth_data[0]; /* Variable len but >=4. Mind the 64 bit alignment! */
+};
+
+struct ip_esp_hdr {
+ __be32 spi;
+ __be32 seq_no; /* Sequence number */
+ __u8 enc_data[0]; /* Variable len but >=8. Mind the 64 bit alignment! */
+};
+
+struct ip_comp_hdr {
+ __u8 nexthdr;
+ __u8 flags;
+ __be16 cpi;
+};
+
+struct ip_beet_phdr {
+ __u8 nexthdr;
+ __u8 hdrlen;
+ __u8 padlen;
+ __u8 reserved;
+};
+
+/* index values for the variables in ipv4_devconf */
+enum
+{
+ IPV4_DEVCONF_FORWARDING=1,
+ IPV4_DEVCONF_MC_FORWARDING,
+ IPV4_DEVCONF_PROXY_ARP,
+ IPV4_DEVCONF_ACCEPT_REDIRECTS,
+ IPV4_DEVCONF_SECURE_REDIRECTS,
+ IPV4_DEVCONF_SEND_REDIRECTS,
+ IPV4_DEVCONF_SHARED_MEDIA,
+ IPV4_DEVCONF_RP_FILTER,
+ IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE,
+ IPV4_DEVCONF_BOOTP_RELAY,
+ IPV4_DEVCONF_LOG_MARTIANS,
+ IPV4_DEVCONF_TAG,
+ IPV4_DEVCONF_ARPFILTER,
+ IPV4_DEVCONF_MEDIUM_ID,
+ IPV4_DEVCONF_NOXFRM,
+ IPV4_DEVCONF_NOPOLICY,
+ IPV4_DEVCONF_FORCE_IGMP_VERSION,
+ IPV4_DEVCONF_ARP_ANNOUNCE,
+ IPV4_DEVCONF_ARP_IGNORE,
+ IPV4_DEVCONF_PROMOTE_SECONDARIES,
+ IPV4_DEVCONF_ARP_ACCEPT,
+ IPV4_DEVCONF_ARP_NOTIFY,
+ IPV4_DEVCONF_ACCEPT_LOCAL,
+ IPV4_DEVCONF_SRC_VMARK,
+ IPV4_DEVCONF_PROXY_ARP_PVLAN,
+ IPV4_DEVCONF_ROUTE_LOCALNET,
+ IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL,
+ IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL,
+ IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
+ IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
+ IPV4_DEVCONF_DROP_GRATUITOUS_ARP,
+ IPV4_DEVCONF_BC_FORWARDING,
+ __IPV4_DEVCONF_MAX
+};
+
+#define IPV4_DEVCONF_MAX (__IPV4_DEVCONF_MAX - 1)
+
+#endif /* _LINUX_IP_H */
diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h
new file mode 100644
index 0000000..0245269
--- /dev/null
+++ b/include/linux/ip6_tunnel.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _IP6_TUNNEL_H
+#define _IP6_TUNNEL_H
+
+#include <linux/types.h>
+#include <linux/if.h> /* For IFNAMSIZ. */
+#include <linux/in6.h> /* For struct in6_addr. */
+
+#define IPV6_TLV_TNL_ENCAP_LIMIT 4
+#define IPV6_DEFAULT_TNL_ENCAP_LIMIT 4
+
+/* don't add encapsulation limit if one isn't present in inner packet */
+#define IP6_TNL_F_IGN_ENCAP_LIMIT 0x1
+/* copy the traffic class field from the inner packet */
+#define IP6_TNL_F_USE_ORIG_TCLASS 0x2
+/* copy the flowlabel from the inner packet */
+#define IP6_TNL_F_USE_ORIG_FLOWLABEL 0x4
+/* being used for Mobile IPv6 */
+#define IP6_TNL_F_MIP6_DEV 0x8
+/* copy DSCP from the outer packet */
+#define IP6_TNL_F_RCV_DSCP_COPY 0x10
+/* copy fwmark from inner packet */
+#define IP6_TNL_F_USE_ORIG_FWMARK 0x20
+/* allow remote endpoint on the local node */
+#define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40
+
+struct ip6_tnl_parm {
+ char name[IFNAMSIZ]; /* name of tunnel device */
+ int link; /* ifindex of underlying L2 interface */
+ __u8 proto; /* tunnel protocol */
+ __u8 encap_limit; /* encapsulation limit for tunnel */
+ __u8 hop_limit; /* hop limit for tunnel */
+ __be32 flowinfo; /* traffic class and flowlabel for tunnel */
+ __u32 flags; /* tunnel flags */
+ struct in6_addr laddr; /* local tunnel end-point address */
+ struct in6_addr raddr; /* remote tunnel end-point address */
+};
+
+struct ip6_tnl_parm2 {
+ char name[IFNAMSIZ]; /* name of tunnel device */
+ int link; /* ifindex of underlying L2 interface */
+ __u8 proto; /* tunnel protocol */
+ __u8 encap_limit; /* encapsulation limit for tunnel */
+ __u8 hop_limit; /* hop limit for tunnel */
+ __be32 flowinfo; /* traffic class and flowlabel for tunnel */
+ __u32 flags; /* tunnel flags */
+ struct in6_addr laddr; /* local tunnel end-point address */
+ struct in6_addr raddr; /* remote tunnel end-point address */
+
+ __be16 i_flags;
+ __be16 o_flags;
+ __be32 i_key;
+ __be32 o_key;
+};
+
+#endif
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
new file mode 100644
index 0000000..7060377
--- /dev/null
+++ b/include/linux/ipv6.h
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_IPV6_H
+#define _UAPI_IPV6_H
+
+#include <linux/libc-compat.h>
+#include <linux/types.h>
+#include <linux/in6.h>
+#include <asm/byteorder.h>
+
+/* The latest drafts declared increase in minimal mtu up to 1280. */
+
+#define IPV6_MIN_MTU 1280
+
+/*
+ * Advanced API
+ * source interface/address selection, source routing, etc...
+ * *under construction*
+ */
+
+#if __UAPI_DEF_IN6_PKTINFO
+struct in6_pktinfo {
+ struct in6_addr ipi6_addr;
+ int ipi6_ifindex;
+};
+#endif
+
+#if __UAPI_DEF_IP6_MTUINFO
+struct ip6_mtuinfo {
+ struct sockaddr_in6 ip6m_addr;
+ __u32 ip6m_mtu;
+};
+#endif
+
+struct in6_ifreq {
+ struct in6_addr ifr6_addr;
+ __u32 ifr6_prefixlen;
+ int ifr6_ifindex;
+};
+
+#define IPV6_SRCRT_STRICT 0x01 /* Deprecated; will be removed */
+#define IPV6_SRCRT_TYPE_0 0 /* Deprecated; will be removed */
+#define IPV6_SRCRT_TYPE_2 2 /* IPv6 type 2 Routing Header */
+#define IPV6_SRCRT_TYPE_3 3 /* RPL Segment Routing with IPv6 */
+#define IPV6_SRCRT_TYPE_4 4 /* Segment Routing with IPv6 */
+
+/*
+ * routing header
+ */
+struct ipv6_rt_hdr {
+ __u8 nexthdr;
+ __u8 hdrlen;
+ __u8 type;
+ __u8 segments_left;
+
+ /*
+ * type specific data
+ * variable length field
+ */
+};
+
+
+struct ipv6_opt_hdr {
+ __u8 nexthdr;
+ __u8 hdrlen;
+ /*
+ * TLV encoded option data follows.
+ */
+} __attribute__((packed)); /* required for some archs */
+
+#define ipv6_destopt_hdr ipv6_opt_hdr
+#define ipv6_hopopt_hdr ipv6_opt_hdr
+
+/* Router Alert option values (RFC2711) */
+#define IPV6_OPT_ROUTERALERT_MLD 0x0000 /* MLD(RFC2710) */
+
+/*
+ * routing header type 0 (used in cmsghdr struct)
+ */
+
+struct rt0_hdr {
+ struct ipv6_rt_hdr rt_hdr;
+ __u32 reserved;
+ struct in6_addr addr[0];
+
+#define rt0_type rt_hdr.type
+};
+
+/*
+ * routing header type 2
+ */
+
+struct rt2_hdr {
+ struct ipv6_rt_hdr rt_hdr;
+ __u32 reserved;
+ struct in6_addr addr;
+
+#define rt2_type rt_hdr.type
+};
+
+/*
+ * home address option in destination options header
+ */
+
+struct ipv6_destopt_hao {
+ __u8 type;
+ __u8 length;
+ struct in6_addr addr;
+} __attribute__((packed));
+
+/*
+ * IPv6 fixed header
+ *
+ * BEWARE, it is incorrect. The first 4 bits of flow_lbl
+ * are glued to priority now, forming "class".
+ */
+
+struct ipv6hdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 priority:4,
+ version:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 version:4,
+ priority:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u8 flow_lbl[3];
+
+ __be16 payload_len;
+ __u8 nexthdr;
+ __u8 hop_limit;
+
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+};
+
+
+/* index values for the variables in ipv6_devconf */
+enum {
+ DEVCONF_FORWARDING = 0,
+ DEVCONF_HOPLIMIT,
+ DEVCONF_MTU6,
+ DEVCONF_ACCEPT_RA,
+ DEVCONF_ACCEPT_REDIRECTS,
+ DEVCONF_AUTOCONF,
+ DEVCONF_DAD_TRANSMITS,
+ DEVCONF_RTR_SOLICITS,
+ DEVCONF_RTR_SOLICIT_INTERVAL,
+ DEVCONF_RTR_SOLICIT_DELAY,
+ DEVCONF_USE_TEMPADDR,
+ DEVCONF_TEMP_VALID_LFT,
+ DEVCONF_TEMP_PREFERED_LFT,
+ DEVCONF_REGEN_MAX_RETRY,
+ DEVCONF_MAX_DESYNC_FACTOR,
+ DEVCONF_MAX_ADDRESSES,
+ DEVCONF_FORCE_MLD_VERSION,
+ DEVCONF_ACCEPT_RA_DEFRTR,
+ DEVCONF_ACCEPT_RA_PINFO,
+ DEVCONF_ACCEPT_RA_RTR_PREF,
+ DEVCONF_RTR_PROBE_INTERVAL,
+ DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN,
+ DEVCONF_PROXY_NDP,
+ DEVCONF_OPTIMISTIC_DAD,
+ DEVCONF_ACCEPT_SOURCE_ROUTE,
+ DEVCONF_MC_FORWARDING,
+ DEVCONF_DISABLE_IPV6,
+ DEVCONF_ACCEPT_DAD,
+ DEVCONF_FORCE_TLLAO,
+ DEVCONF_NDISC_NOTIFY,
+ DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL,
+ DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL,
+ DEVCONF_SUPPRESS_FRAG_NDISC,
+ DEVCONF_ACCEPT_RA_FROM_LOCAL,
+ DEVCONF_USE_OPTIMISTIC,
+ DEVCONF_ACCEPT_RA_MTU,
+ DEVCONF_STABLE_SECRET,
+ DEVCONF_USE_OIF_ADDRS_ONLY,
+ DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT,
+ DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
+ DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
+ DEVCONF_DROP_UNSOLICITED_NA,
+ DEVCONF_KEEP_ADDR_ON_DOWN,
+ DEVCONF_RTR_SOLICIT_MAX_INTERVAL,
+ DEVCONF_SEG6_ENABLED,
+ DEVCONF_SEG6_REQUIRE_HMAC,
+ DEVCONF_ENHANCED_DAD,
+ DEVCONF_ADDR_GEN_MODE,
+ DEVCONF_DISABLE_POLICY,
+ DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
+ DEVCONF_NDISC_TCLASS,
+ DEVCONF_RPL_SEG_ENABLED,
+ DEVCONF_RA_DEFRTR_METRIC,
+ DEVCONF_MAX
+};
+
+
+#endif /* _UAPI_IPV6_H */
diff --git a/include/linux/lwtunnel.h b/include/linux/lwtunnel.h
new file mode 100644
index 0000000..b7c0191
--- /dev/null
+++ b/include/linux/lwtunnel.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LWTUNNEL_H_
+#define _LWTUNNEL_H_
+
+#include <linux/types.h>
+
+enum lwtunnel_encap_types {
+ LWTUNNEL_ENCAP_NONE,
+ LWTUNNEL_ENCAP_MPLS,
+ LWTUNNEL_ENCAP_IP,
+ LWTUNNEL_ENCAP_ILA,
+ LWTUNNEL_ENCAP_IP6,
+ LWTUNNEL_ENCAP_SEG6,
+ LWTUNNEL_ENCAP_BPF,
+ LWTUNNEL_ENCAP_SEG6_LOCAL,
+ LWTUNNEL_ENCAP_RPL,
+ __LWTUNNEL_ENCAP_MAX,
+};
+
+#define LWTUNNEL_ENCAP_MAX (__LWTUNNEL_ENCAP_MAX - 1)
+
+enum lwtunnel_ip_t {
+ LWTUNNEL_IP_UNSPEC,
+ LWTUNNEL_IP_ID,
+ LWTUNNEL_IP_DST,
+ LWTUNNEL_IP_SRC,
+ LWTUNNEL_IP_TTL,
+ LWTUNNEL_IP_TOS,
+ LWTUNNEL_IP_FLAGS,
+ LWTUNNEL_IP_PAD,
+ LWTUNNEL_IP_OPTS,
+ __LWTUNNEL_IP_MAX,
+};
+
+#define LWTUNNEL_IP_MAX (__LWTUNNEL_IP_MAX - 1)
+
+enum lwtunnel_ip6_t {
+ LWTUNNEL_IP6_UNSPEC,
+ LWTUNNEL_IP6_ID,
+ LWTUNNEL_IP6_DST,
+ LWTUNNEL_IP6_SRC,
+ LWTUNNEL_IP6_HOPLIMIT,
+ LWTUNNEL_IP6_TC,
+ LWTUNNEL_IP6_FLAGS,
+ LWTUNNEL_IP6_PAD,
+ LWTUNNEL_IP6_OPTS,
+ __LWTUNNEL_IP6_MAX,
+};
+
+#define LWTUNNEL_IP6_MAX (__LWTUNNEL_IP6_MAX - 1)
+
+enum {
+ LWTUNNEL_IP_OPTS_UNSPEC,
+ LWTUNNEL_IP_OPTS_GENEVE,
+ LWTUNNEL_IP_OPTS_VXLAN,
+ LWTUNNEL_IP_OPTS_ERSPAN,
+ __LWTUNNEL_IP_OPTS_MAX,
+};
+
+#define LWTUNNEL_IP_OPTS_MAX (__LWTUNNEL_IP_OPTS_MAX - 1)
+
+enum {
+ LWTUNNEL_IP_OPT_GENEVE_UNSPEC,
+ LWTUNNEL_IP_OPT_GENEVE_CLASS,
+ LWTUNNEL_IP_OPT_GENEVE_TYPE,
+ LWTUNNEL_IP_OPT_GENEVE_DATA,
+ __LWTUNNEL_IP_OPT_GENEVE_MAX,
+};
+
+#define LWTUNNEL_IP_OPT_GENEVE_MAX (__LWTUNNEL_IP_OPT_GENEVE_MAX - 1)
+
+enum {
+ LWTUNNEL_IP_OPT_VXLAN_UNSPEC,
+ LWTUNNEL_IP_OPT_VXLAN_GBP,
+ __LWTUNNEL_IP_OPT_VXLAN_MAX,
+};
+
+#define LWTUNNEL_IP_OPT_VXLAN_MAX (__LWTUNNEL_IP_OPT_VXLAN_MAX - 1)
+
+enum {
+ LWTUNNEL_IP_OPT_ERSPAN_UNSPEC,
+ LWTUNNEL_IP_OPT_ERSPAN_VER,
+ LWTUNNEL_IP_OPT_ERSPAN_INDEX,
+ LWTUNNEL_IP_OPT_ERSPAN_DIR,
+ LWTUNNEL_IP_OPT_ERSPAN_HWID,
+ __LWTUNNEL_IP_OPT_ERSPAN_MAX,
+};
+
+#define LWTUNNEL_IP_OPT_ERSPAN_MAX (__LWTUNNEL_IP_OPT_ERSPAN_MAX - 1)
+
+enum {
+ LWT_BPF_PROG_UNSPEC,
+ LWT_BPF_PROG_FD,
+ LWT_BPF_PROG_NAME,
+ __LWT_BPF_PROG_MAX,
+};
+
+#define LWT_BPF_PROG_MAX (__LWT_BPF_PROG_MAX - 1)
+
+enum {
+ LWT_BPF_UNSPEC,
+ LWT_BPF_IN,
+ LWT_BPF_OUT,
+ LWT_BPF_XMIT,
+ LWT_BPF_XMIT_HEADROOM,
+ __LWT_BPF_MAX,
+};
+
+#define LWT_BPF_MAX (__LWT_BPF_MAX - 1)
+
+#define LWT_BPF_MAX_HEADROOM 256
+
+#endif /* _LWTUNNEL_H_ */
diff --git a/include/linux/mpls.h b/include/linux/mpls.h
new file mode 100644
index 0000000..9effbf9
--- /dev/null
+++ b/include/linux/mpls.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _MPLS_H
+#define _MPLS_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/* Reference: RFC 5462, RFC 3032
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Label | TC |S| TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Label: Label Value, 20 bits
+ * TC: Traffic Class field, 3 bits
+ * S: Bottom of Stack, 1 bit
+ * TTL: Time to Live, 8 bits
+ */
+
+struct mpls_label {
+ __be32 entry;
+};
+
+#define MPLS_LS_LABEL_MASK 0xFFFFF000
+#define MPLS_LS_LABEL_SHIFT 12
+#define MPLS_LS_TC_MASK 0x00000E00
+#define MPLS_LS_TC_SHIFT 9
+#define MPLS_LS_S_MASK 0x00000100
+#define MPLS_LS_S_SHIFT 8
+#define MPLS_LS_TTL_MASK 0x000000FF
+#define MPLS_LS_TTL_SHIFT 0
+
+/* Reserved labels */
+#define MPLS_LABEL_IPV4NULL 0 /* RFC3032 */
+#define MPLS_LABEL_RTALERT 1 /* RFC3032 */
+#define MPLS_LABEL_IPV6NULL 2 /* RFC3032 */
+#define MPLS_LABEL_IMPLNULL 3 /* RFC3032 */
+#define MPLS_LABEL_ENTROPY 7 /* RFC6790 */
+#define MPLS_LABEL_GAL 13 /* RFC5586 */
+#define MPLS_LABEL_OAMALERT 14 /* RFC3429 */
+#define MPLS_LABEL_EXTENSION 15 /* RFC7274 */
+
+#define MPLS_LABEL_FIRST_UNRESERVED 16 /* RFC3032 */
+
+/* These are embedded into IFLA_STATS_AF_SPEC:
+ * [IFLA_STATS_AF_SPEC]
+ * -> [AF_MPLS]
+ * -> [MPLS_STATS_xxx]
+ *
+ * Attributes:
+ * [MPLS_STATS_LINK] = {
+ * struct mpls_link_stats
+ * }
+ */
+enum {
+ MPLS_STATS_UNSPEC, /* also used as 64bit pad attribute */
+ MPLS_STATS_LINK,
+ __MPLS_STATS_MAX,
+};
+
+#define MPLS_STATS_MAX (__MPLS_STATS_MAX - 1)
+
+struct mpls_link_stats {
+ __u64 rx_packets; /* total packets received */
+ __u64 tx_packets; /* total packets transmitted */
+ __u64 rx_bytes; /* total bytes received */
+ __u64 tx_bytes; /* total bytes transmitted */
+ __u64 rx_errors; /* bad packets received */
+ __u64 tx_errors; /* packet transmit problems */
+ __u64 rx_dropped; /* packet dropped on receive */
+ __u64 tx_dropped; /* packet dropped on transmit */
+ __u64 rx_noroute; /* no route for packet dest */
+};
+
+#endif /* _MPLS_H */
diff --git a/include/linux/mpls_iptunnel.h b/include/linux/mpls_iptunnel.h
new file mode 100644
index 0000000..2c69b7d
--- /dev/null
+++ b/include/linux/mpls_iptunnel.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * mpls tunnel api
+ *
+ * Authors:
+ * Roopa Prabhu <roopa@cumulusnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_MPLS_IPTUNNEL_H
+#define _LINUX_MPLS_IPTUNNEL_H
+
+/* MPLS tunnel attributes
+ * [RTA_ENCAP] = {
+ * [MPLS_IPTUNNEL_DST]
+ * [MPLS_IPTUNNEL_TTL]
+ * }
+ */
+enum {
+ MPLS_IPTUNNEL_UNSPEC,
+ MPLS_IPTUNNEL_DST,
+ MPLS_IPTUNNEL_TTL,
+ __MPLS_IPTUNNEL_MAX,
+};
+#define MPLS_IPTUNNEL_MAX (__MPLS_IPTUNNEL_MAX - 1)
+
+#endif /* _LINUX_MPLS_IPTUNNEL_H */
diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h
new file mode 100644
index 0000000..dc8b722
--- /dev/null
+++ b/include/linux/neighbour.h
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_NEIGHBOUR_H
+#define __LINUX_NEIGHBOUR_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct ndmsg {
+ __u8 ndm_family;
+ __u8 ndm_pad1;
+ __u16 ndm_pad2;
+ __s32 ndm_ifindex;
+ __u16 ndm_state;
+ __u8 ndm_flags;
+ __u8 ndm_type;
+};
+
+enum {
+ NDA_UNSPEC,
+ NDA_DST,
+ NDA_LLADDR,
+ NDA_CACHEINFO,
+ NDA_PROBES,
+ NDA_VLAN,
+ NDA_PORT,
+ NDA_VNI,
+ NDA_IFINDEX,
+ NDA_MASTER,
+ NDA_LINK_NETNSID,
+ NDA_SRC_VNI,
+ NDA_PROTOCOL, /* Originator of entry */
+ NDA_NH_ID,
+ NDA_FDB_EXT_ATTRS,
+ __NDA_MAX
+};
+
+#define NDA_MAX (__NDA_MAX - 1)
+
+/*
+ * Neighbor Cache Entry Flags
+ */
+
+#define NTF_USE 0x01
+#define NTF_SELF 0x02
+#define NTF_MASTER 0x04
+#define NTF_PROXY 0x08 /* == ATF_PUBL */
+#define NTF_EXT_LEARNED 0x10
+#define NTF_OFFLOADED 0x20
+#define NTF_STICKY 0x40
+#define NTF_ROUTER 0x80
+
+/*
+ * Neighbor Cache Entry States.
+ */
+
+#define NUD_INCOMPLETE 0x01
+#define NUD_REACHABLE 0x02
+#define NUD_STALE 0x04
+#define NUD_DELAY 0x08
+#define NUD_PROBE 0x10
+#define NUD_FAILED 0x20
+
+/* Dummy states */
+#define NUD_NOARP 0x40
+#define NUD_PERMANENT 0x80
+#define NUD_NONE 0x00
+
+/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change
+ and make no address resolution or NUD.
+ NUD_PERMANENT also cannot be deleted by garbage collectors.
+ */
+
+struct nda_cacheinfo {
+ __u32 ndm_confirmed;
+ __u32 ndm_used;
+ __u32 ndm_updated;
+ __u32 ndm_refcnt;
+};
+
+/*****************************************************************
+ * Neighbour tables specific messages.
+ *
+ * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the
+ * NLM_F_DUMP flag set. Every neighbour table configuration is
+ * spread over multiple messages to avoid running into message
+ * size limits on systems with many interfaces. The first message
+ * in the sequence transports all not device specific data such as
+ * statistics, configuration, and the default parameter set.
+ * This message is followed by 0..n messages carrying device
+ * specific parameter sets.
+ * Although the ordering should be sufficient, NDTA_NAME can be
+ * used to identify sequences. The initial message can be identified
+ * by checking for NDTA_CONFIG. The device specific messages do
+ * not contain this TLV but have NDTPA_IFINDEX set to the
+ * corresponding interface index.
+ *
+ * To change neighbour table attributes, send RTM_SETNEIGHTBL
+ * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3],
+ * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked
+ * otherwise. Device specific parameter sets can be changed by
+ * setting NDTPA_IFINDEX to the interface index of the corresponding
+ * device.
+ ****/
+
+struct ndt_stats {
+ __u64 ndts_allocs;
+ __u64 ndts_destroys;
+ __u64 ndts_hash_grows;
+ __u64 ndts_res_failed;
+ __u64 ndts_lookups;
+ __u64 ndts_hits;
+ __u64 ndts_rcv_probes_mcast;
+ __u64 ndts_rcv_probes_ucast;
+ __u64 ndts_periodic_gc_runs;
+ __u64 ndts_forced_gc_runs;
+ __u64 ndts_table_fulls;
+};
+
+enum {
+ NDTPA_UNSPEC,
+ NDTPA_IFINDEX, /* u32, unchangeable */
+ NDTPA_REFCNT, /* u32, read-only */
+ NDTPA_REACHABLE_TIME, /* u64, read-only, msecs */
+ NDTPA_BASE_REACHABLE_TIME, /* u64, msecs */
+ NDTPA_RETRANS_TIME, /* u64, msecs */
+ NDTPA_GC_STALETIME, /* u64, msecs */
+ NDTPA_DELAY_PROBE_TIME, /* u64, msecs */
+ NDTPA_QUEUE_LEN, /* u32 */
+ NDTPA_APP_PROBES, /* u32 */
+ NDTPA_UCAST_PROBES, /* u32 */
+ NDTPA_MCAST_PROBES, /* u32 */
+ NDTPA_ANYCAST_DELAY, /* u64, msecs */
+ NDTPA_PROXY_DELAY, /* u64, msecs */
+ NDTPA_PROXY_QLEN, /* u32 */
+ NDTPA_LOCKTIME, /* u64, msecs */
+ NDTPA_QUEUE_LENBYTES, /* u32 */
+ NDTPA_MCAST_REPROBES, /* u32 */
+ NDTPA_PAD,
+ __NDTPA_MAX
+};
+#define NDTPA_MAX (__NDTPA_MAX - 1)
+
+struct ndtmsg {
+ __u8 ndtm_family;
+ __u8 ndtm_pad1;
+ __u16 ndtm_pad2;
+};
+
+struct ndt_config {
+ __u16 ndtc_key_len;
+ __u16 ndtc_entry_size;
+ __u32 ndtc_entries;
+ __u32 ndtc_last_flush; /* delta to now in msecs */
+ __u32 ndtc_last_rand; /* delta to now in msecs */
+ __u32 ndtc_hash_rnd;
+ __u32 ndtc_hash_mask;
+ __u32 ndtc_hash_chain_gc;
+ __u32 ndtc_proxy_qlen;
+};
+
+enum {
+ NDTA_UNSPEC,
+ NDTA_NAME, /* char *, unchangeable */
+ NDTA_THRESH1, /* u32 */
+ NDTA_THRESH2, /* u32 */
+ NDTA_THRESH3, /* u32 */
+ NDTA_CONFIG, /* struct ndt_config, read-only */
+ NDTA_PARMS, /* nested TLV NDTPA_* */
+ NDTA_STATS, /* struct ndt_stats, read-only */
+ NDTA_GC_INTERVAL, /* u64, msecs */
+ NDTA_PAD,
+ __NDTA_MAX
+};
+#define NDTA_MAX (__NDTA_MAX - 1)
+
+ /* FDB activity notification bits used in NFEA_ACTIVITY_NOTIFY:
+ * - FDB_NOTIFY_BIT - notify on activity/expire for any entry
+ * - FDB_NOTIFY_INACTIVE_BIT - mark as inactive to avoid multiple notifications
+ */
+enum {
+ FDB_NOTIFY_BIT = (1 << 0),
+ FDB_NOTIFY_INACTIVE_BIT = (1 << 1)
+};
+
+/* embedded into NDA_FDB_EXT_ATTRS:
+ * [NDA_FDB_EXT_ATTRS] = {
+ * [NFEA_ACTIVITY_NOTIFY]
+ * ...
+ * }
+ */
+enum {
+ NFEA_UNSPEC,
+ NFEA_ACTIVITY_NOTIFY,
+ NFEA_DONT_REFRESH,
+ __NFEA_MAX
+};
+#define NFEA_MAX (__NFEA_MAX - 1)
+
+#endif
diff --git a/include/linux/netconf.h b/include/linux/netconf.h
new file mode 100644
index 0000000..229e885
--- /dev/null
+++ b/include/linux/netconf.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_NETCONF_H_
+#define _LINUX_NETCONF_H_
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct netconfmsg {
+ __u8 ncm_family;
+};
+
+enum {
+ NETCONFA_UNSPEC,
+ NETCONFA_IFINDEX,
+ NETCONFA_FORWARDING,
+ NETCONFA_RP_FILTER,
+ NETCONFA_MC_FORWARDING,
+ NETCONFA_PROXY_NEIGH,
+ NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
+ NETCONFA_INPUT,
+ NETCONFA_BC_FORWARDING,
+ __NETCONFA_MAX
+};
+#define NETCONFA_MAX (__NETCONFA_MAX - 1)
+#define NETCONFA_ALL -1
+
+#define NETCONFA_IFINDEX_ALL -1
+#define NETCONFA_IFINDEX_DEFAULT -2
+
+#endif /* _LINUX_NETCONF_H_ */
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
new file mode 100644
index 0000000..5024c54
--- /dev/null
+++ b/include/linux/netlink.h
@@ -0,0 +1,355 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_NETLINK_H
+#define __LINUX_NETLINK_H
+
+#include <linux/const.h>
+#include <linux/socket.h> /* for __kernel_sa_family_t */
+#include <linux/types.h>
+
+#define NETLINK_ROUTE 0 /* Routing/device hook */
+#define NETLINK_UNUSED 1 /* Unused number */
+#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
+#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */
+#define NETLINK_SOCK_DIAG 4 /* socket monitoring */
+#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
+#define NETLINK_XFRM 6 /* ipsec */
+#define NETLINK_SELINUX 7 /* SELinux event notifications */
+#define NETLINK_ISCSI 8 /* Open-iSCSI */
+#define NETLINK_AUDIT 9 /* auditing */
+#define NETLINK_FIB_LOOKUP 10
+#define NETLINK_CONNECTOR 11
+#define NETLINK_NETFILTER 12 /* netfilter subsystem */
+#define NETLINK_IP6_FW 13
+#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
+#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
+#define NETLINK_GENERIC 16
+/* leave room for NETLINK_DM (DM Events) */
+#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
+#define NETLINK_ECRYPTFS 19
+#define NETLINK_RDMA 20
+#define NETLINK_CRYPTO 21 /* Crypto layer */
+#define NETLINK_SMC 22 /* SMC monitoring */
+
+#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG
+
+#define MAX_LINKS 32
+
+struct sockaddr_nl {
+ __kernel_sa_family_t nl_family; /* AF_NETLINK */
+ unsigned short nl_pad; /* zero */
+ __u32 nl_pid; /* port ID */
+ __u32 nl_groups; /* multicast groups mask */
+};
+
+struct nlmsghdr {
+ __u32 nlmsg_len; /* Length of message including header */
+ __u16 nlmsg_type; /* Message content */
+ __u16 nlmsg_flags; /* Additional flags */
+ __u32 nlmsg_seq; /* Sequence number */
+ __u32 nlmsg_pid; /* Sending process port ID */
+};
+
+/* Flags values */
+
+#define NLM_F_REQUEST 0x01 /* It is request message. */
+#define NLM_F_MULTI 0x02 /* Multipart message, terminated by NLMSG_DONE */
+#define NLM_F_ACK 0x04 /* Reply with ack, with zero or error code */
+#define NLM_F_ECHO 0x08 /* Echo this request */
+#define NLM_F_DUMP_INTR 0x10 /* Dump was inconsistent due to sequence change */
+#define NLM_F_DUMP_FILTERED 0x20 /* Dump was filtered as requested */
+
+/* Modifiers to GET request */
+#define NLM_F_ROOT 0x100 /* specify tree root */
+#define NLM_F_MATCH 0x200 /* return all matching */
+#define NLM_F_ATOMIC 0x400 /* atomic GET */
+#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
+
+/* Modifiers to NEW request */
+#define NLM_F_REPLACE 0x100 /* Override existing */
+#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */
+#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
+#define NLM_F_APPEND 0x800 /* Add to end of list */
+
+/* Modifiers to DELETE request */
+#define NLM_F_NONREC 0x100 /* Do not delete recursively */
+
+/* Flags for ACK message */
+#define NLM_F_CAPPED 0x100 /* request was capped */
+#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
+
+/*
+ 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
+ 4.4BSD CHANGE NLM_F_REPLACE
+
+ True CHANGE NLM_F_CREATE|NLM_F_REPLACE
+ Append NLM_F_CREATE
+ Check NLM_F_EXCL
+ */
+
+#define NLMSG_ALIGNTO 4U
+#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+ (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define NLMSG_NOOP 0x1 /* Nothing. */
+#define NLMSG_ERROR 0x2 /* Error */
+#define NLMSG_DONE 0x3 /* End of a dump */
+#define NLMSG_OVERRUN 0x4 /* Data lost */
+
+#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */
+
+struct nlmsgerr {
+ int error;
+ struct nlmsghdr msg;
+ /*
+ * followed by the message contents unless NETLINK_CAP_ACK was set
+ * or the ACK indicates success (error == 0)
+ * message length is aligned with NLMSG_ALIGN()
+ */
+ /*
+ * followed by TLVs defined in enum nlmsgerr_attrs
+ * if NETLINK_EXT_ACK was set
+ */
+};
+
+/**
+ * enum nlmsgerr_attrs - nlmsgerr attributes
+ * @NLMSGERR_ATTR_UNUSED: unused
+ * @NLMSGERR_ATTR_MSG: error message string (string)
+ * @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original
+ * message, counting from the beginning of the header (u32)
+ * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to
+ * be used - in the success case - to identify a created
+ * object or operation or similar (binary)
+ * @NLMSGERR_ATTR_POLICY: policy for a rejected attribute
+ * @__NLMSGERR_ATTR_MAX: number of attributes
+ * @NLMSGERR_ATTR_MAX: highest attribute number
+ */
+enum nlmsgerr_attrs {
+ NLMSGERR_ATTR_UNUSED,
+ NLMSGERR_ATTR_MSG,
+ NLMSGERR_ATTR_OFFS,
+ NLMSGERR_ATTR_COOKIE,
+ NLMSGERR_ATTR_POLICY,
+
+ __NLMSGERR_ATTR_MAX,
+ NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+
+#define NETLINK_ADD_MEMBERSHIP 1
+#define NETLINK_DROP_MEMBERSHIP 2
+#define NETLINK_PKTINFO 3
+#define NETLINK_BROADCAST_ERROR 4
+#define NETLINK_NO_ENOBUFS 5
+#define NETLINK_RX_RING 6
+#define NETLINK_TX_RING 7
+#define NETLINK_LISTEN_ALL_NSID 8
+#define NETLINK_LIST_MEMBERSHIPS 9
+#define NETLINK_CAP_ACK 10
+#define NETLINK_EXT_ACK 11
+#define NETLINK_GET_STRICT_CHK 12
+
+struct nl_pktinfo {
+ __u32 group;
+};
+
+struct nl_mmap_req {
+ unsigned int nm_block_size;
+ unsigned int nm_block_nr;
+ unsigned int nm_frame_size;
+ unsigned int nm_frame_nr;
+};
+
+struct nl_mmap_hdr {
+ unsigned int nm_status;
+ unsigned int nm_len;
+ __u32 nm_group;
+ /* credentials */
+ __u32 nm_pid;
+ __u32 nm_uid;
+ __u32 nm_gid;
+};
+
+enum nl_mmap_status {
+ NL_MMAP_STATUS_UNUSED,
+ NL_MMAP_STATUS_RESERVED,
+ NL_MMAP_STATUS_VALID,
+ NL_MMAP_STATUS_COPY,
+ NL_MMAP_STATUS_SKIP,
+};
+
+#define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO
+#define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
+#define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+
+#define NET_MAJOR 36 /* Major 36 is reserved for networking */
+
+enum {
+ NETLINK_UNCONNECTED = 0,
+ NETLINK_CONNECTED,
+};
+
+/*
+ * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * | Header | Pad | Payload | Pad |
+ * | (struct nlattr) | ing | | ing |
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * <-------------- nlattr->nla_len -------------->
+ */
+
+struct nlattr {
+ __u16 nla_len;
+ __u16 nla_type;
+};
+
+/*
+ * nla_type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ *
+ * Note: The N and O flag are mutually exclusive.
+ */
+#define NLA_F_NESTED (1 << 15)
+#define NLA_F_NET_BYTEORDER (1 << 14)
+#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
+
+#define NLA_ALIGNTO 4
+#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
+
+/* Generic 32 bitflags attribute content sent to the kernel.
+ *
+ * The value is a bitmap that defines the values being set
+ * The selector is a bitmask that defines which value is legit
+ *
+ * Examples:
+ * value = 0x0, and selector = 0x1
+ * implies we are selecting bit 1 and we want to set its value to 0.
+ *
+ * value = 0x2, and selector = 0x2
+ * implies we are selecting bit 2 and we want to set its value to 1.
+ *
+ */
+struct nla_bitfield32 {
+ __u32 value;
+ __u32 selector;
+};
+
+/*
+ * policy descriptions - it's specific to each family how this is used
+ * Normally, it should be retrieved via a dump inside another attribute
+ * specifying where it applies.
+ */
+
+/**
+ * enum netlink_attribute_type - type of an attribute
+ * @NL_ATTR_TYPE_INVALID: unused
+ * @NL_ATTR_TYPE_FLAG: flag attribute (present/not present)
+ * @NL_ATTR_TYPE_U8: 8-bit unsigned attribute
+ * @NL_ATTR_TYPE_U16: 16-bit unsigned attribute
+ * @NL_ATTR_TYPE_U32: 32-bit unsigned attribute
+ * @NL_ATTR_TYPE_U64: 64-bit unsigned attribute
+ * @NL_ATTR_TYPE_S8: 8-bit signed attribute
+ * @NL_ATTR_TYPE_S16: 16-bit signed attribute
+ * @NL_ATTR_TYPE_S32: 32-bit signed attribute
+ * @NL_ATTR_TYPE_S64: 64-bit signed attribute
+ * @NL_ATTR_TYPE_BINARY: binary data, min/max length may be specified
+ * @NL_ATTR_TYPE_STRING: string, min/max length may be specified
+ * @NL_ATTR_TYPE_NUL_STRING: NUL-terminated string,
+ * min/max length may be specified
+ * @NL_ATTR_TYPE_NESTED: nested, i.e. the content of this attribute
+ * consists of sub-attributes. The nested policy and maxtype
+ * inside may be specified.
+ * @NL_ATTR_TYPE_NESTED_ARRAY: nested array, i.e. the content of this
+ * attribute contains sub-attributes whose type is irrelevant
+ * (just used to separate the array entries) and each such array
+ * entry has attributes again, the policy for those inner ones
+ * and the corresponding maxtype may be specified.
+ * @NL_ATTR_TYPE_BITFIELD32: &struct nla_bitfield32 attribute
+ */
+enum netlink_attribute_type {
+ NL_ATTR_TYPE_INVALID,
+
+ NL_ATTR_TYPE_FLAG,
+
+ NL_ATTR_TYPE_U8,
+ NL_ATTR_TYPE_U16,
+ NL_ATTR_TYPE_U32,
+ NL_ATTR_TYPE_U64,
+
+ NL_ATTR_TYPE_S8,
+ NL_ATTR_TYPE_S16,
+ NL_ATTR_TYPE_S32,
+ NL_ATTR_TYPE_S64,
+
+ NL_ATTR_TYPE_BINARY,
+ NL_ATTR_TYPE_STRING,
+ NL_ATTR_TYPE_NUL_STRING,
+
+ NL_ATTR_TYPE_NESTED,
+ NL_ATTR_TYPE_NESTED_ARRAY,
+
+ NL_ATTR_TYPE_BITFIELD32,
+};
+
+/**
+ * enum netlink_policy_type_attr - policy type attributes
+ * @NL_POLICY_TYPE_ATTR_UNSPEC: unused
+ * @NL_POLICY_TYPE_ATTR_TYPE: type of the attribute,
+ * &enum netlink_attribute_type (U32)
+ * @NL_POLICY_TYPE_ATTR_MIN_VALUE_S: minimum value for signed
+ * integers (S64)
+ * @NL_POLICY_TYPE_ATTR_MAX_VALUE_S: maximum value for signed
+ * integers (S64)
+ * @NL_POLICY_TYPE_ATTR_MIN_VALUE_U: minimum value for unsigned
+ * integers (U64)
+ * @NL_POLICY_TYPE_ATTR_MAX_VALUE_U: maximum value for unsigned
+ * integers (U64)
+ * @NL_POLICY_TYPE_ATTR_MIN_LENGTH: minimum length for binary
+ * attributes, no minimum if not given (U32)
+ * @NL_POLICY_TYPE_ATTR_MAX_LENGTH: maximum length for binary
+ * attributes, no maximum if not given (U32)
+ * @NL_POLICY_TYPE_ATTR_POLICY_IDX: sub policy for nested and
+ * nested array types (U32)
+ * @NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE: maximum sub policy
+ * attribute for nested and nested array types, this can
+ * in theory be < the size of the policy pointed to by
+ * the index, if limited inside the nesting (U32)
+ * @NL_POLICY_TYPE_ATTR_BITFIELD32_MASK: valid mask for the
+ * bitfield32 type (U32)
+ * @NL_POLICY_TYPE_ATTR_MASK: mask of valid bits for unsigned integers (U64)
+ * @NL_POLICY_TYPE_ATTR_PAD: pad attribute for 64-bit alignment
+ */
+enum netlink_policy_type_attr {
+ NL_POLICY_TYPE_ATTR_UNSPEC,
+ NL_POLICY_TYPE_ATTR_TYPE,
+ NL_POLICY_TYPE_ATTR_MIN_VALUE_S,
+ NL_POLICY_TYPE_ATTR_MAX_VALUE_S,
+ NL_POLICY_TYPE_ATTR_MIN_VALUE_U,
+ NL_POLICY_TYPE_ATTR_MAX_VALUE_U,
+ NL_POLICY_TYPE_ATTR_MIN_LENGTH,
+ NL_POLICY_TYPE_ATTR_MAX_LENGTH,
+ NL_POLICY_TYPE_ATTR_POLICY_IDX,
+ NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,
+ NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
+ NL_POLICY_TYPE_ATTR_PAD,
+ NL_POLICY_TYPE_ATTR_MASK,
+
+ /* keep last */
+ __NL_POLICY_TYPE_ATTR_MAX,
+ NL_POLICY_TYPE_ATTR_MAX = __NL_POLICY_TYPE_ATTR_MAX - 1
+};
+
+#endif /* __LINUX_NETLINK_H */
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
new file mode 100644
index 0000000..b34b9ad
--- /dev/null
+++ b/include/linux/rtnetlink.h
@@ -0,0 +1,800 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_RTNETLINK_H
+#define __LINUX_RTNETLINK_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/if_link.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
+
+/* rtnetlink families. Values up to 127 are reserved for real address
+ * families, values above 128 may be used arbitrarily.
+ */
+#define RTNL_FAMILY_IPMR 128
+#define RTNL_FAMILY_IP6MR 129
+#define RTNL_FAMILY_MAX 129
+
+/****
+ * Routing/neighbour discovery messages.
+ ****/
+
+/* Types of messages */
+
+enum {
+ RTM_BASE = 16,
+#define RTM_BASE RTM_BASE
+
+ RTM_NEWLINK = 16,
+#define RTM_NEWLINK RTM_NEWLINK
+ RTM_DELLINK,
+#define RTM_DELLINK RTM_DELLINK
+ RTM_GETLINK,
+#define RTM_GETLINK RTM_GETLINK
+ RTM_SETLINK,
+#define RTM_SETLINK RTM_SETLINK
+
+ RTM_NEWADDR = 20,
+#define RTM_NEWADDR RTM_NEWADDR
+ RTM_DELADDR,
+#define RTM_DELADDR RTM_DELADDR
+ RTM_GETADDR,
+#define RTM_GETADDR RTM_GETADDR
+
+ RTM_NEWROUTE = 24,
+#define RTM_NEWROUTE RTM_NEWROUTE
+ RTM_DELROUTE,
+#define RTM_DELROUTE RTM_DELROUTE
+ RTM_GETROUTE,
+#define RTM_GETROUTE RTM_GETROUTE
+
+ RTM_NEWNEIGH = 28,
+#define RTM_NEWNEIGH RTM_NEWNEIGH
+ RTM_DELNEIGH,
+#define RTM_DELNEIGH RTM_DELNEIGH
+ RTM_GETNEIGH,
+#define RTM_GETNEIGH RTM_GETNEIGH
+
+ RTM_NEWRULE = 32,
+#define RTM_NEWRULE RTM_NEWRULE
+ RTM_DELRULE,
+#define RTM_DELRULE RTM_DELRULE
+ RTM_GETRULE,
+#define RTM_GETRULE RTM_GETRULE
+
+ RTM_NEWQDISC = 36,
+#define RTM_NEWQDISC RTM_NEWQDISC
+ RTM_DELQDISC,
+#define RTM_DELQDISC RTM_DELQDISC
+ RTM_GETQDISC,
+#define RTM_GETQDISC RTM_GETQDISC
+
+ RTM_NEWTCLASS = 40,
+#define RTM_NEWTCLASS RTM_NEWTCLASS
+ RTM_DELTCLASS,
+#define RTM_DELTCLASS RTM_DELTCLASS
+ RTM_GETTCLASS,
+#define RTM_GETTCLASS RTM_GETTCLASS
+
+ RTM_NEWTFILTER = 44,
+#define RTM_NEWTFILTER RTM_NEWTFILTER
+ RTM_DELTFILTER,
+#define RTM_DELTFILTER RTM_DELTFILTER
+ RTM_GETTFILTER,
+#define RTM_GETTFILTER RTM_GETTFILTER
+
+ RTM_NEWACTION = 48,
+#define RTM_NEWACTION RTM_NEWACTION
+ RTM_DELACTION,
+#define RTM_DELACTION RTM_DELACTION
+ RTM_GETACTION,
+#define RTM_GETACTION RTM_GETACTION
+
+ RTM_NEWPREFIX = 52,
+#define RTM_NEWPREFIX RTM_NEWPREFIX
+
+ RTM_GETMULTICAST = 58,
+#define RTM_GETMULTICAST RTM_GETMULTICAST
+
+ RTM_GETANYCAST = 62,
+#define RTM_GETANYCAST RTM_GETANYCAST
+
+ RTM_NEWNEIGHTBL = 64,
+#define RTM_NEWNEIGHTBL RTM_NEWNEIGHTBL
+ RTM_GETNEIGHTBL = 66,
+#define RTM_GETNEIGHTBL RTM_GETNEIGHTBL
+ RTM_SETNEIGHTBL,
+#define RTM_SETNEIGHTBL RTM_SETNEIGHTBL
+
+ RTM_NEWNDUSEROPT = 68,
+#define RTM_NEWNDUSEROPT RTM_NEWNDUSEROPT
+
+ RTM_NEWADDRLABEL = 72,
+#define RTM_NEWADDRLABEL RTM_NEWADDRLABEL
+ RTM_DELADDRLABEL,
+#define RTM_DELADDRLABEL RTM_DELADDRLABEL
+ RTM_GETADDRLABEL,
+#define RTM_GETADDRLABEL RTM_GETADDRLABEL
+
+ RTM_GETDCB = 78,
+#define RTM_GETDCB RTM_GETDCB
+ RTM_SETDCB,
+#define RTM_SETDCB RTM_SETDCB
+
+ RTM_NEWNETCONF = 80,
+#define RTM_NEWNETCONF RTM_NEWNETCONF
+ RTM_DELNETCONF,
+#define RTM_DELNETCONF RTM_DELNETCONF
+ RTM_GETNETCONF = 82,
+#define RTM_GETNETCONF RTM_GETNETCONF
+
+ RTM_NEWMDB = 84,
+#define RTM_NEWMDB RTM_NEWMDB
+ RTM_DELMDB = 85,
+#define RTM_DELMDB RTM_DELMDB
+ RTM_GETMDB = 86,
+#define RTM_GETMDB RTM_GETMDB
+
+ RTM_NEWNSID = 88,
+#define RTM_NEWNSID RTM_NEWNSID
+ RTM_DELNSID = 89,
+#define RTM_DELNSID RTM_DELNSID
+ RTM_GETNSID = 90,
+#define RTM_GETNSID RTM_GETNSID
+
+ RTM_NEWSTATS = 92,
+#define RTM_NEWSTATS RTM_NEWSTATS
+ RTM_GETSTATS = 94,
+#define RTM_GETSTATS RTM_GETSTATS
+
+ RTM_NEWCACHEREPORT = 96,
+#define RTM_NEWCACHEREPORT RTM_NEWCACHEREPORT
+
+ RTM_NEWCHAIN = 100,
+#define RTM_NEWCHAIN RTM_NEWCHAIN
+ RTM_DELCHAIN,
+#define RTM_DELCHAIN RTM_DELCHAIN
+ RTM_GETCHAIN,
+#define RTM_GETCHAIN RTM_GETCHAIN
+
+ RTM_NEWNEXTHOP = 104,
+#define RTM_NEWNEXTHOP RTM_NEWNEXTHOP
+ RTM_DELNEXTHOP,
+#define RTM_DELNEXTHOP RTM_DELNEXTHOP
+ RTM_GETNEXTHOP,
+#define RTM_GETNEXTHOP RTM_GETNEXTHOP
+
+ RTM_NEWLINKPROP = 108,
+#define RTM_NEWLINKPROP RTM_NEWLINKPROP
+ RTM_DELLINKPROP,
+#define RTM_DELLINKPROP RTM_DELLINKPROP
+ RTM_GETLINKPROP,
+#define RTM_GETLINKPROP RTM_GETLINKPROP
+
+ RTM_NEWVLAN = 112,
+#define RTM_NEWNVLAN RTM_NEWVLAN
+ RTM_DELVLAN,
+#define RTM_DELVLAN RTM_DELVLAN
+ RTM_GETVLAN,
+#define RTM_GETVLAN RTM_GETVLAN
+
+ __RTM_MAX,
+#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
+};
+
+#define RTM_NR_MSGTYPES (RTM_MAX + 1 - RTM_BASE)
+#define RTM_NR_FAMILIES (RTM_NR_MSGTYPES >> 2)
+#define RTM_FAM(cmd) (((cmd) - RTM_BASE) >> 2)
+
+/*
+ Generic structure for encapsulation of optional route information.
+ It is reminiscent of sockaddr, but with sa_family replaced
+ with attribute type.
+ */
+
+struct rtattr {
+ unsigned short rta_len;
+ unsigned short rta_type;
+};
+
+/* Macros to handle rtattributes */
+
+#define RTA_ALIGNTO 4U
+#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
+#define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \
+ (rta)->rta_len >= sizeof(struct rtattr) && \
+ (rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+ (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
+#define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
+#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
+
+
+
+
+/******************************************************************************
+ * Definitions used in routing table administration.
+ ****/
+
+struct rtmsg {
+ unsigned char rtm_family;
+ unsigned char rtm_dst_len;
+ unsigned char rtm_src_len;
+ unsigned char rtm_tos;
+
+ unsigned char rtm_table; /* Routing table id */
+ unsigned char rtm_protocol; /* Routing protocol; see below */
+ unsigned char rtm_scope; /* See below */
+ unsigned char rtm_type; /* See below */
+
+ unsigned rtm_flags;
+};
+
+/* rtm_type */
+
+enum {
+ RTN_UNSPEC,
+ RTN_UNICAST, /* Gateway or direct route */
+ RTN_LOCAL, /* Accept locally */
+ RTN_BROADCAST, /* Accept locally as broadcast,
+ send as broadcast */
+ RTN_ANYCAST, /* Accept locally as broadcast,
+ but send as unicast */
+ RTN_MULTICAST, /* Multicast route */
+ RTN_BLACKHOLE, /* Drop */
+ RTN_UNREACHABLE, /* Destination is unreachable */
+ RTN_PROHIBIT, /* Administratively prohibited */
+ RTN_THROW, /* Not in this table */
+ RTN_NAT, /* Translate this address */
+ RTN_XRESOLVE, /* Use external resolver */
+ __RTN_MAX
+};
+
+#define RTN_MAX (__RTN_MAX - 1)
+
+
+/* rtm_protocol */
+
+#define RTPROT_UNSPEC 0
+#define RTPROT_REDIRECT 1 /* Route installed by ICMP redirects;
+ not used by current IPv4 */
+#define RTPROT_KERNEL 2 /* Route installed by kernel */
+#define RTPROT_BOOT 3 /* Route installed during boot */
+#define RTPROT_STATIC 4 /* Route installed by administrator */
+
+/* Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
+ they are just passed from user and back as is.
+ It will be used by hypothetical multiple routing daemons.
+ Note that protocol values should be standardized in order to
+ avoid conflicts.
+ */
+
+#define RTPROT_GATED 8 /* Apparently, GateD */
+#define RTPROT_RA 9 /* RDISC/ND router advertisements */
+#define RTPROT_MRT 10 /* Merit MRT */
+#define RTPROT_ZEBRA 11 /* Zebra */
+#define RTPROT_BIRD 12 /* BIRD */
+#define RTPROT_DNROUTED 13 /* DECnet routing daemon */
+#define RTPROT_XORP 14 /* XORP */
+#define RTPROT_NTK 15 /* Netsukuku */
+#define RTPROT_DHCP 16 /* DHCP client */
+#define RTPROT_MROUTED 17 /* Multicast daemon */
+#define RTPROT_KEEPALIVED 18 /* Keepalived daemon */
+#define RTPROT_BABEL 42 /* Babel daemon */
+#define RTPROT_BGP 186 /* BGP Routes */
+#define RTPROT_ISIS 187 /* ISIS Routes */
+#define RTPROT_OSPF 188 /* OSPF Routes */
+#define RTPROT_RIP 189 /* RIP Routes */
+#define RTPROT_EIGRP 192 /* EIGRP Routes */
+
+/* rtm_scope
+
+ Really it is not scope, but sort of distance to the destination.
+ NOWHERE are reserved for not existing destinations, HOST is our
+ local addresses, LINK are destinations, located on directly attached
+ link and UNIVERSE is everywhere in the Universe.
+
+ Intermediate values are also possible f.e. interior routes
+ could be assigned a value between UNIVERSE and LINK.
+*/
+
+enum rt_scope_t {
+ RT_SCOPE_UNIVERSE=0,
+/* User defined values */
+ RT_SCOPE_SITE=200,
+ RT_SCOPE_LINK=253,
+ RT_SCOPE_HOST=254,
+ RT_SCOPE_NOWHERE=255
+};
+
+/* rtm_flags */
+
+#define RTM_F_NOTIFY 0x100 /* Notify user of route change */
+#define RTM_F_CLONED 0x200 /* This route is cloned */
+#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */
+#define RTM_F_PREFIX 0x800 /* Prefix addresses */
+#define RTM_F_LOOKUP_TABLE 0x1000 /* set rtm_table to FIB lookup result */
+#define RTM_F_FIB_MATCH 0x2000 /* return full fib lookup match */
+#define RTM_F_OFFLOAD 0x4000 /* route is offloaded */
+#define RTM_F_TRAP 0x8000 /* route is trapping packets */
+#define RTM_F_OFFLOAD_FAILED 0x20000000 /* route offload failed, this value
+ * is chosen to avoid conflicts with
+ * other flags defined in
+ * include/uapi/linux/ipv6_route.h
+ */
+
+/* Reserved table identifiers */
+
+enum rt_class_t {
+ RT_TABLE_UNSPEC=0,
+/* User defined values */
+ RT_TABLE_COMPAT=252,
+ RT_TABLE_DEFAULT=253,
+ RT_TABLE_MAIN=254,
+ RT_TABLE_LOCAL=255,
+ RT_TABLE_MAX=0xFFFFFFFF
+};
+
+
+/* Routing message attributes */
+
+enum rtattr_type_t {
+ RTA_UNSPEC,
+ RTA_DST,
+ RTA_SRC,
+ RTA_IIF,
+ RTA_OIF,
+ RTA_GATEWAY,
+ RTA_PRIORITY,
+ RTA_PREFSRC,
+ RTA_METRICS,
+ RTA_MULTIPATH,
+ RTA_PROTOINFO, /* no longer used */
+ RTA_FLOW,
+ RTA_CACHEINFO,
+ RTA_SESSION, /* no longer used */
+ RTA_MP_ALGO, /* no longer used */
+ RTA_TABLE,
+ RTA_MARK,
+ RTA_MFC_STATS,
+ RTA_VIA,
+ RTA_NEWDST,
+ RTA_PREF,
+ RTA_ENCAP_TYPE,
+ RTA_ENCAP,
+ RTA_EXPIRES,
+ RTA_PAD,
+ RTA_UID,
+ RTA_TTL_PROPAGATE,
+ RTA_IP_PROTO,
+ RTA_SPORT,
+ RTA_DPORT,
+ RTA_NH_ID,
+ __RTA_MAX
+};
+
+#define RTA_MAX (__RTA_MAX - 1)
+
+#define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg))))
+#define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg))
+
+/* RTM_MULTIPATH --- array of struct rtnexthop.
+ *
+ * "struct rtnexthop" describes all necessary nexthop information,
+ * i.e. parameters of path to a destination via this nexthop.
+ *
+ * At the moment it is impossible to set different prefsrc, mtu, window
+ * and rtt for different paths from multipath.
+ */
+
+struct rtnexthop {
+ unsigned short rtnh_len;
+ unsigned char rtnh_flags;
+ unsigned char rtnh_hops;
+ int rtnh_ifindex;
+};
+
+/* rtnh_flags */
+
+#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */
+#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
+#define RTNH_F_ONLINK 4 /* Gateway is forced on link */
+#define RTNH_F_OFFLOAD 8 /* Nexthop is offloaded */
+#define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */
+#define RTNH_F_UNRESOLVED 32 /* The entry is unresolved (ipmr) */
+#define RTNH_F_TRAP 64 /* Nexthop is trapping packets */
+
+#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | \
+ RTNH_F_OFFLOAD | RTNH_F_TRAP)
+
+/* Macros to handle hexthops */
+
+#define RTNH_ALIGNTO 4
+#define RTNH_ALIGN(len) ( ((len)+RTNH_ALIGNTO-1) & ~(RTNH_ALIGNTO-1) )
+#define RTNH_OK(rtnh,len) ((rtnh)->rtnh_len >= sizeof(struct rtnexthop) && \
+ ((int)(rtnh)->rtnh_len) <= (len))
+#define RTNH_NEXT(rtnh) ((struct rtnexthop*)(((char*)(rtnh)) + RTNH_ALIGN((rtnh)->rtnh_len)))
+#define RTNH_LENGTH(len) (RTNH_ALIGN(sizeof(struct rtnexthop)) + (len))
+#define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len))
+#define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0)))
+
+/* RTA_VIA */
+struct rtvia {
+ __kernel_sa_family_t rtvia_family;
+ __u8 rtvia_addr[0];
+};
+
+/* RTM_CACHEINFO */
+
+struct rta_cacheinfo {
+ __u32 rta_clntref;
+ __u32 rta_lastuse;
+ __s32 rta_expires;
+ __u32 rta_error;
+ __u32 rta_used;
+
+#define RTNETLINK_HAVE_PEERINFO 1
+ __u32 rta_id;
+ __u32 rta_ts;
+ __u32 rta_tsage;
+};
+
+/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */
+
+enum {
+ RTAX_UNSPEC,
+#define RTAX_UNSPEC RTAX_UNSPEC
+ RTAX_LOCK,
+#define RTAX_LOCK RTAX_LOCK
+ RTAX_MTU,
+#define RTAX_MTU RTAX_MTU
+ RTAX_WINDOW,
+#define RTAX_WINDOW RTAX_WINDOW
+ RTAX_RTT,
+#define RTAX_RTT RTAX_RTT
+ RTAX_RTTVAR,
+#define RTAX_RTTVAR RTAX_RTTVAR
+ RTAX_SSTHRESH,
+#define RTAX_SSTHRESH RTAX_SSTHRESH
+ RTAX_CWND,
+#define RTAX_CWND RTAX_CWND
+ RTAX_ADVMSS,
+#define RTAX_ADVMSS RTAX_ADVMSS
+ RTAX_REORDERING,
+#define RTAX_REORDERING RTAX_REORDERING
+ RTAX_HOPLIMIT,
+#define RTAX_HOPLIMIT RTAX_HOPLIMIT
+ RTAX_INITCWND,
+#define RTAX_INITCWND RTAX_INITCWND
+ RTAX_FEATURES,
+#define RTAX_FEATURES RTAX_FEATURES
+ RTAX_RTO_MIN,
+#define RTAX_RTO_MIN RTAX_RTO_MIN
+ RTAX_INITRWND,
+#define RTAX_INITRWND RTAX_INITRWND
+ RTAX_QUICKACK,
+#define RTAX_QUICKACK RTAX_QUICKACK
+ RTAX_CC_ALGO,
+#define RTAX_CC_ALGO RTAX_CC_ALGO
+ RTAX_FASTOPEN_NO_COOKIE,
+#define RTAX_FASTOPEN_NO_COOKIE RTAX_FASTOPEN_NO_COOKIE
+ __RTAX_MAX
+};
+
+#define RTAX_MAX (__RTAX_MAX - 1)
+
+#define RTAX_FEATURE_ECN (1 << 0)
+#define RTAX_FEATURE_SACK (1 << 1)
+#define RTAX_FEATURE_TIMESTAMP (1 << 2)
+#define RTAX_FEATURE_ALLFRAG (1 << 3)
+
+#define RTAX_FEATURE_MASK (RTAX_FEATURE_ECN | RTAX_FEATURE_SACK | \
+ RTAX_FEATURE_TIMESTAMP | RTAX_FEATURE_ALLFRAG)
+
+struct rta_session {
+ __u8 proto;
+ __u8 pad1;
+ __u16 pad2;
+
+ union {
+ struct {
+ __u16 sport;
+ __u16 dport;
+ } ports;
+
+ struct {
+ __u8 type;
+ __u8 code;
+ __u16 ident;
+ } icmpt;
+
+ __u32 spi;
+ } u;
+};
+
+struct rta_mfc_stats {
+ __u64 mfcs_packets;
+ __u64 mfcs_bytes;
+ __u64 mfcs_wrong_if;
+};
+
+/****
+ * General form of address family dependent message.
+ ****/
+
+struct rtgenmsg {
+ unsigned char rtgen_family;
+};
+
+/*****************************************************************
+ * Link layer specific messages.
+ ****/
+
+/* struct ifinfomsg
+ * passes link level specific information, not dependent
+ * on network protocol.
+ */
+
+struct ifinfomsg {
+ unsigned char ifi_family;
+ unsigned char __ifi_pad;
+ unsigned short ifi_type; /* ARPHRD_* */
+ int ifi_index; /* Link index */
+ unsigned ifi_flags; /* IFF_* flags */
+ unsigned ifi_change; /* IFF_* change mask */
+};
+
+/********************************************************************
+ * prefix information
+ ****/
+
+struct prefixmsg {
+ unsigned char prefix_family;
+ unsigned char prefix_pad1;
+ unsigned short prefix_pad2;
+ int prefix_ifindex;
+ unsigned char prefix_type;
+ unsigned char prefix_len;
+ unsigned char prefix_flags;
+ unsigned char prefix_pad3;
+};
+
+enum
+{
+ PREFIX_UNSPEC,
+ PREFIX_ADDRESS,
+ PREFIX_CACHEINFO,
+ __PREFIX_MAX
+};
+
+#define PREFIX_MAX (__PREFIX_MAX - 1)
+
+struct prefix_cacheinfo {
+ __u32 preferred_time;
+ __u32 valid_time;
+};
+
+
+/*****************************************************************
+ * Traffic control messages.
+ ****/
+
+struct tcmsg {
+ unsigned char tcm_family;
+ unsigned char tcm__pad1;
+ unsigned short tcm__pad2;
+ int tcm_ifindex;
+ __u32 tcm_handle;
+ __u32 tcm_parent;
+/* tcm_block_index is used instead of tcm_parent
+ * in case tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK
+ */
+#define tcm_block_index tcm_parent
+ __u32 tcm_info;
+};
+
+/* For manipulation of filters in shared block, tcm_ifindex is set to
+ * TCM_IFINDEX_MAGIC_BLOCK, and tcm_parent is aliased to tcm_block_index
+ * which is the block index.
+ */
+#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
+
+enum {
+ TCA_UNSPEC,
+ TCA_KIND,
+ TCA_OPTIONS,
+ TCA_STATS,
+ TCA_XSTATS,
+ TCA_RATE,
+ TCA_FCNT,
+ TCA_STATS2,
+ TCA_STAB,
+ TCA_PAD,
+ TCA_DUMP_INVISIBLE,
+ TCA_CHAIN,
+ TCA_HW_OFFLOAD,
+ TCA_INGRESS_BLOCK,
+ TCA_EGRESS_BLOCK,
+ TCA_DUMP_FLAGS,
+ __TCA_MAX
+};
+
+#define TCA_MAX (__TCA_MAX - 1)
+
+#define TCA_DUMP_FLAGS_TERSE (1 << 0) /* Means that in dump user gets only basic
+ * data necessary to identify the objects
+ * (handle, cookie, etc.) and stats.
+ */
+
+#define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg))))
+#define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg))
+
+/********************************************************************
+ * Neighbor Discovery userland options
+ ****/
+
+struct nduseroptmsg {
+ unsigned char nduseropt_family;
+ unsigned char nduseropt_pad1;
+ unsigned short nduseropt_opts_len; /* Total length of options */
+ int nduseropt_ifindex;
+ __u8 nduseropt_icmp_type;
+ __u8 nduseropt_icmp_code;
+ unsigned short nduseropt_pad2;
+ unsigned int nduseropt_pad3;
+ /* Followed by one or more ND options */
+};
+
+enum {
+ NDUSEROPT_UNSPEC,
+ NDUSEROPT_SRCADDR,
+ __NDUSEROPT_MAX
+};
+
+#define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1)
+
+/* RTnetlink multicast groups - backwards compatibility for userspace */
+#define RTMGRP_LINK 1
+#define RTMGRP_NOTIFY 2
+#define RTMGRP_NEIGH 4
+#define RTMGRP_TC 8
+
+#define RTMGRP_IPV4_IFADDR 0x10
+#define RTMGRP_IPV4_MROUTE 0x20
+#define RTMGRP_IPV4_ROUTE 0x40
+#define RTMGRP_IPV4_RULE 0x80
+
+#define RTMGRP_IPV6_IFADDR 0x100
+#define RTMGRP_IPV6_MROUTE 0x200
+#define RTMGRP_IPV6_ROUTE 0x400
+#define RTMGRP_IPV6_IFINFO 0x800
+
+#define RTMGRP_DECnet_IFADDR 0x1000
+#define RTMGRP_DECnet_ROUTE 0x4000
+
+#define RTMGRP_IPV6_PREFIX 0x20000
+
+/* RTnetlink multicast groups */
+enum rtnetlink_groups {
+ RTNLGRP_NONE,
+#define RTNLGRP_NONE RTNLGRP_NONE
+ RTNLGRP_LINK,
+#define RTNLGRP_LINK RTNLGRP_LINK
+ RTNLGRP_NOTIFY,
+#define RTNLGRP_NOTIFY RTNLGRP_NOTIFY
+ RTNLGRP_NEIGH,
+#define RTNLGRP_NEIGH RTNLGRP_NEIGH
+ RTNLGRP_TC,
+#define RTNLGRP_TC RTNLGRP_TC
+ RTNLGRP_IPV4_IFADDR,
+#define RTNLGRP_IPV4_IFADDR RTNLGRP_IPV4_IFADDR
+ RTNLGRP_IPV4_MROUTE,
+#define RTNLGRP_IPV4_MROUTE RTNLGRP_IPV4_MROUTE
+ RTNLGRP_IPV4_ROUTE,
+#define RTNLGRP_IPV4_ROUTE RTNLGRP_IPV4_ROUTE
+ RTNLGRP_IPV4_RULE,
+#define RTNLGRP_IPV4_RULE RTNLGRP_IPV4_RULE
+ RTNLGRP_IPV6_IFADDR,
+#define RTNLGRP_IPV6_IFADDR RTNLGRP_IPV6_IFADDR
+ RTNLGRP_IPV6_MROUTE,
+#define RTNLGRP_IPV6_MROUTE RTNLGRP_IPV6_MROUTE
+ RTNLGRP_IPV6_ROUTE,
+#define RTNLGRP_IPV6_ROUTE RTNLGRP_IPV6_ROUTE
+ RTNLGRP_IPV6_IFINFO,
+#define RTNLGRP_IPV6_IFINFO RTNLGRP_IPV6_IFINFO
+ RTNLGRP_DECnet_IFADDR,
+#define RTNLGRP_DECnet_IFADDR RTNLGRP_DECnet_IFADDR
+ RTNLGRP_NOP2,
+ RTNLGRP_DECnet_ROUTE,
+#define RTNLGRP_DECnet_ROUTE RTNLGRP_DECnet_ROUTE
+ RTNLGRP_DECnet_RULE,
+#define RTNLGRP_DECnet_RULE RTNLGRP_DECnet_RULE
+ RTNLGRP_NOP4,
+ RTNLGRP_IPV6_PREFIX,
+#define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX
+ RTNLGRP_IPV6_RULE,
+#define RTNLGRP_IPV6_RULE RTNLGRP_IPV6_RULE
+ RTNLGRP_ND_USEROPT,
+#define RTNLGRP_ND_USEROPT RTNLGRP_ND_USEROPT
+ RTNLGRP_PHONET_IFADDR,
+#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR
+ RTNLGRP_PHONET_ROUTE,
+#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
+ RTNLGRP_DCB,
+#define RTNLGRP_DCB RTNLGRP_DCB
+ RTNLGRP_IPV4_NETCONF,
+#define RTNLGRP_IPV4_NETCONF RTNLGRP_IPV4_NETCONF
+ RTNLGRP_IPV6_NETCONF,
+#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF
+ RTNLGRP_MDB,
+#define RTNLGRP_MDB RTNLGRP_MDB
+ RTNLGRP_MPLS_ROUTE,
+#define RTNLGRP_MPLS_ROUTE RTNLGRP_MPLS_ROUTE
+ RTNLGRP_NSID,
+#define RTNLGRP_NSID RTNLGRP_NSID
+ RTNLGRP_MPLS_NETCONF,
+#define RTNLGRP_MPLS_NETCONF RTNLGRP_MPLS_NETCONF
+ RTNLGRP_IPV4_MROUTE_R,
+#define RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV4_MROUTE_R
+ RTNLGRP_IPV6_MROUTE_R,
+#define RTNLGRP_IPV6_MROUTE_R RTNLGRP_IPV6_MROUTE_R
+ RTNLGRP_NEXTHOP,
+#define RTNLGRP_NEXTHOP RTNLGRP_NEXTHOP
+ RTNLGRP_BRVLAN,
+#define RTNLGRP_BRVLAN RTNLGRP_BRVLAN
+ __RTNLGRP_MAX
+};
+#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
+
+/* TC action piece */
+struct tcamsg {
+ unsigned char tca_family;
+ unsigned char tca__pad1;
+ unsigned short tca__pad2;
+};
+
+enum {
+ TCA_ROOT_UNSPEC,
+ TCA_ROOT_TAB,
+#define TCA_ACT_TAB TCA_ROOT_TAB
+#define TCAA_MAX TCA_ROOT_TAB
+ TCA_ROOT_FLAGS,
+ TCA_ROOT_COUNT,
+ TCA_ROOT_TIME_DELTA, /* in msecs */
+ __TCA_ROOT_MAX,
+#define TCA_ROOT_MAX (__TCA_ROOT_MAX - 1)
+};
+
+#define TA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg))))
+#define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg))
+/* tcamsg flags stored in attribute TCA_ROOT_FLAGS
+ *
+ * TCA_ACT_FLAG_LARGE_DUMP_ON user->kernel to request for larger than
+ * TCA_ACT_MAX_PRIO actions in a dump. All dump responses will contain the
+ * number of actions being dumped stored in for user app's consumption in
+ * TCA_ROOT_COUNT
+ *
+ * TCA_ACT_FLAG_TERSE_DUMP user->kernel to request terse (brief) dump that only
+ * includes essential action info (kind, index, etc.)
+ *
+ */
+#define TCA_FLAG_LARGE_DUMP_ON (1 << 0)
+#define TCA_ACT_FLAG_LARGE_DUMP_ON TCA_FLAG_LARGE_DUMP_ON
+#define TCA_ACT_FLAG_TERSE_DUMP (1 << 1)
+
+/* New extended info filters for IFLA_EXT_MASK */
+#define RTEXT_FILTER_VF (1 << 0)
+#define RTEXT_FILTER_BRVLAN (1 << 1)
+#define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2)
+#define RTEXT_FILTER_SKIP_STATS (1 << 3)
+#define RTEXT_FILTER_MRP (1 << 4)
+#define RTEXT_FILTER_CFM_CONFIG (1 << 5)
+#define RTEXT_FILTER_CFM_STATUS (1 << 6)
+
+/* End of information exported to user level */
+
+
+
+#endif /* __LINUX_RTNETLINK_H */
diff --git a/include/linux/seg6.h b/include/linux/seg6.h
new file mode 100644
index 0000000..329163e
--- /dev/null
+++ b/include/linux/seg6.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * SR-IPv6 implementation
+ *
+ * Author:
+ * David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_SEG6_H
+#define _LINUX_SEG6_H
+
+#include <linux/types.h>
+#include <linux/in6.h> /* For struct in6_addr. */
+
+/*
+ * SRH
+ */
+struct ipv6_sr_hdr {
+ __u8 nexthdr;
+ __u8 hdrlen;
+ __u8 type;
+ __u8 segments_left;
+ __u8 first_segment; /* Represents the last_entry field of SRH */
+ __u8 flags;
+ __u16 tag;
+
+ struct in6_addr segments[0];
+};
+
+#define SR6_FLAG1_PROTECTED (1 << 6)
+#define SR6_FLAG1_OAM (1 << 5)
+#define SR6_FLAG1_ALERT (1 << 4)
+#define SR6_FLAG1_HMAC (1 << 3)
+
+#define SR6_TLV_INGRESS 1
+#define SR6_TLV_EGRESS 2
+#define SR6_TLV_OPAQUE 3
+#define SR6_TLV_PADDING 4
+#define SR6_TLV_HMAC 5
+
+#define sr_has_hmac(srh) ((srh)->flags & SR6_FLAG1_HMAC)
+
+struct sr6_tlv {
+ __u8 type;
+ __u8 len;
+ __u8 data[0];
+};
+
+#endif
diff --git a/include/linux/seg6_hmac.h b/include/linux/seg6_hmac.h
new file mode 100644
index 0000000..3fb3412
--- /dev/null
+++ b/include/linux/seg6_hmac.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_SEG6_HMAC_H
+#define _LINUX_SEG6_HMAC_H
+
+#include <linux/types.h>
+#include <linux/seg6.h>
+
+#define SEG6_HMAC_SECRET_LEN 64
+#define SEG6_HMAC_FIELD_LEN 32
+
+struct sr6_tlv_hmac {
+ struct sr6_tlv tlvhdr;
+ __u16 reserved;
+ __be32 hmackeyid;
+ __u8 hmac[SEG6_HMAC_FIELD_LEN];
+};
+
+enum {
+ SEG6_HMAC_ALGO_SHA1 = 1,
+ SEG6_HMAC_ALGO_SHA256 = 2,
+};
+
+#endif
diff --git a/include/linux/seg6_iptunnel.h b/include/linux/seg6_iptunnel.h
new file mode 100644
index 0000000..ee6d1dd
--- /dev/null
+++ b/include/linux/seg6_iptunnel.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * SR-IPv6 implementation
+ *
+ * Author:
+ * David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_SEG6_IPTUNNEL_H
+#define _LINUX_SEG6_IPTUNNEL_H
+
+#include <linux/seg6.h> /* For struct ipv6_sr_hdr. */
+
+enum {
+ SEG6_IPTUNNEL_UNSPEC,
+ SEG6_IPTUNNEL_SRH,
+ __SEG6_IPTUNNEL_MAX,
+};
+#define SEG6_IPTUNNEL_MAX (__SEG6_IPTUNNEL_MAX - 1)
+
+struct seg6_iptunnel_encap {
+ int mode;
+ struct ipv6_sr_hdr srh[0];
+};
+
+#define SEG6_IPTUN_ENCAP_SIZE(x) ((sizeof(*x)) + (((x)->srh->hdrlen + 1) << 3))
+
+enum {
+ SEG6_IPTUN_MODE_INLINE,
+ SEG6_IPTUN_MODE_ENCAP,
+ SEG6_IPTUN_MODE_L2ENCAP,
+};
+
+#endif
diff --git a/include/linux/socket.h b/include/linux/socket.h
new file mode 100644
index 0000000..debcf26
--- /dev/null
+++ b/include/linux/socket.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_SOCKET_H
+#define _LINUX_SOCKET_H
+
+/*
+ * Desired design of maximum size and alignment (see RFC2553)
+ */
+#define _K_SS_MAXSIZE 128 /* Implementation specific max size */
+
+typedef unsigned short __kernel_sa_family_t;
+
+/*
+ * The definition uses anonymous union and struct in order to control the
+ * default alignment.
+ */
+struct __kernel_sockaddr_storage {
+ union {
+ struct {
+ __kernel_sa_family_t ss_family; /* address family */
+ /* Following field(s) are implementation specific */
+ char __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
+ /* space to achieve desired size, */
+ /* _SS_MAXSIZE value minus size of ss_family */
+ };
+ void *__align; /* implementation specific desired alignment */
+ };
+};
+
+#endif /* _LINUX_SOCKET_H */
diff --git a/include/linux/types.h b/include/linux/types.h
new file mode 100644
index 0000000..999cb0f
--- /dev/null
+++ b/include/linux/types.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_TYPES_H
+#define _LINUX_TYPES_H
+
+#include <asm/types.h>
+
+#ifndef __ASSEMBLY__
+
+#include <linux/posix_types.h>
+
+
+/*
+ * Below are truly Linux-specific types that should never collide with
+ * any application/library that wants linux/types.h.
+ */
+
+#ifdef __CHECKER__
+#define __bitwise__ __attribute__((bitwise))
+#else
+#define __bitwise__
+#endif
+#define __bitwise __bitwise__
+
+typedef __u16 __bitwise __le16;
+typedef __u16 __bitwise __be16;
+typedef __u32 __bitwise __le32;
+typedef __u32 __bitwise __be32;
+typedef __u64 __bitwise __le64;
+typedef __u64 __bitwise __be64;
+
+typedef __u16 __bitwise __sum16;
+typedef __u32 __bitwise __wsum;
+
+/*
+ * aligned_u64 should be used in defining kernel<->userspace ABIs to avoid
+ * common 32/64-bit compat problems.
+ * 64-bit values align to 4-byte boundaries on x86_32 (and possibly other
+ * architectures) and to 8-byte boundaries on 64-bit architectures. The new
+ * aligned_64 type enforces 8-byte alignment so that structs containing
+ * aligned_64 values have the same alignment on 32-bit and 64-bit architectures.
+ * No conversions are necessary between 32-bit user-space and a 64-bit kernel.
+ */
+#define __aligned_u64 __u64 __attribute__((aligned(8)))
+#define __aligned_be64 __be64 __attribute__((aligned(8)))
+#define __aligned_le64 __le64 __attribute__((aligned(8)))
+
+typedef unsigned __bitwise __poll_t;
+
+#endif /* __ASSEMBLY__ */
+#endif /* _LINUX_TYPES_H */
diff --git a/include/linux/veth.h b/include/linux/veth.h
new file mode 100644
index 0000000..52b58e5
--- /dev/null
+++ b/include/linux/veth.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __NET_VETH_H_
+#define __NET_VETH_H_
+
+enum {
+ VETH_INFO_UNSPEC,
+ VETH_INFO_PEER,
+
+ __VETH_INFO_MAX
+#define VETH_INFO_MAX (__VETH_INFO_MAX - 1)
+};
+
+#endif
diff --git a/lib/rtnl.c b/lib/rtnl.c
new file mode 100644
index 0000000..2393264
--- /dev/null
+++ b/lib/rtnl.c
@@ -0,0 +1,3653 @@
+/*
+Copyright 2021 Jo-Philipp Wich <jo@mein.io>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+#include <assert.h>
+#include <endian.h>
+
+#include <netinet/ether.h>
+#include <arpa/inet.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+#include <netlink/socket.h>
+
+#include <linux/rtnetlink.h>
+#include <linux/if_tunnel.h>
+#include <linux/ip6_tunnel.h>
+#include <linux/lwtunnel.h>
+#include <linux/mpls.h>
+#include <linux/mpls_iptunnel.h>
+#include <linux/seg6.h>
+#include <linux/seg6_iptunnel.h>
+#include <linux/seg6_hmac.h>
+#include <linux/veth.h>
+#include <linux/ila.h>
+#include <linux/fib_rules.h>
+#include <linux/if_addrlabel.h>
+#include <linux/if_bridge.h>
+#include <linux/netconf.h>
+#include <linux/ipv6.h>
+
+#include "ucode/module.h"
+
+#define err_return(code, ...) do { set_error(code, __VA_ARGS__); return NULL; } while(0)
+
+#define NLM_F_STRICT_CHK (1 << 15)
+
+/* Can't use net/if.h for declarations as it clashes with linux/if.h
+ * on certain musl versions.
+ * Ref: https://www.openwall.com/lists/musl/2017/04/16/1 */
+extern unsigned int if_nametoindex (const char *);
+extern char *if_indextoname (unsigned int ifindex, char *ifname);
+
+static struct {
+ int code;
+ char *msg;
+} last_error;
+
+__attribute__((format(printf, 2, 3))) static void
+set_error(int errcode, const char *fmt, ...) {
+ va_list ap;
+
+ free(last_error.msg);
+
+ last_error.code = errcode;
+ last_error.msg = NULL;
+
+ if (fmt) {
+ va_start(ap, fmt);
+ vasprintf(&last_error.msg, fmt, ap);
+ va_end(ap);
+ }
+}
+
+typedef struct {
+ uint8_t family;
+ uint8_t mask;
+ uint8_t alen;
+ uint8_t bitlen;
+ union {
+ struct in_addr in;
+ struct in6_addr in6;
+ struct mpls_label mpls[16];
+ } addr;
+} uc_nl_cidr_t;
+
+static bool
+uc_nl_parse_u32(uc_value_t *val, uint32_t *n)
+{
+ uc_type_t t;
+ int64_t i;
+ double d;
+
+ t = ucv_cast_number(val, &i, &d);
+
+ if (t == UC_DOUBLE) {
+ if (isnan(d) || d < 0 || d > UINT32_MAX)
+ return false;
+
+ i = (int64_t)d;
+
+ if (d - i > 0)
+ return false;
+ }
+ else if (errno != 0) {
+ return false;
+ }
+
+ if (i < 0 || i > UINT32_MAX)
+ return false;
+
+ *n = (uint32_t)i;
+
+ return true;
+}
+
+static bool
+uc_nl_parse_s32(uc_value_t *val, uint32_t *n)
+{
+ uc_type_t t;
+ int64_t i;
+ double d;
+
+ t = ucv_cast_number(val, &i, &d);
+
+ if (t == UC_DOUBLE) {
+ if (isnan(d) || d < INT32_MIN || d > INT32_MAX)
+ return false;
+
+ i = (int64_t)d;
+
+ if (d - i > 0)
+ return false;
+ }
+ else if (errno != 0) {
+ return false;
+ }
+
+ if (i < INT32_MIN || i > INT32_MAX)
+ return false;
+
+ *n = (uint32_t)i;
+
+ return true;
+}
+
+static bool
+uc_nl_parse_u64(uc_value_t *val, uint64_t *n)
+{
+ uc_type_t t;
+ int64_t i;
+ double d;
+
+ if (ucv_type(val) == UC_INTEGER) {
+ *n = ucv_uint64_get(val);
+
+ return true;
+ }
+
+ t = ucv_cast_number(val, &i, &d);
+
+ if (t == UC_DOUBLE) {
+ if (isnan(d) || d < 0)
+ return false;
+
+ i = (int64_t)d;
+
+ if (d - i > 0)
+ return false;
+ }
+ else if (errno != 0) {
+ return false;
+ }
+
+ if (i < 0)
+ return false;
+
+ *n = (uint64_t)i;
+
+ return true;
+}
+
+static const char *
+addr64_ntop(const void *addr, char *buf, size_t buflen)
+{
+ const union { uint64_t u64; uint16_t u16[4]; } *a64 = addr;
+ int len;
+
+ errno = 0;
+
+ len = snprintf(buf, buflen, "%04x:%04x:%04x:%04x",
+ ntohs(a64->u16[0]), ntohs(a64->u16[1]),
+ ntohs(a64->u16[2]), ntohs(a64->u16[3]));
+
+ if ((size_t)len >= buflen) {
+ errno = ENOSPC;
+
+ return NULL;
+ }
+
+ return buf;
+}
+
+static int
+addr64_pton(const char *src, void *dst)
+{
+ union { uint64_t u64; uint16_t u16[4]; } *a64 = dst;
+ unsigned long n;
+ size_t i;
+ char *e;
+
+ for (i = 0; i < ARRAY_SIZE(a64->u16); i++) {
+ n = strtoul(src, &e, 16);
+
+ if (e == src || n > 0xffff)
+ return -1;
+
+ a64->u16[i] = htons(n);
+
+ if (*e == 0)
+ break;
+
+ if (i >= 3 || *e != ':')
+ return -1;
+
+ src += (e - src) + 1;
+ }
+
+ return 0;
+}
+
+static const char *
+mpls_ntop(const void *addr, size_t addrlen, char *buf, size_t buflen)
+{
+ const struct mpls_label *p = addr;
+ size_t remlen = buflen;
+ uint32_t entry, label;
+ char *s = buf;
+ int len;
+
+ errno = 0;
+
+ while (addrlen >= sizeof(*p)) {
+ entry = ntohl(p->entry);
+ label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
+
+ len = snprintf(s, remlen, "%u", label);
+
+ if ((size_t)len >= remlen)
+ break;
+
+ if (entry & MPLS_LS_S_MASK)
+ return buf;
+
+ s += len;
+ remlen -= len;
+
+ if (remlen) {
+ *s++ = '/';
+ remlen--;
+ }
+
+ p++;
+
+ addrlen -= sizeof(*p);
+ }
+
+ errno = ENOSPC;
+
+ return NULL;
+}
+
+static int
+mpls_pton(int af, const char *src, void *dst, size_t dstlen)
+{
+ size_t max = dstlen / sizeof(struct mpls_label);
+ struct mpls_label *p = dst;
+ uint32_t label;
+ char *e;
+
+ errno = 0;
+
+ if (af != AF_MPLS) {
+ errno = EAFNOSUPPORT;
+
+ return -1;
+ }
+
+ while (max > 0) {
+ label = strtoul(src, &e, 0);
+
+ if (label >= (1 << 20))
+ return 0;
+
+ if (e == src)
+ return 0;
+
+ p->entry = htonl(label << MPLS_LS_LABEL_SHIFT);
+
+ if (*e == 0) {
+ p->entry |= htonl(1 << MPLS_LS_S_SHIFT);
+
+ return 1;
+ }
+
+ if (*e != '/')
+ return 0;
+
+ src += (e - src) + 1;
+ max--;
+ p++;
+ }
+
+ errno = ENOSPC;
+
+ return -1;
+}
+
+static bool
+uc_nl_parse_cidr(uc_vm_t *vm, uc_value_t *val, uc_nl_cidr_t *p)
+{
+ char *s = ucv_to_string(vm, val);
+ struct in6_addr mask6 = { 0 };
+ struct in_addr mask = { 0 };
+ bool valid = true;
+ char *m, *e;
+ long n = 0;
+ size_t i;
+
+ if (!s)
+ return false;
+
+ m = strchr(s, '/');
+
+ if (m)
+ *m++ = '\0';
+
+ if (inet_pton(AF_INET6, s, &p->addr.in6) == 1) {
+ if (m) {
+ if (inet_pton(AF_INET6, m, &mask6) == 1) {
+ while (n < 128 && (mask6.s6_addr[n / 8] << (n % 8)) & 128)
+ n++;
+ }
+ else {
+ n = strtol(m, &e, 10);
+
+ if (e == m || *e || n < 0 || n > 128)
+ valid = false;
+ }
+
+ p->mask = (uint8_t)n;
+ }
+ else {
+ p->mask = 128;
+ }
+
+ p->family = AF_INET6;
+ p->alen = sizeof(mask6);
+ p->bitlen = p->alen * 8;
+ }
+ else if (strchr(s, '.') && inet_pton(AF_INET, s, &p->addr.in) == 1) {
+ if (m) {
+ if (inet_pton(AF_INET, m, &mask) == 1) {
+ mask.s_addr = ntohl(mask.s_addr);
+
+ while (n < 32 && (mask.s_addr << n) & 0x80000000)
+ n++;
+ }
+ else {
+ n = strtol(m, &e, 10);
+
+ if (e == m || *e || n < 0 || n > 32)
+ valid = false;
+ }
+
+ p->mask = (uint8_t)n;
+ }
+ else {
+ p->mask = 32;
+ }
+
+ p->family = AF_INET;
+ p->alen = sizeof(mask);
+ p->bitlen = p->alen * 8;
+ }
+ else {
+ if (m)
+ m[-1] = '/';
+
+ if (mpls_pton(AF_MPLS, s, &p->addr.mpls, sizeof(p->addr.mpls)) == 1) {
+ p->family = AF_MPLS;
+ p->alen = 0;
+
+ for (i = 0; i < ARRAY_SIZE(p->addr.mpls); i++) {
+ p->alen += sizeof(struct mpls_label);
+
+ if (ntohl(p->addr.mpls[i].entry) & MPLS_LS_S_MASK)
+ break;
+ }
+
+ p->bitlen = p->alen * 8;
+ p->mask = p->bitlen;
+ }
+ else {
+ valid = false;
+ }
+ }
+
+ free(s);
+
+ return valid;
+}
+
+typedef enum {
+ DT_FLAG,
+ DT_BOOL,
+ DT_U8,
+ DT_U16,
+ DT_U32,
+ DT_S32,
+ DT_U64,
+ DT_STRING,
+ DT_NETDEV,
+ DT_LLADDR,
+ DT_INADDR,
+ DT_IN6ADDR,
+ DT_U64ADDR,
+ DT_MPLSADDR,
+ DT_ANYADDR,
+ DT_BRIDGEID,
+ DT_LINKINFO,
+ DT_MULTIPATH,
+ DT_NUMRANGE,
+ DT_FLAGS,
+ DT_ENCAP,
+ DT_SRH,
+ DT_IPOPTS,
+ DT_U32_OR_MEMBER,
+ DT_NESTED,
+} uc_nl_attr_datatype_t;
+
+enum {
+ DF_NO_SET = (1 << 0),
+ DF_NO_GET = (1 << 1),
+ DF_ALLOW_NONE = (1 << 2),
+ DF_BYTESWAP = (1 << 3),
+ DF_MAX_1 = (1 << 4),
+ DF_MAX_255 = (1 << 5),
+ DF_MAX_65535 = (1 << 6),
+ DF_MAX_16777215 = (1 << 7),
+ DF_STORE_MASK = (1 << 8),
+ DF_MULTIPLE = (1 << 9),
+ DF_FLAT = (1 << 10),
+ DF_FAMILY_HINT = (1 << 11),
+};
+
+typedef struct uc_nl_attr_spec {
+ size_t attr;
+ const char *key;
+ uc_nl_attr_datatype_t type;
+ uint32_t flags;
+ const void *auxdata;
+} uc_nl_attr_spec_t;
+
+typedef struct uc_nl_nested_spec {
+ size_t headsize;
+ size_t nattrs;
+ const uc_nl_attr_spec_t attrs[];
+} uc_nl_nested_spec_t;
+
+#define SIZE(type) (void *)(uintptr_t)sizeof(struct type)
+#define MEMBER(type, field) (void *)(uintptr_t)offsetof(struct type, field)
+
+static const uc_nl_nested_spec_t route_cacheinfo_rta = {
+ .headsize = NLA_ALIGN(sizeof(struct rta_cacheinfo)),
+ .nattrs = 8,
+ .attrs = {
+ { RTA_UNSPEC, "clntref", DT_U32, 0, MEMBER(rta_cacheinfo, rta_clntref) },
+ { RTA_UNSPEC, "lastuse", DT_U32, 0, MEMBER(rta_cacheinfo, rta_lastuse) },
+ { RTA_UNSPEC, "expires", DT_S32, 0, MEMBER(rta_cacheinfo, rta_expires) },
+ { RTA_UNSPEC, "error", DT_U32, 0, MEMBER(rta_cacheinfo, rta_error) },
+ { RTA_UNSPEC, "used", DT_U32, 0, MEMBER(rta_cacheinfo, rta_used) },
+ { RTA_UNSPEC, "id", DT_U32, 0, MEMBER(rta_cacheinfo, rta_id) },
+ { RTA_UNSPEC, "ts", DT_U32, 0, MEMBER(rta_cacheinfo, rta_ts) },
+ { RTA_UNSPEC, "tsage", DT_U32, 0, MEMBER(rta_cacheinfo, rta_tsage) },
+ }
+};
+
+static const uc_nl_nested_spec_t route_metrics_rta = {
+ .headsize = 0,
+ .nattrs = 16,
+ .attrs = {
+ { RTAX_MTU, "mtu", DT_U32, 0, NULL },
+ { RTAX_HOPLIMIT, "hoplimit", DT_U32, DF_MAX_255, NULL },
+ { RTAX_ADVMSS, "advmss", DT_U32, 0, NULL },
+ { RTAX_REORDERING, "reordering", DT_U32, 0, NULL },
+ { RTAX_RTT, "rtt", DT_U32, 0, NULL },
+ { RTAX_WINDOW, "window", DT_U32, 0, NULL },
+ { RTAX_CWND, "cwnd", DT_U32, 0, NULL },
+ { RTAX_INITCWND, "initcwnd", DT_U32, 0, NULL },
+ { RTAX_INITRWND, "initrwnd", DT_U32, 0, NULL },
+ { RTAX_FEATURES, "ecn", DT_U32, DF_MAX_1, NULL },
+ { RTAX_QUICKACK, "quickack", DT_U32, DF_MAX_1, NULL },
+ { RTAX_CC_ALGO, "cc_algo", DT_STRING, 0, NULL },
+ { RTAX_RTTVAR, "rttvar", DT_U32, 0, NULL },
+ { RTAX_SSTHRESH, "ssthresh", DT_U32, 0, NULL },
+ { RTAX_FASTOPEN_NO_COOKIE, "fastopen_no_cookie", DT_U32, DF_MAX_1, NULL },
+ { RTAX_LOCK, "lock", DT_U32, 0, NULL },
+ }
+};
+
+static const uc_nl_nested_spec_t route_msg = {
+ .headsize = NLA_ALIGN(sizeof(struct rtmsg)),
+ .nattrs = 28,
+ .attrs = {
+ { RTA_UNSPEC, "family", DT_U8, 0, MEMBER(rtmsg, rtm_family) },
+ { RTA_UNSPEC, "tos", DT_U8, 0, MEMBER(rtmsg, rtm_tos) },
+ { RTA_UNSPEC, "protocol", DT_U8, 0, MEMBER(rtmsg, rtm_protocol) },
+ { RTA_UNSPEC, "scope", DT_U8, 0, MEMBER(rtmsg, rtm_scope) },
+ { RTA_UNSPEC, "type", DT_U8, 0, MEMBER(rtmsg, rtm_type) },
+ { RTA_UNSPEC, "flags", DT_U32, 0, MEMBER(rtmsg, rtm_flags) },
+ { RTA_SRC, "src", DT_ANYADDR, DF_STORE_MASK|DF_FAMILY_HINT, MEMBER(rtmsg, rtm_src_len) },
+ { RTA_DST, "dst", DT_ANYADDR, DF_STORE_MASK|DF_FAMILY_HINT, MEMBER(rtmsg, rtm_dst_len) },
+ { RTA_IIF, "iif", DT_NETDEV, 0, NULL },
+ { RTA_OIF, "oif", DT_NETDEV, 0, NULL },
+ { RTA_GATEWAY, "gateway", DT_ANYADDR, DF_FAMILY_HINT, NULL },
+ { RTA_PRIORITY, "priority", DT_U32, 0, NULL },
+ { RTA_PREFSRC, "prefsrc", DT_ANYADDR, DF_FAMILY_HINT, NULL },
+ { RTA_METRICS, "metrics", DT_NESTED, 0, &route_metrics_rta },
+ { RTA_MULTIPATH, "multipath", DT_MULTIPATH, 0, NULL },
+ { RTA_FLOW, "flow", DT_U32, 0, NULL },
+ { RTA_CACHEINFO, "cacheinfo", DT_NESTED, DF_NO_SET, &route_cacheinfo_rta },
+ { RTA_TABLE, "table", DT_U32_OR_MEMBER, DF_MAX_255, MEMBER(rtmsg, rtm_table) },
+ { RTA_MARK, "mark", DT_U32, 0, NULL },
+ //RTA_MFC_STATS,
+ { RTA_PREF, "pref", DT_U8, 0, NULL },
+ { RTA_ENCAP, "encap", DT_ENCAP, 0, NULL },
+ { RTA_EXPIRES, "expires", DT_U32, 0, NULL },
+ { RTA_UID, "uid", DT_U32, 0, NULL },
+ { RTA_TTL_PROPAGATE, "ttl_propagate", DT_BOOL, 0, NULL },
+ { RTA_IP_PROTO, "ip_proto", DT_U8, 0, NULL },
+ { RTA_SPORT, "sport", DT_U16, DF_BYTESWAP, NULL },
+ { RTA_DPORT, "dport", DT_U16, DF_BYTESWAP, NULL },
+ { RTA_NH_ID, "nh_id", DT_U32, 0, NULL },
+ }
+};
+
+static const uc_nl_attr_spec_t route_encap_mpls_attrs[] = {
+ { MPLS_IPTUNNEL_DST, "dst", DT_MPLSADDR, 0, NULL },
+ { MPLS_IPTUNNEL_TTL, "ttl", DT_U8, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t route_encap_ip_attrs[] = {
+ { LWTUNNEL_IP_ID, "id", DT_U64, DF_BYTESWAP, NULL },
+ { LWTUNNEL_IP_DST, "dst", DT_INADDR, 0, NULL },
+ { LWTUNNEL_IP_SRC, "src", DT_INADDR, 0, NULL },
+ { LWTUNNEL_IP_TOS, "tos", DT_U8, 0, NULL },
+ { LWTUNNEL_IP_TTL, "ttl", DT_U8, 0, NULL },
+ { LWTUNNEL_IP_OPTS, "opts", DT_IPOPTS, 0, NULL },
+ { LWTUNNEL_IP_FLAGS, "flags", DT_U16, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t route_encap_ila_attrs[] = {
+ { ILA_ATTR_LOCATOR, "locator", DT_U64ADDR, 0, NULL },
+ { ILA_ATTR_CSUM_MODE, "csum_mode", DT_U8, 0, NULL },
+ { ILA_ATTR_IDENT_TYPE, "ident_type", DT_U8, 0, NULL },
+ { ILA_ATTR_HOOK_TYPE, "hook_type", DT_U8, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t route_encap_ip6_attrs[] = {
+ { LWTUNNEL_IP6_ID, "id", DT_U64, DF_BYTESWAP, NULL },
+ { LWTUNNEL_IP6_DST, "dst", DT_IN6ADDR, 0, NULL },
+ { LWTUNNEL_IP6_SRC, "src", DT_IN6ADDR, 0, NULL },
+ { LWTUNNEL_IP6_TC, "tc", DT_U32, 0, NULL },
+ { LWTUNNEL_IP6_HOPLIMIT, "hoplimit", DT_U8, 0, NULL },
+ { LWTUNNEL_IP6_OPTS, "opts", DT_IPOPTS, 0, NULL },
+ { LWTUNNEL_IP6_FLAGS, "flags", DT_U16, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t route_encap_seg6_attrs[] = {
+ { SEG6_IPTUNNEL_SRH, "srh", DT_SRH, 0, NULL },
+};
+
+#define IPV4_DEVCONF_ENTRY(name) ((void *)((IPV4_DEVCONF_##name - 1) * sizeof(uint32_t)))
+
+static const uc_nl_nested_spec_t link_attrs_af_spec_inet_devconf_rta = {
+ .headsize = NLA_ALIGN(IPV4_DEVCONF_MAX * sizeof(uint32_t)),
+ .nattrs = 32,
+ .attrs = {
+ { 0, "forwarding", DT_U32, 0, IPV4_DEVCONF_ENTRY(FORWARDING) },
+ { 0, "mc_forwarding", DT_U32, 0, IPV4_DEVCONF_ENTRY(MC_FORWARDING) },
+ { 0, "proxy_arp", DT_U32, 0, IPV4_DEVCONF_ENTRY(PROXY_ARP) },
+ { 0, "accept_redirects", DT_U32, 0, IPV4_DEVCONF_ENTRY(ACCEPT_REDIRECTS) },
+ { 0, "secure_redirects", DT_U32, 0, IPV4_DEVCONF_ENTRY(SECURE_REDIRECTS) },
+ { 0, "send_redirects", DT_U32, 0, IPV4_DEVCONF_ENTRY(SEND_REDIRECTS) },
+ { 0, "shared_media", DT_U32, 0, IPV4_DEVCONF_ENTRY(SHARED_MEDIA) },
+ { 0, "rp_filter", DT_U32, 0, IPV4_DEVCONF_ENTRY(RP_FILTER) },
+ { 0, "accept_source_route", DT_U32, 0, IPV4_DEVCONF_ENTRY(ACCEPT_SOURCE_ROUTE) },
+ { 0, "bootp_relay", DT_U32, 0, IPV4_DEVCONF_ENTRY(BOOTP_RELAY) },
+ { 0, "log_martians", DT_U32, 0, IPV4_DEVCONF_ENTRY(LOG_MARTIANS) },
+ { 0, "tag", DT_U32, 0, IPV4_DEVCONF_ENTRY(TAG) },
+ { 0, "arpfilter", DT_U32, 0, IPV4_DEVCONF_ENTRY(ARPFILTER) },
+ { 0, "medium_id", DT_U32, 0, IPV4_DEVCONF_ENTRY(MEDIUM_ID) },
+ { 0, "noxfrm", DT_U32, 0, IPV4_DEVCONF_ENTRY(NOXFRM) },
+ { 0, "nopolicy", DT_U32, 0, IPV4_DEVCONF_ENTRY(NOPOLICY) },
+ { 0, "force_igmp_version", DT_U32, 0, IPV4_DEVCONF_ENTRY(FORCE_IGMP_VERSION) },
+ { 0, "arp_announce", DT_U32, 0, IPV4_DEVCONF_ENTRY(ARP_ANNOUNCE) },
+ { 0, "arp_ignore", DT_U32, 0, IPV4_DEVCONF_ENTRY(ARP_IGNORE) },
+ { 0, "promote_secondaries", DT_U32, 0, IPV4_DEVCONF_ENTRY(PROMOTE_SECONDARIES) },
+ { 0, "arp_accept", DT_U32, 0, IPV4_DEVCONF_ENTRY(ARP_ACCEPT) },
+ { 0, "arp_notify", DT_U32, 0, IPV4_DEVCONF_ENTRY(ARP_NOTIFY) },
+ { 0, "accept_local", DT_U32, 0, IPV4_DEVCONF_ENTRY(ACCEPT_LOCAL) },
+ { 0, "src_vmark", DT_U32, 0, IPV4_DEVCONF_ENTRY(SRC_VMARK) },
+ { 0, "proxy_arp_pvlan", DT_U32, 0, IPV4_DEVCONF_ENTRY(PROXY_ARP_PVLAN) },
+ { 0, "route_localnet", DT_U32, 0, IPV4_DEVCONF_ENTRY(ROUTE_LOCALNET) },
+ { 0, "igmpv2_unsolicited_report_interval", DT_U32, 0, IPV4_DEVCONF_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL) },
+ { 0, "igmpv3_unsolicited_report_interval", DT_U32, 0, IPV4_DEVCONF_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL) },
+ { 0, "ignore_routes_with_linkdown", DT_U32, 0, IPV4_DEVCONF_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN) },
+ { 0, "drop_unicast_in_l2_multicast", DT_U32, 0, IPV4_DEVCONF_ENTRY(DROP_UNICAST_IN_L2_MULTICAST) },
+ { 0, "drop_gratuitous_arp", DT_U32, 0, IPV4_DEVCONF_ENTRY(DROP_GRATUITOUS_ARP) },
+ { 0, "bc_forwarding", DT_U32, 0, IPV4_DEVCONF_ENTRY(BC_FORWARDING) },
+ }
+};
+
+static const uc_nl_nested_spec_t link_attrs_af_spec_inet_rta = {
+ .headsize = 0,
+ .nattrs = 1,
+ .attrs = {
+ { IFLA_INET_CONF, "conf", DT_NESTED, 0, &link_attrs_af_spec_inet_devconf_rta },
+ }
+};
+
+#define IPV6_DEVCONF_ENTRY(name) ((void *)(DEVCONF_##name * sizeof(uint32_t)))
+
+static const uc_nl_nested_spec_t link_attrs_af_spec_inet6_devconf_rta = {
+ .headsize = NLA_ALIGN(DEVCONF_MAX * sizeof(uint32_t)),
+ .nattrs = 53,
+ .attrs = {
+ { 0, "forwarding", DT_S32, 0, IPV6_DEVCONF_ENTRY(FORWARDING) },
+ { 0, "hoplimit", DT_S32, 0, IPV6_DEVCONF_ENTRY(HOPLIMIT) },
+ { 0, "mtu6", DT_S32, 0, IPV6_DEVCONF_ENTRY(MTU6) },
+ { 0, "accept_ra", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA) },
+ { 0, "accept_redirects", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_REDIRECTS) },
+ { 0, "autoconf", DT_S32, 0, IPV6_DEVCONF_ENTRY(AUTOCONF) },
+ { 0, "dad_transmits", DT_S32, 0, IPV6_DEVCONF_ENTRY(DAD_TRANSMITS) },
+ { 0, "rtr_solicits", DT_S32, 0, IPV6_DEVCONF_ENTRY(RTR_SOLICITS) },
+ { 0, "rtr_solicit_interval", DT_S32, 0, IPV6_DEVCONF_ENTRY(RTR_SOLICIT_INTERVAL) },
+ { 0, "rtr_solicit_delay", DT_S32, 0, IPV6_DEVCONF_ENTRY(RTR_SOLICIT_DELAY) },
+ { 0, "use_tempaddr", DT_S32, 0, IPV6_DEVCONF_ENTRY(USE_TEMPADDR) },
+ { 0, "temp_valid_lft", DT_S32, 0, IPV6_DEVCONF_ENTRY(TEMP_VALID_LFT) },
+ { 0, "temp_prefered_lft", DT_S32, 0, IPV6_DEVCONF_ENTRY(TEMP_PREFERED_LFT) },
+ { 0, "regen_max_retry", DT_S32, 0, IPV6_DEVCONF_ENTRY(REGEN_MAX_RETRY) },
+ { 0, "max_desync_factor", DT_S32, 0, IPV6_DEVCONF_ENTRY(MAX_DESYNC_FACTOR) },
+ { 0, "max_addresses", DT_S32, 0, IPV6_DEVCONF_ENTRY(MAX_ADDRESSES) },
+ { 0, "force_mld_version", DT_S32, 0, IPV6_DEVCONF_ENTRY(FORCE_MLD_VERSION) },
+ { 0, "accept_ra_defrtr", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_DEFRTR) },
+ { 0, "accept_ra_pinfo", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_PINFO) },
+ { 0, "accept_ra_rtr_pref", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_RTR_PREF) },
+ { 0, "rtr_probe_interval", DT_S32, 0, IPV6_DEVCONF_ENTRY(RTR_PROBE_INTERVAL) },
+ { 0, "accept_ra_rt_info_max_plen", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_RT_INFO_MAX_PLEN) },
+ { 0, "proxy_ndp", DT_S32, 0, IPV6_DEVCONF_ENTRY(PROXY_NDP) },
+ { 0, "optimistic_dad", DT_S32, 0, IPV6_DEVCONF_ENTRY(OPTIMISTIC_DAD) },
+ { 0, "accept_source_route", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_SOURCE_ROUTE) },
+ { 0, "mc_forwarding", DT_S32, 0, IPV6_DEVCONF_ENTRY(MC_FORWARDING) },
+ { 0, "disable_ipv6", DT_S32, 0, IPV6_DEVCONF_ENTRY(DISABLE_IPV6) },
+ { 0, "accept_dad", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_DAD) },
+ { 0, "force_tllao", DT_S32, 0, IPV6_DEVCONF_ENTRY(FORCE_TLLAO) },
+ { 0, "ndisc_notify", DT_S32, 0, IPV6_DEVCONF_ENTRY(NDISC_NOTIFY) },
+ { 0, "mldv1_unsolicited_report_interval", DT_S32, 0, IPV6_DEVCONF_ENTRY(MLDV1_UNSOLICITED_REPORT_INTERVAL) },
+ { 0, "mldv2_unsolicited_report_interval", DT_S32, 0, IPV6_DEVCONF_ENTRY(MLDV2_UNSOLICITED_REPORT_INTERVAL) },
+ { 0, "suppress_frag_ndisc", DT_S32, 0, IPV6_DEVCONF_ENTRY(SUPPRESS_FRAG_NDISC) },
+ { 0, "accept_ra_from_local", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_FROM_LOCAL) },
+ { 0, "use_optimistic", DT_S32, 0, IPV6_DEVCONF_ENTRY(USE_OPTIMISTIC) },
+ { 0, "accept_ra_mtu", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_MTU) },
+ { 0, "stable_secret", DT_S32, 0, IPV6_DEVCONF_ENTRY(STABLE_SECRET) },
+ { 0, "use_oif_addrs_only", DT_S32, 0, IPV6_DEVCONF_ENTRY(USE_OIF_ADDRS_ONLY) },
+ { 0, "accept_ra_min_hop_limit", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_MIN_HOP_LIMIT) },
+ { 0, "ignore_routes_with_linkdown", DT_S32, 0, IPV6_DEVCONF_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN) },
+ { 0, "drop_unicast_in_l2_multicast", DT_S32, 0, IPV6_DEVCONF_ENTRY(DROP_UNICAST_IN_L2_MULTICAST) },
+ { 0, "drop_unsolicited_na", DT_S32, 0, IPV6_DEVCONF_ENTRY(DROP_UNSOLICITED_NA) },
+ { 0, "keep_addr_on_down", DT_S32, 0, IPV6_DEVCONF_ENTRY(KEEP_ADDR_ON_DOWN) },
+ { 0, "rtr_solicit_max_interval", DT_S32, 0, IPV6_DEVCONF_ENTRY(RTR_SOLICIT_MAX_INTERVAL) },
+ { 0, "seg6_enabled", DT_S32, 0, IPV6_DEVCONF_ENTRY(SEG6_ENABLED) },
+ { 0, "seg6_require_hmac", DT_S32, 0, IPV6_DEVCONF_ENTRY(SEG6_REQUIRE_HMAC) },
+ { 0, "enhanced_dad", DT_S32, 0, IPV6_DEVCONF_ENTRY(ENHANCED_DAD) },
+ { 0, "addr_gen_mode", DT_S32, 0, IPV6_DEVCONF_ENTRY(ADDR_GEN_MODE) },
+ { 0, "disable_policy", DT_S32, 0, IPV6_DEVCONF_ENTRY(DISABLE_POLICY) },
+ { 0, "accept_ra_rt_info_min_plen", DT_S32, 0, IPV6_DEVCONF_ENTRY(ACCEPT_RA_RT_INFO_MIN_PLEN) },
+ { 0, "ndisc_tclass", DT_S32, 0, IPV6_DEVCONF_ENTRY(NDISC_TCLASS) },
+ { 0, "rpl_seg_enabled", DT_S32, 0, IPV6_DEVCONF_ENTRY(RPL_SEG_ENABLED) },
+ { 0, "ra_defrtr_metric", DT_S32, 0, IPV6_DEVCONF_ENTRY(RA_DEFRTR_METRIC) },
+ }
+};
+
+static const uc_nl_nested_spec_t link_attrs_af_spec_inet6_rta = {
+ .headsize = 0,
+ .nattrs = 3,
+ .attrs = {
+ { IFLA_INET6_ADDR_GEN_MODE, "mode", DT_U8, 0, NULL },
+ { IFLA_INET6_FLAGS, "flags", DT_U32, DF_NO_SET, NULL },
+ { IFLA_INET6_CONF, "conf", DT_NESTED, DF_NO_SET, &link_attrs_af_spec_inet6_devconf_rta },
+ }
+};
+
+static const uc_nl_nested_spec_t link_attrs_bridge_vinfo_rta = {
+ .headsize = sizeof(struct bridge_vlan_info),
+ .nattrs = 2,
+ .attrs = {
+ { IFLA_UNSPEC, "flags", DT_U16, 0, MEMBER(bridge_vlan_info, flags) },
+ { IFLA_UNSPEC, "vid", DT_U16, 0, MEMBER(bridge_vlan_info, vid) },
+ }
+};
+
+static const uc_nl_nested_spec_t link_attrs_af_spec_rta = {
+ .headsize = 0,
+ .nattrs = 4,
+ .attrs = {
+ { AF_INET, "inet", DT_NESTED, DF_NO_SET, &link_attrs_af_spec_inet_rta },
+ { AF_INET6, "inet6", DT_NESTED, 0, &link_attrs_af_spec_inet6_rta },
+ { IFLA_BRIDGE_FLAGS, "bridge_flags", DT_U16, 0, NULL },
+ { IFLA_BRIDGE_VLAN_INFO, "bridge_vlan_info", DT_NESTED, DF_MULTIPLE|DF_FLAT, &link_attrs_bridge_vinfo_rta },
+ }
+};
+
+static const uc_nl_nested_spec_t link_msg = {
+ .headsize = NLA_ALIGN(sizeof(struct ifinfomsg)),
+ .nattrs = 23,
+ .attrs = {
+ { IFLA_UNSPEC, "family", DT_U8, 0, MEMBER(ifinfomsg, ifi_family) },
+ { IFLA_UNSPEC, "type", DT_U16, 0, MEMBER(ifinfomsg, ifi_type) },
+ { IFLA_UNSPEC, "dev", DT_NETDEV, 0, MEMBER(ifinfomsg, ifi_index) },
+ { IFLA_UNSPEC, "flags", DT_FLAGS, 0, MEMBER(ifinfomsg, ifi_flags) },
+ { IFLA_ADDRESS, "address", DT_LLADDR, 0, NULL },
+ { IFLA_BROADCAST, "broadcast", DT_LLADDR, 0, NULL },
+ { IFLA_TXQLEN, "txqlen", DT_U32, 0, NULL },
+ { IFLA_MTU, "mtu", DT_U32, 0, NULL },
+ /* { IFLA_NETNS_PID, "netns", DT_U32, 0, NULL }, */
+ { IFLA_CARRIER, "carrier", DT_BOOL, 0, NULL },
+ /* IFLA_VFINFO_LIST */
+ { IFLA_MASTER, "master", DT_NETDEV, DF_ALLOW_NONE, NULL },
+ { IFLA_IFALIAS, "ifalias", DT_STRING, 0, NULL },
+ { IFLA_LINKMODE, "linkmode", DT_U8, 0, NULL },
+ { IFLA_OPERSTATE, "operstate", DT_U8, 0, NULL },
+ { IFLA_NUM_TX_QUEUES, "num_tx_queues", DT_U32, 0, NULL },
+ { IFLA_NUM_RX_QUEUES, "num_rx_queues", DT_U32, 0, NULL },
+ { IFLA_AF_SPEC, "af_spec", DT_NESTED, 0, &link_attrs_af_spec_rta },
+ { IFLA_LINK_NETNSID, "link_netnsid", DT_U32, 0, NULL },
+ { IFLA_PROTO_DOWN, "proto_down", DT_BOOL, 0, NULL },
+ { IFLA_GROUP, "group", DT_U32, 0, NULL },
+ { IFLA_LINK, "link", DT_NETDEV, 0, NULL },
+ { IFLA_IFNAME, "ifname", DT_STRING, 0, NULL },
+ { IFLA_LINKINFO, "linkinfo", DT_LINKINFO, 0, NULL }, /* XXX: DF_NO_GET ? */
+ { IFLA_EXT_MASK, "ext_mask", DT_U32, 0, NULL },
+ }
+};
+
+static const uc_nl_attr_spec_t link_bareudp_attrs[] = {
+ { IFLA_BAREUDP_ETHERTYPE, "ethertype", DT_U16, 0, NULL },
+ { IFLA_BAREUDP_MULTIPROTO_MODE, "multiproto_mode", DT_FLAG, 0, NULL },
+ { IFLA_BAREUDP_PORT, "port", DT_U16, 0, NULL },
+ { IFLA_BAREUDP_SRCPORT_MIN, "srcport_min", DT_U16, 0, NULL },
+};
+
+static const uc_nl_nested_spec_t link_bond_ad_info_rta = {
+ .headsize = 0,
+ .nattrs = 5,
+ .attrs = {
+ { IFLA_BOND_AD_INFO_ACTOR_KEY, "ad_info_actor_key", DT_U16, DF_NO_SET, NULL },
+ { IFLA_BOND_AD_INFO_AGGREGATOR, "ad_info_aggregator", DT_U16, DF_NO_SET, NULL },
+ { IFLA_BOND_AD_INFO_NUM_PORTS, "ad_info_num_ports", DT_U16, DF_NO_SET, NULL },
+ { IFLA_BOND_AD_INFO_PARTNER_KEY, "ad_info_partner_key", DT_U16, DF_NO_SET, NULL },
+ { IFLA_BOND_AD_INFO_PARTNER_MAC, "ad_info_partner_mac", DT_LLADDR, DF_NO_SET, NULL },
+ }
+};
+
+static const uc_nl_attr_spec_t link_bond_attrs[] = {
+ { IFLA_BOND_ACTIVE_SLAVE, "active_slave", DT_NETDEV, DF_ALLOW_NONE, NULL },
+ { IFLA_BOND_AD_ACTOR_SYSTEM, "ad_actor_system", DT_LLADDR, 0, NULL },
+ { IFLA_BOND_AD_ACTOR_SYS_PRIO, "ad_actor_sys_prio", DT_U16, 0, NULL },
+ { IFLA_BOND_AD_INFO, "ad_info", DT_NESTED, DF_NO_SET, &link_bond_ad_info_rta },
+ { IFLA_BOND_AD_LACP_RATE, "ad_lacp_rate", DT_U8, 0, NULL },
+ { IFLA_BOND_AD_SELECT, "ad_select", DT_U8, 0, NULL },
+ { IFLA_BOND_AD_USER_PORT_KEY, "ad_user_port_key", DT_U16, 0, NULL },
+ { IFLA_BOND_ALL_SLAVES_ACTIVE, "all_slaves_active", DT_U8, 0, NULL },
+ { IFLA_BOND_ARP_ALL_TARGETS, "arp_all_targets", DT_U32, 0, NULL },
+ { IFLA_BOND_ARP_INTERVAL, "arp_interval", DT_U32, 0, NULL },
+ { IFLA_BOND_ARP_IP_TARGET, "arp_ip_target", DT_INADDR, DF_MULTIPLE, NULL },
+ { IFLA_BOND_ARP_VALIDATE, "arp_validate", DT_U32, 0, NULL },
+ { IFLA_BOND_DOWNDELAY, "downdelay", DT_U32, 0, NULL },
+ { IFLA_BOND_FAIL_OVER_MAC, "fail_over_mac", DT_U8, 0, NULL },
+ { IFLA_BOND_LP_INTERVAL, "lp_interval", DT_U32, 0, NULL },
+ { IFLA_BOND_MIIMON, "miimon", DT_U32, 0, NULL },
+ { IFLA_BOND_MIN_LINKS, "min_links", DT_U32, 0, NULL },
+ { IFLA_BOND_MODE, "mode", DT_U8, 0, NULL },
+ { IFLA_BOND_NUM_PEER_NOTIF, "num_peer_notif", DT_U8, 0, NULL },
+ { IFLA_BOND_PACKETS_PER_SLAVE, "packets_per_slave", DT_U32, 0, NULL },
+ { IFLA_BOND_PRIMARY, "primary", DT_NETDEV, 0, NULL },
+ { IFLA_BOND_PRIMARY_RESELECT, "primary_reselect", DT_U8, 0, NULL },
+ { IFLA_BOND_RESEND_IGMP, "resend_igmp", DT_U32, 0, NULL },
+ { IFLA_BOND_TLB_DYNAMIC_LB, "tlb_dynamic_lb", DT_U8, 0, NULL },
+ { IFLA_BOND_UPDELAY, "updelay", DT_U32, 0, NULL },
+ { IFLA_BOND_USE_CARRIER, "use_carrier", DT_U8, 0, NULL },
+ { IFLA_BOND_XMIT_HASH_POLICY, "xmit_hash_policy", DT_U8, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t link_bond_slave_attrs[] = {
+ { IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, "ad_actor_oper_port_state", DT_U8, DF_NO_SET, NULL },
+ { IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, "ad_aggregator_id", DT_U16, DF_NO_SET, NULL },
+ { IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, "ad_partner_oper_port_state", DT_U8, DF_NO_SET, NULL },
+ { IFLA_BOND_SLAVE_LINK_FAILURE_COUNT, "link_failure_count", DT_U32, DF_NO_SET, NULL },
+ { IFLA_BOND_SLAVE_MII_STATUS, "mii_status", DT_U8, DF_NO_SET, NULL },
+ { IFLA_BOND_SLAVE_PERM_HWADDR, "perm_hwaddr", DT_LLADDR, DF_NO_SET, NULL },
+ { IFLA_BOND_SLAVE_QUEUE_ID, "queue_id", DT_U16, 0, NULL },
+ { IFLA_BOND_SLAVE_STATE, "state", DT_U8, DF_NO_SET, NULL },
+};
+
+static const uc_nl_attr_spec_t link_bridge_attrs[] = {
+ { IFLA_BR_AGEING_TIME, "ageing_time", DT_U32, 0, NULL },
+ { IFLA_BR_BRIDGE_ID, "bridge_id", DT_BRIDGEID, DF_NO_SET, NULL },
+ { IFLA_BR_FDB_FLUSH, "fdb_flush", DT_FLAG, DF_NO_GET, NULL },
+ { IFLA_BR_FORWARD_DELAY, "forward_delay", DT_U32, 0, NULL },
+ { IFLA_BR_GC_TIMER, "gc_timer", DT_U64, DF_NO_SET, NULL },
+ { IFLA_BR_GROUP_ADDR, "group_addr", DT_LLADDR, 0, NULL },
+ { IFLA_BR_GROUP_FWD_MASK, "group_fwd_mask", DT_U16, 0, NULL },
+ { IFLA_BR_HELLO_TIME, "hello_time", DT_U32, 0, NULL },
+ { IFLA_BR_HELLO_TIMER, "hello_timer", DT_U64, DF_NO_SET, NULL },
+ { IFLA_BR_MAX_AGE, "max_age", DT_U32, 0, NULL },
+ { IFLA_BR_MCAST_HASH_ELASTICITY, "mcast_hash_elasticity", DT_U32, 0, NULL },
+ { IFLA_BR_MCAST_HASH_MAX, "mcast_hash_max", DT_U32, 0, NULL },
+ { IFLA_BR_MCAST_IGMP_VERSION, "mcast_igmp_version", DT_U8, 0, NULL },
+ { IFLA_BR_MCAST_LAST_MEMBER_CNT, "mcast_last_member_cnt", DT_U32, 0, NULL },
+ { IFLA_BR_MCAST_LAST_MEMBER_INTVL, "mcast_last_member_intvl", DT_U64, 0, NULL },
+ { IFLA_BR_MCAST_MEMBERSHIP_INTVL, "mcast_membership_intvl", DT_U64, 0, NULL },
+ { IFLA_BR_MCAST_MLD_VERSION, "mcast_mld_version", DT_U8, 0, NULL },
+ { IFLA_BR_MCAST_QUERIER, "mcast_querier", DT_U8, 0, NULL },
+ { IFLA_BR_MCAST_QUERIER_INTVL, "mcast_querier_intvl", DT_U64, 0, NULL },
+ { IFLA_BR_MCAST_QUERY_INTVL, "mcast_query_intvl", DT_U64, 0, NULL },
+ { IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, "mcast_query_response_intvl", DT_U64, 0, NULL },
+ { IFLA_BR_MCAST_QUERY_USE_IFADDR, "mcast_query_use_ifaddr", DT_U8, 0, NULL },
+ { IFLA_BR_MCAST_ROUTER, "mcast_router", DT_U8, 0, NULL },
+ { IFLA_BR_MCAST_SNOOPING, "mcast_snooping", DT_U8, 0, NULL },
+ { IFLA_BR_MCAST_STARTUP_QUERY_CNT, "mcast_startup_query_cnt", DT_U32, 0, NULL },
+ { IFLA_BR_MCAST_STARTUP_QUERY_INTVL, "mcast_startup_query_intvl", DT_U64, 0, NULL },
+ { IFLA_BR_MCAST_STATS_ENABLED, "mcast_stats_enabled", DT_U8, 0, NULL },
+ { IFLA_BR_NF_CALL_ARPTABLES, "nf_call_arptables", DT_U8, 0, NULL },
+ { IFLA_BR_NF_CALL_IP6TABLES, "nf_call_ip6tables", DT_U8, 0, NULL },
+ { IFLA_BR_NF_CALL_IPTABLES, "nf_call_iptables", DT_U8, 0, NULL },
+ { IFLA_BR_PRIORITY, "priority", DT_U16, 0, NULL },
+ { IFLA_BR_ROOT_ID, "root_id", DT_BRIDGEID, DF_NO_SET, NULL },
+ { IFLA_BR_ROOT_PATH_COST, "root_path_cost", DT_U32, DF_NO_SET, NULL },
+ { IFLA_BR_ROOT_PORT, "root_port", DT_U16, DF_NO_SET, NULL },
+ { IFLA_BR_STP_STATE, "stp_state", DT_U32, 0, NULL },
+ { IFLA_BR_TCN_TIMER, "tcn_timer", DT_U64, DF_NO_SET, NULL },
+ { IFLA_BR_TOPOLOGY_CHANGE, "topology_change", DT_U8, DF_NO_SET, NULL },
+ { IFLA_BR_TOPOLOGY_CHANGE_DETECTED, "topology_change_detected", DT_U8, DF_NO_SET, NULL },
+ { IFLA_BR_TOPOLOGY_CHANGE_TIMER, "topology_change_timer", DT_U64, DF_NO_SET, NULL },
+ { IFLA_BR_VLAN_DEFAULT_PVID, "vlan_default_pvid", DT_U16, 0, NULL },
+ { IFLA_BR_VLAN_FILTERING, "vlan_filtering", DT_U8, 0, NULL },
+ { IFLA_BR_VLAN_PROTOCOL, "vlan_protocol", DT_U16, 0, NULL },
+ { IFLA_BR_VLAN_STATS_ENABLED, "vlan_stats_enabled", DT_U8, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t link_bridge_slave_attrs[] = {
+ { IFLA_BRPORT_BACKUP_PORT, "backup_port", DT_NETDEV, 0, NULL },
+ //{ IFLA_BRPORT_BCAST_FLOOD, "bcast-flood", DT_??, 0, NULL },
+ { IFLA_BRPORT_BRIDGE_ID, "bridge_id", DT_BRIDGEID, DF_NO_SET, NULL },
+ { IFLA_BRPORT_CONFIG_PENDING, "config_pending", DT_U8, DF_NO_SET, NULL },
+ { IFLA_BRPORT_COST, "cost", DT_U32, 0, NULL },
+ { IFLA_BRPORT_DESIGNATED_COST, "designated_cost", DT_U16, DF_NO_SET, NULL },
+ { IFLA_BRPORT_DESIGNATED_PORT, "designated_port", DT_U16, DF_NO_SET, NULL },
+ { IFLA_BRPORT_FAST_LEAVE, "fast_leave", DT_U8, 0, NULL },
+ { IFLA_BRPORT_FLUSH, "flush", DT_FLAG, DF_NO_GET, NULL },
+ { IFLA_BRPORT_FORWARD_DELAY_TIMER, "forward_delay_timer", DT_U64, DF_NO_SET, NULL },
+ { IFLA_BRPORT_GROUP_FWD_MASK, "group_fwd_mask", DT_U16, 0, NULL },
+ { IFLA_BRPORT_GUARD, "guard", DT_U8, 0, NULL },
+ { IFLA_BRPORT_HOLD_TIMER, "hold_timer", DT_U64, DF_NO_SET, NULL },
+ { IFLA_BRPORT_ID, "id", DT_U16, DF_NO_SET, NULL },
+ { IFLA_BRPORT_ISOLATED, "isolated", DT_U8, 0, NULL },
+ { IFLA_BRPORT_LEARNING, "learning", DT_U8, 0, NULL },
+ { IFLA_BRPORT_LEARNING_SYNC, "learning_sync", DT_U8, 0, NULL },
+ { IFLA_BRPORT_MCAST_FLOOD, "mcast_flood", DT_U8, 0, NULL },
+ { IFLA_BRPORT_MCAST_TO_UCAST, "mcast_to_ucast", DT_U8, 0, NULL },
+ { IFLA_BRPORT_MESSAGE_AGE_TIMER, "message_age_timer", DT_U64, DF_NO_SET, NULL },
+ { IFLA_BRPORT_MODE, "mode", DT_U8, 0, NULL },
+ { IFLA_BRPORT_MULTICAST_ROUTER, "multicast_router", DT_U8, 0, NULL },
+ { IFLA_BRPORT_NEIGH_SUPPRESS, "neigh_suppress", DT_U8, 0, NULL },
+ { IFLA_BRPORT_NO, "no", DT_U16, DF_NO_SET, NULL },
+ { IFLA_BRPORT_PRIORITY, "priority", DT_U16, 0, NULL },
+ { IFLA_BRPORT_PROTECT, "protect", DT_U8, 0, NULL },
+ { IFLA_BRPORT_PROXYARP, "proxyarp", DT_U8, DF_NO_SET, NULL },
+ { IFLA_BRPORT_PROXYARP_WIFI, "proxyarp_wifi", DT_U8, DF_NO_SET, NULL },
+ { IFLA_BRPORT_ROOT_ID, "root_id", DT_BRIDGEID, DF_NO_SET, NULL },
+ { IFLA_BRPORT_STATE, "state", DT_U8, 0, NULL },
+ { IFLA_BRPORT_TOPOLOGY_CHANGE_ACK, "topology_change_ack", DT_U8, DF_NO_SET, NULL },
+ { IFLA_BRPORT_UNICAST_FLOOD, "unicast_flood", DT_U8, 0, NULL },
+ { IFLA_BRPORT_VLAN_TUNNEL, "vlan_tunnel", DT_U8, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t link_geneve_attrs[] = {
+ { IFLA_GENEVE_COLLECT_METADATA, "collect_metadata", DT_FLAG, DF_NO_GET, NULL },
+ { IFLA_GENEVE_ID, "id", DT_U32, 0, NULL },
+ { IFLA_GENEVE_LABEL, "label", DT_U32, 0, NULL },
+ { IFLA_GENEVE_PORT, "port", DT_U16, 0, NULL },
+ { IFLA_GENEVE_REMOTE, "remote", DT_INADDR, 0, NULL },
+ { IFLA_GENEVE_REMOTE6, "remote6", DT_IN6ADDR, 0, NULL },
+ { IFLA_GENEVE_TOS, "tos", DT_U8, 0, NULL },
+ { IFLA_GENEVE_TTL, "ttl", DT_U8, 0, NULL },
+ { IFLA_GENEVE_UDP_CSUM, "udp_csum", DT_U8, 0, NULL },
+ { IFLA_GENEVE_UDP_ZERO_CSUM6_RX, "udp_zero_csum6_rx", DT_U8, 0, NULL },
+ { IFLA_GENEVE_UDP_ZERO_CSUM6_TX, "udp_zero_csum6_tx", DT_U8, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t link_hsr_attrs[] = {
+ { IFLA_HSR_MULTICAST_SPEC, "multicast_spec", DT_STRING, DF_NO_GET, NULL },
+ { IFLA_HSR_SEQ_NR, "seq_nr", DT_U16, DF_NO_SET, NULL },
+ { IFLA_HSR_SLAVE1, "slave1", DT_NETDEV, 0, NULL },
+ { IFLA_HSR_SLAVE2, "slave2", DT_NETDEV, 0, NULL },
+ { IFLA_HSR_SUPERVISION_ADDR, "supervision_addr", DT_LLADDR, DF_NO_SET, NULL },
+ { IFLA_HSR_VERSION, "version", DT_STRING, DF_NO_GET, NULL },
+};
+
+static const uc_nl_attr_spec_t link_ipoib_attrs[] = {
+ { IFLA_IPOIB_MODE, "mode", DT_U16, 0, NULL },
+ { IFLA_IPOIB_PKEY, "pkey", DT_U16, 0, NULL },
+ { IFLA_IPOIB_UMCAST, "umcast", DT_U16, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t link_ipvlan_attrs[] = {
+ { IFLA_IPVLAN_FLAGS, "flags", DT_U16, 0, NULL },
+ { IFLA_IPVLAN_MODE, "mode", DT_U16, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t link_macvlan_attrs[] = {
+ { IFLA_MACVLAN_FLAGS, "flags", DT_U16, 0, NULL },
+ { IFLA_MACVLAN_MACADDR, "macaddr", DT_LLADDR, DF_NO_GET, NULL },
+ { IFLA_MACVLAN_MACADDR_COUNT, "macaddr_count", DT_U32, DF_NO_SET, NULL },
+ { IFLA_MACVLAN_MACADDR_DATA, "macaddr_data", DT_LLADDR, DF_MULTIPLE, (void *)IFLA_MACVLAN_MACADDR },
+ { IFLA_MACVLAN_MACADDR_MODE, "macaddr_mode", DT_U32, DF_NO_GET, NULL },
+ { IFLA_MACVLAN_MODE, "mode", DT_U32, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t link_rmnet_attrs[] = {
+ //{ IFLA_RMNET_FLAGS, "flags", DT_??, 0, NULL },
+ { IFLA_RMNET_MUX_ID, "mux_id", DT_U16, 0, NULL },
+};
+
+
+static const uc_nl_attr_spec_t link_vlan_attrs[] = {
+ { IFLA_VLAN_EGRESS_QOS, "egress_qos_map", DT_NUMRANGE, DF_MULTIPLE, (void *)IFLA_VLAN_QOS_MAPPING },
+ { IFLA_VLAN_FLAGS, "flags", DT_FLAGS, 0, NULL },
+ { IFLA_VLAN_ID, "id", DT_U16, 0, NULL },
+ { IFLA_VLAN_INGRESS_QOS, "ingress_qos_map", DT_NUMRANGE, DF_MULTIPLE, (void *)IFLA_VLAN_QOS_MAPPING },
+ { IFLA_VLAN_PROTOCOL, "protocol", DT_U16, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t link_vrf_attrs[] = {
+ { IFLA_VRF_PORT_TABLE, "port_table", DT_U32, DF_NO_SET, NULL },
+ { IFLA_VRF_TABLE, "table", DT_U32, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t link_vxlan_attrs[] = {
+ { IFLA_VXLAN_AGEING, "ageing", DT_U32, 0, NULL },
+ { IFLA_VXLAN_COLLECT_METADATA, "collect_metadata", DT_U8, 0, NULL },
+ { IFLA_VXLAN_GBP, "gbp", DT_FLAG, 0, NULL },
+ { IFLA_VXLAN_GPE, "gpe", DT_FLAG, 0, NULL },
+ { IFLA_VXLAN_GROUP, "group", DT_INADDR, 0, NULL },
+ { IFLA_VXLAN_GROUP6, "group6", DT_IN6ADDR, 0, NULL },
+ { IFLA_VXLAN_ID, "id", DT_U32, 0, NULL },
+ { IFLA_VXLAN_L2MISS, "l2miss", DT_U8, 0, NULL },
+ { IFLA_VXLAN_L3MISS, "l3miss", DT_U8, 0, NULL },
+ { IFLA_VXLAN_LABEL, "label", DT_U32, 0, NULL },
+ { IFLA_VXLAN_LEARNING, "learning", DT_U8, 0, NULL },
+ { IFLA_VXLAN_LIMIT, "limit", DT_U32, 0, NULL },
+ { IFLA_VXLAN_LINK, "link", DT_U32, 0, NULL },
+ { IFLA_VXLAN_LOCAL, "local", DT_INADDR, 0, NULL },
+ { IFLA_VXLAN_LOCAL6, "local6", DT_IN6ADDR, 0, NULL },
+ { IFLA_VXLAN_PORT, "port", DT_U16, DF_BYTESWAP, NULL },
+ { IFLA_VXLAN_PORT_RANGE, "port_range", DT_NUMRANGE, DF_MAX_65535|DF_BYTESWAP, NULL },
+ { IFLA_VXLAN_PROXY, "proxy", DT_U8, 0, NULL },
+ //{ IFLA_VXLAN_REMCSUM_NOPARTIAL, "remcsum-nopartial", DT_??, 0, NULL },
+ { IFLA_VXLAN_REMCSUM_RX, "remcsum_rx", DT_BOOL, 0, NULL },
+ { IFLA_VXLAN_REMCSUM_TX, "remcsum_tx", DT_BOOL, 0, NULL },
+ { IFLA_VXLAN_RSC, "rsc", DT_BOOL, 0, NULL },
+ { IFLA_VXLAN_TOS, "tos", DT_U8, 0, NULL },
+ { IFLA_VXLAN_TTL, "ttl", DT_U8, 0, NULL },
+ { IFLA_VXLAN_TTL_INHERIT, "ttl_inherit", DT_FLAG, 0, NULL },
+ { IFLA_VXLAN_UDP_CSUM, "udp_csum", DT_BOOL, 0, NULL },
+ { IFLA_VXLAN_UDP_ZERO_CSUM6_RX, "udp_zero_csum6_rx", DT_BOOL, 0, NULL },
+ { IFLA_VXLAN_UDP_ZERO_CSUM6_TX, "udp_zero_csum6_tx", DT_BOOL, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t link_gre_attrs[] = {
+ { IFLA_GRE_COLLECT_METADATA, "collect_metadata", DT_FLAG, 0, NULL },
+ { IFLA_GRE_ENCAP_DPORT, "encap_dport", DT_U16, DF_BYTESWAP, NULL },
+ { IFLA_GRE_ENCAP_FLAGS, "encap_flags", DT_U16, 0, NULL },
+ { IFLA_GRE_ENCAP_LIMIT, "encap_limit", DT_U8, 0, NULL },
+ { IFLA_GRE_ENCAP_SPORT, "encap_sport", DT_U16, DF_BYTESWAP, NULL },
+ { IFLA_GRE_ENCAP_TYPE, "encap_type", DT_U16, 0, NULL },
+ { IFLA_GRE_ERSPAN_DIR, "erspan_dir", DT_U8, 0, NULL },
+ { IFLA_GRE_ERSPAN_HWID, "erspan_hwid", DT_U16, 0, NULL },
+ { IFLA_GRE_ERSPAN_INDEX, "erspan_index", DT_U32, 0, NULL },
+ { IFLA_GRE_ERSPAN_VER, "erspan_ver", DT_U8, 0, NULL },
+ { IFLA_GRE_FLAGS, "flags", DT_U32, 0, NULL },
+ { IFLA_GRE_FLOWINFO, "flowinfo", DT_U32, DF_BYTESWAP, NULL },
+ { IFLA_GRE_FWMARK, "fwmark", DT_U32, 0, NULL },
+ { IFLA_GRE_IFLAGS, "iflags", DT_U16, 0, NULL },
+ { IFLA_GRE_IGNORE_DF, "ignore_df", DT_BOOL, 0, NULL },
+ { IFLA_GRE_IKEY, "ikey", DT_U32, 0, NULL },
+ { IFLA_GRE_LINK, "link", DT_NETDEV, 0, NULL },
+ { IFLA_GRE_LOCAL, "local", DT_ANYADDR, 0, NULL },
+ { IFLA_GRE_OFLAGS, "oflags", DT_U16, 0, NULL },
+ { IFLA_GRE_OKEY, "okey", DT_U32, 0, NULL },
+ { IFLA_GRE_PMTUDISC, "pmtudisc", DT_BOOL, 0, NULL },
+ { IFLA_GRE_REMOTE, "remote", DT_ANYADDR, 0, NULL },
+ { IFLA_GRE_TOS, "tos", DT_U8, 0, NULL },
+ { IFLA_GRE_TTL, "ttl", DT_U8, 0, NULL },
+};
+
+#define link_gretap_attrs link_gre_attrs
+#define link_erspan_attrs link_gre_attrs
+#define link_ip6gre_attrs link_gre_attrs
+#define link_ip6gretap_attrs link_gre_attrs
+#define link_ip6erspan_attrs link_gre_attrs
+
+static const uc_nl_attr_spec_t link_ip6tnl_attrs[] = {
+ { IFLA_IPTUN_6RD_PREFIX, "6rd_prefix", DT_IN6ADDR, 0, NULL },
+ { IFLA_IPTUN_6RD_PREFIXLEN, "6rd_prefixlen", DT_U16, 0, NULL },
+ { IFLA_IPTUN_6RD_RELAY_PREFIX, "6rd_relay_prefix", DT_INADDR, 0, NULL },
+ { IFLA_IPTUN_6RD_RELAY_PREFIXLEN, "6rd_relay_prefixlen", DT_U16, 0, NULL },
+ { IFLA_IPTUN_COLLECT_METADATA, "collect_metadata", DT_BOOL, 0, NULL },
+ { IFLA_IPTUN_ENCAP_DPORT, "encap_dport", DT_U16, DF_BYTESWAP, NULL },
+ { IFLA_IPTUN_ENCAP_FLAGS, "encap_flags", DT_U16, 0, NULL },
+ { IFLA_IPTUN_ENCAP_LIMIT, "encap_limit", DT_U8, 0, NULL },
+ { IFLA_IPTUN_ENCAP_SPORT, "encap_sport", DT_U16, DF_BYTESWAP, NULL },
+ { IFLA_IPTUN_ENCAP_TYPE, "encap_type", DT_U16, 0, NULL },
+ { IFLA_IPTUN_FLAGS, "flags", DT_U16, 0, NULL },
+ { IFLA_IPTUN_FLOWINFO, "flowinfo", DT_U32, DF_BYTESWAP, NULL },
+ { IFLA_IPTUN_FWMARK, "fwmark", DT_U32, 0, NULL },
+ { IFLA_IPTUN_LINK, "link", DT_NETDEV, 0, NULL },
+ { IFLA_IPTUN_LOCAL, "local", DT_ANYADDR, 0, NULL },
+ { IFLA_IPTUN_PMTUDISC, "pmtudisc", DT_BOOL, 0, NULL },
+ { IFLA_IPTUN_PROTO, "proto", DT_U8, 0, NULL },
+ { IFLA_IPTUN_REMOTE, "remote", DT_ANYADDR, 0, NULL },
+ { IFLA_IPTUN_TOS, "tos", DT_U8, 0, NULL },
+ { IFLA_IPTUN_TTL, "ttl", DT_U8, 0, NULL },
+};
+
+#define link_ipip_attrs link_ip6tnl_attrs
+#define link_sit_attrs link_ip6tnl_attrs
+
+static const uc_nl_attr_spec_t link_veth_attrs[] = {
+ { VETH_INFO_PEER, "info_peer", DT_NESTED, 0, &link_msg },
+};
+
+static const uc_nl_attr_spec_t link_vti_attrs[] = {
+ { IFLA_VTI_FWMARK, "fwmark", DT_U32, 0, NULL },
+ { IFLA_VTI_IKEY, "ikey", DT_U32, 0, NULL },
+ { IFLA_VTI_LINK, "link", DT_U32, 0, NULL },
+ { IFLA_VTI_LOCAL, "local", DT_ANYADDR, 0, NULL },
+ { IFLA_VTI_OKEY, "okey", DT_U32, 0, NULL },
+ { IFLA_VTI_REMOTE, "remote", DT_ANYADDR, 0, NULL },
+};
+
+#define link_vti6_attrs link_vti_attrs
+
+static const uc_nl_attr_spec_t link_xfrm_attrs[] = {
+ { IFLA_XFRM_IF_ID, "if_id", DT_U32, 0, NULL },
+ { IFLA_XFRM_LINK, "link", DT_NETDEV, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t lwtipopt_erspan_attrs[] = {
+ { LWTUNNEL_IP_OPT_ERSPAN_VER, "ver", DT_U8, 0, NULL },
+ { LWTUNNEL_IP_OPT_ERSPAN_INDEX, "index", DT_U16, DF_BYTESWAP, NULL },
+ { LWTUNNEL_IP_OPT_ERSPAN_DIR, "dir", DT_U8, 0, NULL },
+ { LWTUNNEL_IP_OPT_ERSPAN_HWID, "hwid", DT_U8, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t lwtipopt_geneve_attrs[] = {
+ { LWTUNNEL_IP_OPT_GENEVE_CLASS, "class", DT_U16, DF_BYTESWAP, NULL },
+ { LWTUNNEL_IP_OPT_GENEVE_TYPE, "type", DT_U8, 0, NULL },
+ { LWTUNNEL_IP_OPT_GENEVE_DATA, "data", DT_STRING, 0, NULL },
+};
+
+static const uc_nl_attr_spec_t lwtipopt_vxlan_attrs[] = {
+ { LWTUNNEL_IP_OPT_VXLAN_GBP, "gbp", DT_U32, 0, NULL },
+};
+
+static const uc_nl_nested_spec_t neigh_cacheinfo_rta = {
+ .headsize = NLA_ALIGN(sizeof(struct nda_cacheinfo)),
+ .nattrs = 4,
+ .attrs = {
+ { NDA_UNSPEC, "confirmed", DT_U32, 0, MEMBER(nda_cacheinfo, ndm_confirmed) },
+ { NDA_UNSPEC, "used", DT_U32, 0, MEMBER(nda_cacheinfo, ndm_used) },
+ { NDA_UNSPEC, "updated", DT_U32, 0, MEMBER(nda_cacheinfo, ndm_updated) },
+ { NDA_UNSPEC, "refcnt", DT_U32, 0, MEMBER(nda_cacheinfo, ndm_refcnt) },
+ }
+};
+
+static const uc_nl_nested_spec_t neigh_msg = {
+ .headsize = NLA_ALIGN(sizeof(struct ndmsg)),
+ .nattrs = 16,
+ .attrs = {
+ { NDA_UNSPEC, "family", DT_U8, 0, MEMBER(ndmsg, ndm_family) },
+ { NDA_UNSPEC, "dev" /* actually ifindex, but avoid clash with NDA_IFINDEX */, DT_NETDEV, DF_ALLOW_NONE, MEMBER(ndmsg, ndm_ifindex) },
+ { NDA_UNSPEC, "state", DT_U16, 0, MEMBER(ndmsg, ndm_state) },
+ { NDA_UNSPEC, "flags", DT_U8, 0, MEMBER(ndmsg, ndm_flags) },
+ { NDA_UNSPEC, "type", DT_U8, 0, MEMBER(ndmsg, ndm_type) },
+ { NDA_CACHEINFO, "cacheinfo", DT_NESTED, DF_NO_SET, &neigh_cacheinfo_rta },
+ { NDA_DST, "dst", DT_ANYADDR, 0, NULL },
+ { NDA_IFINDEX, "ifindex", DT_NETDEV, 0, NULL },
+ { NDA_LINK_NETNSID, "link_netnsid", DT_U32, DF_NO_SET, NULL },
+ { NDA_LLADDR, "lladdr", DT_LLADDR, 0, NULL },
+ { NDA_MASTER, "master", DT_NETDEV, 0, NULL },
+ { NDA_PORT, "port", DT_U16, DF_BYTESWAP, NULL },
+ { NDA_PROBES, "probes", DT_U32, DF_NO_SET, NULL },
+ { NDA_SRC_VNI, "src_vni", DT_U32, DF_NO_SET, NULL },
+ { NDA_VLAN, "vlan", DT_U16, 0, NULL },
+ { NDA_VNI, "vni", DT_U32, DF_MAX_16777215, NULL },
+ }
+};
+
+static const uc_nl_nested_spec_t addr_cacheinfo_rta = {
+ .headsize = NLA_ALIGN(sizeof(struct ifa_cacheinfo)),
+ .nattrs = 4,
+ .attrs = {
+ { IFA_UNSPEC, "preferred", DT_U32, 0, MEMBER(ifa_cacheinfo, ifa_prefered) },
+ { IFA_UNSPEC, "valid", DT_U32, 0, MEMBER(ifa_cacheinfo, ifa_valid) },
+ { IFA_UNSPEC, "cstamp", DT_U32, 0, MEMBER(ifa_cacheinfo, cstamp) },
+ { IFA_UNSPEC, "tstamp", DT_U32, 0, MEMBER(ifa_cacheinfo, tstamp) },
+ }
+};
+
+static const uc_nl_nested_spec_t addr_msg = {
+ .headsize = NLA_ALIGN(sizeof(struct ifaddrmsg)),
+ .nattrs = 11,
+ .attrs = {
+ { IFA_UNSPEC, "family", DT_U8, 0, MEMBER(ifaddrmsg, ifa_family) },
+ { IFA_FLAGS, "flags", DT_U32_OR_MEMBER, DF_MAX_255, MEMBER(ifaddrmsg, ifa_flags) },
+ { IFA_UNSPEC, "scope", DT_U8, 0, MEMBER(ifaddrmsg, ifa_scope) },
+ { IFA_UNSPEC, "dev", DT_NETDEV, 0, MEMBER(ifaddrmsg, ifa_index) },
+ { IFA_ADDRESS, "address", DT_ANYADDR, DF_STORE_MASK, MEMBER(ifaddrmsg, ifa_prefixlen) },
+ { IFA_LOCAL, "local", DT_ANYADDR, 0, NULL },
+ { IFA_LABEL, "label", DT_STRING, 0, NULL },
+ { IFA_BROADCAST, "broadcast", DT_ANYADDR, 0, NULL },
+ { IFA_ANYCAST, "anycast", DT_ANYADDR, 0, NULL },
+ { IFA_CACHEINFO, "cacheinfo", DT_NESTED, DF_NO_SET, &addr_cacheinfo_rta },
+ { IFA_RT_PRIORITY, "metric", DT_U32, 0, NULL },
+ }
+};
+
+static const uc_nl_nested_spec_t rule_msg = {
+ .headsize = NLA_ALIGN(sizeof(struct fib_rule_hdr)),
+ .nattrs = 23,
+ .attrs = {
+ { FRA_UNSPEC, "family", DT_U8, 0, MEMBER(fib_rule_hdr, family) },
+ { FRA_UNSPEC, "tos", DT_U8, 0, MEMBER(fib_rule_hdr, tos) },
+ { FRA_UNSPEC, "action", DT_U8, 0, MEMBER(fib_rule_hdr, action) },
+ { FRA_UNSPEC, "flags", DT_U32, 0, MEMBER(fib_rule_hdr, flags) },
+ { FRA_PRIORITY, "priority", DT_U32, 0, NULL },
+ { FRA_SRC, "src", DT_ANYADDR, DF_STORE_MASK|DF_FAMILY_HINT, MEMBER(fib_rule_hdr, src_len) },
+ { FRA_DST, "dst", DT_ANYADDR, DF_STORE_MASK|DF_FAMILY_HINT, MEMBER(fib_rule_hdr, dst_len) },
+ { FRA_FWMARK, "fwmark", DT_U32, 0, NULL },
+ { FRA_FWMASK, "fwmask", DT_U32, 0, NULL },
+ { FRA_IFNAME, "iif", DT_NETDEV, 0, NULL },
+ { FRA_OIFNAME, "oif", DT_NETDEV, 0, NULL },
+ { FRA_L3MDEV, "l3mdev", DT_U8, 0, NULL },
+ { FRA_UID_RANGE, "uid_range", DT_NUMRANGE, 0, NULL },
+ { FRA_IP_PROTO, "ip_proto", DT_U8, 0, NULL },
+ { FRA_SPORT_RANGE, "sport_range", DT_NUMRANGE, DF_MAX_65535, NULL },
+ { FRA_DPORT_RANGE, "dport_range", DT_NUMRANGE, DF_MAX_65535, NULL },
+ { FRA_TABLE, "table", DT_U32_OR_MEMBER, DF_MAX_255, MEMBER(fib_rule_hdr, table) },
+ { FRA_SUPPRESS_PREFIXLEN, "suppress_prefixlen", DT_S32, 0, NULL },
+ { FRA_SUPPRESS_IFGROUP, "suppress_ifgroup", DT_U32, 0, NULL },
+ { FRA_FLOW, "flow", DT_U32, 0, NULL },
+ { RTA_GATEWAY, "gateway", DT_ANYADDR, DF_FAMILY_HINT, NULL },
+ { FRA_GOTO, "goto", DT_U32, 0, NULL },
+ { FRA_PROTOCOL, "protocol", DT_U8, 0, NULL },
+ }
+};
+
+#define IFAL_UNSPEC 0
+
+static const uc_nl_nested_spec_t addrlabel_msg = {
+ .headsize = NLA_ALIGN(sizeof(struct ifaddrlblmsg)),
+ .nattrs = 6,
+ .attrs = {
+ { IFAL_UNSPEC, "family", DT_U8, 0, MEMBER(ifaddrlblmsg, ifal_family) },
+ { IFAL_UNSPEC, "flags", DT_U8, 0, MEMBER(ifaddrlblmsg, ifal_flags) },
+ { IFAL_UNSPEC, "dev", DT_NETDEV, 0, MEMBER(ifaddrlblmsg, ifal_index) },
+ { IFAL_UNSPEC, "seq", DT_U32, 0, MEMBER(ifaddrlblmsg, ifal_seq) },
+ { IFAL_ADDRESS, "address", DT_ANYADDR, DF_STORE_MASK, MEMBER(ifaddrlblmsg, ifal_prefixlen) },
+ { IFAL_LABEL, "label", DT_U32, 0, NULL },
+ }
+};
+
+static const uc_nl_nested_spec_t neightbl_params_rta = {
+ .headsize = 0,
+ .nattrs = 13,
+ .attrs = {
+ { NDTPA_IFINDEX, "dev", DT_NETDEV, 0, NULL },
+ { NDTPA_BASE_REACHABLE_TIME, "base_reachable_time", DT_U64, 0, NULL },
+ { NDTPA_RETRANS_TIME, "retrans_time", DT_U64, 0, NULL },
+ { NDTPA_GC_STALETIME, "gc_staletime", DT_U64, 0, NULL },
+ { NDTPA_DELAY_PROBE_TIME, "delay_probe_time", DT_U64, 0, NULL },
+ { NDTPA_QUEUE_LEN, "queue_len", DT_U32, 0, NULL },
+ { NDTPA_APP_PROBES, "app_probes", DT_U32, 0, NULL },
+ { NDTPA_UCAST_PROBES, "ucast_probes", DT_U32, 0, NULL },
+ { NDTPA_MCAST_PROBES, "mcast_probes", DT_U32, 0, NULL },
+ { NDTPA_ANYCAST_DELAY, "anycast_delay", DT_U64, 0, NULL },
+ { NDTPA_PROXY_DELAY, "proxy_delay", DT_U64, 0, NULL },
+ { NDTPA_PROXY_QLEN, "proxy_qlen", DT_U32, 0, NULL },
+ { NDTPA_LOCKTIME, "locktime", DT_U64, 0, NULL },
+ }
+};
+
+static const uc_nl_nested_spec_t neightbl_config_rta = {
+ .headsize = NLA_ALIGN(sizeof(struct ndt_config)),
+ .nattrs = 9,
+ .attrs = {
+ { NDTA_UNSPEC, "key_len", DT_U16, 0, MEMBER(ndt_config, ndtc_key_len) },
+ { NDTA_UNSPEC, "entry_size", DT_U16, 0, MEMBER(ndt_config, ndtc_entry_size) },
+ { NDTA_UNSPEC, "entries", DT_U32, 0, MEMBER(ndt_config, ndtc_entries) },
+ { NDTA_UNSPEC, "last_flush", DT_U32, 0, MEMBER(ndt_config, ndtc_last_flush) },
+ { NDTA_UNSPEC, "last_rand", DT_U32, 0, MEMBER(ndt_config, ndtc_last_rand) },
+ { NDTA_UNSPEC, "hash_rnd", DT_U32, 0, MEMBER(ndt_config, ndtc_hash_rnd) },
+ { NDTA_UNSPEC, "hash_mask", DT_U32, 0, MEMBER(ndt_config, ndtc_hash_mask) },
+ { NDTA_UNSPEC, "hash_chain_gc", DT_U32, 0, MEMBER(ndt_config, ndtc_hash_chain_gc) },
+ { NDTA_UNSPEC, "proxy_qlen", DT_U32, 0, MEMBER(ndt_config, ndtc_proxy_qlen) },
+ }
+};
+
+static const uc_nl_nested_spec_t neightbl_stats_rta = {
+ .headsize = NLA_ALIGN(sizeof(struct ndt_stats)),
+ .nattrs = 10,
+ .attrs = {
+ { NDTA_UNSPEC, "allocs", DT_U64, 0, MEMBER(ndt_stats, ndts_allocs) },
+ { NDTA_UNSPEC, "destroys", DT_U64, 0, MEMBER(ndt_stats, ndts_destroys) },
+ { NDTA_UNSPEC, "hash_grows", DT_U64, 0, MEMBER(ndt_stats, ndts_hash_grows) },
+ { NDTA_UNSPEC, "res_failed", DT_U64, 0, MEMBER(ndt_stats, ndts_res_failed) },
+ { NDTA_UNSPEC, "lookups", DT_U64, 0, MEMBER(ndt_stats, ndts_lookups) },
+ { NDTA_UNSPEC, "hits", DT_U64, 0, MEMBER(ndt_stats, ndts_hits) },
+ { NDTA_UNSPEC, "rcv_probes_mcast", DT_U64, 0, MEMBER(ndt_stats, ndts_rcv_probes_mcast) },
+ { NDTA_UNSPEC, "rcv_probes_ucast", DT_U64, 0, MEMBER(ndt_stats, ndts_rcv_probes_ucast) },
+ { NDTA_UNSPEC, "periodic_gc_runs", DT_U64, 0, MEMBER(ndt_stats, ndts_periodic_gc_runs) },
+ { NDTA_UNSPEC, "forced_gc_runs", DT_U64, 0, MEMBER(ndt_stats, ndts_forced_gc_runs) },
+ }
+};
+
+static const uc_nl_nested_spec_t neightbl_msg = {
+ .headsize = NLA_ALIGN(sizeof(struct ndtmsg)),
+ .nattrs = 9,
+ .attrs = {
+ { NDTA_UNSPEC, "family", DT_U8, 0, MEMBER(ndtmsg, ndtm_family) },
+ { NDTA_NAME, "name", DT_STRING, 0, NULL },
+ { NDTA_THRESH1, "thresh1", DT_U32, 0, NULL },
+ { NDTA_THRESH2, "thresh2", DT_U32, 0, NULL },
+ { NDTA_THRESH3, "thresh3", DT_U32, 0, NULL },
+ { NDTA_GC_INTERVAL, "gc_interval", DT_U64, 0, NULL },
+ { NDTA_PARMS, "params", DT_NESTED, 0, &neightbl_params_rta },
+ { NDTA_CONFIG, "config", DT_NESTED, DF_NO_SET, &neightbl_config_rta },
+ { NDTA_STATS, "stats", DT_NESTED, DF_NO_SET, &neightbl_stats_rta },
+ }
+};
+
+static const uc_nl_nested_spec_t netconf_msg = {
+ .headsize = NLA_ALIGN(sizeof(struct netconfmsg)),
+ .nattrs = 8,
+ .attrs = {
+ { NETCONFA_UNSPEC, "family", DT_U8, 0, MEMBER(netconfmsg, ncm_family) },
+ { NETCONFA_IFINDEX, "dev", DT_NETDEV, 0, NULL },
+ { NETCONFA_FORWARDING, "forwarding", DT_U32, DF_NO_SET, NULL },
+ { NETCONFA_RP_FILTER, "rp_filter", DT_U32, DF_NO_SET, NULL },
+ { NETCONFA_MC_FORWARDING, "mc_forwarding", DT_U32, DF_NO_SET, NULL },
+ { NETCONFA_PROXY_NEIGH, "proxy_neigh", DT_U32, DF_NO_SET, NULL },
+ { NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, "ignore_routes_with_linkdown", DT_U32, DF_NO_SET, NULL },
+ { NETCONFA_INPUT, "input", DT_U32, DF_NO_SET, NULL },
+ }
+};
+
+
+static bool
+nla_check_len(struct nlattr *nla, size_t sz)
+{
+ return (nla && nla_len(nla) >= (ssize_t)sz);
+}
+
+static bool
+nla_parse_error(const uc_nl_attr_spec_t *spec, uc_vm_t *vm, uc_value_t *v, const char *msg)
+{
+ char *s;
+
+ s = ucv_to_string(vm, v);
+
+ set_error(NLE_INVAL, "%s `%s` has invalid value `%s`: %s",
+ spec->attr ? "attribute" : "field",
+ spec->key,
+ s,
+ msg);
+
+ free(s);
+
+ return false;
+}
+
+static void
+uc_nl_put_struct_member(char *base, const void *offset, size_t datalen, void *data)
+{
+ memcpy(base + (uintptr_t)offset, data, datalen);
+}
+
+static void
+uc_nl_put_struct_member_u8(char *base, const void *offset, uint8_t u8)
+{
+ base[(uintptr_t)offset] = u8;
+}
+
+static void
+uc_nl_put_struct_member_u16(char *base, const void *offset, uint16_t u16)
+{
+ uc_nl_put_struct_member(base, offset, sizeof(u16), &u16);
+}
+
+static void
+uc_nl_put_struct_member_u32(char *base, const void *offset, uint32_t u32)
+{
+ uc_nl_put_struct_member(base, offset, sizeof(u32), &u32);
+}
+
+static void *
+uc_nl_get_struct_member(char *base, const void *offset, size_t datalen, void *data)
+{
+ memcpy(data, base + (uintptr_t)offset, datalen);
+
+ return data;
+}
+
+static uint8_t
+uc_nl_get_struct_member_u8(char *base, const void *offset)
+{
+ return (uint8_t)base[(uintptr_t)offset];
+}
+
+static uint16_t
+uc_nl_get_struct_member_u16(char *base, const void *offset)
+{
+ uint16_t u16;
+
+ uc_nl_get_struct_member(base, offset, sizeof(u16), &u16);
+
+ return u16;
+}
+
+static uint32_t
+uc_nl_get_struct_member_u32(char *base, const void *offset)
+{
+ uint32_t u32;
+
+ uc_nl_get_struct_member(base, offset, sizeof(u32), &u32);
+
+ return u32;
+}
+
+static uint64_t
+uc_nl_get_struct_member_u64(char *base, const void *offset)
+{
+ uint64_t u64;
+
+ uc_nl_get_struct_member(base, offset, sizeof(u64), &u64);
+
+ return u64;
+}
+
+static bool
+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);
+
+static uc_value_t *
+uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr **tb, uc_vm_t *vm);
+
+static bool
+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)
+{
+ size_t i, maxattr = 0, structlen = headsize;
+ struct nlattr **tb, *nla, *nla_nest;
+ uc_value_t *v, *arr;
+ int rem;
+
+ for (i = 0; i < nattrs; i++)
+ if (attrs[i].attr > maxattr)
+ maxattr = attrs[i].attr;
+
+ tb = calloc(maxattr + 1, sizeof(struct nlattr *));
+
+ if (!tb)
+ return false;
+
+ if (buflen > headsize)
+ nla_parse(tb, maxattr, buf + headsize, buflen - headsize, NULL);
+ else
+ structlen = buflen;
+
+ for (i = 0; i < nattrs; i++) {
+ if (attrs[i].attr == 0 && (uintptr_t)attrs[i].auxdata >= structlen)
+ continue;
+
+ if (attrs[i].attr != 0 && !tb[attrs[i].attr])
+ continue;
+
+ if (attrs[i].flags & DF_NO_GET)
+ continue;
+
+ if (attrs[i].flags & DF_MULTIPLE) {
+ /* can't happen, but needed to nudge clang-analyzer */
+ if (!tb[attrs[i].attr])
+ continue;
+
+ arr = ucv_array_new(vm);
+ nla_nest = tb[attrs[i].attr];
+
+ nla_for_each_attr(nla, nla_data(nla_nest), nla_len(nla_nest), rem) {
+ if (attrs[i].auxdata && nla_type(nla) != (intptr_t)attrs[i].auxdata)
+ continue;
+
+ tb[attrs[i].attr] = nla;
+
+ v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, tb, vm);
+
+ if (!v)
+ continue;
+
+ ucv_array_push(arr, v);
+ }
+
+ if (!ucv_array_length(arr)) {
+ ucv_put(arr);
+
+ continue;
+ }
+
+ v = arr;
+ }
+ else {
+ v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, tb, vm);
+
+ if (!v)
+ continue;
+ }
+
+ ucv_object_add(obj, attrs[i].key, v);
+ }
+
+ free(tb);
+
+ return true;
+}
+
+static bool
+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)
+{
+ struct nlattr *nla_nest = NULL;
+ size_t i, j, idx;
+ uc_value_t *v;
+ bool exists;
+
+ for (i = 0; i < nattrs; i++) {
+ v = ucv_object_get(obj, attrs[i].key, &exists);
+
+ if (!exists)
+ continue;
+
+ if (attrs[i].flags & DF_MULTIPLE) {
+ if (!(attrs[i].flags & DF_FLAT))
+ nla_nest = nla_nest_start(msg, attrs[i].attr);
+
+ if (ucv_type(v) == UC_ARRAY) {
+ for (j = 0; j < ucv_array_length(v); j++) {
+ if (attrs[i].flags & DF_FLAT)
+ idx = attrs[i].attr;
+ else if (attrs[i].auxdata)
+ idx = (uintptr_t)attrs[i].auxdata;
+ else
+ idx = j;
+
+ if (!uc_nl_parse_attr(&attrs[i], msg, base, vm, ucv_array_get(v, j), idx))
+ return false;
+ }
+ }
+ else {
+ if (attrs[i].flags & DF_FLAT)
+ idx = attrs[i].attr;
+ else if (attrs[i].auxdata)
+ idx = (uintptr_t)attrs[i].auxdata;
+ else
+ idx = 0;
+
+ if (!uc_nl_parse_attr(&attrs[i], msg, base, vm, v, idx))
+ return false;
+ }
+
+ if (nla_nest)
+ nla_nest_end(msg, nla_nest);
+ }
+ else if (!uc_nl_parse_attr(&attrs[i], msg, base, vm, v, 0)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool
+uc_nl_parse_rta_nexthop(struct nl_msg *msg, uc_vm_t *vm, uc_value_t *val)
+{
+ struct { uint16_t family; char addr[sizeof(struct in6_addr)]; } via;
+ struct nlmsghdr *hdr = nlmsg_hdr(msg);
+ struct rtmsg *rtm = NLMSG_DATA(hdr);
+ struct nlattr *rta_gateway;
+ struct rtnexthop *rtnh;
+ uc_nl_cidr_t cidr = { 0 };
+ uc_value_t *v;
+ uint32_t u;
+ int aflen;
+ char *s;
+
+ if (ucv_type(val) != UC_OBJECT)
+ return false;
+
+ if (uc_nl_parse_cidr(vm, ucv_object_get(val, "via", NULL), &cidr))
+ return false;
+
+ aflen = (cidr.family == AF_INET6 ? sizeof(cidr.addr.in6) : sizeof(cidr.addr.in));
+
+ if (cidr.mask != (aflen * 8))
+ return false;
+
+ rta_gateway = nla_reserve(msg, RTA_GATEWAY, sizeof(*rtnh));
+
+ rtnh = nla_data(rta_gateway);
+ rtnh->rtnh_len = sizeof(*rtnh);
+
+ if (rtm->rtm_family == AF_UNSPEC)
+ rtm->rtm_family = cidr.family;
+
+ if (cidr.family == rtm->rtm_family) {
+ nla_put(msg, RTA_GATEWAY, aflen, &cidr.addr.in6);
+ rtnh->rtnh_len += nla_total_size(aflen);
+ }
+ else {
+ via.family = cidr.family;
+ memcpy(via.addr, &cidr.addr.in6, aflen);
+ nla_put(msg, RTA_VIA, sizeof(via.family) + aflen, &via);
+ rtnh->rtnh_len += nla_total_size(sizeof(via.family) + aflen);
+ }
+
+ v = ucv_object_get(val, "dev", NULL);
+ s = ucv_string_get(v);
+
+ if (s) {
+ rtnh->rtnh_ifindex = if_nametoindex(s);
+
+ if (rtnh->rtnh_ifindex == 0)
+ return false;
+ }
+
+ v = ucv_object_get(val, "weight", NULL);
+
+ if (v) {
+ if (!uc_nl_parse_u32(v, &u) || u == 0 || u > 256)
+ return false;
+
+ rtnh->rtnh_hops = u - 1;
+ }
+
+ if (ucv_is_truish(ucv_object_get(val, "onlink", NULL)))
+ rtnh->rtnh_flags |= RTNH_F_ONLINK;
+
+ v = ucv_object_get(val, "realm", NULL);
+
+ if (v) {
+ if (!uc_nl_parse_u32(v, &u))
+ return false;
+
+ nla_put_u32(msg, RTA_FLOW, u);
+ rtnh->rtnh_len += nla_total_size(sizeof(uint32_t));
+ }
+
+ v = ucv_object_get(val, "as", NULL);
+
+ if (v) {
+ if (!uc_nl_parse_cidr(vm, v, &cidr) || cidr.family != rtm->rtm_family)
+ return false;
+
+ if (cidr.mask != cidr.bitlen)
+ return false;
+
+ nla_put(msg, RTA_NEWDST, cidr.alen, &cidr.addr.in6);
+ rtnh->rtnh_len += nla_total_size(cidr.alen);
+ }
+
+ /* XXX: nla_nest_end(rta_gateway) ? */
+
+ return true;
+}
+
+static bool
+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)
+{
+ struct nlattr *rta_multipath = nla_nest_start(msg, spec->attr);
+ size_t i;
+
+ for (i = 0; i < ucv_array_length(val); i++)
+ if (!uc_nl_parse_rta_nexthop(msg, vm, ucv_array_get(val, i)))
+ return false;
+
+ nla_nest_end(msg, rta_multipath);
+
+ return true;
+}
+
+static uc_value_t *
+uc_nl_convert_rta_encap(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm);
+
+static uc_value_t *
+uc_nl_convert_rta_multipath(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm)
+{
+ uc_nl_attr_spec_t encap_spec = { .attr = RTA_ENCAP };
+ struct rtnexthop *nh = nla_data(tb[spec->attr]);
+ struct nlattr *multipath_tb[RTA_MAX + 1];
+ size_t len = nla_len(tb[spec->attr]);
+ uc_value_t *nh_obj, *nh_arr;
+ char buf[INET6_ADDRSTRLEN];
+ struct rtvia *via;
+ int af;
+
+ nh_arr = ucv_array_new(vm);
+
+ while (len >= sizeof(*nh)) {
+ if ((size_t)NLA_ALIGN(nh->rtnh_len) > len)
+ break;
+
+ nh_obj = ucv_object_new(vm);
+ ucv_array_push(nh_arr, nh_obj);
+
+ nla_parse(multipath_tb, RTA_MAX + 1, (struct nlattr *)RTNH_DATA(nh), nh->rtnh_len - sizeof(*nh), NULL);
+
+ if (multipath_tb[RTA_GATEWAY]) {
+ switch (nla_len(multipath_tb[RTA_GATEWAY])) {
+ case 4: af = AF_INET; break;
+ case 16: af = AF_INET6; break;
+ default: af = AF_UNSPEC; break;
+ }
+
+ if (inet_ntop(af, nla_data(multipath_tb[RTA_GATEWAY]), buf, sizeof(buf)))
+ ucv_object_add(nh_obj, "via", ucv_string_new(buf));
+ }
+
+ if (multipath_tb[RTA_VIA]) {
+ if (nla_len(multipath_tb[RTA_VIA]) > (ssize_t)sizeof(*via)) {
+ via = nla_data(multipath_tb[RTA_VIA]);
+ af = via->rtvia_family;
+
+ if ((af == AF_INET &&
+ nla_len(multipath_tb[RTA_VIA]) == sizeof(*via) + sizeof(struct in_addr)) ||
+ (af == AF_INET6 &&
+ nla_len(multipath_tb[RTA_VIA]) == sizeof(*via) + sizeof(struct in6_addr))) {
+ if (inet_ntop(af, via->rtvia_addr, buf, sizeof(buf)))
+ ucv_object_add(nh_obj, "via", ucv_string_new(buf));
+ }
+ }
+ }
+
+ if (if_indextoname(nh->rtnh_ifindex, buf))
+ ucv_object_add(nh_obj, "dev", ucv_string_new(buf));
+
+ ucv_object_add(nh_obj, "weight", ucv_int64_new(nh->rtnh_hops + 1));
+ ucv_object_add(nh_obj, "onlink", ucv_boolean_new(nh->rtnh_flags & RTNH_F_ONLINK));
+
+ if (multipath_tb[RTA_FLOW] && nla_len(multipath_tb[RTA_FLOW]) == sizeof(uint32_t))
+ ucv_object_add(nh_obj, "realm", ucv_int64_new(nla_get_u32(multipath_tb[RTA_FLOW])));
+
+ if (multipath_tb[RTA_ENCAP])
+ ucv_object_add(nh_obj, "encap",
+ uc_nl_convert_rta_encap(&encap_spec, msg, multipath_tb, vm));
+
+ if (multipath_tb[RTA_NEWDST]) {
+ switch (nla_len(multipath_tb[RTA_NEWDST])) {
+ case 4: af = AF_INET; break;
+ case 16: af = AF_INET6; break;
+ default: af = AF_UNSPEC; break;
+ }
+
+ if (inet_ntop(af, nla_data(multipath_tb[RTA_NEWDST]), buf, sizeof(buf)))
+ ucv_object_add(nh_obj, "as", ucv_string_new(buf));
+ }
+
+ len -= NLA_ALIGN(nh->rtnh_len);
+ nh = RTNH_NEXT(nh);
+ }
+
+ return nh_arr;
+}
+
+static bool
+parse_num(const uc_nl_attr_spec_t *spec, uc_vm_t *vm, uc_value_t *val, void *dst)
+{
+ int64_t n = ucv_int64_get(val);
+ uint32_t *u32;
+ uint16_t *u16;
+ uint8_t *u8;
+
+ if (spec->flags & DF_MAX_255) {
+ if (n < 0 || n > 255)
+ return nla_parse_error(spec, vm, val, "number out of range 0-255");
+
+ u8 = dst; *u8 = n;
+ }
+ else if (spec->flags & DF_MAX_65535) {
+ if (n < 0 || n > 65535)
+ return nla_parse_error(spec, vm, val, "number out of range 0-65535");
+
+ u16 = dst; *u16 = n;
+
+ if (spec->flags & DF_BYTESWAP)
+ *u16 = htons(*u16);
+ }
+ else if (spec->flags & DF_MAX_16777215) {
+ if (n < 0 || n > 16777215)
+ return nla_parse_error(spec, vm, val, "number out of range 0-16777215");
+
+ u32 = dst; *u32 = n;
+
+ if (spec->flags & DF_BYTESWAP)
+ *u32 = htonl(*u32);
+ }
+ else {
+ if (n < 0 || n > 4294967295)
+ return nla_parse_error(spec, vm, val, "number out of range 0-4294967295");
+
+ u32 = dst; *u32 = n;
+
+ if (spec->flags & DF_BYTESWAP)
+ *u32 = htonl(*u32);
+ }
+
+ return true;
+}
+
+static bool
+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)
+{
+ union {
+ struct { uint8_t low; uint8_t high; } u8;
+ struct { uint16_t low; uint16_t high; } u16;
+ struct { uint32_t low; uint32_t high; } u32;
+ } ranges = { 0 };
+
+ void *d1, *d2;
+ size_t len;
+
+ if (ucv_array_length(val) != 2 ||
+ ucv_type(ucv_array_get(val, 0)) != UC_INTEGER ||
+ ucv_type(ucv_array_get(val, 1)) != UC_INTEGER)
+ return nla_parse_error(spec, vm, val, "not a two-element array of numbers");
+
+ if (spec->flags & DF_MAX_255) {
+ len = sizeof(ranges.u8);
+ d1 = &ranges.u8.low;
+ d2 = &ranges.u8.high;
+ }
+ else if (spec->flags & DF_MAX_65535) {
+ len = sizeof(ranges.u16);
+ d1 = &ranges.u16.low;
+ d2 = &ranges.u16.high;
+ }
+ else {
+ len = sizeof(ranges.u32);
+ d1 = &ranges.u32.low;
+ d2 = &ranges.u32.high;
+ }
+
+ if (!parse_num(spec, vm, ucv_array_get(val, 0), d1) ||
+ !parse_num(spec, vm, ucv_array_get(val, 1), d2))
+ return false;
+
+ nla_put(msg, spec->attr, len, d1);
+
+ return true;
+}
+
+static uc_value_t *
+uc_nl_convert_rta_numrange(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm)
+{
+ union {
+ struct { uint8_t low; uint8_t high; } *u8;
+ struct { uint16_t low; uint16_t high; } *u16;
+ struct { uint32_t low; uint32_t high; } *u32;
+ } ranges = { 0 };
+
+ bool swap = (spec->flags & DF_BYTESWAP);
+ uc_value_t *arr, *n1, *n2;
+
+ if (spec->flags & DF_MAX_255) {
+ if (!nla_check_len(tb[spec->attr], sizeof(*ranges.u8)))
+ return NULL;
+
+ ranges.u8 = nla_data(tb[spec->attr]);
+ n1 = ucv_int64_new(ranges.u8->low);
+ n2 = ucv_int64_new(ranges.u8->high);
+ }
+ else if (spec->flags & DF_MAX_65535) {
+ if (!nla_check_len(tb[spec->attr], sizeof(*ranges.u16)))
+ return NULL;
+
+ ranges.u16 = nla_data(tb[spec->attr]);
+ n1 = ucv_int64_new(swap ? ntohs(ranges.u16->low) : ranges.u16->low);
+ n2 = ucv_int64_new(swap ? ntohs(ranges.u16->high) : ranges.u16->high);
+ }
+ else {
+ if (!nla_check_len(tb[spec->attr], sizeof(*ranges.u32)))
+ return NULL;
+
+ ranges.u32 = nla_data(tb[spec->attr]);
+ n1 = ucv_int64_new(swap ? ntohl(ranges.u32->low) : ranges.u32->low);
+ n2 = ucv_int64_new(swap ? ntohl(ranges.u32->high) : ranges.u32->high);
+ }
+
+ arr = ucv_array_new(vm);
+
+ ucv_array_push(arr, n1);
+ ucv_array_push(arr, n2);
+
+ return arr;
+}
+
+
+#define LINK_TYPE(name) \
+ { #name, link_##name##_attrs, ARRAY_SIZE(link_##name##_attrs) }
+
+static const struct {
+ const char *name;
+ const uc_nl_attr_spec_t *attrs;
+ size_t nattrs;
+} link_types[] = {
+ LINK_TYPE(bareudp),
+ LINK_TYPE(bond),
+ LINK_TYPE(bond_slave),
+ LINK_TYPE(bridge),
+ LINK_TYPE(bridge_slave),
+ LINK_TYPE(geneve),
+ LINK_TYPE(hsr),
+ LINK_TYPE(ipoib),
+ LINK_TYPE(ipvlan),
+ LINK_TYPE(macvlan),
+ LINK_TYPE(rmnet),
+ LINK_TYPE(vlan),
+ LINK_TYPE(vrf),
+ //LINK_TYPE(vxcan),
+ LINK_TYPE(vxlan),
+ //LINK_TYPE(xdp),
+ //LINK_TYPE(xstats),
+ LINK_TYPE(gre),
+ LINK_TYPE(gretap),
+ LINK_TYPE(erspan),
+ LINK_TYPE(ip6gre),
+ LINK_TYPE(ip6gretap),
+ LINK_TYPE(ip6erspan),
+ LINK_TYPE(ip6tnl),
+ LINK_TYPE(ipip),
+ LINK_TYPE(sit),
+ LINK_TYPE(veth),
+ LINK_TYPE(vti),
+ LINK_TYPE(vti6),
+ LINK_TYPE(xfrm),
+};
+
+static bool
+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)
+{
+ const uc_nl_attr_spec_t *attrs = NULL;
+ struct nlattr *li_nla, *info_nla;
+ size_t i, nattrs = 0;
+ char *kind, *p;
+ uc_value_t *k;
+
+ k = ucv_object_get(val, "type", NULL);
+ kind = ucv_string_get(k);
+
+ if (!kind)
+ return nla_parse_error(spec, vm, val, "linkinfo does not specify kind");
+
+ li_nla = nla_nest_start(msg, spec->attr);
+
+ nla_put_string(msg, IFLA_INFO_KIND, kind);
+
+ for (i = 0; i < ARRAY_SIZE(link_types); i++) {
+ if (!strcmp(link_types[i].name, kind)) {
+ attrs = link_types[i].attrs;
+ nattrs = link_types[i].nattrs;
+ break;
+ }
+ }
+
+ p = strchr(kind, '_');
+
+ if (!p || strcmp(p, "_slave"))
+ info_nla = nla_nest_start(msg, IFLA_INFO_DATA);
+ else
+ info_nla = nla_nest_start(msg, IFLA_INFO_SLAVE_DATA);
+
+ if (!uc_nl_parse_attrs(msg, base, attrs, nattrs, vm, val))
+ return false;
+
+ nla_nest_end(msg, info_nla);
+ nla_nest_end(msg, li_nla);
+
+ return true;
+}
+
+static uc_value_t *
+uc_nl_convert_rta_linkinfo_data(uc_value_t *obj, size_t attr, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm)
+{
+ const uc_nl_attr_spec_t *attrs = NULL;
+ size_t i, nattrs = 0;
+ uc_value_t *v;
+ bool rv;
+
+ if (!tb[attr] || nla_len(tb[attr]) < 1)
+ return NULL;
+
+ v = ucv_string_new_length(nla_data(tb[attr]), nla_len(tb[attr]) - 1);
+
+ ucv_object_add(obj, "type", v);
+
+ for (i = 0; i < ARRAY_SIZE(link_types); i++) {
+ if (!strcmp(link_types[i].name, ucv_string_get(v))) {
+ attrs = link_types[i].attrs;
+ nattrs = link_types[i].nattrs;
+ break;
+ }
+ }
+
+ if (nattrs > 0) {
+ attr = (attr == IFLA_INFO_KIND) ? IFLA_INFO_DATA : IFLA_INFO_SLAVE_DATA;
+ rv = uc_nl_convert_attrs(msg, nla_data(tb[attr]), nla_len(tb[attr]), 0, attrs, nattrs, vm, obj);
+
+ if (!rv)
+ return NULL;
+ }
+
+ return obj;
+}
+
+static uc_value_t *
+uc_nl_convert_rta_linkinfo(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm)
+{
+ struct nlattr *linkinfo_tb[IFLA_INFO_MAX];
+ uc_value_t *info_obj, *slave_obj;
+
+ if (!tb[spec->attr])
+ return NULL;
+
+ nla_parse(linkinfo_tb, IFLA_INFO_MAX, nla_data(tb[spec->attr]), nla_len(tb[spec->attr]), NULL);
+
+ info_obj = ucv_object_new(vm);
+
+ if (linkinfo_tb[IFLA_INFO_KIND]) {
+ if (!uc_nl_convert_rta_linkinfo_data(info_obj, IFLA_INFO_KIND, msg, linkinfo_tb, vm)) {
+ ucv_put(info_obj);
+
+ return NULL;
+ }
+ }
+
+ if (linkinfo_tb[IFLA_INFO_SLAVE_KIND]) {
+ slave_obj = ucv_object_new(vm);
+
+ if (!uc_nl_convert_rta_linkinfo_data(slave_obj, IFLA_INFO_SLAVE_KIND, msg, linkinfo_tb, vm)) {
+ ucv_put(info_obj);
+ ucv_put(slave_obj);
+
+ return NULL;
+ }
+
+ ucv_object_add(info_obj, "slave", slave_obj);
+ }
+
+ return info_obj;
+}
+
+static uc_value_t *
+uc_nl_convert_rta_bridgeid(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm)
+{
+ char buf[sizeof("ffff.ff:ff:ff:ff:ff:ff")];
+ struct ifla_bridge_id *id;
+
+ if (!nla_check_len(tb[spec->attr], sizeof(*id)))
+ return NULL;
+
+ id = nla_data(tb[spec->attr]);
+
+ snprintf(buf, sizeof(buf), "%02x%02x.%02x:%02x:%02x:%02x:%02x:%02x",
+ id->prio[0], id->prio[1],
+ id->addr[0], id->addr[1],
+ id->addr[2], id->addr[3],
+ id->addr[4], id->addr[5]);
+
+ return ucv_string_new(buf);
+}
+
+static bool
+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)
+{
+ uc_value_t *mode, *hmac, *segs, *seg;
+ struct seg6_iptunnel_encap *tun;
+ struct sr6_tlv_hmac *tlv;
+ struct ipv6_sr_hdr *srh;
+ size_t i, nsegs, srhlen;
+ char *s;
+
+ mode = ucv_object_get(val, "mode", NULL);
+ hmac = ucv_object_get(val, "hmac", NULL);
+ segs = ucv_object_get(val, "segs", NULL);
+
+ if (mode != NULL &&
+ (ucv_type(mode) != UC_INTEGER ||
+ ucv_int64_get(mode) < 0 ||
+ ucv_int64_get(mode) > UINT32_MAX))
+ return nla_parse_error(spec, vm, val, "srh mode not an integer in range 0-4294967295");
+
+ if (hmac != NULL &&
+ (ucv_type(hmac) != UC_INTEGER ||
+ ucv_int64_get(hmac) < 0 ||
+ ucv_int64_get(hmac) > UINT32_MAX))
+ return nla_parse_error(spec, vm, val, "srh hmac not an integer in range 0-4294967295");
+
+ if (ucv_type(segs) != UC_ARRAY ||
+ ucv_array_length(segs) == 0)
+ return nla_parse_error(spec, vm, val, "srh segs array missing or empty");
+
+ nsegs = ucv_array_length(segs);
+
+ if (!mode || !ucv_int64_get(mode))
+ nsegs++;
+
+ srhlen = 8 + 16 * nsegs;
+
+ if (hmac && ucv_int64_get(hmac))
+ srhlen += 40;
+
+
+ tun = calloc(1, sizeof(*tun) + srhlen);
+
+ if (!tun)
+ return nla_parse_error(spec, vm, val, "cannot allocate srh header");
+
+ tun->mode = (int)ucv_int64_get(mode);
+
+ srh = tun->srh;
+ srh->hdrlen = (srhlen >> 3) - 1;
+ srh->type = 4;
+ srh->segments_left = nsegs - 1;
+ srh->first_segment = nsegs - 1;
+
+ if (hmac && ucv_int64_get(hmac))
+ srh->flags |= SR6_FLAG1_HMAC;
+
+ for (i = 0; i < ucv_array_length(segs); i++) {
+ seg = ucv_array_get(segs, i);
+ s = ucv_string_get(seg);
+
+ if (!s || inet_pton(AF_INET6, s, &srh->segments[--nsegs]) != 1) {
+ free(tun);
+
+ return nla_parse_error(spec, vm, val, "srh segs array contains invalid IPv6 address");
+ }
+ }
+
+ if (hmac && ucv_int64_get(hmac)) {
+ tlv = (struct sr6_tlv_hmac *)((char *)srh + srhlen - 40);
+ tlv->tlvhdr.type = SR6_TLV_HMAC;
+ tlv->tlvhdr.len = 38;
+ tlv->hmackeyid = htonl((uint32_t)ucv_int64_get(hmac));
+ }
+
+ nla_put(msg, spec->attr, sizeof(*tun) + srhlen, tun);
+ free(tun);
+
+ return true;
+}
+
+static uc_value_t *
+uc_nl_convert_rta_srh(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm)
+{
+ char buf[INET6_ADDRSTRLEN], *p, *e;
+ struct seg6_iptunnel_encap *tun;
+ uc_value_t *tun_obj, *seg_arr;
+ struct sr6_tlv_hmac *tlv;
+ size_t i;
+
+ if (!nla_check_len(tb[spec->attr], sizeof(*tun)))
+ return NULL;
+
+ tun = nla_data(tb[spec->attr]);
+ tun_obj = ucv_object_new(vm);
+
+ ucv_object_add(tun_obj, "mode", ucv_int64_new(tun->mode));
+
+ seg_arr = ucv_array_new(vm);
+
+ p = (char *)tun->srh->segments;
+ e = (char *)tun + nla_len(tb[spec->attr]);
+
+ for (i = tun->srh->first_segment + 1;
+ p + sizeof(struct in6_addr) <= e && i > 0;
+ i--, p += sizeof(struct in6_addr)) {
+ if (inet_ntop(AF_INET6, p, buf, sizeof(buf)))
+ ucv_array_push(seg_arr, ucv_string_new(buf));
+ else
+ ucv_array_push(seg_arr, NULL);
+ }
+
+ ucv_object_add(tun_obj, "segs", seg_arr);
+
+ if (sr_has_hmac(tun->srh)) {
+ i = ((tun->srh->hdrlen + 1) << 3) - 40;
+ tlv = (struct sr6_tlv_hmac *)((char *)tun->srh + i);
+
+ ucv_object_add(tun_obj, "hmac", ucv_int64_new(ntohl(tlv->hmackeyid)));
+ }
+
+ return tun_obj;
+}
+
+#define ENCAP_TYPE(name, type) \
+ { #name, LWTUNNEL_ENCAP_##type, route_encap_##name##_attrs, ARRAY_SIZE(route_encap_##name##_attrs) }
+
+static const struct {
+ const char *name;
+ uint16_t type;
+ const uc_nl_attr_spec_t *attrs;
+ size_t nattrs;
+} encap_types[] = {
+ ENCAP_TYPE(mpls, MPLS),
+ ENCAP_TYPE(ip, IP),
+ ENCAP_TYPE(ip6, IP6),
+ ENCAP_TYPE(ila, ILA),
+ //ENCAP_TYPE(bpf, BPF),
+ ENCAP_TYPE(seg6, SEG6),
+ //ENCAP_TYPE(seg6local, SEG6_LOCAL),
+ //ENCAP_TYPE(rpl, RPL),
+};
+
+static bool
+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)
+{
+ const uc_nl_attr_spec_t *attrs = NULL;
+ struct nlattr *enc_nla;
+ size_t i, nattrs = 0;
+ uint16_t ntype = 0;
+ uc_value_t *t;
+ char *type;
+
+ t = ucv_object_get(val, "type", NULL);
+ type = ucv_string_get(t);
+
+ if (!type)
+ return nla_parse_error(spec, vm, val, "encap does not specify type");
+
+ for (i = 0; i < ARRAY_SIZE(encap_types); i++) {
+ if (!strcmp(encap_types[i].name, type)) {
+ ntype = encap_types[i].type;
+ attrs = encap_types[i].attrs;
+ nattrs = encap_types[i].nattrs;
+ break;
+ }
+ }
+
+ if (!ntype)
+ return nla_parse_error(spec, vm, val, "encap specifies unknown type");
+
+ nla_put_u16(msg, RTA_ENCAP_TYPE, ntype);
+
+ enc_nla = nla_nest_start(msg, spec->attr);
+
+ if (!uc_nl_parse_attrs(msg, base, attrs, nattrs, vm, val))
+ return false;
+
+ nla_nest_end(msg, enc_nla);
+
+ return true;
+}
+
+static uc_value_t *
+uc_nl_convert_rta_encap(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm)
+{
+ const uc_nl_attr_spec_t *attrs = NULL;
+ const char *name = NULL;
+ uc_value_t *encap_obj;
+ size_t i, nattrs = 0;
+ bool rv;
+
+ if (!tb[spec->attr] ||
+ !nla_check_len(tb[RTA_ENCAP_TYPE], sizeof(uint16_t)))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(encap_types); i++) {
+ if (encap_types[i].type != nla_get_u16(tb[RTA_ENCAP_TYPE]))
+ continue;
+
+ name = encap_types[i].name;
+ attrs = encap_types[i].attrs;
+ nattrs = encap_types[i].nattrs;
+
+ break;
+ }
+
+ if (!name)
+ return NULL;
+
+ encap_obj = ucv_object_new(vm);
+
+ rv = uc_nl_convert_attrs(msg,
+ nla_data(tb[spec->attr]), nla_len(tb[spec->attr]), 0,
+ attrs, nattrs, vm, encap_obj);
+
+ if (!rv) {
+ ucv_put(encap_obj);
+
+ return NULL;
+ }
+
+ ucv_object_add(encap_obj, "type", ucv_string_new(name));
+
+ return encap_obj;
+}
+
+#define IPOPTS_TYPE(name, type, multiple) \
+ { #name, LWTUNNEL_IP_OPTS_##type, multiple, lwtipopt_##name##_attrs, ARRAY_SIZE(lwtipopt_##name##_attrs) }
+
+static const struct {
+ const char *name;
+ uint16_t type;
+ bool multiple;
+ const uc_nl_attr_spec_t *attrs;
+ size_t nattrs;
+} lwtipopt_types[] = {
+ IPOPTS_TYPE(erspan, ERSPAN, false),
+ IPOPTS_TYPE(geneve, GENEVE, true),
+ IPOPTS_TYPE(vxlan, VXLAN, false),
+};
+
+static bool
+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)
+{
+ const uc_nl_attr_spec_t *attrs = NULL;
+ struct nlattr *opt_nla, *type_nla;
+ bool exists, multiple = false;
+ size_t i, j, nattrs = 0;
+ uint16_t ntype = 0;
+ uc_value_t *item;
+
+ ucv_object_foreach(val, type, v) {
+ for (i = 0; i < ARRAY_SIZE(lwtipopt_types); i++) {
+ if (!strcmp(lwtipopt_types[i].name, type)) {
+ val = v;
+ ntype = lwtipopt_types[i].type;
+ attrs = lwtipopt_types[i].attrs;
+ nattrs = lwtipopt_types[i].nattrs;
+ multiple = lwtipopt_types[i].multiple;
+ break;
+ }
+ }
+ }
+
+ if (!ntype)
+ return nla_parse_error(spec, vm, val, "unknown IP options type specified");
+
+ opt_nla = nla_nest_start(msg, spec->attr);
+
+ j = 0;
+ item = (ucv_type(val) == UC_ARRAY) ? ucv_array_get(val, j++) : val;
+
+ while (true) {
+ type_nla = nla_nest_start(msg, ntype);
+
+ for (i = 0; i < nattrs; i++) {
+ v = ucv_object_get(item, attrs[i].key, &exists);
+
+ if (!exists)
+ continue;
+
+ if (!uc_nl_parse_attr(&attrs[i], msg, nla_data(type_nla), vm, v, 0))
+ return false;
+ }
+
+ nla_nest_end(msg, type_nla);
+
+ if (!multiple || ucv_type(val) != UC_ARRAY || j >= ucv_array_length(val))
+ break;
+
+ item = ucv_array_get(val, j++);
+ }
+
+ nla_nest_end(msg, opt_nla);
+
+ return true;
+}
+
+static uc_value_t *
+uc_nl_convert_rta_ipopts(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm)
+{
+ struct nlattr *opt_tb[LWTUNNEL_IP_OPTS_MAX + 1];
+ const uc_nl_attr_spec_t *attrs = NULL;
+ uc_value_t *opt_obj, *type_obj;
+ const char *name = NULL;
+ size_t i, nattrs = 0;
+ uint16_t type = 0;
+ bool rv;
+
+ if (!tb[spec->attr] ||
+ !nla_parse(opt_tb, LWTUNNEL_IP_OPTS_MAX, nla_data(tb[spec->attr]), nla_len(tb[spec->attr]), NULL))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(lwtipopt_types); i++) {
+ if (!opt_tb[lwtipopt_types[i].type])
+ continue;
+
+ type = lwtipopt_types[i].type;
+ name = lwtipopt_types[i].name;
+ attrs = lwtipopt_types[i].attrs;
+ nattrs = lwtipopt_types[i].nattrs;
+
+ break;
+ }
+
+ if (!name)
+ return NULL;
+
+ type_obj = ucv_object_new(vm);
+
+ rv = uc_nl_convert_attrs(msg,
+ nla_data(opt_tb[type]), nla_len(opt_tb[type]), 0,
+ attrs, nattrs, vm, type_obj);
+
+ if (!rv) {
+ ucv_put(type_obj);
+
+ return NULL;
+ }
+
+ opt_obj = ucv_object_new(vm);
+
+ ucv_object_add(opt_obj, name, type_obj);
+
+ return opt_obj;
+}
+
+static bool
+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)
+{
+ uint32_t u32;
+
+ if (!uc_nl_parse_u32(val, &u32))
+ return nla_parse_error(spec, vm, val, "not an integer or out of range 0-4294967295");
+
+ if (spec->flags & DF_MAX_255) {
+ if (u32 <= 255) {
+ uc_nl_put_struct_member_u8(base, spec->auxdata, u32);
+
+ return true;
+ }
+
+ uc_nl_put_struct_member_u8(base, spec->auxdata, 0);
+ }
+ else if (spec->flags & DF_MAX_65535) {
+ if (u32 <= 65535) {
+ uc_nl_put_struct_member_u16(base, spec->auxdata,
+ (spec->flags & DF_BYTESWAP) ? htons((uint16_t)u32) : (uint16_t)u32);
+
+ return true;
+ }
+
+ uc_nl_put_struct_member_u16(base, spec->auxdata, 0);
+ }
+ else if (spec->flags & DF_MAX_16777215) {
+ if (u32 <= 16777215) {
+ uc_nl_put_struct_member_u32(base, spec->auxdata,
+ (spec->flags & DF_BYTESWAP) ? htonl(u32) : u32);
+
+ return true;
+ }
+
+ uc_nl_put_struct_member_u32(base, spec->auxdata, 0);
+ }
+
+ nla_put_u32(msg, spec->attr,
+ (spec->flags & DF_BYTESWAP) ? htonl(u32) : u32);
+
+ return true;
+}
+
+static uc_value_t *
+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)
+{
+ uint32_t u32 = 0;
+
+ if (nla_check_len(tb[spec->attr], sizeof(uint32_t))) {
+ if (spec->flags & DF_BYTESWAP)
+ u32 = ntohl(nla_get_u32(tb[spec->attr]));
+ else
+ u32 = nla_get_u32(tb[spec->attr]);
+ }
+ else if (spec->flags & DF_MAX_255) {
+ u32 = uc_nl_get_struct_member_u8(base, spec->auxdata);
+ }
+ else if (spec->flags & DF_MAX_65535) {
+ if (spec->flags & DF_BYTESWAP)
+ u32 = ntohs(uc_nl_get_struct_member_u16(base, spec->auxdata));
+ else
+ u32 = uc_nl_get_struct_member_u16(base, spec->auxdata);
+ }
+ else if (spec->flags & DF_MAX_16777215) {
+ if (spec->flags & DF_BYTESWAP)
+ u32 = ntohl(uc_nl_get_struct_member_u32(base, spec->auxdata));
+ else
+ u32 = uc_nl_get_struct_member_u32(base, spec->auxdata);
+ }
+ else {
+ return NULL;
+ }
+
+ return ucv_uint64_new(u32);
+}
+
+static bool
+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)
+{
+ const uc_nl_nested_spec_t *nest = spec->auxdata;
+ struct nlattr *nested_nla;
+
+ nested_nla = nla_reserve(msg, spec->attr, nest->headsize);
+
+ if (!uc_nl_parse_attrs(msg, nla_data(nested_nla), nest->attrs, nest->nattrs, vm, val))
+ return false;
+
+ nla_nest_end(msg, nested_nla);
+
+ return true;
+}
+
+static uc_value_t *
+uc_nl_convert_rta_nested(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm)
+{
+ const uc_nl_nested_spec_t *nest = spec->auxdata;
+ uc_value_t *nested_obj;
+ bool rv;
+
+ nested_obj = ucv_object_new(vm);
+
+ rv = uc_nl_convert_attrs(msg,
+ nla_data(tb[spec->attr]), nla_len(tb[spec->attr]), nest->headsize,
+ nest->attrs, nest->nattrs,
+ vm, nested_obj);
+
+ if (!rv) {
+ ucv_put(nested_obj);
+
+ return NULL;
+ }
+
+ return nested_obj;
+}
+
+
+static bool
+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)
+{
+ uc_nl_cidr_t cidr = { 0 };
+ struct ether_addr *ea;
+ struct rtgenmsg *rtg;
+ uint64_t u64;
+ uint32_t u32;
+ uint16_t u16;
+ size_t attr;
+ char *s;
+
+ if (spec->flags & DF_MULTIPLE)
+ attr = idx;
+ else
+ attr = spec->attr;
+
+ switch (spec->type) {
+ case DT_U8:
+ if (!uc_nl_parse_u32(val, &u32) || u32 > 255)
+ return nla_parse_error(spec, vm, val, "not an integer or out of range 0-255");
+
+ if ((spec->flags & DF_MAX_1) && u32 > 1)
+ return nla_parse_error(spec, vm, val, "integer must be 0 or 1");
+
+ if (spec->attr == 0)
+ uc_nl_put_struct_member_u8(base, spec->auxdata, u32);
+ else
+ nla_put_u8(msg, attr, u32);
+
+ break;
+
+ case DT_U16:
+ if (!uc_nl_parse_u32(val, &u32) || u32 > 65535)
+ return nla_parse_error(spec, vm, val, "not an integer or out of range 0-65535");
+
+ u16 = (uint16_t)u32;
+
+ if (spec->flags & DF_BYTESWAP)
+ u16 = htons(u16);
+
+ if ((spec->flags & DF_MAX_1) && u32 > 1)
+ return nla_parse_error(spec, vm, val, "integer must be 0 or 1");
+ else if ((spec->flags & DF_MAX_255) && u32 > 255)
+ return nla_parse_error(spec, vm, val, "integer out of range 0-255");
+
+ if (spec->attr == 0)
+ uc_nl_put_struct_member_u16(base, spec->auxdata, u16);
+ else
+ nla_put_u16(msg, attr, u16);
+
+ break;
+
+ case DT_S32:
+ case DT_U32:
+ if (spec->type == DT_S32 && !uc_nl_parse_s32(val, &u32))
+ return nla_parse_error(spec, vm, val, "not an integer or out of range -2147483648-2147483647");
+ else if (spec->type == DT_U32 && !uc_nl_parse_u32(val, &u32))
+ return nla_parse_error(spec, vm, val, "not an integer or out of range 0-4294967295");
+
+ if (spec->flags & DF_BYTESWAP)
+ u32 = htonl(u32);
+
+ if ((spec->flags & DF_MAX_1) && u32 > 1)
+ return nla_parse_error(spec, vm, val, "integer must be 0 or 1");
+ else if ((spec->flags & DF_MAX_255) && u32 > 255)
+ return nla_parse_error(spec, vm, val, "integer out of range 0-255");
+ else if ((spec->flags & DF_MAX_65535) && u32 > 65535)
+ return nla_parse_error(spec, vm, val, "integer out of range 0-65535");
+ else if ((spec->flags & DF_MAX_16777215) && u32 > 16777215)
+ return nla_parse_error(spec, vm, val, "integer out of range 0-16777215");
+
+ if (spec->attr == 0)
+ uc_nl_put_struct_member_u32(base, spec->auxdata, u32);
+ else
+ nla_put_u32(msg, attr, u32);
+
+ break;
+
+ case DT_U64:
+ assert(spec->attr != 0);
+
+ if (!uc_nl_parse_u64(val, &u64))
+ return nla_parse_error(spec, vm, val, "not an integer or negative");
+
+ if (spec->flags & DF_BYTESWAP)
+ u64 = htobe64(u64);
+
+ nla_put_u64(msg, attr, u64);
+ break;
+
+ case DT_BOOL:
+ u32 = (uint32_t)ucv_is_truish(val);
+
+ if (spec->attr == 0)
+ uc_nl_put_struct_member_u8(base, spec->auxdata, u32);
+ else
+ nla_put_u8(msg, attr, u32);
+
+ break;
+
+ case DT_FLAG:
+ u32 = (uint32_t)ucv_is_truish(val);
+
+ if (spec->attr == 0)
+ uc_nl_put_struct_member_u8(base, spec->auxdata, u32);
+ else if (u32 == 1)
+ nla_put_flag(msg, attr);
+
+ break;
+
+ case DT_STRING:
+ assert(spec->attr != 0);
+
+ s = ucv_to_string(vm, val);
+
+ if (!s)
+ return nla_parse_error(spec, vm, val, "out of memory");
+
+ nla_put_string(msg, attr, s);
+ free(s);
+
+ break;
+
+ case DT_NETDEV:
+ if (ucv_type(val) == UC_INTEGER) {
+ if (ucv_int64_get(val) < 0 ||
+ ucv_int64_get(val) > UINT32_MAX)
+ return nla_parse_error(spec, vm, val, "interface index out of range 0-4294967295");
+
+ u32 = (uint32_t)ucv_int64_get(val);
+ }
+ else {
+ s = ucv_to_string(vm, val);
+
+ if (!s)
+ return nla_parse_error(spec, vm, val, "out of memory");
+
+ u32 = if_nametoindex(s);
+
+ free(s);
+ }
+
+ if (u32 == 0 && !(spec->flags & DF_ALLOW_NONE))
+ return nla_parse_error(spec, vm, val, "interface not found");
+
+ if (spec->attr == 0)
+ uc_nl_put_struct_member_u32(base, spec->auxdata, u32);
+ else
+ nla_put_u32(msg, attr, u32);
+
+ break;
+
+ case DT_LLADDR:
+ assert(spec->attr != 0);
+
+ s = ucv_to_string(vm, val);
+
+ if (!s)
+ return nla_parse_error(spec, vm, val, "out of memory");
+
+ ea = ether_aton(s);
+
+ free(s);
+
+ if (!ea)
+ return nla_parse_error(spec, vm, val, "invalid MAC address");
+
+ nla_put(msg, attr, sizeof(*ea), ea);
+
+ break;
+
+ case DT_U64ADDR:
+ assert(spec->attr != 0);
+
+ if (ucv_type(val) == UC_INTEGER) {
+ u64 = ucv_uint64_get(val);
+ }
+ else {
+ s = ucv_to_string(vm, val);
+
+ if (!s)
+ return nla_parse_error(spec, vm, val, "out of memory");
+
+ u16 = addr64_pton(s, &u64);
+
+ free(s);
+
+ if (u16 != 1)
+ return nla_parse_error(spec, vm, val, "invalid address");
+ }
+
+ nla_put_u64(msg, attr, u64);
+
+ break;
+
+ case DT_INADDR:
+ case DT_IN6ADDR:
+ case DT_MPLSADDR:
+ case DT_ANYADDR:
+ assert(spec->attr != 0);
+
+ rtg = nlmsg_data(nlmsg_hdr(msg));
+
+ if (!uc_nl_parse_cidr(vm, val, &cidr))
+ return nla_parse_error(spec, vm, val, "invalid IP address");
+
+ if ((spec->type == DT_INADDR && cidr.family != AF_INET) ||
+ (spec->type == DT_IN6ADDR && cidr.family != AF_INET6) ||
+ (spec->type == DT_MPLSADDR && cidr.family != AF_MPLS))
+ return nla_parse_error(spec, vm, val, "wrong address family");
+
+ if (spec->flags & DF_STORE_MASK)
+ uc_nl_put_struct_member_u8(base, spec->auxdata, cidr.mask);
+ else if (cidr.mask != cidr.bitlen)
+ return nla_parse_error(spec, vm, val, "address range given but single address expected");
+
+ nla_put(msg, attr, cidr.alen, &cidr.addr.in6);
+
+ if ((rtg->rtgen_family == AF_UNSPEC) && (spec->flags & DF_FAMILY_HINT))
+ rtg->rtgen_family = cidr.family;
+
+ break;
+
+ case DT_MULTIPATH:
+ if (!uc_nl_parse_rta_multipath(spec, msg, base, vm, val))
+ return nla_parse_error(spec, vm, val, "invalid nexthop data");
+
+ break;
+
+ case DT_NUMRANGE:
+ if (!uc_nl_parse_rta_numrange(spec, msg, base, vm, val))
+ return false;
+
+ break;
+
+ case DT_FLAGS:
+ if (ucv_array_length(val) == 2) {
+ if (ucv_type(ucv_array_get(val, 0)) != UC_INTEGER ||
+ ucv_type(ucv_array_get(val, 1)) != UC_INTEGER)
+ return nla_parse_error(spec, vm, val, "flag or mask value not an integer");
+
+ if (!uc_nl_parse_u32(ucv_array_get(val, 0), &u32))
+ return nla_parse_error(spec, vm, val, "flag value not an integer or out of range 0-4294967295");
+
+ memcpy(&u64, &u32, sizeof(u32));
+
+ if (!uc_nl_parse_u32(ucv_array_get(val, 1), &u32))
+ return nla_parse_error(spec, vm, val, "mask value not an integer or out of range 0-4294967295");
+
+ memcpy((char *)&u64 + sizeof(u32), &u32, sizeof(u32));
+ }
+ else if (ucv_type(val) == UC_INTEGER) {
+ if (!uc_nl_parse_u32(val, &u32))
+ return nla_parse_error(spec, vm, val, "flag value not an integer or out of range 0-4294967295");
+
+ memcpy(&u64, &u32, sizeof(u32));
+ memset((char *)&u64 + sizeof(u32), 0xff, sizeof(u32));
+ }
+ else {
+ return nla_parse_error(spec, vm, val, "value neither an array of flags, mask nor an integer");
+ }
+
+ if (spec->attr == 0)
+ uc_nl_put_struct_member(base, spec->auxdata, sizeof(u64), &u64);
+ else
+ nla_put_u64(msg, attr, u64);
+
+ break;
+
+ case DT_LINKINFO:
+ if (!uc_nl_parse_rta_linkinfo(spec, msg, base, vm, val))
+ return false;
+
+ break;
+
+ case DT_SRH:
+ if (!uc_nl_parse_rta_srh(spec, msg, base, vm, val))
+ return false;
+
+ break;
+
+ case DT_ENCAP:
+ if (!uc_nl_parse_rta_encap(spec, msg, base, vm, val))
+ return false;
+
+ break;
+
+ case DT_IPOPTS:
+ if (!uc_nl_parse_rta_ipopts(spec, msg, base, vm, val))
+ return false;
+
+ break;
+
+ case DT_U32_OR_MEMBER:
+ if (!uc_nl_parse_rta_u32_or_member(spec, msg, base, vm, val))
+ return false;
+
+ break;
+
+ case DT_NESTED:
+ if (!uc_nl_parse_rta_nested(spec, msg, base, vm, val))
+ return false;
+
+ break;
+
+ default:
+ assert(0);
+ }
+
+ return true;
+}
+
+static uc_value_t *
+uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr **tb, uc_vm_t *vm)
+{
+ union { uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; size_t sz; } t = { 0 };
+ struct { uint32_t flags; uint32_t mask; } flags;
+ char buf[sizeof(struct mpls_label) * 16];
+ struct nlmsghdr *hdr = nlmsg_hdr(msg);
+ struct rtgenmsg *rtg = nlmsg_data(hdr);
+ struct ether_addr *ea;
+ uc_value_t *v;
+ char *s;
+
+ switch (spec->type) {
+ case DT_U8:
+ if (spec->attr == 0)
+ t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata);
+ else if (nla_check_len(tb[spec->attr], sizeof(t.u8)))
+ t.u8 = nla_get_u8(tb[spec->attr]);
+
+ return ucv_uint64_new(t.u8);
+
+ case DT_U16:
+ if (spec->attr == 0)
+ t.u16 = uc_nl_get_struct_member_u16(base, spec->auxdata);
+ else if (nla_check_len(tb[spec->attr], sizeof(t.u16)))
+ t.u16 = nla_get_u16(tb[spec->attr]);
+
+ if (spec->flags & DF_BYTESWAP)
+ t.u16 = ntohs(t.u16);
+
+ return ucv_uint64_new(t.u16);
+
+ case DT_U32:
+ case DT_S32:
+ if (spec->attr == 0)
+ t.u32 = uc_nl_get_struct_member_u32(base, spec->auxdata);
+ else if (nla_check_len(tb[spec->attr], sizeof(t.u32)))
+ t.u32 = nla_get_u32(tb[spec->attr]);
+
+ if (spec->flags & DF_BYTESWAP)
+ t.u32 = ntohl(t.u32);
+
+ if (spec->type == DT_S32)
+ return ucv_int64_new((int32_t)t.u32);
+
+ return ucv_uint64_new(t.u32);
+
+ case DT_U64:
+ if (spec->attr == 0)
+ t.u64 = uc_nl_get_struct_member_u64(base, spec->auxdata);
+ else if (nla_check_len(tb[spec->attr], sizeof(t.u64)))
+ memcpy(&t.u64, nla_data(tb[spec->attr]), sizeof(t.u64));
+
+ return ucv_uint64_new(t.u64);
+
+ case DT_BOOL:
+ if (spec->attr == 0)
+ t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata);
+ else if (nla_check_len(tb[spec->attr], sizeof(t.u8)))
+ t.u8 = nla_get_u8(tb[spec->attr]);
+
+ return ucv_boolean_new(t.u8 != 0);
+
+ case DT_FLAG:
+ if (spec->attr == 0)
+ t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata);
+ else if (tb[spec->attr] != NULL)
+ t.u8 = 1;
+
+ return ucv_boolean_new(t.u8 != 0);
+
+ case DT_STRING:
+ assert(spec->attr != 0);
+
+ if (!nla_check_len(tb[spec->attr], 1))
+ return NULL;
+
+ return ucv_string_new_length(
+ nla_data(tb[spec->attr]), nla_len(tb[spec->attr]) - 1);
+
+ case DT_NETDEV:
+ if (spec->attr == 0)
+ t.u32 = uc_nl_get_struct_member_u32(base, spec->auxdata);
+ else if (nla_check_len(tb[spec->attr], sizeof(t.u32)))
+ t.u32 = nla_get_u32(tb[spec->attr]);
+
+ if (if_indextoname(t.u32, buf))
+ return ucv_string_new(buf);
+ else if (spec->flags & DF_ALLOW_NONE)
+ return ucv_int64_new(0);
+
+ return NULL;
+
+ case DT_LLADDR:
+ assert(spec->attr != 0);
+
+ if (!nla_check_len(tb[spec->attr], sizeof(*ea)))
+ return NULL;
+
+ ea = nla_data(tb[spec->attr]);
+
+ snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
+ ea->ether_addr_octet[0], ea->ether_addr_octet[1],
+ ea->ether_addr_octet[2], ea->ether_addr_octet[3],
+ ea->ether_addr_octet[4], ea->ether_addr_octet[5]);
+
+ return ucv_string_new(buf);
+
+ case DT_U64ADDR:
+ assert(spec->attr != 0);
+
+ if (!nla_check_len(tb[spec->attr], sizeof(uint64_t)) ||
+ !addr64_ntop(nla_data(tb[spec->attr]), buf, sizeof(buf)))
+ return NULL;
+
+ return ucv_string_new(buf);
+
+ case DT_INADDR:
+ case DT_IN6ADDR:
+ case DT_MPLSADDR:
+ case DT_ANYADDR:
+ assert(spec->attr != 0);
+
+ t.sz = (size_t)nla_len(tb[spec->attr]);
+
+ switch (spec->type) {
+ case DT_INADDR:
+ if (t.sz < sizeof(struct in_addr) ||
+ !inet_ntop(AF_INET, nla_data(tb[spec->attr]), buf, sizeof(buf)))
+ return NULL;
+
+ break;
+
+ case DT_IN6ADDR:
+ if (t.sz < sizeof(struct in6_addr) ||
+ !inet_ntop(AF_INET6, nla_data(tb[spec->attr]), buf, sizeof(buf)))
+ return NULL;
+
+ break;
+
+ case DT_MPLSADDR:
+ if (t.sz < sizeof(struct mpls_label) ||
+ !mpls_ntop(nla_data(tb[spec->attr]), t.sz, buf, sizeof(buf)))
+ return NULL;
+
+ break;
+
+ default:
+ switch (rtg->rtgen_family) {
+ case AF_MPLS:
+ if (t.sz < sizeof(struct mpls_label) ||
+ !mpls_ntop(nla_data(tb[spec->attr]), t.sz, buf, sizeof(buf)))
+ return NULL;
+
+ break;
+
+ case AF_INET6:
+ if (t.sz < sizeof(struct in6_addr) ||
+ !inet_ntop(AF_INET6, nla_data(tb[spec->attr]), buf, sizeof(buf)))
+ return NULL;
+
+ break;
+
+ case AF_INET:
+ if (t.sz < sizeof(struct in_addr) ||
+ !inet_ntop(AF_INET, nla_data(tb[spec->attr]), buf, sizeof(buf)))
+ return NULL;
+
+ break;
+
+ default:
+ return NULL;
+ }
+
+ break;
+ }
+
+ if (spec->flags & DF_STORE_MASK) {
+ s = buf + strlen(buf);
+ snprintf(s, buf + sizeof(buf) - s, "/%hhu",
+ uc_nl_get_struct_member_u8(base, spec->auxdata));
+ }
+
+ return ucv_string_new(buf);
+
+ case DT_MULTIPATH:
+ return uc_nl_convert_rta_multipath(spec, msg, tb, vm);
+
+ case DT_NUMRANGE:
+ return uc_nl_convert_rta_numrange(spec, msg, tb, vm);
+
+ case DT_FLAGS:
+ if (spec->attr == 0)
+ uc_nl_get_struct_member(base, spec->auxdata, sizeof(flags), &flags);
+ else if (nla_check_len(tb[spec->attr], sizeof(flags)))
+ memcpy(&flags, nla_data(tb[spec->attr]), sizeof(flags));
+ else
+ return NULL;
+
+ if (flags.mask == 0)
+ return ucv_uint64_new(flags.flags);
+
+ v = ucv_array_new(vm);
+
+ ucv_array_push(v, ucv_uint64_new(flags.flags));
+ ucv_array_push(v, ucv_uint64_new(flags.mask));
+
+ return v;
+
+ case DT_LINKINFO:
+ return uc_nl_convert_rta_linkinfo(spec, msg, tb, vm);
+
+ case DT_BRIDGEID:
+ return uc_nl_convert_rta_bridgeid(spec, msg, tb, vm);
+
+ case DT_SRH:
+ return uc_nl_convert_rta_srh(spec, msg, tb, vm);
+
+ case DT_ENCAP:
+ return uc_nl_convert_rta_encap(spec, msg, tb, vm);
+
+ case DT_IPOPTS:
+ return uc_nl_convert_rta_ipopts(spec, msg, tb, vm);
+
+ case DT_U32_OR_MEMBER:
+ return uc_nl_convert_rta_u32_or_member(spec, msg, base, tb, vm);
+
+ case DT_NESTED:
+ return uc_nl_convert_rta_nested(spec, msg, tb, vm);
+
+ default:
+ assert(0);
+ }
+
+ return NULL;
+}
+
+
+static struct nl_sock *sock = NULL;
+
+typedef enum {
+ STATE_UNREPLIED,
+ STATE_CONTINUE,
+ STATE_REPLIED,
+ STATE_ERROR
+} reply_state_t;
+
+typedef struct {
+ reply_state_t state;
+ uc_vm_t *vm;
+ uc_value_t *res;
+ int family;
+ const uc_nl_nested_spec_t *spec;
+} request_state_t;
+
+
+static uc_value_t *
+uc_nl_error(uc_vm_t *vm, size_t nargs)
+{
+ uc_stringbuf_t *buf;
+ const char *s;
+
+ if (last_error.code == 0)
+ return NULL;
+
+ buf = ucv_stringbuf_new();
+
+ if (last_error.code == NLE_FAILURE && last_error.msg) {
+ ucv_stringbuf_addstr(buf, last_error.msg, strlen(last_error.msg));
+ }
+ else {
+ s = nl_geterror(last_error.code);
+
+ ucv_stringbuf_addstr(buf, s, strlen(s));
+
+ if (last_error.msg)
+ ucv_stringbuf_printf(buf, ": %s", last_error.msg);
+ }
+
+ set_error(0, NULL);
+
+ return ucv_stringbuf_finish(buf);
+}
+
+/*
+ * route functions
+ */
+
+static int
+cb_done(struct nl_msg *msg, void *arg)
+{
+ request_state_t *s = arg;
+
+ s->state = STATE_REPLIED;
+
+ return NL_STOP;
+}
+
+static int
+cb_error(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
+{
+ request_state_t *s = arg;
+ int errnum = err->error;
+
+ set_error(NLE_FAILURE, "RTNETLINK answers: %s",
+ strerror(errnum < 0 ? -errnum : errnum));
+
+ s->state = STATE_ERROR;
+
+ return NL_STOP;
+}
+
+static int
+cb_reply(struct nl_msg *msg, void *arg)
+{
+ struct nlmsghdr *hdr = nlmsg_hdr(msg);
+ request_state_t *s = arg;
+ uc_value_t *o;
+ bool rv;
+
+ if (RTM_FAM(hdr->nlmsg_type) != s->family)
+ return NL_SKIP;
+
+ if (s->spec) {
+ if (nlmsg_attrlen(hdr, 0) < (ssize_t)s->spec->headsize)
+ return NL_SKIP;
+
+ o = ucv_object_new(s->vm);
+
+ rv = uc_nl_convert_attrs(msg,
+ nlmsg_attrdata(hdr, 0),
+ nlmsg_attrlen(hdr, 0),
+ s->spec->headsize,
+ s->spec->attrs, s->spec->nattrs, s->vm, o);
+
+ if (rv) {
+ if (hdr->nlmsg_flags & NLM_F_MULTI) {
+ if (!s->res)
+ s->res = ucv_array_new(s->vm);
+
+ ucv_array_push(s->res, o);
+ }
+ else {
+ s->res = o;
+ }
+ }
+ else {
+ ucv_put(o);
+ }
+ }
+
+ if (hdr->nlmsg_flags & NLM_F_MULTI)
+ s->state = STATE_CONTINUE;
+ else
+ s->state = STATE_REPLIED;
+
+ return NL_SKIP;
+}
+
+
+static const struct {
+ int family;
+ const uc_nl_nested_spec_t *spec;
+} rtm_families[] = {
+ { RTM_FAM(RTM_GETLINK), &link_msg },
+ { RTM_FAM(RTM_GETROUTE), &route_msg },
+ { RTM_FAM(RTM_GETNEIGH), &neigh_msg },
+ { RTM_FAM(RTM_GETADDR), &addr_msg },
+ { RTM_FAM(RTM_GETRULE), &rule_msg },
+ { RTM_FAM(RTM_GETADDRLABEL), &addrlabel_msg },
+ { RTM_FAM(RTM_GETNEIGHTBL), &neightbl_msg },
+ { RTM_FAM(RTM_GETNETCONF), &netconf_msg },
+};
+
+static uc_value_t *
+uc_nl_request(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *cmd = uc_fn_arg(0);
+ uc_value_t *flags = uc_fn_arg(1);
+ uc_value_t *payload = uc_fn_arg(2);
+ request_state_t st = { .vm = vm };
+ uint16_t flagval = 0;
+ int enable = 1, err;
+ struct nl_msg *msg;
+ struct nl_cb *cb;
+ size_t i;
+
+ if (ucv_type(cmd) != UC_INTEGER || ucv_int64_get(cmd) < 0 ||
+ (flags != NULL && ucv_type(flags) != UC_INTEGER) ||
+ (payload != NULL && ucv_type(payload) != UC_OBJECT))
+ err_return(NLE_INVAL, NULL);
+
+ if (flags) {
+ if (ucv_int64_get(flags) < 0 || ucv_int64_get(flags) > 0xffff)
+ err_return(NLE_INVAL, NULL);
+ else
+ flagval = (uint16_t)ucv_int64_get(flags);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(rtm_families); i++) {
+ if (rtm_families[i].family == RTM_FAM(ucv_int64_get(cmd))) {
+ st.spec = rtm_families[i].spec;
+ st.family = rtm_families[i].family;
+ break;
+ }
+ }
+
+ if (!sock) {
+ sock = nl_socket_alloc();
+
+ if (!sock)
+ err_return(NLE_NOMEM, NULL);
+
+ err = nl_connect(sock, NETLINK_ROUTE);
+
+ if (err != 0)
+ err_return(err, NULL);
+
+ if (flagval & NLM_F_STRICT_CHK) {
+ if (setsockopt(sock->s_fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &enable, sizeof(enable)) < 0)
+ err_return(nl_syserr2nlerr(errno), "Unable to enable NETLINK_GET_STRICT_CHK");
+
+ flagval &= ~NLM_F_STRICT_CHK;
+ }
+ }
+
+ msg = nlmsg_alloc_simple(ucv_int64_get(cmd), NLM_F_REQUEST | flagval);
+
+ if (!msg)
+ err_return(NLE_NOMEM, NULL);
+
+ if (st.spec) {
+ nlmsg_reserve(msg, st.spec->headsize, 0);
+
+ if (!uc_nl_parse_attrs(msg, NLMSG_DATA(nlmsg_hdr(msg)), st.spec->attrs, st.spec->nattrs, vm, payload)) {
+ nlmsg_free(msg);
+
+ return NULL;
+ }
+ }
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+
+ if (!cb) {
+ nlmsg_free(msg);
+ err_return(NLE_NOMEM, NULL);
+ }
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_reply, &st);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &st);
+ nl_cb_err(cb, NL_CB_CUSTOM, cb_error, &st);
+
+ nl_send_auto_complete(sock, msg);
+
+ do {
+ err = nl_recvmsgs(sock, cb);
+
+ if (err && st.state != STATE_ERROR) {
+ set_error(err, NULL);
+
+ st.state = STATE_ERROR;
+ }
+ }
+ while (st.state == STATE_CONTINUE);
+
+ nlmsg_free(msg);
+ nl_cb_put(cb);
+
+ switch (st.state) {
+ case STATE_REPLIED:
+ return st.res;
+
+ case STATE_UNREPLIED:
+ return ucv_boolean_new(true);
+
+ case STATE_ERROR:
+ return ucv_boolean_new(false);
+
+ default:
+ set_error(NLE_FAILURE, "Interrupted reply");
+
+ return ucv_boolean_new(false);
+ }
+}
+
+
+static void
+register_constants(uc_vm_t *vm, uc_value_t *scope)
+{
+ uc_value_t *c = ucv_object_new(vm);
+
+#define ADD_CONST(x) ucv_object_add(c, #x, ucv_int64_new(x))
+
+ ADD_CONST(NLM_F_ACK);
+ ADD_CONST(NLM_F_ACK_TLVS);
+ ADD_CONST(NLM_F_APPEND);
+ ADD_CONST(NLM_F_ATOMIC);
+ ADD_CONST(NLM_F_CAPPED);
+ ADD_CONST(NLM_F_CREATE);
+ ADD_CONST(NLM_F_DUMP);
+ ADD_CONST(NLM_F_DUMP_FILTERED);
+ ADD_CONST(NLM_F_DUMP_INTR);
+ ADD_CONST(NLM_F_ECHO);
+ ADD_CONST(NLM_F_EXCL);
+ ADD_CONST(NLM_F_MATCH);
+ ADD_CONST(NLM_F_MULTI);
+ ADD_CONST(NLM_F_NONREC);
+ ADD_CONST(NLM_F_REPLACE);
+ ADD_CONST(NLM_F_REQUEST);
+ ADD_CONST(NLM_F_ROOT);
+ ADD_CONST(NLM_F_STRICT_CHK); /* custom */
+
+ ADD_CONST(IN6_ADDR_GEN_MODE_EUI64);
+ ADD_CONST(IN6_ADDR_GEN_MODE_NONE);
+ ADD_CONST(IN6_ADDR_GEN_MODE_STABLE_PRIVACY);
+ ADD_CONST(IN6_ADDR_GEN_MODE_RANDOM);
+
+ ADD_CONST(BRIDGE_MODE_UNSPEC);
+ ADD_CONST(BRIDGE_MODE_HAIRPIN);
+
+ ADD_CONST(MACVLAN_MODE_PRIVATE);
+ ADD_CONST(MACVLAN_MODE_VEPA);
+ ADD_CONST(MACVLAN_MODE_BRIDGE);
+ ADD_CONST(MACVLAN_MODE_PASSTHRU);
+ ADD_CONST(MACVLAN_MODE_SOURCE);
+
+ ADD_CONST(MACVLAN_MACADDR_ADD);
+ ADD_CONST(MACVLAN_MACADDR_DEL);
+ ADD_CONST(MACVLAN_MACADDR_FLUSH);
+ ADD_CONST(MACVLAN_MACADDR_SET);
+
+ ADD_CONST(MACSEC_VALIDATE_DISABLED);
+ ADD_CONST(MACSEC_VALIDATE_CHECK);
+ ADD_CONST(MACSEC_VALIDATE_STRICT);
+ ADD_CONST(MACSEC_VALIDATE_MAX);
+
+ ADD_CONST(MACSEC_OFFLOAD_OFF);
+ ADD_CONST(MACSEC_OFFLOAD_PHY);
+ ADD_CONST(MACSEC_OFFLOAD_MAC);
+ ADD_CONST(MACSEC_OFFLOAD_MAX);
+
+ ADD_CONST(IPVLAN_MODE_L2);
+ ADD_CONST(IPVLAN_MODE_L3);
+ ADD_CONST(IPVLAN_MODE_L3S);
+
+ ADD_CONST(VXLAN_DF_UNSET);
+ ADD_CONST(VXLAN_DF_SET);
+ ADD_CONST(VXLAN_DF_INHERIT);
+ ADD_CONST(VXLAN_DF_MAX);
+
+ ADD_CONST(GENEVE_DF_UNSET);
+ ADD_CONST(GENEVE_DF_SET);
+ ADD_CONST(GENEVE_DF_INHERIT);
+ ADD_CONST(GENEVE_DF_MAX);
+
+ ADD_CONST(GTP_ROLE_GGSN);
+ ADD_CONST(GTP_ROLE_SGSN);
+
+ ADD_CONST(PORT_REQUEST_PREASSOCIATE);
+ ADD_CONST(PORT_REQUEST_PREASSOCIATE_RR);
+ ADD_CONST(PORT_REQUEST_ASSOCIATE);
+ ADD_CONST(PORT_REQUEST_DISASSOCIATE);
+
+ ADD_CONST(PORT_VDP_RESPONSE_SUCCESS);
+ ADD_CONST(PORT_VDP_RESPONSE_INVALID_FORMAT);
+ ADD_CONST(PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES);
+ ADD_CONST(PORT_VDP_RESPONSE_UNUSED_VTID);
+ ADD_CONST(PORT_VDP_RESPONSE_VTID_VIOLATION);
+ ADD_CONST(PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION);
+ ADD_CONST(PORT_VDP_RESPONSE_OUT_OF_SYNC);
+ ADD_CONST(PORT_PROFILE_RESPONSE_SUCCESS);
+ ADD_CONST(PORT_PROFILE_RESPONSE_INPROGRESS);
+ ADD_CONST(PORT_PROFILE_RESPONSE_INVALID);
+ ADD_CONST(PORT_PROFILE_RESPONSE_BADSTATE);
+ ADD_CONST(PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES);
+ ADD_CONST(PORT_PROFILE_RESPONSE_ERROR);
+
+ ADD_CONST(IPOIB_MODE_DATAGRAM);
+ ADD_CONST(IPOIB_MODE_CONNECTED);
+
+ ADD_CONST(HSR_PROTOCOL_HSR);
+ ADD_CONST(HSR_PROTOCOL_PRP);
+
+ ADD_CONST(LINK_XSTATS_TYPE_UNSPEC);
+ ADD_CONST(LINK_XSTATS_TYPE_BRIDGE);
+ ADD_CONST(LINK_XSTATS_TYPE_BOND);
+
+ ADD_CONST(XDP_ATTACHED_NONE);
+ ADD_CONST(XDP_ATTACHED_DRV);
+ ADD_CONST(XDP_ATTACHED_SKB);
+ ADD_CONST(XDP_ATTACHED_HW);
+ ADD_CONST(XDP_ATTACHED_MULTI);
+
+ ADD_CONST(FDB_NOTIFY_BIT);
+ ADD_CONST(FDB_NOTIFY_INACTIVE_BIT);
+
+ ADD_CONST(RTM_BASE);
+ ADD_CONST(RTM_NEWLINK);
+ ADD_CONST(RTM_DELLINK);
+ ADD_CONST(RTM_GETLINK);
+ ADD_CONST(RTM_SETLINK);
+ ADD_CONST(RTM_NEWADDR);
+ ADD_CONST(RTM_DELADDR);
+ ADD_CONST(RTM_GETADDR);
+ ADD_CONST(RTM_NEWROUTE);
+ ADD_CONST(RTM_DELROUTE);
+ ADD_CONST(RTM_GETROUTE);
+ ADD_CONST(RTM_NEWNEIGH);
+ ADD_CONST(RTM_DELNEIGH);
+ ADD_CONST(RTM_GETNEIGH);
+ ADD_CONST(RTM_NEWRULE);
+ ADD_CONST(RTM_DELRULE);
+ ADD_CONST(RTM_GETRULE);
+ ADD_CONST(RTM_NEWQDISC);
+ ADD_CONST(RTM_DELQDISC);
+ ADD_CONST(RTM_GETQDISC);
+ ADD_CONST(RTM_NEWTCLASS);
+ ADD_CONST(RTM_DELTCLASS);
+ ADD_CONST(RTM_GETTCLASS);
+ ADD_CONST(RTM_NEWTFILTER);
+ ADD_CONST(RTM_DELTFILTER);
+ ADD_CONST(RTM_GETTFILTER);
+ ADD_CONST(RTM_NEWACTION);
+ ADD_CONST(RTM_DELACTION);
+ ADD_CONST(RTM_GETACTION);
+ ADD_CONST(RTM_NEWPREFIX);
+ ADD_CONST(RTM_GETMULTICAST);
+ ADD_CONST(RTM_GETANYCAST);
+ ADD_CONST(RTM_NEWNEIGHTBL);
+ ADD_CONST(RTM_GETNEIGHTBL);
+ ADD_CONST(RTM_SETNEIGHTBL);
+ ADD_CONST(RTM_NEWNDUSEROPT);
+ ADD_CONST(RTM_NEWADDRLABEL);
+ ADD_CONST(RTM_DELADDRLABEL);
+ ADD_CONST(RTM_GETADDRLABEL);
+ ADD_CONST(RTM_GETDCB);
+ ADD_CONST(RTM_SETDCB);
+ ADD_CONST(RTM_NEWNETCONF);
+ ADD_CONST(RTM_DELNETCONF);
+ ADD_CONST(RTM_GETNETCONF);
+ ADD_CONST(RTM_NEWMDB);
+ ADD_CONST(RTM_DELMDB);
+ ADD_CONST(RTM_GETMDB);
+ ADD_CONST(RTM_NEWNSID);
+ ADD_CONST(RTM_DELNSID);
+ ADD_CONST(RTM_GETNSID);
+ ADD_CONST(RTM_NEWSTATS);
+ ADD_CONST(RTM_GETSTATS);
+ ADD_CONST(RTM_NEWCACHEREPORT);
+ ADD_CONST(RTM_NEWCHAIN);
+ ADD_CONST(RTM_DELCHAIN);
+ ADD_CONST(RTM_GETCHAIN);
+ ADD_CONST(RTM_NEWNEXTHOP);
+ ADD_CONST(RTM_DELNEXTHOP);
+ ADD_CONST(RTM_GETNEXTHOP);
+ ADD_CONST(RTM_NEWLINKPROP);
+ ADD_CONST(RTM_DELLINKPROP);
+ ADD_CONST(RTM_GETLINKPROP);
+ ADD_CONST(RTM_NEWVLAN);
+ ADD_CONST(RTM_DELVLAN);
+ ADD_CONST(RTM_GETVLAN);
+
+ ADD_CONST(RTN_UNSPEC);
+ ADD_CONST(RTN_UNICAST);
+ ADD_CONST(RTN_LOCAL);
+ ADD_CONST(RTN_BROADCAST);
+ ADD_CONST(RTN_ANYCAST);
+ ADD_CONST(RTN_MULTICAST);
+ ADD_CONST(RTN_BLACKHOLE);
+ ADD_CONST(RTN_UNREACHABLE);
+ ADD_CONST(RTN_PROHIBIT);
+ ADD_CONST(RTN_THROW);
+ ADD_CONST(RTN_NAT);
+ ADD_CONST(RTN_XRESOLVE);
+
+ ADD_CONST(RT_SCOPE_UNIVERSE);
+ ADD_CONST(RT_SCOPE_SITE);
+ ADD_CONST(RT_SCOPE_LINK);
+ ADD_CONST(RT_SCOPE_HOST);
+ ADD_CONST(RT_SCOPE_NOWHERE);
+
+ ADD_CONST(RT_TABLE_UNSPEC);
+ ADD_CONST(RT_TABLE_COMPAT);
+ ADD_CONST(RT_TABLE_DEFAULT);
+ ADD_CONST(RT_TABLE_MAIN);
+ ADD_CONST(RT_TABLE_LOCAL);
+ ADD_CONST(RT_TABLE_MAX);
+
+ /* required to construct RTAX_LOCK */
+ ADD_CONST(RTAX_MTU);
+ ADD_CONST(RTAX_HOPLIMIT);
+ ADD_CONST(RTAX_ADVMSS);
+ ADD_CONST(RTAX_REORDERING);
+ ADD_CONST(RTAX_RTT);
+ ADD_CONST(RTAX_WINDOW);
+ ADD_CONST(RTAX_CWND);
+ ADD_CONST(RTAX_INITCWND);
+ ADD_CONST(RTAX_INITRWND);
+ ADD_CONST(RTAX_FEATURES);
+ ADD_CONST(RTAX_QUICKACK);
+ ADD_CONST(RTAX_CC_ALGO);
+ ADD_CONST(RTAX_RTTVAR);
+ ADD_CONST(RTAX_SSTHRESH);
+ ADD_CONST(RTAX_FASTOPEN_NO_COOKIE);
+
+ ADD_CONST(PREFIX_UNSPEC);
+ ADD_CONST(PREFIX_ADDRESS);
+ ADD_CONST(PREFIX_CACHEINFO);
+
+ ADD_CONST(NDUSEROPT_UNSPEC);
+ ADD_CONST(NDUSEROPT_SRCADDR);
+
+ ADD_CONST(RTNLGRP_NONE);
+ ADD_CONST(RTNLGRP_LINK);
+ ADD_CONST(RTNLGRP_NOTIFY);
+ ADD_CONST(RTNLGRP_NEIGH);
+ ADD_CONST(RTNLGRP_TC);
+ ADD_CONST(RTNLGRP_IPV4_IFADDR);
+ ADD_CONST(RTNLGRP_IPV4_MROUTE);
+ ADD_CONST(RTNLGRP_IPV4_ROUTE);
+ ADD_CONST(RTNLGRP_IPV4_RULE);
+ ADD_CONST(RTNLGRP_IPV6_IFADDR);
+ ADD_CONST(RTNLGRP_IPV6_MROUTE);
+ ADD_CONST(RTNLGRP_IPV6_ROUTE);
+ ADD_CONST(RTNLGRP_IPV6_IFINFO);
+ ADD_CONST(RTNLGRP_DECnet_IFADDR);
+ ADD_CONST(RTNLGRP_NOP2);
+ ADD_CONST(RTNLGRP_DECnet_ROUTE);
+ ADD_CONST(RTNLGRP_DECnet_RULE);
+ ADD_CONST(RTNLGRP_NOP4);
+ ADD_CONST(RTNLGRP_IPV6_PREFIX);
+ ADD_CONST(RTNLGRP_IPV6_RULE);
+ ADD_CONST(RTNLGRP_ND_USEROPT);
+ ADD_CONST(RTNLGRP_PHONET_IFADDR);
+ ADD_CONST(RTNLGRP_PHONET_ROUTE);
+ ADD_CONST(RTNLGRP_DCB);
+ ADD_CONST(RTNLGRP_IPV4_NETCONF);
+ ADD_CONST(RTNLGRP_IPV6_NETCONF);
+ ADD_CONST(RTNLGRP_MDB);
+ ADD_CONST(RTNLGRP_MPLS_ROUTE);
+ ADD_CONST(RTNLGRP_NSID);
+ ADD_CONST(RTNLGRP_MPLS_NETCONF);
+ ADD_CONST(RTNLGRP_IPV4_MROUTE_R);
+ ADD_CONST(RTNLGRP_IPV6_MROUTE_R);
+ ADD_CONST(RTNLGRP_NEXTHOP);
+ ADD_CONST(RTNLGRP_BRVLAN);
+
+ ADD_CONST(RTM_F_CLONED);
+ ADD_CONST(RTM_F_EQUALIZE);
+ ADD_CONST(RTM_F_FIB_MATCH);
+ ADD_CONST(RTM_F_LOOKUP_TABLE);
+ ADD_CONST(RTM_F_NOTIFY);
+ ADD_CONST(RTM_F_PREFIX);
+
+ ADD_CONST(AF_UNSPEC);
+ ADD_CONST(AF_INET);
+ ADD_CONST(AF_INET6);
+ ADD_CONST(AF_MPLS);
+ ADD_CONST(AF_BRIDGE);
+
+ ADD_CONST(GRE_CSUM);
+ ADD_CONST(GRE_ROUTING);
+ ADD_CONST(GRE_KEY);
+ ADD_CONST(GRE_SEQ);
+ ADD_CONST(GRE_STRICT);
+ ADD_CONST(GRE_REC);
+ ADD_CONST(GRE_ACK);
+
+ ADD_CONST(TUNNEL_ENCAP_NONE);
+ ADD_CONST(TUNNEL_ENCAP_FOU);
+ ADD_CONST(TUNNEL_ENCAP_GUE);
+ ADD_CONST(TUNNEL_ENCAP_MPLS);
+
+ ADD_CONST(TUNNEL_ENCAP_FLAG_CSUM);
+ ADD_CONST(TUNNEL_ENCAP_FLAG_CSUM6);
+ ADD_CONST(TUNNEL_ENCAP_FLAG_REMCSUM);
+
+ ADD_CONST(IP6_TNL_F_ALLOW_LOCAL_REMOTE);
+ ADD_CONST(IP6_TNL_F_IGN_ENCAP_LIMIT);
+ ADD_CONST(IP6_TNL_F_MIP6_DEV);
+ ADD_CONST(IP6_TNL_F_RCV_DSCP_COPY);
+ ADD_CONST(IP6_TNL_F_USE_ORIG_FLOWLABEL);
+ ADD_CONST(IP6_TNL_F_USE_ORIG_FWMARK);
+ ADD_CONST(IP6_TNL_F_USE_ORIG_TCLASS);
+
+ ADD_CONST(NTF_EXT_LEARNED);
+ ADD_CONST(NTF_MASTER);
+ ADD_CONST(NTF_OFFLOADED);
+ ADD_CONST(NTF_PROXY);
+ ADD_CONST(NTF_ROUTER);
+ ADD_CONST(NTF_SELF);
+ ADD_CONST(NTF_STICKY);
+ ADD_CONST(NTF_USE);
+
+ ADD_CONST(NUD_DELAY);
+ ADD_CONST(NUD_FAILED);
+ ADD_CONST(NUD_INCOMPLETE);
+ ADD_CONST(NUD_NOARP);
+ ADD_CONST(NUD_NONE);
+ ADD_CONST(NUD_PERMANENT);
+ ADD_CONST(NUD_PROBE);
+ ADD_CONST(NUD_REACHABLE);
+ ADD_CONST(NUD_STALE);
+
+ ADD_CONST(IFA_F_DADFAILED);
+ ADD_CONST(IFA_F_DEPRECATED);
+ ADD_CONST(IFA_F_HOMEADDRESS);
+ ADD_CONST(IFA_F_MANAGETEMPADDR);
+ ADD_CONST(IFA_F_MCAUTOJOIN);
+ ADD_CONST(IFA_F_NODAD);
+ ADD_CONST(IFA_F_NOPREFIXROUTE);
+ ADD_CONST(IFA_F_OPTIMISTIC);
+ ADD_CONST(IFA_F_PERMANENT);
+ ADD_CONST(IFA_F_SECONDARY);
+ ADD_CONST(IFA_F_STABLE_PRIVACY);
+ ADD_CONST(IFA_F_TEMPORARY);
+ ADD_CONST(IFA_F_TENTATIVE);
+
+ ADD_CONST(FIB_RULE_PERMANENT);
+ ADD_CONST(FIB_RULE_INVERT);
+ ADD_CONST(FIB_RULE_UNRESOLVED);
+ ADD_CONST(FIB_RULE_IIF_DETACHED);
+ ADD_CONST(FIB_RULE_DEV_DETACHED);
+ ADD_CONST(FIB_RULE_OIF_DETACHED);
+
+ ADD_CONST(FR_ACT_TO_TBL);
+ ADD_CONST(FR_ACT_GOTO);
+ ADD_CONST(FR_ACT_NOP);
+ ADD_CONST(FR_ACT_BLACKHOLE);
+ ADD_CONST(FR_ACT_UNREACHABLE);
+ ADD_CONST(FR_ACT_PROHIBIT);
+
+ ADD_CONST(NETCONFA_IFINDEX_ALL);
+ ADD_CONST(NETCONFA_IFINDEX_DEFAULT);
+
+ ADD_CONST(BRIDGE_VLAN_INFO_MASTER);
+ ADD_CONST(BRIDGE_VLAN_INFO_PVID);
+ ADD_CONST(BRIDGE_VLAN_INFO_UNTAGGED);
+ ADD_CONST(BRIDGE_VLAN_INFO_RANGE_BEGIN);
+ ADD_CONST(BRIDGE_VLAN_INFO_RANGE_END);
+ ADD_CONST(BRIDGE_VLAN_INFO_BRENTRY);
+
+ ucv_object_add(scope, "const", c);
+};
+
+static const uc_function_list_t global_fns[] = {
+ { "error", uc_nl_error },
+ { "request", uc_nl_request },
+};
+
+
+void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
+{
+ uc_function_list_register(scope, global_fns);
+
+ register_constants(vm, scope);
+}