+static const nla_decoder_t ifla_port_nla_decoders[] = {
+ [IFLA_PORT_VF] = decode_nla_u32,
+ [IFLA_PORT_PROFILE] = decode_nla_str,
+ [IFLA_PORT_VSI_TYPE] = decode_ifla_port_vsi,
+ [IFLA_PORT_INSTANCE_UUID] = NULL, /* default parser */
+ [IFLA_PORT_HOST_UUID] = NULL, /* default parser */
+ [IFLA_PORT_REQUEST] = decode_nla_u8,
+ [IFLA_PORT_RESPONSE] = decode_nla_u16
+};
+
+static bool
+decode_ifla_port(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ decode_nlattr(tcp, addr, len, rtnl_ifla_port_attrs,
+ "IFLA_VF_PORT_???", ARRSZ_PAIR(ifla_port_nla_decoders),
+ opaque_data);
+
+ return true;
+}
+
+static const nla_decoder_t ifla_vf_port_nla_decoders[] = {
+ [IFLA_VF_PORT] = decode_ifla_port
+};
+
+static bool
+decode_ifla_vf_ports(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ decode_nlattr(tcp, addr, len, rtnl_ifla_vf_port_attrs,
+ "IFLA_VF_PORT_???", ARRSZ_PAIR(ifla_vf_port_nla_decoders),
+ opaque_data);
+
+ return true;
+}
+
+static bool
+decode_ifla_xdp_flags(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ uint32_t flags;
+
+ if (len < sizeof(flags))
+ return false;
+ else if (!umove_or_printaddr(tcp, addr, &flags))
+ printflags(xdp_flags, flags, "XDP_FLAGS_???");
+
+ return true;
+}
+
+bool
+decode_ifla_xdp_attached(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ static const struct decode_nla_xlat_opts opts = {
+ .xlat = rtnl_ifla_xdp_attached_mode,
+ .dflt = "XDP_ATTACHED_???",
+ .size = 1,
+ };
+
+ return decode_nla_xval(tcp, addr, len, &opts);
+}
+
+static const nla_decoder_t ifla_xdp_nla_decoders[] = {
+ [IFLA_XDP_FD] = decode_nla_fd,
+ [IFLA_XDP_ATTACHED] = decode_ifla_xdp_attached,
+ [IFLA_XDP_FLAGS] = decode_ifla_xdp_flags,
+ [IFLA_XDP_PROG_ID] = decode_nla_u32,
+ [IFLA_XDP_DRV_PROG_ID] = decode_nla_u32,
+ [IFLA_XDP_SKB_PROG_ID] = decode_nla_u32,
+ [IFLA_XDP_HW_PROG_ID] = decode_nla_u32,
+};
+
+static bool
+decode_ifla_xdp(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ decode_nlattr(tcp, addr, len, rtnl_ifla_xdp_attrs,
+ "IFLA_XDP_???", ARRSZ_PAIR(ifla_xdp_nla_decoders),
+ opaque_data);
+
+ return true;
+}
+
+static bool
+decode_ifla_event(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ uint32_t ev;
+
+ if (len < sizeof(ev))
+ return false;
+ else if (!umove_or_printaddr(tcp, addr, &ev))
+ printxval(rtnl_ifla_events, ev, "IFLA_EVENT_???");
+
+ return true;
+}
+
+
+static bool
+decode_ifla_inet_conf(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ int elem;
+ size_t cnt = len / sizeof(elem);
+
+ if (!cnt)
+ return false;
+
+ print_array_ex(tcp, addr, cnt, &elem, sizeof(elem),
+ tfetch_mem, print_int32_array_member, NULL,
+ PAF_PRINT_INDICES | XLAT_STYLE_FMT_D,
+ inet_devconf_indices, "IPV4_DEVCONF_???");
+
+ return true;
+}
+
+static const nla_decoder_t ifla_inet_nla_decoders[] = {
+ [IFLA_INET_CONF] = decode_ifla_inet_conf,
+};
+
+static bool
+decode_ifla_inet6_flags(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ static const struct decode_nla_xlat_opts opts = {
+ inet6_if_flags, "IF_???",
+ .size = 4,
+ };
+
+ return decode_nla_flags(tcp, addr, len, &opts);
+}
+
+static bool
+decode_ifla_inet6_conf(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ int elem;
+ size_t cnt = len / sizeof(elem);
+
+ if (!cnt)
+ return false;
+
+ print_array_ex(tcp, addr, cnt, &elem, sizeof(elem),
+ tfetch_mem, print_int32_array_member, NULL,
+ PAF_PRINT_INDICES | XLAT_STYLE_FMT_D,
+ inet6_devconf_indices, "DEVCONF_???");
+
+ return true;
+}
+
+static bool
+decode_ifla_inet6_stats(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ uint64_t elem;
+ size_t cnt = len / sizeof(elem);
+
+ if (!cnt)
+ return false;
+
+ print_array_ex(tcp, addr, cnt, &elem, sizeof(elem),
+ tfetch_mem, print_uint64_array_member, NULL,
+ PAF_PRINT_INDICES | XLAT_STYLE_FMT_U,
+ snmp_ip_stats, "IPSTATS_MIB_???");
+
+ return true;
+}
+
+static bool
+decode_ifla_inet6_cacheinfo(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ struct {
+ uint32_t max_reasm_len;
+ uint32_t tstamp;
+ uint32_t reachable_time;
+ uint32_t retrans_time;
+ } ci;
+
+ if (len < sizeof(ci))
+ return false;
+ else if (!umove_or_printaddr(tcp, addr, &ci)) {
+ PRINT_FIELD_U("{", ci, max_reasm_len);
+ PRINT_FIELD_U(", ", ci, tstamp);
+ PRINT_FIELD_U(", ", ci, reachable_time);
+ PRINT_FIELD_U(", ", ci, retrans_time);
+ tprints("}");
+ }
+
+ return true;
+}
+
+static bool
+decode_ifla_inet6_icmp6_stats(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ uint64_t elem;
+ size_t cnt = len / sizeof(elem);
+
+ if (!cnt)
+ return false;
+
+ print_array_ex(tcp, addr, cnt, &elem, sizeof(elem),
+ tfetch_mem, print_uint64_array_member, NULL,
+ PAF_PRINT_INDICES | XLAT_STYLE_FMT_U,
+ snmp_icmp6_stats, "ICMP6_MIB_???");
+
+ return true;
+}
+
+static bool
+decode_ifla_inet6_agm(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ static const struct decode_nla_xlat_opts opts = {
+ in6_addr_gen_mode, "IN6_ADDR_GEN_MODE_???",
+ .size = 1,
+ };
+
+ return decode_nla_xval(tcp, addr, len, &opts);
+}
+
+static const nla_decoder_t ifla_inet6_nla_decoders[] = {
+ [IFLA_INET6_FLAGS] = decode_ifla_inet6_flags,
+ [IFLA_INET6_CONF] = decode_ifla_inet6_conf,
+ [IFLA_INET6_STATS] = decode_ifla_inet6_stats,
+ [IFLA_INET6_MCAST] = NULL, /* unused */
+ [IFLA_INET6_CACHEINFO] = decode_ifla_inet6_cacheinfo,
+ [IFLA_INET6_ICMP6STATS] = decode_ifla_inet6_icmp6_stats,
+ [IFLA_INET6_TOKEN] = decode_nla_in6_addr,
+ [IFLA_INET6_ADDR_GEN_MODE] = decode_ifla_inet6_agm,
+};
+
+static const struct nla_decoder_table_desc {
+ const struct xlat *xlat;
+ const char *dflt;
+ const nla_decoder_t *table;
+ size_t size;
+} ifla_af_spec_protos[] = {
+ [AF_INET] = {
+ rtnl_ifla_af_spec_inet_attrs, "IFLA_INET_???",
+ ARRSZ_PAIR(ifla_inet_nla_decoders),
+ },
+ [AF_INET6] = {
+ rtnl_ifla_af_spec_inet6_attrs, "IFLA_INET6_???",
+ ARRSZ_PAIR(ifla_inet6_nla_decoders),
+ },
+};
+
+static bool
+decode_ifla_af(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ uintptr_t proto = (uintptr_t) opaque_data;
+ const struct nla_decoder_table_desc *desc
+ = proto < ARRAY_SIZE(ifla_af_spec_protos)
+ ? ifla_af_spec_protos + proto : NULL;
+
+ if (!desc || !desc->table)
+ return false;
+
+ decode_nlattr(tcp, addr, len,
+ desc->xlat, desc->dflt, desc->table, desc->size, NULL);
+
+ return true;
+}
+
+static bool
+decode_ifla_af_spec(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ nla_decoder_t af_spec_decoder = &decode_ifla_af;
+
+ decode_nlattr(tcp, addr, len, addrfams, "AF_???",
+ &af_spec_decoder, 0, opaque_data);
+
+ return true;
+}
+