]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/lsfd-sock-xinfo.c
tests: (mkfds) add ping and ping6 factories
[thirdparty/util-linux.git] / misc-utils / lsfd-sock-xinfo.c
CommitLineData
0ee16e43
MY
1/*
2 * lsfd-sock-xinfo.c - read various information from files under /proc/net/
3 *
4 * Copyright (C) 2022 Red Hat, Inc. All rights reserved.
5 * Written by Masatake YAMATO <yamato@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it would be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
7b2a9be0 21#include <arpa/inet.h> /* inet_ntop */
1656da13 22#include <netinet/in.h> /* in6_addr */
2e38e61c 23#include <fcntl.h> /* open(2) */
73df46fc 24#include <inttypes.h> /* SCNu16 */
2e38e61c
MY
25#include <linux/net.h> /* SS_* */
26#include <linux/un.h> /* UNIX_PATH_MAX */
0ee16e43
MY
27#include <sched.h> /* for setns(2) */
28#include <search.h>
2e38e61c
MY
29#include <stdint.h>
30#include <string.h>
31#include <sys/socket.h> /* SOCK_* */
0ee16e43
MY
32
33#include "xalloc.h"
34#include "nls.h"
35#include "libsmartcols.h"
db79a100
TW
36#include "sysfs.h"
37#include "bitops.h"
0ee16e43
MY
38
39#include "lsfd.h"
40#include "lsfd-sock.h"
41
2e38e61c 42static void load_xinfo_from_proc_unix(ino_t netns_inode);
0188afb3 43static void load_xinfo_from_proc_raw(ino_t netns_inode);
7b2a9be0 44static void load_xinfo_from_proc_tcp(ino_t netns_inode);
92a0dbce 45static void load_xinfo_from_proc_udp(ino_t netns_inode);
c779f412 46static void load_xinfo_from_proc_udplite(ino_t netns_inode);
1656da13 47static void load_xinfo_from_proc_tcp6(ino_t netns_inode);
28cf2b21 48static void load_xinfo_from_proc_udp6(ino_t netns_inode);
93bca151 49static void load_xinfo_from_proc_udplite6(ino_t netns_inode);
2dd373c3 50static void load_xinfo_from_proc_raw6(ino_t netns_inode);
2e38e61c 51
0ee16e43 52static int self_netns_fd = -1;
44f9aec7 53static struct stat self_netns_sb;
0ee16e43
MY
54
55static void *xinfo_tree; /* for tsearch/tfind */
56static void *netns_tree;
57
58static int netns_compare(const void *a, const void *b)
59{
60 if (*(ino_t *)a < *(ino_t *)b)
61 return -1;
62 else if (*(ino_t *)a > *(ino_t *)b)
63 return 1;
64 else
65 return 0;
66}
67
68static bool is_sock_xinfo_loaded(ino_t netns)
69{
70 return tfind(&netns, &netns_tree, netns_compare)? true: false;
71}
72
73static void mark_sock_xinfo_loaded(ino_t ino)
74{
75 ino_t *netns = xmalloc(sizeof(ino));
76 ino_t **tmp;
77
78 *netns = ino;
79 tmp = tsearch(netns, &netns_tree, netns_compare);
80 if (tmp == NULL)
81 errx(EXIT_FAILURE, _("failed to allocate memory"));
82}
83
2e38e61c 84static void load_sock_xinfo_no_nsswitch(ino_t netns)
0ee16e43 85{
2e38e61c 86 load_xinfo_from_proc_unix(netns);
7b2a9be0 87 load_xinfo_from_proc_tcp(netns);
92a0dbce 88 load_xinfo_from_proc_udp(netns);
c779f412 89 load_xinfo_from_proc_udplite(netns);
0188afb3 90 load_xinfo_from_proc_raw(netns);
1656da13 91 load_xinfo_from_proc_tcp6(netns);
28cf2b21 92 load_xinfo_from_proc_udp6(netns);
93bca151 93 load_xinfo_from_proc_udplite6(netns);
2dd373c3 94 load_xinfo_from_proc_raw6(netns);
0ee16e43
MY
95}
96
97static void load_sock_xinfo_with_fd(int fd, ino_t netns)
98{
b3649945 99 if (setns(fd, CLONE_NEWNET) == 0) {
0ee16e43 100 load_sock_xinfo_no_nsswitch(netns);
b3649945 101 setns(self_netns_fd, CLONE_NEWNET);
0ee16e43
MY
102 }
103}
104
105void load_sock_xinfo(struct path_cxt *pc, const char *name, ino_t netns)
106{
107 if (self_netns_fd == -1)
108 return;
109
110 if (!is_sock_xinfo_loaded(netns)) {
111 int fd;
112
113 mark_sock_xinfo_loaded(netns);
114 fd = ul_path_open(pc, O_RDONLY, name);
115 if (fd < 0)
116 return;
117
118 load_sock_xinfo_with_fd(fd, netns);
119 close(fd);
120 }
121}
122
123void initialize_sock_xinfos(void)
124{
125 struct path_cxt *pc;
126 DIR *dir;
127 struct dirent *d;
128
129 self_netns_fd = open("/proc/self/ns/net", O_RDONLY);
130
131 if (self_netns_fd < 0)
132 load_sock_xinfo_no_nsswitch(0);
133 else {
134 if (fstat(self_netns_fd, &self_netns_sb) == 0) {
135 mark_sock_xinfo_loaded(self_netns_sb.st_ino);
136 load_sock_xinfo_no_nsswitch(self_netns_sb.st_ino);
137 }
138 }
139
140 /* Load /proc/net/{unix,...} of the network namespace
141 * specified with netns files under /var/run/netns/.
142 *
143 * `ip netns' command pins a network namespace on
144 * /var/run/netns.
145 */
146 pc = ul_new_path("/var/run/netns");
147 if (!pc)
148 err(EXIT_FAILURE, _("failed to alloc path context for /var/run/netns"));
149 dir = ul_path_opendir(pc, NULL);
150 if (dir == NULL) {
151 ul_unref_path(pc);
152 return;
153 }
154 while ((d = readdir(dir))) {
155 struct stat sb;
156 int fd;
157 if (ul_path_stat(pc, &sb, 0, d->d_name) < 0)
158 continue;
159 if (is_sock_xinfo_loaded(sb.st_ino))
160 continue;
161 mark_sock_xinfo_loaded(sb.st_ino);
162 fd = ul_path_open(pc, O_RDONLY, d->d_name);
163 if (fd < 0)
164 continue;
165 load_sock_xinfo_with_fd(fd, sb.st_ino);
166 close(fd);
167 }
168 closedir(dir);
169 ul_unref_path(pc);
170}
171
b3649945 172static void free_sock_xinfo(void *node)
0ee16e43
MY
173{
174 struct sock_xinfo *xinfo = node;
175 if (xinfo->class->free)
b3649945 176 xinfo->class->free(xinfo);
0ee16e43
MY
177 free(node);
178}
179
180void finalize_sock_xinfos(void)
181{
182 if (self_netns_fd != -1)
183 close(self_netns_fd);
184 tdestroy(netns_tree, free);
185 tdestroy(xinfo_tree, free_sock_xinfo);
186}
187
188static int xinfo_compare(const void *a, const void *b)
189{
190 if (((struct sock_xinfo *)a)->inode < ((struct sock_xinfo *)b)->inode)
191 return -1;
192 if (((struct sock_xinfo *)a)->inode > ((struct sock_xinfo *)b)->inode)
193 return 1;
194 return 0;
195}
196
2e38e61c
MY
197static void add_sock_info(struct sock_xinfo *xinfo)
198{
199 struct sock_xinfo **tmp = tsearch(xinfo, &xinfo_tree, xinfo_compare);
200
201 if (tmp == NULL)
202 errx(EXIT_FAILURE, _("failed to allocate memory"));
203}
204
0ee16e43
MY
205struct sock_xinfo *get_sock_xinfo(ino_t netns_inode)
206{
207 struct sock_xinfo **xinfo = tfind(&netns_inode, &xinfo_tree, xinfo_compare);
208
209 if (xinfo)
210 return *xinfo;
211 return NULL;
212}
213
214bool is_nsfs_dev(dev_t dev)
215{
621cf7e9 216 return dev == self_netns_sb.st_dev;
0ee16e43 217}
2e38e61c
MY
218
219static const char *sock_decode_type(uint16_t type)
220{
221 switch (type) {
222 case SOCK_STREAM:
223 return "stream";
224 case SOCK_DGRAM:
225 return "dgram";
226 case SOCK_RAW:
227 return "raw";
228 case SOCK_RDM:
229 return "rdm";
230 case SOCK_SEQPACKET:
231 return "seqpacket";
232 case SOCK_DCCP:
233 return "dccp";
234 case SOCK_PACKET:
235 return "packet";
236 default:
237 return "unknown";
238 }
239}
240
241/*
242 * Protocol specific code
243 */
244
245/*
246 * UNIX
247 */
248struct unix_xinfo {
249 struct sock_xinfo sock;
250 int acceptcon; /* flags */
251 uint16_t type;
252 uint8_t st;
253 char path[
254 UNIX_PATH_MAX
255 + 1 /* for @ */
256 + 1 /* \0? */
257 ];
258};
259
260static const char *unix_decode_state(uint8_t st)
261{
262 switch (st) {
263 case SS_FREE:
264 return "free";
265 case SS_UNCONNECTED:
266 return "unconnected";
267 case SS_CONNECTING:
268 return "connecting";
269 case SS_CONNECTED:
270 return "connected";
271 case SS_DISCONNECTING:
272 return "disconnecting";
273 default:
274 return "unknown";
275 }
276}
277
278static char *unix_get_name(struct sock_xinfo *sock_xinfo,
279 struct sock *sock)
280{
281 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
282 const char *state = unix_decode_state(ux->st);
283 char *str = NULL;
284
285 if (sock->protoname && (strcmp(sock->protoname, "UNIX-STREAM") == 0))
286 xasprintf(&str, "state=%s%s%s",
287 (ux->acceptcon)? "listen": state,
288 *(ux->path)? " path=": "",
289 *(ux->path)? ux->path: "");
290 else
291 xasprintf(&str, "state=%s%s%s type=%s",
292 (ux->acceptcon)? "listen": state,
293 *(ux->path)? " path=": "",
294 *(ux->path)? ux->path: "",
295 sock_decode_type(ux->type));
296 return str;
297}
298
299static char *unix_get_type(struct sock_xinfo *sock_xinfo,
300 struct sock *sock __attribute__((__unused__)))
301{
302 const char *str;
303 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
304
305 str = sock_decode_type(ux->type);
306 return strdup(str);
307}
308
309static char *unix_get_state(struct sock_xinfo *sock_xinfo,
310 struct sock *sock __attribute__((__unused__)))
311{
312 const char *str;
313 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
314
315 if (ux->acceptcon)
316 return strdup("listen");
317
318 str = unix_decode_state(ux->st);
319 return strdup(str);
320}
321
45d61bff
MY
322static bool unix_get_listening(struct sock_xinfo *sock_xinfo,
323 struct sock *sock __attribute__((__unused__)))
324{
325 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
326
327 return ux->acceptcon;
328}
329
2e38e61c
MY
330static bool unix_fill_column(struct proc *proc __attribute__((__unused__)),
331 struct sock_xinfo *sock_xinfo,
332 struct sock *sock __attribute__((__unused__)),
333 struct libscols_line *ln __attribute__((__unused__)),
334 int column_id,
335 size_t column_index __attribute__((__unused__)),
336 char **str)
337{
338 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
339
854ddd0d 340 switch (column_id) {
2e38e61c
MY
341 case COL_UNIX_PATH:
342 if (*ux->path) {
343 *str = strdup(ux->path);
344 return true;
345 }
346 break;
347 }
348
349 return false;
350}
351
54a06438 352static const struct sock_xinfo_class unix_xinfo_class = {
2e38e61c
MY
353 .get_name = unix_get_name,
354 .get_type = unix_get_type,
355 .get_state = unix_get_state,
45d61bff 356 .get_listening = unix_get_listening,
2e38e61c
MY
357 .fill_column = unix_fill_column,
358 .free = NULL,
359};
360
e8e14a28 361/* UNIX_LINE_LEN need at least 54 + 21 + UNIX_PATH_MAX + 1.
eeaf7677
MY
362 *
363 * An actual number must be used in this definition
364 * since UNIX_LINE_LEN is specified as an argument for
365 * stringify_value().
366 */
2e38e61c
MY
367#define UNIX_LINE_LEN 256
368static void load_xinfo_from_proc_unix(ino_t netns_inode)
369{
370 char line[UNIX_LINE_LEN];
371 FILE *unix_fp;
372
373 unix_fp = fopen("/proc/net/unix", "r");
374 if (!unix_fp)
375 return;
376
377 if (fgets(line, sizeof(line), unix_fp) == NULL)
378 goto out;
b3649945 379 if (!(line[0] == 'N' && line[1] == 'u' && line[2] == 'm'))
2e38e61c
MY
380 /* Unexpected line */
381 goto out;
382
383 while (fgets(line, sizeof(line), unix_fp)) {
384 uint64_t flags;
385 uint32_t type;
386 unsigned int st;
387 unsigned long inode;
2e38e61c 388 struct unix_xinfo *ux;
eeaf7677 389 char path[UNIX_LINE_LEN + 1] = { 0 };
91a484fe 390
2e38e61c 391
eeaf7677
MY
392 if (sscanf(line, "%*x: %*x %*x %" SCNx64 " %x %x %lu %"
393 stringify_value(UNIX_LINE_LEN) "[^\n]",
2e38e61c
MY
394 &flags, &type, &st, &inode, path) < 4)
395 continue;
396
397 if (inode == 0)
398 continue;
399
8ff22ccb 400 ux = xcalloc(1, sizeof(*ux));
2e38e61c
MY
401 ux->sock.class = &unix_xinfo_class;
402 ux->sock.inode = (ino_t)inode;
403 ux->sock.netns_inode = netns_inode;
404
405 ux->acceptcon = !!flags;
406 ux->type = type;
407 ux->st = st;
91a484fe 408 xstrncpy(ux->path, path, sizeof(ux->path));
2e38e61c 409
2ac8d1a3 410 add_sock_info(&ux->sock);
2e38e61c
MY
411 }
412
413 out:
414 fclose(unix_fp);
415}
7b2a9be0
MY
416
417/*
418 * AF_INET
419 */
420struct inet_xinfo {
421 struct sock_xinfo sock;
643f30c7
MY
422 struct in_addr local_addr;
423 struct in_addr remote_addr;
7b2a9be0
MY
424};
425
9020c2e0 426static uint32_t kernel32_to_cpu(enum sysfs_byteorder byteorder, uint32_t v)
7b2a9be0 427{
9020c2e0
MY
428 if (byteorder == SYSFS_BYTEORDER_LITTLE)
429 return le32_to_cpu(v);
430 else
431 return be32_to_cpu(v);
7b2a9be0
MY
432}
433
1656da13
MY
434/*
435 * AF_INET6
436 */
437struct inet6_xinfo {
438 struct sock_xinfo sock;
439 struct in6_addr local_addr;
440 struct in6_addr remote_addr;
441};
442
7b2a9be0 443/*
4a2b51c1 444 * L4 abstract-layer for protocols stacked on IP and IP6.
7b2a9be0 445 */
303b41fe 446enum l4_state {
7b2a9be0
MY
447 /*
448 * Taken from linux/include/net/tcp_states.h.
449 * (GPL-2.0-or-later)
303b41fe
MY
450 *
451 * UDP and RAW sockets also uses the contents in Linux.
7b2a9be0
MY
452 */
453 TCP_ESTABLISHED = 1,
454 TCP_SYN_SENT,
455 TCP_SYN_RECV,
456 TCP_FIN_WAIT1,
457 TCP_FIN_WAIT2,
458 TCP_TIME_WAIT,
459 TCP_CLOSE,
460 TCP_CLOSE_WAIT,
461 TCP_LAST_ACK,
462 TCP_LISTEN,
463 TCP_CLOSING,
464 TCP_NEW_SYN_RECV,
465
466 TCP_MAX_STATES /* Leave at the end! */
467};
468
303b41fe 469static const char *l4_decode_state(enum l4_state st)
7b2a9be0
MY
470{
471 const char * table [] = {
472 [TCP_ESTABLISHED] = "established",
473 [TCP_SYN_SENT] = "syn-sent",
474 [TCP_SYN_RECV] = "syn-recv",
475 [TCP_FIN_WAIT1] = "fin-wait1",
476 [TCP_FIN_WAIT2] = "fin-wait2",
477 [TCP_TIME_WAIT] = "time-wait",
478 [TCP_CLOSE] = "close",
479 [TCP_CLOSE_WAIT] = "close-wait",
480 [TCP_LAST_ACK] = "last-ack",
481 [TCP_LISTEN] = "listen",
482 [TCP_CLOSING] = "closing",
483 [TCP_NEW_SYN_RECV] = "new-syn-recv",
484 };
485
486 if (st < TCP_MAX_STATES)
487 return table[st];
488 return "unknown";
489}
490
4a2b51c1 491struct l4_xinfo {
1656da13
MY
492 union {
493 struct inet_xinfo inet;
494 struct inet6_xinfo inet6;
495 };
303b41fe 496 enum l4_state st;
4a2b51c1
MY
497};
498
2a4f2b1b 499enum l4_side { L4_LOCAL, L4_REMOTE };
1656da13 500enum l3_decorator { L3_DECO_START, L3_DECO_END };
2a4f2b1b 501
4a2b51c1
MY
502struct l4_xinfo_class {
503 struct sock_xinfo_class sock;
19e40223
MY
504 struct sock_xinfo *(*scan_line)(const struct sock_xinfo_class *,
505 char *,
506 ino_t,
507 enum sysfs_byteorder);
2a4f2b1b
MY
508 void * (*get_addr)(struct l4_xinfo *, enum l4_side);
509 bool (*is_any_addr)(void *);
510 int family;
1656da13 511 const char *l3_decorator[2];
4a2b51c1
MY
512};
513
838fa270
MY
514#define l3_fill_column_handler(L3, SOCK_XINFO, COLUMN_ID, STR) __extension__ \
515 ({ \
516 struct l4_xinfo_class *class = (struct l4_xinfo_class *)SOCK_XINFO->class; \
517 struct l4_xinfo *l4 = (struct l4_xinfo *)SOCK_XINFO; \
518 void *n = NULL; \
519 char s[BUFSIZ]; \
520 bool r = false; \
521 \
522 switch (COLUMN_ID) { \
523 case COL_##L3##_LADDR: \
524 n = class->get_addr(l4, L4_LOCAL); \
525 break; \
526 case COL_##L3##_RADDR: \
527 n = class->get_addr(l4, L4_REMOTE); \
528 break; \
529 default: \
530 break; \
531 } \
532 \
533 if (n && inet_ntop(class->family, n, s, sizeof(s))) { \
534 *STR = strdup(s); \
535 r = true; \
536 } \
537 r; \
538 })
539
7b2a9be0
MY
540/*
541 * TCP
542 */
543struct tcp_xinfo {
4a2b51c1 544 struct l4_xinfo l4;
7b2a9be0
MY
545 uint16_t local_port;
546 uint16_t remote_port;
7b2a9be0
MY
547};
548
7b2a9be0
MY
549static char *tcp_get_name(struct sock_xinfo *sock_xinfo,
550 struct sock *sock __attribute__((__unused__)))
551{
552 char *str = NULL;
7b2a9be0 553 struct tcp_xinfo *tcp = ((struct tcp_xinfo *)sock_xinfo);
8db07ebc 554 struct l4_xinfo *l4 = &tcp->l4;
303b41fe 555 const char *st_str = l4_decode_state(l4->st);
838fa270
MY
556 struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
557 void *laddr = class->get_addr(l4, L4_LOCAL);
558 void *raddr = class->get_addr(l4, L4_REMOTE);
559 char local_s[BUFSIZ];
560 char remote_s[BUFSIZ];
1656da13
MY
561 const char *start = class->l3_decorator[L3_DECO_START];
562 const char *end = class->l3_decorator[L3_DECO_END];
7b2a9be0 563
838fa270 564 if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
3b182ee7
MY
565 xasprintf(&str, "state=%s", st_str);
566 else if (l4->st == TCP_LISTEN
838fa270 567 || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
b4e39841 568 xasprintf(&str, "state=%s laddr=%s%s%s:%"PRIu16,
3b182ee7 569 st_str,
1656da13 570 start, local_s, end, tcp->local_port);
7b2a9be0 571 else
b4e39841 572 xasprintf(&str, "state=%s laddr=%s%s%s:%"PRIu16" raddr=%s%s%s:%"PRIu16,
3b182ee7 573 st_str,
1656da13
MY
574 start, local_s, end, tcp->local_port,
575 start, remote_s, end, tcp->remote_port);
7b2a9be0
MY
576 return str;
577}
578
579static char *tcp_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
580 struct sock *sock __attribute__((__unused__)))
581{
582 return strdup("stream");
583}
584
585static char *tcp_get_state(struct sock_xinfo *sock_xinfo,
586 struct sock *sock __attribute__((__unused__)))
587{
303b41fe 588 return strdup(l4_decode_state(((struct l4_xinfo *)sock_xinfo)->st));
7b2a9be0
MY
589}
590
591static bool tcp_get_listening(struct sock_xinfo *sock_xinfo,
592 struct sock *sock __attribute__((__unused__)))
593{
8db07ebc 594 return ((struct l4_xinfo *)sock_xinfo)->st == TCP_LISTEN;
7b2a9be0
MY
595}
596
838fa270
MY
597#define l4_fill_column_handler(L4, SOCK_XINFO, COLUMN_ID, STR) __extension__ \
598 ({ \
599 struct l4_xinfo_class *class = (struct l4_xinfo_class *)SOCK_XINFO->class; \
600 struct tcp_xinfo *tcp = (struct tcp_xinfo *)SOCK_XINFO; \
601 struct l4_xinfo *l4 = &tcp->l4; \
602 void *n = NULL; \
92a0dbce 603 bool has_laddr = false; \
73df46fc 604 unsigned short p; \
92a0dbce 605 bool has_lport = false; \
838fa270
MY
606 char s[BUFSIZ]; \
607 bool r = true; \
92a0dbce 608 \
838fa270 609 switch (COLUMN_ID) { \
cda2b2a0 610 case COL_##L4##_LADDR: \
838fa270 611 n = class->get_addr(l4, L4_LOCAL); \
92a0dbce 612 has_laddr = true; \
73df46fc 613 p = tcp->local_port; \
92a0dbce 614 /* FALL THROUGH */ \
cda2b2a0 615 case COL_##L4##_RADDR: \
92a0dbce 616 if (!has_laddr) { \
838fa270 617 n = class->get_addr(l4, L4_REMOTE); \
73df46fc 618 p = tcp->remote_port; \
92a0dbce 619 } \
838fa270 620 if (n && inet_ntop(class->family, n, s, sizeof(s))) \
b4e39841 621 xasprintf(STR, "%s%s%s:%"PRIu16, \
1656da13
MY
622 class->l3_decorator[L3_DECO_START], \
623 s, \
624 class->l3_decorator[L3_DECO_END], \
625 p); \
92a0dbce 626 break; \
cda2b2a0 627 case COL_##L4##_LPORT: \
73df46fc 628 p = tcp->local_port; \
92a0dbce
MY
629 has_lport = true; \
630 /* FALL THROUGH */ \
cda2b2a0 631 case COL_##L4##_RPORT: \
92a0dbce 632 if (!has_lport) \
73df46fc 633 p = tcp->remote_port; \
b4e39841 634 xasprintf(STR, "%"PRIu16, p); \
92a0dbce
MY
635 break; \
636 default: \
838fa270
MY
637 r = false; \
638 break; \
92a0dbce 639 } \
838fa270
MY
640 r; \
641 })
7b2a9be0 642
19e40223
MY
643static struct sock_xinfo *tcp_xinfo_scan_line(const struct sock_xinfo_class *class,
644 char * line,
645 ino_t netns_inode,
646 enum sysfs_byteorder byteorder)
647{
648 unsigned long local_addr;
649 unsigned long local_port;
650 unsigned long remote_addr;
651 unsigned long remote_port;
652 unsigned long st;
653 unsigned long long inode;
654 struct tcp_xinfo *tcp;
655 struct inet_xinfo *inet;
656 struct sock_xinfo *sock;
657
658 if (sscanf(line, "%*d: %lx:%lx %lx:%lx %lx %*x:%*x %*x:%*x %*x %*u %*u %lld",
659 &local_addr, &local_port, &remote_addr, &remote_port,
660 &st, &inode) != 6)
661 return NULL;
662
663 if (inode == 0)
664 return NULL;
665
8ff22ccb 666 tcp = xcalloc(1, sizeof(*tcp));
19e40223
MY
667 inet = &tcp->l4.inet;
668 sock = &inet->sock;
669 sock->class = class;
670 sock->inode = (ino_t)inode;
671 sock->netns_inode = netns_inode;
672 inet->local_addr.s_addr = kernel32_to_cpu(byteorder, local_addr);
673 tcp->local_port = local_port;
674 inet->remote_addr.s_addr = kernel32_to_cpu(byteorder, remote_addr);
675 tcp->remote_port = remote_port;
8db07ebc 676 tcp->l4.st = st;
19e40223
MY
677
678 return sock;
679}
680
2a4f2b1b
MY
681static void *tcp_xinfo_get_addr(struct l4_xinfo *l4, enum l4_side side)
682{
683 return (side == L4_LOCAL)
684 ? &l4->inet.local_addr
685 : &l4->inet.remote_addr;
686}
687
688static bool tcp_xinfo_is_any_addr(void *addr)
689{
690 return ((struct in_addr *)addr)->s_addr == INADDR_ANY;
691}
692
838fa270
MY
693static bool tcp_fill_column(struct proc *proc __attribute__((__unused__)),
694 struct sock_xinfo *sock_xinfo,
695 struct sock *sock __attribute__((__unused__)),
696 struct libscols_line *ln __attribute__((__unused__)),
697 int column_id,
698 size_t column_index __attribute__((__unused__)),
699 char **str)
700{
701 return l3_fill_column_handler(INET, sock_xinfo, column_id, str)
702 || l4_fill_column_handler(TCP, sock_xinfo, column_id, str);
703}
704
4a2b51c1
MY
705static const struct l4_xinfo_class tcp_xinfo_class = {
706 .sock = {
707 .get_name = tcp_get_name,
708 .get_type = tcp_get_type,
709 .get_state = tcp_get_state,
710 .get_listening = tcp_get_listening,
711 .fill_column = tcp_fill_column,
712 .free = NULL,
713 },
19e40223 714 .scan_line = tcp_xinfo_scan_line,
2a4f2b1b
MY
715 .get_addr = tcp_xinfo_get_addr,
716 .is_any_addr = tcp_xinfo_is_any_addr,
717 .family = AF_INET,
1656da13 718 .l3_decorator = {"", ""},
7b2a9be0
MY
719};
720
cda2b2a0 721static bool L4_verify_initial_line(const char *line)
58d2f31e
MY
722{
723 /* At least we expect two white spaces. */
cb097fb7 724 if (strncmp(line, " ", 2) != 0)
58d2f31e
MY
725 return false;
726 line += 2;
727
728 /* Skip white spaces. */
4658bfb1 729 line = skip_space(line);
58d2f31e 730
621cf7e9 731 return strncmp(line, "sl", 2) == 0;
db79a100
TW
732}
733
7b2a9be0 734#define TCP_LINE_LEN 256
cda2b2a0 735static void load_xinfo_from_proc_inet_L4(ino_t netns_inode, const char *proc_file,
4a2b51c1 736 const struct l4_xinfo_class *class)
7b2a9be0
MY
737{
738 char line[TCP_LINE_LEN];
739 FILE *tcp_fp;
740
92a0dbce 741 tcp_fp = fopen(proc_file, "r");
7b2a9be0
MY
742 if (!tcp_fp)
743 return;
744
745 if (fgets(line, sizeof(line), tcp_fp) == NULL)
746 goto out;
cda2b2a0 747 if (!L4_verify_initial_line(line))
7b2a9be0
MY
748 /* Unexpected line */
749 goto out;
750
7578e03f 751 enum sysfs_byteorder byteorder = sysfs_get_byteorder(NULL);
db79a100 752
7b2a9be0 753 while (fgets(line, sizeof(line), tcp_fp)) {
19e40223
MY
754 struct sock_xinfo *sock = class->scan_line(&class->sock, line, netns_inode, byteorder);
755 if (sock)
756 add_sock_info(sock);
7b2a9be0
MY
757 }
758
759 out:
760 fclose(tcp_fp);
761}
92a0dbce 762
92a0dbce
MY
763static void load_xinfo_from_proc_tcp(ino_t netns_inode)
764{
cda2b2a0 765 load_xinfo_from_proc_inet_L4(netns_inode,
58d2f31e 766 "/proc/net/tcp",
92a0dbce
MY
767 &tcp_xinfo_class);
768}
769
770/*
771 * UDP
772 */
773static char *udp_get_name(struct sock_xinfo *sock_xinfo,
774 struct sock *sock __attribute__((__unused__)))
775{
776 char *str = NULL;
92a0dbce 777 struct tcp_xinfo *tcp = ((struct tcp_xinfo *)sock_xinfo);
8db07ebc 778 struct l4_xinfo *l4 = &tcp->l4;
8db07ebc 779 unsigned int st = l4->st;
303b41fe 780 const char *st_str = l4_decode_state(st);
838fa270
MY
781 struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
782 void *laddr = class->get_addr(l4, L4_LOCAL);
783 void *raddr = class->get_addr(l4, L4_REMOTE);
784 char local_s[BUFSIZ];
785 char remote_s[BUFSIZ];
28cf2b21
MY
786 const char *start = class->l3_decorator[L3_DECO_START];
787 const char *end = class->l3_decorator[L3_DECO_END];
92a0dbce 788
838fa270 789 if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
3b182ee7 790 xasprintf(&str, "state=%s", st_str);
838fa270
MY
791 else if ((class->is_any_addr(raddr) && tcp->remote_port == 0)
792 || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
28cf2b21 793 xasprintf(&str, "state=%s laddr=%s%s%s:%"PRIu16,
3b182ee7 794 st_str,
28cf2b21 795 start, local_s, end, tcp->local_port);
92a0dbce 796 else
28cf2b21 797 xasprintf(&str, "state=%s laddr=%s%s%s:%"PRIu16" raddr=%s%s%s:%"PRIu16,
3b182ee7 798 st_str,
28cf2b21
MY
799 start, local_s, end, tcp->local_port,
800 start, remote_s, end, tcp->remote_port);
92a0dbce
MY
801 return str;
802}
803
804static char *udp_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
805 struct sock *sock __attribute__((__unused__)))
806{
807 return strdup("dgram");
808}
809
838fa270
MY
810static bool udp_fill_column(struct proc *proc __attribute__((__unused__)),
811 struct sock_xinfo *sock_xinfo,
812 struct sock *sock __attribute__((__unused__)),
813 struct libscols_line *ln __attribute__((__unused__)),
814 int column_id,
815 size_t column_index __attribute__((__unused__)),
816 char **str)
817{
818 return l3_fill_column_handler(INET, sock_xinfo, column_id, str)
819 || l4_fill_column_handler(UDP, sock_xinfo, column_id, str);
820}
821
4a2b51c1
MY
822static const struct l4_xinfo_class udp_xinfo_class = {
823 .sock = {
824 .get_name = udp_get_name,
825 .get_type = udp_get_type,
826 .get_state = tcp_get_state,
827 .get_listening = NULL,
828 .fill_column = udp_fill_column,
829 .free = NULL,
830 },
19e40223 831 .scan_line = tcp_xinfo_scan_line,
2a4f2b1b
MY
832 .get_addr = tcp_xinfo_get_addr,
833 .is_any_addr = tcp_xinfo_is_any_addr,
834 .family = AF_INET,
1656da13 835 .l3_decorator = {"", ""},
92a0dbce
MY
836};
837
92a0dbce
MY
838static void load_xinfo_from_proc_udp(ino_t netns_inode)
839{
cda2b2a0 840 load_xinfo_from_proc_inet_L4(netns_inode,
92a0dbce 841 "/proc/net/udp",
92a0dbce
MY
842 &udp_xinfo_class);
843}
0188afb3 844
c779f412
MY
845/*
846 * UDP-Lite
847 */
848static bool udplite_fill_column(struct proc *proc __attribute__((__unused__)),
849 struct sock_xinfo *sock_xinfo,
850 struct sock *sock __attribute__((__unused__)),
851 struct libscols_line *ln __attribute__((__unused__)),
852 int column_id,
853 size_t column_index __attribute__((__unused__)),
854 char **str)
855{
856 return l3_fill_column_handler(INET, sock_xinfo, column_id, str)
857 || l4_fill_column_handler(UDPLITE, sock_xinfo, column_id, str);
858}
859
860static const struct l4_xinfo_class udplite_xinfo_class = {
861 .sock = {
862 .get_name = udp_get_name,
863 .get_type = udp_get_type,
864 .get_state = tcp_get_state,
865 .get_listening = NULL,
866 .fill_column = udplite_fill_column,
867 .free = NULL,
868 },
869 .scan_line = tcp_xinfo_scan_line,
870 .get_addr = tcp_xinfo_get_addr,
871 .is_any_addr = tcp_xinfo_is_any_addr,
872 .family = AF_INET,
873 .l3_decorator = {"", ""},
874};
875
876static void load_xinfo_from_proc_udplite(ino_t netns_inode)
877{
878 load_xinfo_from_proc_inet_L4(netns_inode,
879 "/proc/net/udplite",
880 &udplite_xinfo_class);
881}
882
883
0188afb3
MY
884/*
885 * RAW
886 */
887struct raw_xinfo {
888 struct l4_xinfo l4;
889 uint16_t protocol;
890};
891
892static char *raw_get_name(struct sock_xinfo *sock_xinfo,
893 struct sock *sock __attribute__((__unused__)))
894{
895 char *str = NULL;
896 struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
897 struct raw_xinfo *raw = ((struct raw_xinfo *)sock_xinfo);
898 struct l4_xinfo *l4 = &raw->l4;
303b41fe 899 const char *st_str = l4_decode_state(l4->st);
0188afb3
MY
900 void *laddr = class->get_addr(l4, L4_LOCAL);
901 void *raddr = class->get_addr(l4, L4_REMOTE);
902 char local_s[BUFSIZ];
903 char remote_s[BUFSIZ];
904
905 if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
906 xasprintf(&str, "state=%s", st_str);
907 else if (class->is_any_addr(raddr)
908 || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
b4e39841 909 xasprintf(&str, "state=%s protocol=%"PRIu16" laddr=%s",
0188afb3
MY
910 st_str,
911 raw->protocol, local_s);
912 else
b4e39841 913 xasprintf(&str, "state=%s protocol=%"PRIu16" laddr=%s raddr=%s",
0188afb3
MY
914 st_str,
915 raw->protocol, local_s, remote_s);
916 return str;
917}
918
919static char *raw_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
920 struct sock *sock __attribute__((__unused__)))
921{
922 return strdup("raw");
923}
924
925static bool raw_fill_column(struct proc *proc __attribute__((__unused__)),
926 struct sock_xinfo *sock_xinfo,
927 struct sock *sock __attribute__((__unused__)),
928 struct libscols_line *ln __attribute__((__unused__)),
929 int column_id,
930 size_t column_index __attribute__((__unused__)),
931 char **str)
932{
933 if (l3_fill_column_handler(INET, sock_xinfo, column_id, str))
934 return true;
935
936 if (column_id == COL_RAW_PROTOCOL) {
b4e39841 937 xasprintf(str, "%"PRIu16,
73df46fc 938 ((struct raw_xinfo *)sock_xinfo)->protocol);
0188afb3
MY
939 return true;
940 }
941
942 return false;
943}
944
945static struct sock_xinfo *raw_xinfo_scan_line(const struct sock_xinfo_class *class,
946 char * line,
947 ino_t netns_inode,
948 enum sysfs_byteorder byteorder)
949{
950 unsigned long local_addr;
951 unsigned long protocol;
952 unsigned long remote_addr;
953 unsigned long st;
954 unsigned long long inode;
955 struct raw_xinfo *raw;
956 struct inet_xinfo *inet;
957 struct sock_xinfo *sock;
958
959 if (sscanf(line, "%*d: %lx:%lx %lx:%*x %lx %*x:%*x %*x:%*x %*x %*u %*u %lld",
960 &local_addr, &protocol, &remote_addr,
961 &st, &inode) != 5)
962 return NULL;
963
964 if (inode == 0)
965 return NULL;
966
8ff22ccb 967 raw = xcalloc(1, sizeof(*raw));
0188afb3
MY
968 inet = &raw->l4.inet;
969 sock = &inet->sock;
970 sock->class = class;
971 sock->inode = (ino_t)inode;
972 sock->netns_inode = netns_inode;
973 inet->local_addr.s_addr = kernel32_to_cpu(byteorder, local_addr);
974 inet->remote_addr.s_addr = kernel32_to_cpu(byteorder, remote_addr);
975 raw->protocol = protocol;
976 raw->l4.st = st;
977
978 return sock;
979}
980
981static const struct l4_xinfo_class raw_xinfo_class = {
982 .sock = {
983 .get_name = raw_get_name,
984 .get_type = raw_get_type,
985 .get_state = tcp_get_state,
986 .get_listening = NULL,
987 .fill_column = raw_fill_column,
988 .free = NULL,
989 },
990 .scan_line = raw_xinfo_scan_line,
991 .get_addr = tcp_xinfo_get_addr,
992 .is_any_addr = tcp_xinfo_is_any_addr,
993 .family = AF_INET,
1656da13 994 .l3_decorator = {"", ""},
0188afb3
MY
995};
996
997static void load_xinfo_from_proc_raw(ino_t netns_inode)
998{
999 load_xinfo_from_proc_inet_L4(netns_inode,
1000 "/proc/net/raw",
1001 &raw_xinfo_class);
1002}
1656da13
MY
1003
1004/*
1005 * TCP6
1006 */
1007static struct sock_xinfo *tcp6_xinfo_scan_line(const struct sock_xinfo_class *class,
1008 char * line,
1009 ino_t netns_inode,
1010 enum sysfs_byteorder byteorder)
1011{
1012 uint32_t local_addr[4];
1013 unsigned int local_port;
1014 uint32_t remote_addr[4];
1015 unsigned int remote_port;
1016 unsigned int st;
1017 unsigned long inode;
1018 struct tcp_xinfo *tcp;
1019 struct inet6_xinfo *inet6;
1020 struct sock_xinfo *sock;
1021
1022 if (sscanf(line,
1023 "%*d: "
1024 "%08x%08x%08x%08x:%04x "
1025 "%08x%08x%08x%08x:%04x "
1026 "%x %*x:%*x %*x:%*x %*x %*u %*d %lu ",
1027 local_addr+0, local_addr+1, local_addr+2, local_addr+3, &local_port,
1028 remote_addr+0, remote_addr+1, remote_addr+2, remote_addr+3, &remote_port,
1029 &st, &inode) != 12)
1030 return NULL;
1031
1032 if (inode == 0)
1033 return NULL;
1034
8ff22ccb 1035 tcp = xmalloc(sizeof(*tcp));
1656da13
MY
1036 inet6 = &tcp->l4.inet6;
1037 sock = &inet6->sock;
1038 sock->class = class;
1039 sock->inode = (ino_t)inode;
1040 sock->netns_inode = netns_inode;
1041 tcp->local_port = local_port;
1042 for (int i = 0; i < 4; i++) {
1043 inet6->local_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, local_addr[i]);
1044 inet6->remote_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, remote_addr[i]);
1045 }
1046 tcp->remote_port = remote_port;
1047 tcp->l4.st = st;
1048
1049 return sock;
1050}
1051
1052static bool tcp6_fill_column(struct proc *proc __attribute__((__unused__)),
1053 struct sock_xinfo *sock_xinfo,
1054 struct sock *sock __attribute__((__unused__)),
1055 struct libscols_line *ln __attribute__((__unused__)),
1056 int column_id,
1057 size_t column_index __attribute__((__unused__)),
1058 char **str)
1059{
1060 return l3_fill_column_handler(INET6, sock_xinfo, column_id, str)
1061 || l4_fill_column_handler(TCP, sock_xinfo, column_id, str);
1062}
1063
1064static void *tcp6_xinfo_get_addr(struct l4_xinfo * l4, enum l4_side side)
1065{
1066 return (side == L4_LOCAL)
1067 ? &l4->inet6.local_addr
1068 : &l4->inet6.remote_addr;
1069}
1070
1071static bool tcp6_xinfo_is_any_addr(void *addr)
1072{
1073 return IN6_ARE_ADDR_EQUAL(addr, &(struct in6_addr)IN6ADDR_ANY_INIT);
1074}
1075
1076static const struct l4_xinfo_class tcp6_xinfo_class = {
1077 .sock = {
1078 .get_name = tcp_get_name,
1079 .get_type = tcp_get_type,
1080 .get_state = tcp_get_state,
1081 .get_listening = tcp_get_listening,
1082 .fill_column = tcp6_fill_column,
1083 .free = NULL,
1084 },
1085 .scan_line = tcp6_xinfo_scan_line,
1086 .get_addr = tcp6_xinfo_get_addr,
1087 .is_any_addr = tcp6_xinfo_is_any_addr,
1088 .family = AF_INET6,
1089 .l3_decorator = {"[", "]"},
1090};
1091
1092static void load_xinfo_from_proc_tcp6(ino_t netns_inode)
1093{
1094 load_xinfo_from_proc_inet_L4(netns_inode,
1095 "/proc/net/tcp6",
1096 &tcp6_xinfo_class);
1097}
28cf2b21
MY
1098
1099/*
1100 * UDP6
1101 */
1102static bool udp6_fill_column(struct proc *proc __attribute__((__unused__)),
1103 struct sock_xinfo *sock_xinfo,
1104 struct sock *sock __attribute__((__unused__)),
1105 struct libscols_line *ln __attribute__((__unused__)),
1106 int column_id,
1107 size_t column_index __attribute__((__unused__)),
1108 char **str)
1109{
1110 return l3_fill_column_handler(INET6, sock_xinfo, column_id, str)
1111 || l4_fill_column_handler(UDP, sock_xinfo, column_id, str);
1112}
1113
1114static const struct l4_xinfo_class udp6_xinfo_class = {
1115 .sock = {
1116 .get_name = udp_get_name,
1117 .get_type = udp_get_type,
1118 .get_state = tcp_get_state,
1119 .get_listening = NULL,
1120 .fill_column = udp6_fill_column,
1121 .free = NULL,
1122 },
1123 .scan_line = tcp6_xinfo_scan_line,
1124 .get_addr = tcp6_xinfo_get_addr,
1125 .is_any_addr = tcp6_xinfo_is_any_addr,
1126 .family = AF_INET6,
1127 .l3_decorator = {"[", "]"},
1128};
1129
1130static void load_xinfo_from_proc_udp6(ino_t netns_inode)
1131{
1132 load_xinfo_from_proc_inet_L4(netns_inode,
1133 "/proc/net/udp6",
1134 &udp6_xinfo_class);
1135}
2dd373c3 1136
93bca151
MY
1137/*
1138 * UDPLITEv6
1139 */
1140static bool udplite6_fill_column(struct proc *proc __attribute__((__unused__)),
1141 struct sock_xinfo *sock_xinfo,
1142 struct sock *sock __attribute__((__unused__)),
1143 struct libscols_line *ln __attribute__((__unused__)),
1144 int column_id,
1145 size_t column_index __attribute__((__unused__)),
1146 char **str)
1147{
1148 return l3_fill_column_handler(INET6, sock_xinfo, column_id, str)
1149 || l4_fill_column_handler(UDPLITE, sock_xinfo, column_id, str);
1150}
1151
1152static const struct l4_xinfo_class udplite6_xinfo_class = {
1153 .sock = {
1154 .get_name = udp_get_name,
1155 .get_type = udp_get_type,
1156 .get_state = tcp_get_state,
1157 .get_listening = NULL,
1158 .fill_column = udplite6_fill_column,
1159 .free = NULL,
1160 },
1161 .scan_line = tcp6_xinfo_scan_line,
1162 .get_addr = tcp6_xinfo_get_addr,
1163 .is_any_addr = tcp6_xinfo_is_any_addr,
1164 .family = AF_INET6,
1165 .l3_decorator = {"[", "]"},
1166};
1167
1168static void load_xinfo_from_proc_udplite6(ino_t netns_inode)
1169{
1170 load_xinfo_from_proc_inet_L4(netns_inode,
1171 "/proc/net/udplite6",
1172 &udplite6_xinfo_class);
1173}
1174
2dd373c3
MY
1175/*
1176 * RAW6
1177 */
1178static struct sock_xinfo *raw6_xinfo_scan_line(const struct sock_xinfo_class *class,
1179 char * line,
1180 ino_t netns_inode,
1181 enum sysfs_byteorder byteorder)
1182{
1183 uint32_t local_addr[4];
1184 unsigned int protocol;
1185 uint32_t remote_addr[4];
1186 unsigned int st;
1187 unsigned long inode;
1188 struct raw_xinfo *raw;
1189 struct inet6_xinfo *inet6;
1190 struct sock_xinfo *sock;
1191
1192 if (sscanf(line,
1193 "%*d: "
1194 "%08x%08x%08x%08x:%04x "
1195 "%08x%08x%08x%08x:0000 "
1196 "%x %*x:%*x %*x:%*x %*x %*u %*d %lu ",
1197 local_addr+0, local_addr+1, local_addr+2, local_addr+3, &protocol,
1198 remote_addr+0, remote_addr+1, remote_addr+2, remote_addr+3,
1199 &st, &inode) != 11)
1200 return NULL;
1201
1202 if (inode == 0)
1203 return NULL;
1204
1205 raw = xmalloc(sizeof(*raw));
1206 inet6 = &raw->l4.inet6;
1207 sock = &inet6->sock;
1208 sock->class = class;
1209 sock->inode = (ino_t)inode;
1210 sock->netns_inode = netns_inode;
1211 for (int i = 0; i < 4; i++) {
1212 inet6->local_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, local_addr[i]);
1213 inet6->remote_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, remote_addr[i]);
1214 }
1215 raw->protocol = protocol;
1216 raw->l4.st = st;
1217
1218 return sock;
1219}
1220
1221static bool raw6_fill_column(struct proc *proc __attribute__((__unused__)),
1222 struct sock_xinfo *sock_xinfo,
1223 struct sock *sock __attribute__((__unused__)),
1224 struct libscols_line *ln __attribute__((__unused__)),
1225 int column_id,
1226 size_t column_index __attribute__((__unused__)),
1227 char **str)
1228{
1229 struct raw_xinfo *raw;
1230
1231 if (l3_fill_column_handler(INET6, sock_xinfo, column_id, str))
1232 return true;
1233
1234 raw = (struct raw_xinfo *)sock_xinfo;
1235 if (column_id == COL_RAW_PROTOCOL) {
1236 xasprintf(str, "%"PRIu16, raw->protocol);
1237 return true;
1238 }
1239
1240 return false;
1241}
1242
1243static const struct l4_xinfo_class raw6_xinfo_class = {
1244 .sock = {
1245 .get_name = raw_get_name,
1246 .get_type = raw_get_type,
1247 .get_state = tcp_get_state,
1248 .get_listening = NULL,
1249 .fill_column = raw6_fill_column,
1250 .free = NULL,
1251 },
1252 .scan_line = raw6_xinfo_scan_line,
1253 .get_addr = tcp6_xinfo_get_addr,
1254 .is_any_addr = tcp6_xinfo_is_any_addr,
1255 .family = AF_INET6,
1256 .l3_decorator = {"[", "]"},
1257};
1258
1259static void load_xinfo_from_proc_raw6(ino_t netns_inode)
1260{
1261 load_xinfo_from_proc_inet_L4(netns_inode,
1262 "/proc/net/raw6",
1263 &raw6_xinfo_class);
1264}