diff options
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); +} |