(root)/
strace-6.5/
tests/
nlattr_nhmsg.c
       1  /*
       2   * Copyright (c) 2021 Eugene Syromyatnikov <evgsyr@gmail.com>
       3   * All rights reserved.
       4   *
       5   * SPDX-License-Identifier: GPL-2.0-or-later
       6   */
       7  
       8  #include "tests.h"
       9  
      10  #include <arpa/inet.h>
      11  #include <inttypes.h>
      12  #include <linux/ip.h>
      13  #include <linux/rtnetlink.h>
      14  #include <linux/nexthop.h>
      15  #include <netinet/in.h>
      16  #include <stdint.h>
      17  #include <stdio.h>
      18  #include <unistd.h>
      19  
      20  #include "test_nlattr.h"
      21  
      22  #include "xlat.h"
      23  #define XLAT_MACROS_ONLY
      24  # include "xlat/rtnl_nexthop_attrs.h"
      25  # include "xlat/rtnl_nha_res_group_attrs.h"
      26  # include "xlat/rtnl_nha_res_bucket_attrs.h"
      27  #undef XLAT_MACROS_ONLY
      28  
      29  #define DEF_NLATTR_NHMSG_FUNCS(sfx_, af_)				\
      30  	static void							\
      31  	init_##sfx_(struct nlmsghdr *const nlh, const unsigned int msg_len) \
      32  	{								\
      33  		SET_STRUCT(struct nlmsghdr, nlh,			\
      34  			.nlmsg_len = msg_len,				\
      35  			.nlmsg_type = RTM_GETNEXTHOP,			\
      36  			.nlmsg_flags = NLM_F_DUMP,			\
      37  		);							\
      38  									\
      39  		struct nhmsg *const msg = NLMSG_DATA(nlh);		\
      40  		SET_STRUCT(struct nhmsg, msg,				\
      41  			.nh_family = (af_),				\
      42  			.nh_scope = RT_SCOPE_NOWHERE,			\
      43  			.nh_protocol = RTPROT_UNSPEC,			\
      44  			.nh_flags = 0x22,				\
      45  		);							\
      46  	}								\
      47  									\
      48  	static void							\
      49  	print_##sfx_(const unsigned int msg_len)			\
      50  	{								\
      51  		printf("{nlmsg_len=%u, nlmsg_type=" XLAT_FMT		\
      52  		       ", nlmsg_flags=" XLAT_FMT ", nlmsg_seq=0"	\
      53  		       ", nlmsg_pid=0}, {nh_family=" XLAT_FMT		\
      54  		       ", nh_scope=" XLAT_FMT ", nh_protocol=" XLAT_FMT	\
      55  		       ", nh_flags=" XLAT_FMT "}",			\
      56  		       msg_len, XLAT_ARGS(RTM_GETNEXTHOP),		\
      57  		       XLAT_ARGS(NLM_F_DUMP), XLAT_SEL(af_, #af_),	\
      58  		       XLAT_ARGS(RT_SCOPE_NOWHERE),			\
      59  		       XLAT_ARGS(RTPROT_UNSPEC),			\
      60  		       XLAT_ARGS(RTNH_F_PERVASIVE|RTNH_F_UNRESOLVED));	\
      61  	}								\
      62  	/* End of DEF_NLATTR_NHMSG_FUNCS */
      63  
      64  #define DEF_NLATTR_NHMSG_NESTED_FUNCS(sfx_, attr_)			\
      65  	static void							\
      66  	init_nhmsg_##sfx_(struct nlmsghdr *const nlh,			\
      67  			  const unsigned int msg_len)			\
      68  	{								\
      69  		init_nhmsg(nlh, msg_len);				\
      70  		struct nlattr *nla = NLMSG_ATTR(nlh, sizeof(struct nhmsg));	\
      71  		SET_STRUCT(struct nlattr, nla,				\
      72  			.nla_len = msg_len				\
      73  				   - NLMSG_SPACE(sizeof(struct nhmsg)),	\
      74  			.nla_type = attr_,				\
      75  		);							\
      76  	}								\
      77  									\
      78  	static void							\
      79  	print_nhmsg_##sfx_(const unsigned int msg_len)			\
      80  	{								\
      81  		print_nhmsg(msg_len);					\
      82  		printf(", [{nla_len=%u, nla_type=" XLAT_FMT "}",	\
      83  		       (unsigned int) (msg_len - NLMSG_HDRLEN		\
      84  				       - NLMSG_ALIGN(sizeof(struct nhmsg))), \
      85  		       XLAT_SEL(attr_, #attr_));			\
      86  	}								\
      87  	/* End of DEF_NLATTR_NHMSG_NESTED_FUNCS */
      88  
      89  DEF_NLATTR_NHMSG_FUNCS(nhmsg, AF_UNIX)
      90  DEF_NLATTR_NHMSG_FUNCS(nhmsg_inet, AF_INET)
      91  DEF_NLATTR_NHMSG_FUNCS(nhmsg_inet6, AF_INET6)
      92  
      93  DEF_NLATTR_NHMSG_NESTED_FUNCS(res_grp, NHA_RES_GROUP)
      94  DEF_NLATTR_NHMSG_NESTED_FUNCS(res_bkt, NHA_RES_BUCKET)
      95  
      96  static void
      97  print_nh_grp(const struct nexthop_grp *const elem, size_t idx)
      98  {
      99  	switch (idx) {
     100  	case 0: printf("{id=3735928559, weight=0}"); break;
     101  	case 1:	printf("{id=0, weight=218, resvd2=0xdead}"); break;
     102  	case 2: printf("{id=4207869677, weight=190, resvd1=0xec}"); break;
     103  	case 3: printf("{id=0, weight=0, resvd1=0xca, resvd2=0xbeef}"); break;
     104  	default: error_msg_and_fail("Unexpected grp index: %zu", idx);
     105  	}
     106  }
     107  
     108  int
     109  main(void)
     110  {
     111  	skip_if_unavailable("/proc/self/fd/");
     112  
     113  	const int fd = create_nl_socket(NETLINK_ROUTE);
     114  	const unsigned int hdrlen = sizeof(struct nhmsg);
     115  	char nla_type_str[256];
     116  	void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen),
     117  				   NLA_HDRLEN + 42);
     118  
     119  	static char pattern[4096];
     120  	fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
     121  
     122  
     123  	/* Unknown attrs */
     124  	static const uint16_t unk_types[] = { 14, 0xffff & NLA_TYPE_MASK };
     125  	for (size_t i = 0; i < ARRAY_SIZE(unk_types); i++) {
     126  		sprintf(nla_type_str, "%#x" NRAW(" /* NHA_??? */"), unk_types[i]);
     127  		TEST_NLATTR_(fd, nlh0, hdrlen,
     128  			     init_nhmsg, print_nhmsg,
     129  			     unk_types[i], nla_type_str,
     130  			     4, pattern, 4,
     131  			     print_quoted_hex(pattern, 4));
     132  	}
     133  
     134  
     135  	/* unimplemented, no semantics: NHA_UNSPEC, NHA_ENCAP */
     136  	static const struct strval32 unimp_types[] = {
     137  		{ ARG_XLAT_KNOWN(0, "NHA_UNSPEC") },
     138  		{ ARG_XLAT_KNOWN(0x8, "NHA_ENCAP") } };
     139  	for (size_t i = 0; i < ARRAY_SIZE(unimp_types); i++) {
     140  		TEST_NLATTR_(fd, nlh0, hdrlen,
     141  			     init_nhmsg, print_nhmsg,
     142  			     unimp_types[i].val, unimp_types[i].str,
     143  			     42, pattern, 42,
     144  			     print_quoted_hex(pattern, 32);
     145  			     printf("..."));
     146  	}
     147  
     148  
     149  	/* u32 attrs: NHA_ID, NHA_BLACKHOLE, NHA_GROUPS, NHA_FDB */
     150  	static const struct strval32 u32_attrs[] = {
     151  		{ ARG_XLAT_KNOWN(0x1, "NHA_ID") },
     152  		{ ARG_XLAT_KNOWN(0x4, "NHA_BLACKHOLE") },
     153  		{ ARG_XLAT_KNOWN(0x9, "NHA_GROUPS") },
     154  		{ ARG_XLAT_KNOWN(0xb, "NHA_FDB") },
     155  	};
     156  	for (size_t i = 0; i < ARRAY_SIZE(u32_attrs); i++) {
     157  		check_u32_nlattr(fd, nlh0, hdrlen, init_nhmsg, print_nhmsg,
     158  				 u32_attrs[i].val, u32_attrs[i].str, pattern,
     159  				 0);
     160  	}
     161  
     162  
     163  	/* NHA_GROUP */
     164  	static const struct nexthop_grp grps[] = {
     165  		{ .id = 0xdeadbeef, .weight = 0, .resvd1 = 0, .resvd2 = 0 },
     166  		{ .id = 0, .weight = 218, .resvd1 = 0, .resvd2 = 0xdead },
     167  		{ .id = 0xfacefeed, .weight = 190, .resvd1 = 236, .resvd2 = 0 },
     168  		{ .id = 0, .weight = 0, .resvd1 = 202, .resvd2 = 0xbeef },
     169  	};
     170  	TEST_NLATTR_ARRAY_(fd, nlh0, hdrlen, init_nhmsg, print_nhmsg,
     171  			   NHA_GROUP, XLAT_KNOWN(0x2, "NHA_GROUP"),
     172  			   pattern, grps, print_nh_grp);
     173  
     174  
     175  	/* NHA_GROUP_TYPE */
     176  	static const struct strval16 grp_types[] = {
     177  		{ ARG_XLAT_KNOWN(0, "NEXTHOP_GRP_TYPE_MPATH") },
     178  		{ ARG_XLAT_KNOWN(0x1, "NEXTHOP_GRP_TYPE_RES") },
     179  		{ ARG_XLAT_UNKNOWN(0x2, "NEXTHOP_GRP_TYPE_???") },
     180  		{ ARG_XLAT_UNKNOWN(0xbeef, "NEXTHOP_GRP_TYPE_???") },
     181  	};
     182  	for (size_t i = 0; i < ARRAY_SIZE(grp_types); i++) {
     183  		TEST_NLATTR_OBJECT_(fd, nlh0, hdrlen, init_nhmsg, print_nhmsg,
     184  				   NHA_GROUP_TYPE,
     185  				   XLAT_KNOWN(0x3, "NHA_GROUP_TYPE"),
     186  				   pattern, grp_types[i].val,
     187  				   printf("%s", grp_types[i].str));
     188  		TEST_NLATTR_(fd, nlh0, hdrlen, init_nhmsg, print_nhmsg,
     189  			     NHA_GROUP_TYPE, XLAT_KNOWN(0x3, "NHA_GROUP_TYPE"),
     190  			     sizeof(grp_types[i].val) + 4,
     191  			     &grp_types[i].val, sizeof(grp_types[i].val),
     192  			     printf("%s", grp_types[i].str));
     193  	}
     194  
     195  
     196  	/* ifindex: NHA_OIF, NHA_MASTER */
     197  	static const struct strval32 if_attrs[] = {
     198  		{ ARG_XLAT_KNOWN(0x5, "NHA_OIF") },
     199  		{ ARG_XLAT_KNOWN(0xa, "NHA_MASTER") },
     200  	};
     201  	const uint32_t ifindex = ifindex_lo();
     202  	for (size_t i = 0; i < ARRAY_SIZE(if_attrs); i++) {
     203  		static const uint32_t bogus = 0xdeadc0de;
     204  		TEST_NLATTR_OBJECT_(fd, nlh0, hdrlen, init_nhmsg, print_nhmsg,
     205  				   if_attrs[i].val, if_attrs[i].str,
     206  				   pattern, bogus,
     207  				   printf("3735929054"));
     208  		TEST_NLATTR_(fd, nlh0, hdrlen, init_nhmsg, print_nhmsg,
     209  			     if_attrs[i].val, if_attrs[i].str,
     210  			     sizeof(bogus) + 4, &bogus, sizeof(bogus),
     211  			     printf("3735929054"));
     212  
     213  		TEST_NLATTR_OBJECT_(fd, nlh0, hdrlen, init_nhmsg, print_nhmsg,
     214  				   if_attrs[i].val, if_attrs[i].str,
     215  				   pattern, ifindex,
     216  				   printf(XLAT_FMT_U,
     217  					  XLAT_SEL(ifindex, IFINDEX_LO_STR)));
     218  		TEST_NLATTR_(fd, nlh0, hdrlen, init_nhmsg, print_nhmsg,
     219  			     if_attrs[i].val, if_attrs[i].str,
     220  			     sizeof(ifindex) + 4, &ifindex, sizeof(ifindex),
     221  			     printf(XLAT_FMT_U,
     222  				    XLAT_SEL(ifindex, IFINDEX_LO_STR)));
     223  	}
     224  
     225  
     226  	/* NHA_GATEWAY */
     227  	static const struct {
     228  		uint8_t af;
     229  		uint8_t addr[16];
     230  		const char *str;
     231  		void (* init_fn)(struct nlmsghdr *, unsigned int);
     232  		void (* print_fn)(unsigned int);
     233  		uint32_t len;
     234  	} addrs[] = {
     235  		{ AF_UNIX,  { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
     236  		  "\"\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\"",
     237  		  init_nhmsg,       print_nhmsg,       10 },
     238  		{ AF_INET,  { 0xde, 0xca, 0xff, 0xed },
     239  		  "inet_addr(\"222.202.255.237\")",
     240  		  init_nhmsg_inet,  print_nhmsg_inet,  4 },
     241  		{ AF_INET6, { 0xfa, 0xce, 0xbe, 0xef, [15] = 0xda },
     242  		  "inet_pton(AF_INET6, \"face:beef::da\")",
     243  		  init_nhmsg_inet6, print_nhmsg_inet6, 16 },
     244  	};
     245  	static const struct strval32 addr_attrs[] = {
     246  		{ ARG_XLAT_KNOWN(0x6, "NHA_GATEWAY") },
     247  	};
     248  	for (size_t i = 0; i < ARRAY_SIZE(addrs); i++) {
     249  		for (size_t j = 0; j < ARRAY_SIZE(addr_attrs); j++) {
     250  			TEST_NLATTR_(fd, nlh0, hdrlen,
     251  				     addrs[i].init_fn, addrs[i].print_fn,
     252  				     addr_attrs[j].val, addr_attrs[j].str,
     253  				     addrs[i].len - 1, addrs[i].addr,
     254  				     addrs[i].len - 1,
     255  				     print_quoted_hex(addrs[i].addr,
     256  						      addrs[i].len - 1)
     257  				     );
     258  			TEST_NLATTR_(fd, nlh0, hdrlen,
     259  				     addrs[i].init_fn, addrs[i].print_fn,
     260  				     addr_attrs[j].val, addr_attrs[j].str,
     261  				     addrs[i].len, addrs[i].addr, addrs[i].len,
     262  #if XLAT_RAW || XLAT_VERBOSE
     263  				     print_quoted_hex(addrs[i].addr,
     264  						      addrs[i].len);
     265  #endif
     266  #if !XLAT_RAW
     267  				     if (!(XLAT_VERBOSE
     268  					   && addrs[i].af == AF_UNIX))
     269  					     printf(VERB(" /* ") "%s"
     270  						    VERB(" */"), addrs[i].str);
     271  #endif
     272  				     );
     273  		}
     274  	}
     275  
     276  
     277  	/* NHA_ENCAP_TYPE */
     278  	static const struct strval16 enc_types[] = {
     279  		{ ARG_XLAT_KNOWN(0, "LWTUNNEL_ENCAP_NONE") },
     280  		{ ARG_XLAT_KNOWN(0x8, "LWTUNNEL_ENCAP_RPL") },
     281  		{ ARG_XLAT_UNKNOWN(0x9, "LWTUNNEL_ENCAP_???") },
     282  		{ ARG_XLAT_UNKNOWN(0xbeef, "LWTUNNEL_ENCAP_???") },
     283  	};
     284  	for (size_t i = 0; i < ARRAY_SIZE(enc_types); i++) {
     285  		TEST_NLATTR_OBJECT_(fd, nlh0, hdrlen, init_nhmsg, print_nhmsg,
     286  				   NHA_ENCAP_TYPE,
     287  				   XLAT_KNOWN(0x7, "NHA_ENCAP_TYPE"),
     288  				   pattern, enc_types[i].val,
     289  				   printf("%s", enc_types[i].str));
     290  		TEST_NLATTR_(fd, nlh0, hdrlen, init_nhmsg, print_nhmsg,
     291  			     NHA_ENCAP_TYPE, XLAT_KNOWN(0x7, "NHA_ENCAP_TYPE"),
     292  			     sizeof(enc_types[i].val) + 4,
     293  			     &enc_types[i].val, sizeof(enc_types[i].val),
     294  			     printf("%s", enc_types[i].str));
     295  	}
     296  
     297  
     298  	/* NHA_RES_GROUP */
     299  	static const unsigned int res_grp_hdrlen =
     300  		sizeof(struct nhmsg) + sizeof(struct nlattr);
     301  	void *nlh1 = midtail_alloc(NLMSG_SPACE(res_grp_hdrlen),
     302  				   NLA_HDRLEN + 16);
     303  
     304  	TEST_NLATTR_(fd, nlh0, hdrlen, init_nhmsg, print_nhmsg,
     305  		     NHA_RES_GROUP, XLAT_KNOWN(0xc, "NHA_RES_GROUP"),
     306  		     3, pattern, 3,
     307  		     print_quoted_hex(pattern, 3));
     308  
     309  	/* unknown NHA_RES_GROUP_* attr */
     310  	static const uint16_t unk_res_grp_types[] = {
     311  		5, 0xffff & NLA_TYPE_MASK,
     312  	};
     313  	for (size_t i = 0; i < ARRAY_SIZE(unk_res_grp_types); i++) {
     314  		sprintf(nla_type_str, "%#x" NRAW(" /* NHA_RES_GROUP_??? */"),
     315  			unk_res_grp_types[i]);
     316  		TEST_NLATTR_(fd, nlh1, res_grp_hdrlen,
     317  			     init_nhmsg_res_grp, print_nhmsg_res_grp,
     318  			     unk_res_grp_types[i], nla_type_str,
     319  			     16, pattern, 16,
     320  			     print_quoted_hex(pattern, 16);
     321  			     printf("]"));
     322  	}
     323  
     324  	/* not decoded: NHA_RES_GROUP_UNSPEC/NHA_RES_GROUP_PAD */
     325  	TEST_NLATTR_(fd, nlh1, res_grp_hdrlen,
     326  		     init_nhmsg_res_grp, print_nhmsg_res_grp,
     327  		     NHA_RES_GROUP_PAD, XLAT_KNOWN(0, "NHA_RES_GROUP_PAD"),
     328  		     8, pattern, 8,
     329  		     print_quoted_hex(pattern, 8);
     330  		     printf("]"));
     331  
     332  	/* u16: NHA_RES_GROUP_BUCKETS */
     333  	check_u16_nlattr(fd, nlh0, hdrlen,
     334  			 init_nhmsg_res_grp, print_nhmsg_res_grp,
     335  			 ARG_XLAT_KNOWN(0x1, "NHA_RES_GROUP_BUCKETS"),
     336  			 pattern, 1);
     337  
     338  	/* clock_t: NHA_RES_GROUP_IDLE_TIMER, NHA_RES_GROUP_UNBALANCED_TIMER,
     339  	 *          NHA_RES_GROUP_UNBALANCED_TIME */
     340  	static const struct strval32 res_grp_clk_attrs[] = {
     341  		{ ARG_XLAT_KNOWN(0x2, "NHA_RES_GROUP_IDLE_TIMER") },
     342  		{ ARG_XLAT_KNOWN(0x3, "NHA_RES_GROUP_UNBALANCED_TIMER") },
     343  		{ ARG_XLAT_KNOWN(0x4, "NHA_RES_GROUP_UNBALANCED_TIME") },
     344  	};
     345  	for (size_t i = 0; i < ARRAY_SIZE(res_grp_clk_attrs); i++) {
     346  		check_clock_t_nlattr(fd, nlh0, hdrlen,
     347  				     init_nhmsg_res_grp, print_nhmsg_res_grp,
     348  				     res_grp_clk_attrs[i].val,
     349  				     res_grp_clk_attrs[i].str, 1);
     350  	}
     351  
     352  
     353  	/* NHA_RES_BUCKET */
     354  	static const unsigned int res_bkt_hdrlen =
     355  		sizeof(struct nhmsg) + sizeof(struct nlattr);
     356  
     357  	TEST_NLATTR_(fd, nlh0, hdrlen, init_nhmsg, print_nhmsg,
     358  		     NHA_RES_BUCKET, XLAT_KNOWN(0xd, "NHA_RES_BUCKET"),
     359  		     3, pattern, 3,
     360  		     print_quoted_hex(pattern, 3));
     361  
     362  	/* unknown NHA_RES_GROUP_* attr */
     363  	static const uint16_t unk_res_bkt_types[] = {
     364  		4, 0xffff & NLA_TYPE_MASK,
     365  	};
     366  	for (size_t i = 0; i < ARRAY_SIZE(unk_res_bkt_types); i++) {
     367  		sprintf(nla_type_str, "%#x" NRAW(" /* NHA_RES_BUCKET_??? */"),
     368  			unk_res_bkt_types[i]);
     369  		TEST_NLATTR_(fd, nlh1, res_bkt_hdrlen,
     370  			     init_nhmsg_res_bkt, print_nhmsg_res_bkt,
     371  			     unk_res_bkt_types[i], nla_type_str,
     372  			     16, pattern, 16,
     373  			     print_quoted_hex(pattern, 16);
     374  			     printf("]"));
     375  	}
     376  
     377  	/* not decoded: NHA_RES_BUCKET_UNSPEC/NHA_RES_BUCKET_PAD */
     378  	TEST_NLATTR_(fd, nlh1, res_bkt_hdrlen,
     379  		     init_nhmsg_res_bkt, print_nhmsg_res_bkt,
     380  		     NHA_RES_BUCKET_PAD, XLAT_KNOWN(0, "NHA_RES_BUCKET_PAD"),
     381  		     8, pattern, 8,
     382  		     print_quoted_hex(pattern, 8);
     383  		     printf("]"));
     384  
     385  	/* u16: NHA_RES_BUCKET_INDEX */
     386  	check_u16_nlattr(fd, nlh0, hdrlen,
     387  			 init_nhmsg_res_bkt, print_nhmsg_res_bkt,
     388  			 ARG_XLAT_KNOWN(0x1, "NHA_RES_BUCKET_INDEX"),
     389  			 pattern, 1);
     390  
     391  	/* clock_t: NHA_RES_BUCKET_IDLE_TIME */
     392  	static const struct strval32 res_bkt_clk_attrs[] = {
     393  		{ ARG_XLAT_KNOWN(0x2, "NHA_RES_BUCKET_IDLE_TIME") },
     394  	};
     395  	for (size_t i = 0; i < ARRAY_SIZE(res_bkt_clk_attrs); i++) {
     396  		check_clock_t_nlattr(fd, nlh0, hdrlen,
     397  				     init_nhmsg_res_bkt, print_nhmsg_res_bkt,
     398  				     res_bkt_clk_attrs[i].val,
     399  				     res_bkt_clk_attrs[i].str, 1);
     400  	}
     401  
     402  	/* u32: NHA_RES_BUCKET_NH_ID */
     403  	check_u32_nlattr(fd, nlh0, hdrlen,
     404  			 init_nhmsg_res_bkt, print_nhmsg_res_bkt,
     405  			 ARG_XLAT_KNOWN(0x3, "NHA_RES_BUCKET_NH_ID"),
     406  			 pattern, 1);
     407  
     408  
     409  	puts("+++ exited with 0 +++");
     410  	return 0;
     411  }