~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/net/ipv6_flowlabel.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* Test IPV6_FLOWINFO cmsg on send and recv */
  3 
  4 #define _GNU_SOURCE
  5 
  6 #include <arpa/inet.h>
  7 #include <asm/byteorder.h>
  8 #include <error.h>
  9 #include <errno.h>
 10 #include <fcntl.h>
 11 #include <limits.h>
 12 #include <linux/icmpv6.h>
 13 #include <linux/in6.h>
 14 #include <stdbool.h>
 15 #include <stdio.h>
 16 #include <stdint.h>
 17 #include <stdlib.h>
 18 #include <string.h>
 19 #include <sys/socket.h>
 20 #include <sys/stat.h>
 21 #include <sys/time.h>
 22 #include <sys/types.h>
 23 #include <unistd.h>
 24 
 25 /* uapi/glibc weirdness may leave this undefined */
 26 #ifndef IPV6_FLOWINFO
 27 #define IPV6_FLOWINFO 11
 28 #endif
 29 
 30 #ifndef IPV6_FLOWLABEL_MGR
 31 #define IPV6_FLOWLABEL_MGR 32
 32 #endif
 33 #ifndef IPV6_FLOWINFO_SEND
 34 #define IPV6_FLOWINFO_SEND 33
 35 #endif
 36 
 37 #define FLOWLABEL_WILDCARD      ((uint32_t) -1)
 38 
 39 static const char cfg_data[]    = "a";
 40 static uint32_t cfg_label       = 1;
 41 static bool use_ping;
 42 static bool use_flowinfo_send;
 43 
 44 static struct icmp6hdr icmp6 = {
 45         .icmp6_type = ICMPV6_ECHO_REQUEST
 46 };
 47 
 48 static struct sockaddr_in6 addr = {
 49         .sin6_family = AF_INET6,
 50         .sin6_addr = IN6ADDR_LOOPBACK_INIT,
 51 };
 52 
 53 static void do_send(int fd, bool with_flowlabel, uint32_t flowlabel)
 54 {
 55         char control[CMSG_SPACE(sizeof(flowlabel))] = {0};
 56         struct msghdr msg = {0};
 57         struct iovec iov = {
 58                 .iov_base = (char *)cfg_data,
 59                 .iov_len = sizeof(cfg_data)
 60         };
 61         int ret;
 62 
 63         if (use_ping) {
 64                 iov.iov_base = &icmp6;
 65                 iov.iov_len = sizeof(icmp6);
 66         }
 67 
 68         msg.msg_iov = &iov;
 69         msg.msg_iovlen = 1;
 70 
 71         if (use_flowinfo_send) {
 72                 msg.msg_name = &addr;
 73                 msg.msg_namelen = sizeof(addr);
 74         } else if (with_flowlabel) {
 75                 struct cmsghdr *cm;
 76 
 77                 cm = (void *)control;
 78                 cm->cmsg_len = CMSG_LEN(sizeof(flowlabel));
 79                 cm->cmsg_level = SOL_IPV6;
 80                 cm->cmsg_type = IPV6_FLOWINFO;
 81                 *(uint32_t *)CMSG_DATA(cm) = htonl(flowlabel);
 82 
 83                 msg.msg_control = control;
 84                 msg.msg_controllen = sizeof(control);
 85         }
 86 
 87         ret = sendmsg(fd, &msg, 0);
 88         if (ret == -1)
 89                 error(1, errno, "send");
 90 
 91         if (with_flowlabel)
 92                 fprintf(stderr, "sent with label %u\n", flowlabel);
 93         else
 94                 fprintf(stderr, "sent without label\n");
 95 }
 96 
 97 static void do_recv(int fd, bool with_flowlabel, uint32_t expect)
 98 {
 99         char control[CMSG_SPACE(sizeof(expect))];
100         char data[sizeof(cfg_data)];
101         struct msghdr msg = {0};
102         struct iovec iov = {0};
103         struct cmsghdr *cm;
104         uint32_t flowlabel;
105         int ret;
106 
107         iov.iov_base = data;
108         iov.iov_len = sizeof(data);
109 
110         msg.msg_iov = &iov;
111         msg.msg_iovlen = 1;
112 
113         memset(control, 0, sizeof(control));
114         msg.msg_control = control;
115         msg.msg_controllen = sizeof(control);
116 
117         ret = recvmsg(fd, &msg, 0);
118         if (ret == -1)
119                 error(1, errno, "recv");
120         if (use_ping)
121                 goto parse_cmsg;
122         if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))
123                 error(1, 0, "recv: truncated");
124         if (ret != sizeof(cfg_data))
125                 error(1, 0, "recv: length mismatch");
126         if (memcmp(data, cfg_data, sizeof(data)))
127                 error(1, 0, "recv: data mismatch");
128 
129 parse_cmsg:
130         cm = CMSG_FIRSTHDR(&msg);
131         if (with_flowlabel) {
132                 if (!cm)
133                         error(1, 0, "recv: missing cmsg");
134                 if (CMSG_NXTHDR(&msg, cm))
135                         error(1, 0, "recv: too many cmsg");
136                 if (cm->cmsg_level != SOL_IPV6 ||
137                     cm->cmsg_type != IPV6_FLOWINFO)
138                         error(1, 0, "recv: unexpected cmsg level or type");
139 
140                 flowlabel = ntohl(*(uint32_t *)CMSG_DATA(cm));
141                 fprintf(stderr, "recv with label %u\n", flowlabel);
142 
143                 if (expect != FLOWLABEL_WILDCARD && expect != flowlabel) {
144                         fprintf(stderr, "recv: incorrect flowlabel %u != %u\n",
145                                         flowlabel, expect);
146                         error(1, 0, "recv: flowlabel is wrong");
147                 }
148 
149         } else {
150                 fprintf(stderr, "recv without label\n");
151         }
152 }
153 
154 static bool get_autoflowlabel_enabled(void)
155 {
156         int fd, ret;
157         char val;
158 
159         fd = open("/proc/sys/net/ipv6/auto_flowlabels", O_RDONLY);
160         if (fd == -1)
161                 error(1, errno, "open sysctl");
162 
163         ret = read(fd, &val, 1);
164         if (ret == -1)
165                 error(1, errno, "read sysctl");
166         if (ret == 0)
167                 error(1, 0, "read sysctl: 0");
168 
169         if (close(fd))
170                 error(1, errno, "close sysctl");
171 
172         return val == '1';
173 }
174 
175 static void flowlabel_get(int fd, uint32_t label, uint8_t share, uint16_t flags)
176 {
177         struct in6_flowlabel_req req = {
178                 .flr_action = IPV6_FL_A_GET,
179                 .flr_label = htonl(label),
180                 .flr_flags = flags,
181                 .flr_share = share,
182         };
183 
184         /* do not pass IPV6_ADDR_ANY or IPV6_ADDR_MAPPED */
185         req.flr_dst.s6_addr[0] = 0xfd;
186         req.flr_dst.s6_addr[15] = 0x1;
187 
188         if (setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req)))
189                 error(1, errno, "setsockopt flowlabel get");
190 }
191 
192 static void parse_opts(int argc, char **argv)
193 {
194         int c;
195 
196         while ((c = getopt(argc, argv, "l:ps")) != -1) {
197                 switch (c) {
198                 case 'l':
199                         cfg_label = strtoul(optarg, NULL, 0);
200                         break;
201                 case 'p':
202                         use_ping = true;
203                         break;
204                 case 's':
205                         use_flowinfo_send = true;
206                         break;
207                 default:
208                         error(1, 0, "%s: parse error", argv[0]);
209                 }
210         }
211 }
212 
213 int main(int argc, char **argv)
214 {
215         const int one = 1;
216         int fdt, fdr;
217         int prot = 0;
218 
219         addr.sin6_port = htons(8000);
220 
221         parse_opts(argc, argv);
222 
223         if (use_ping) {
224                 fprintf(stderr, "attempting to use ping sockets\n");
225                 prot = IPPROTO_ICMPV6;
226         }
227 
228         fdt = socket(PF_INET6, SOCK_DGRAM, prot);
229         if (fdt == -1)
230                 error(1, errno, "socket t");
231 
232         fdr = use_ping ? fdt : socket(PF_INET6, SOCK_DGRAM, 0);
233         if (fdr == -1)
234                 error(1, errno, "socket r");
235 
236         if (connect(fdt, (void *)&addr, sizeof(addr)))
237                 error(1, errno, "connect");
238         if (!use_ping && bind(fdr, (void *)&addr, sizeof(addr)))
239                 error(1, errno, "bind");
240 
241         flowlabel_get(fdt, cfg_label, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE);
242 
243         if (setsockopt(fdr, SOL_IPV6, IPV6_FLOWINFO, &one, sizeof(one)))
244                 error(1, errno, "setsockopt flowinfo");
245 
246         if (get_autoflowlabel_enabled()) {
247                 fprintf(stderr, "send no label: recv auto flowlabel\n");
248                 do_send(fdt, false, 0);
249                 do_recv(fdr, true, FLOWLABEL_WILDCARD);
250         } else {
251                 fprintf(stderr, "send no label: recv no label (auto off)\n");
252                 do_send(fdt, false, 0);
253                 do_recv(fdr, false, 0);
254         }
255 
256         if (use_flowinfo_send) {
257                 fprintf(stderr, "using IPV6_FLOWINFO_SEND to send label\n");
258                 addr.sin6_flowinfo = htonl(cfg_label);
259                 if (setsockopt(fdt, SOL_IPV6, IPV6_FLOWINFO_SEND, &one,
260                                sizeof(one)) == -1)
261                         error(1, errno, "setsockopt flowinfo_send");
262         }
263 
264         fprintf(stderr, "send label\n");
265         do_send(fdt, true, cfg_label);
266         do_recv(fdr, true, cfg_label);
267 
268         if (close(fdr))
269                 error(1, errno, "close r");
270         if (!use_ping && close(fdt))
271                 error(1, errno, "close t");
272 
273         return 0;
274 }
275 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php