libnl  3.3.0
idiag_msg_obj.c
1 /*
2  * lib/idiag/idiagnl_msg_obj.c Inet Diag Message Object
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation version 2.1
7  * of the License.
8  *
9  * Copyright (c) 2013 Sassano Systems LLC <joe@sassanosystems.com>
10  */
11 
12 #include <netlink-private/netlink.h>
13 #include <netlink/hashtable.h>
14 #include <netlink/idiag/msg.h>
15 #include <netlink/idiag/meminfo.h>
16 #include <netlink/idiag/vegasinfo.h>
17 #include <linux/inet_diag.h>
18 
19 
20 /** @cond SKIP */
21 #define IDIAGNL_ATTR_FAMILY (0x1 << 1)
22 #define IDIAGNL_ATTR_STATE (0x1 << 2)
23 #define IDIAGNL_ATTR_TIMER (0x1 << 3)
24 #define IDIAGNL_ATTR_RETRANS (0x1 << 4)
25 #define IDIAGNL_ATTR_SPORT (0x1 << 5)
26 #define IDIAGNL_ATTR_DPORT (0x1 << 6)
27 #define IDIAGNL_ATTR_SRC (0x1 << 7)
28 #define IDIAGNL_ATTR_DST (0x1 << 8)
29 #define IDIAGNL_ATTR_IFINDEX (0x1 << 9)
30 #define IDIAGNL_ATTR_EXPIRES (0x1 << 10)
31 #define IDIAGNL_ATTR_RQUEUE (0x1 << 11)
32 #define IDIAGNL_ATTR_WQUEUE (0x1 << 12)
33 #define IDIAGNL_ATTR_UID (0x1 << 13)
34 #define IDIAGNL_ATTR_INODE (0x1 << 14)
35 #define IDIAGNL_ATTR_TOS (0x1 << 15)
36 #define IDIAGNL_ATTR_TCLASS (0x1 << 16)
37 #define IDIAGNL_ATTR_SHUTDOWN (0x1 << 17)
38 #define IDIAGNL_ATTR_CONG (0x1 << 18)
39 #define IDIAGNL_ATTR_MEMINFO (0x1 << 19)
40 #define IDIAGNL_ATTR_VEGASINFO (0x1 << 20)
41 #define IDIAGNL_ATTR_TCPINFO (0x1 << 21)
42 #define IDIAGNL_ATTR_SKMEMINFO (0x1 << 22)
43 
44 #define _INET_DIAG_ALL ((1<<(INET_DIAG_MAX+1))-1)
45 /** @endcond */
46 
47 /**
48  * @ingroup idiag
49  * @defgroup idiagnl_msg Inet Diag Messages
50  *
51  * @details
52  * @idiagnl_doc{idiagnl_msg, Inet Diag Message Documentation}
53  * @{
54  */
55 struct idiagnl_msg *idiagnl_msg_alloc(void)
56 {
57  return (struct idiagnl_msg *) nl_object_alloc(&idiagnl_msg_obj_ops);
58 }
59 
60 void idiagnl_msg_get(struct idiagnl_msg *msg)
61 {
62  nl_object_get((struct nl_object *) msg);
63 }
64 
65 void idiagnl_msg_put(struct idiagnl_msg *msg)
66 {
67  nl_object_put((struct nl_object *) msg);
68 }
69 
70 static struct nl_cache_ops idiagnl_msg_ops;
71 
72 static int idiagnl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
73  struct nlmsghdr *nlh, struct nl_parser_param *pp)
74 {
75  struct idiagnl_msg *msg = NULL;
76  int err = 0;
77 
78  if ((err = idiagnl_msg_parse(nlh, &msg)) < 0)
79  return err;
80 
81  err = pp->pp_cb((struct nl_object *) msg, pp);
82  idiagnl_msg_put(msg);
83 
84  return err;
85 }
86 
87 static int idiagnl_request_update(struct nl_cache *cache, struct nl_sock *sk)
88 {
89  int family = cache->c_iarg1;
90  int states = cache->c_iarg2;
91 
92  return idiagnl_send_simple(sk, 0, family, states, _INET_DIAG_ALL);
93 }
94 
95 static struct nl_cache_ops idiagnl_msg_ops = {
96  .co_name = "idiag/idiag",
97  .co_hdrsize = sizeof(struct inet_diag_msg),
98  .co_msgtypes = {
99  { TCPDIAG_GETSOCK, NL_ACT_NEW, "new" },
100  { DCCPDIAG_GETSOCK, NL_ACT_NEW, "new" },
101  END_OF_MSGTYPES_LIST,
102  },
103  .co_protocol = NETLINK_INET_DIAG,
104  .co_request_update = idiagnl_request_update,
105  .co_msg_parser = idiagnl_msg_parser,
106  .co_obj_ops = &idiagnl_msg_obj_ops,
107 };
108 
109 static void __init idiagnl_init(void)
110 {
111  nl_cache_mngt_register(&idiagnl_msg_ops);
112 }
113 
114 static void __exit idiagnl_exit(void)
115 {
116  nl_cache_mngt_unregister(&idiagnl_msg_ops);
117 }
118 
119 /**
120  * @name Cache Management
121  * @{
122  */
123 
124 /**
125  * Build an inetdiag cache to hold socket state information.
126  * @arg sk Netlink socket
127  * @arg family The address family to query
128  * @arg states Socket states to query
129  * @arg result Result pointer
130  *
131  * @note The caller is responsible for destroying and free the cache after using
132  * it.
133  * @return 0 on success of a negative error code.
134  */
135 int idiagnl_msg_alloc_cache(struct nl_sock *sk, int family, int states,
136  struct nl_cache **result)
137 {
138  struct nl_cache *cache = NULL;
139  int err;
140 
141  if (!(cache = nl_cache_alloc(&idiagnl_msg_ops)))
142  return -NLE_NOMEM;
143 
144  cache->c_iarg1 = family;
145  cache->c_iarg2 = states;
146 
147  if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
148  free(cache);
149  return err;
150  }
151 
152  *result = cache;
153  return 0;
154 }
155 
156 /** @} */
157 
158 /**
159  * @name Attributes
160  * @{
161  */
162 
163 uint8_t idiagnl_msg_get_family(const struct idiagnl_msg *msg)
164 {
165  return msg->idiag_family;
166 }
167 
168 void idiagnl_msg_set_family(struct idiagnl_msg *msg, uint8_t family)
169 {
170  msg->idiag_family = family;
171  msg->ce_mask |= IDIAGNL_ATTR_FAMILY;
172 }
173 
174 uint8_t idiagnl_msg_get_state(const struct idiagnl_msg *msg)
175 {
176  return msg->idiag_state;
177 }
178 
179 void idiagnl_msg_set_state(struct idiagnl_msg *msg, uint8_t state)
180 {
181  msg->idiag_state = state;
182  msg->ce_mask |= IDIAGNL_ATTR_STATE;
183 }
184 
185 uint8_t idiagnl_msg_get_timer(const struct idiagnl_msg *msg)
186 {
187  return msg->idiag_timer;
188 }
189 
190 void idiagnl_msg_set_timer(struct idiagnl_msg *msg, uint8_t timer)
191 {
192  msg->idiag_timer = timer;
193  msg->ce_mask |= IDIAGNL_ATTR_TIMER;
194 }
195 
196 uint8_t idiagnl_msg_get_retrans(const struct idiagnl_msg *msg)
197 {
198  return msg->idiag_retrans;
199 }
200 
201 void idiagnl_msg_set_retrans(struct idiagnl_msg *msg, uint8_t retrans)
202 {
203  msg->idiag_retrans = retrans;
204  msg->ce_mask |= IDIAGNL_ATTR_RETRANS;
205 }
206 
207 uint16_t idiagnl_msg_get_sport(struct idiagnl_msg *msg)
208 {
209  return msg->idiag_sport;
210 }
211 
212 void idiagnl_msg_set_sport(struct idiagnl_msg *msg, uint16_t port)
213 {
214  msg->idiag_sport = port;
215  msg->ce_mask |= IDIAGNL_ATTR_SPORT;
216 }
217 
218 uint16_t idiagnl_msg_get_dport(struct idiagnl_msg *msg)
219 {
220  return msg->idiag_dport;
221 }
222 
223 void idiagnl_msg_set_dport(struct idiagnl_msg *msg, uint16_t port)
224 {
225  msg->idiag_dport = port;
226  msg->ce_mask |= IDIAGNL_ATTR_DPORT;
227 }
228 
229 struct nl_addr *idiagnl_msg_get_src(const struct idiagnl_msg *msg)
230 {
231  return msg->idiag_src;
232 }
233 
234 int idiagnl_msg_set_src(struct idiagnl_msg *msg, struct nl_addr *addr)
235 {
236  if (msg->idiag_src)
237  nl_addr_put(msg->idiag_src);
238 
239  nl_addr_get(addr);
240  msg->idiag_src = addr;
241  msg->ce_mask |= IDIAGNL_ATTR_SRC;
242 
243  return 0;
244 }
245 
246 struct nl_addr *idiagnl_msg_get_dst(const struct idiagnl_msg *msg)
247 {
248  return msg->idiag_dst;
249 }
250 
251 int idiagnl_msg_set_dst(struct idiagnl_msg *msg, struct nl_addr *addr)
252 {
253  if (msg->idiag_dst)
254  nl_addr_put(msg->idiag_dst);
255 
256  nl_addr_get(addr);
257  msg->idiag_dst = addr;
258  msg->ce_mask |= IDIAGNL_ATTR_DST;
259 
260  return 0;
261 }
262 
263 uint32_t idiagnl_msg_get_ifindex(const struct idiagnl_msg *msg)
264 {
265  return msg->idiag_ifindex;
266 }
267 
268 void idiagnl_msg_set_ifindex(struct idiagnl_msg *msg, uint32_t ifindex)
269 {
270  msg->idiag_ifindex = ifindex;
271  msg->ce_mask |= IDIAGNL_ATTR_IFINDEX;
272 }
273 
274 uint32_t idiagnl_msg_get_expires(const struct idiagnl_msg *msg)
275 {
276  return msg->idiag_expires;
277 }
278 
279 void idiagnl_msg_set_expires(struct idiagnl_msg *msg, uint32_t expires)
280 {
281  msg->idiag_expires = expires;
282  msg->ce_mask |= IDIAGNL_ATTR_EXPIRES;
283 }
284 
285 uint32_t idiagnl_msg_get_rqueue(const struct idiagnl_msg *msg)
286 {
287  return msg->idiag_rqueue;
288 }
289 
290 void idiagnl_msg_set_rqueue(struct idiagnl_msg *msg, uint32_t rqueue)
291 {
292  msg->idiag_rqueue = rqueue;
293  msg->ce_mask |= IDIAGNL_ATTR_RQUEUE;
294 }
295 
296 uint32_t idiagnl_msg_get_wqueue(const struct idiagnl_msg *msg)
297 {
298  return msg->idiag_wqueue;
299 }
300 
301 void idiagnl_msg_set_wqueue(struct idiagnl_msg *msg, uint32_t wqueue)
302 {
303  msg->idiag_wqueue = wqueue;
304  msg->ce_mask |= IDIAGNL_ATTR_WQUEUE;
305 }
306 
307 uint32_t idiagnl_msg_get_uid(const struct idiagnl_msg *msg)
308 {
309  return msg->idiag_uid;
310 }
311 
312 void idiagnl_msg_set_uid(struct idiagnl_msg *msg, uint32_t uid)
313 {
314  msg->idiag_uid = uid;
315  msg->ce_mask |= IDIAGNL_ATTR_UID;
316 }
317 
318 uint32_t idiagnl_msg_get_inode(const struct idiagnl_msg *msg)
319 {
320  return msg->idiag_inode;
321 }
322 
323 void idiagnl_msg_set_inode(struct idiagnl_msg *msg, uint32_t inode)
324 {
325  msg->idiag_inode = inode;
326  msg->ce_mask |= IDIAGNL_ATTR_INODE;
327 }
328 
329 uint8_t idiagnl_msg_get_tos(const struct idiagnl_msg *msg)
330 {
331  return msg->idiag_tos;
332 }
333 
334 void idiagnl_msg_set_tos(struct idiagnl_msg *msg, uint8_t tos)
335 {
336  msg->idiag_tos = tos;
337  msg->ce_mask |= IDIAGNL_ATTR_TOS;
338 }
339 
340 uint8_t idiagnl_msg_get_tclass(const struct idiagnl_msg *msg)
341 {
342  return msg->idiag_tclass;
343 }
344 
345 void idiagnl_msg_set_tclass(struct idiagnl_msg *msg, uint8_t tclass)
346 {
347  msg->idiag_tclass = tclass;
348  msg->ce_mask |= IDIAGNL_ATTR_TCLASS;
349 }
350 
351 uint8_t idiagnl_msg_get_shutdown(const struct idiagnl_msg *msg)
352 {
353  return msg->idiag_shutdown;
354 }
355 
356 void idiagnl_msg_set_shutdown(struct idiagnl_msg *msg, uint8_t shutdown)
357 {
358  msg->idiag_shutdown = shutdown;
359  msg->ce_mask |= IDIAGNL_ATTR_SHUTDOWN;
360 }
361 
362 char *idiagnl_msg_get_cong(const struct idiagnl_msg *msg)
363 {
364  return msg->idiag_cong;
365 }
366 
367 void idiagnl_msg_set_cong(struct idiagnl_msg *msg, char *cong)
368 {
369  free (msg->idiag_cong);
370  msg->idiag_cong = strdup(cong);
371  msg->ce_mask |= IDIAGNL_ATTR_CONG;
372 }
373 
374 struct idiagnl_meminfo *idiagnl_msg_get_meminfo(const struct idiagnl_msg *msg)
375 {
376  return msg->idiag_meminfo;
377 }
378 
379 void idiagnl_msg_set_meminfo(struct idiagnl_msg *msg, struct idiagnl_meminfo *minfo)
380 {
381  if (msg->idiag_meminfo)
382  idiagnl_meminfo_put(msg->idiag_meminfo);
383 
384  idiagnl_meminfo_get(minfo);
385  msg->idiag_meminfo = minfo;
386  msg->ce_mask |= IDIAGNL_ATTR_MEMINFO;
387 }
388 
389 struct idiagnl_vegasinfo *idiagnl_msg_get_vegasinfo(const struct idiagnl_msg *msg)
390 {
391  return msg->idiag_vegasinfo;
392 }
393 
394 void idiagnl_msg_set_vegasinfo(struct idiagnl_msg *msg, struct idiagnl_vegasinfo *vinfo)
395 {
396  if (msg->idiag_vegasinfo)
397  idiagnl_vegasinfo_put(msg->idiag_vegasinfo);
398 
399  idiagnl_vegasinfo_get(vinfo);
400  msg->idiag_vegasinfo = vinfo;
401  msg->ce_mask |= IDIAGNL_ATTR_VEGASINFO;
402 }
403 
404 struct tcp_info idiagnl_msg_get_tcpinfo(const struct idiagnl_msg *msg)
405 {
406  return msg->idiag_tcpinfo;
407 }
408 
409 void idiagnl_msg_set_tcpinfo(struct idiagnl_msg *msg, struct tcp_info *tinfo)
410 {
411  memcpy(&msg->idiag_tcpinfo, tinfo, sizeof(struct tcp_info));
412  msg->ce_mask |= IDIAGNL_ATTR_TCPINFO;
413 }
414 
415 /** @} */
416 
417 static void idiag_msg_dump_line(struct nl_object *a, struct nl_dump_params *p)
418 {
419  struct idiagnl_msg *msg = (struct idiagnl_msg *) a;
420  char buf[64] = { 0 };
421 
422  nl_dump_line(p, "family: %s ", nl_af2str(msg->idiag_family, buf, sizeof(buf)));
423  nl_dump(p, "src: %s:%d ", nl_addr2str(msg->idiag_src, buf, sizeof(buf)),
424  ntohs(msg->idiag_sport));
425  nl_dump(p, "dst: %s:%d ", nl_addr2str(msg->idiag_dst, buf, sizeof(buf)),
426  ntohs(msg->idiag_dport));
427  nl_dump(p, "iif: %d ", msg->idiag_ifindex);
428  nl_dump(p, "\n");
429 }
430 
431 static void idiag_msg_dump_details(struct nl_object *a, struct nl_dump_params *p)
432 {
433  struct idiagnl_msg *msg = (struct idiagnl_msg *) a;
434  char buf[64], buf2[64];
435 
436  nl_dump(p, "\nfamily: %s\n", nl_af2str(msg->idiag_family, buf, sizeof(buf)));
437  nl_dump(p, "state: %s\n",
438  idiagnl_state2str(msg->idiag_state, buf, sizeof(buf)));
439  nl_dump(p, "timer (%s, %s, retransmits: %d)\n",
440  idiagnl_timer2str(msg->idiag_timer, buf, sizeof(buf)),
441  nl_msec2str(msg->idiag_expires, buf2, sizeof(buf2)),
442  msg->idiag_retrans);
443 
444  nl_dump(p, "source: %s:%d\n", nl_addr2str(msg->idiag_src, buf, sizeof(buf)),
445  ntohs(msg->idiag_sport));
446  nl_dump(p, "destination: %s:%d\n", nl_addr2str(msg->idiag_dst, buf, sizeof(buf)),
447  ntohs(msg->idiag_dport));
448 
449  nl_dump(p, "ifindex: %d\n", msg->idiag_ifindex);
450  nl_dump(p, "rqueue: %-6d wqueue: %-6d\n", msg->idiag_rqueue, msg->idiag_wqueue);
451  nl_dump(p, "uid %d\n", msg->idiag_uid);
452  nl_dump(p, "inode %d\n", msg->idiag_inode);
453  if (msg->idiag_shutdown) {
454  nl_dump(p, "socket shutdown: %s\n",
455  idiagnl_shutdown2str(msg->idiag_shutdown,
456  buf, sizeof(buf)));
457  }
458 
459  nl_dump(p, "tos: 0x%x\n", msg->idiag_tos);
460  nl_dump(p, "traffic class: %d\n", msg->idiag_tclass);
461  nl_dump(p, "congestion algorithm: %s\n", msg->idiag_cong ? : "");
462 }
463 
464 static void idiag_msg_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
465 {
466  struct idiagnl_msg *msg = (struct idiagnl_msg *) obj;
467  char buf[64];
468 
469  idiag_msg_dump_details(obj, p);
470 
471  nl_dump(p, "tcp info: [\n");
472  nl_dump(p, "\tsocket state: %s\n",
473  idiagnl_state2str(msg->idiag_tcpinfo.tcpi_state,
474  buf, sizeof(buf)));
475  nl_dump(p, "\ttcp state: %s\n",
476  idiagnl_tcpstate2str(msg->idiag_tcpinfo.tcpi_ca_state,
477  buf, sizeof(buf)));
478  nl_dump(p, "\tretransmits: %d\n",
479  msg->idiag_tcpinfo.tcpi_retransmits);
480  nl_dump(p, "\tprobes: %d\n",
481  msg->idiag_tcpinfo.tcpi_probes);
482  nl_dump(p, "\tbackoff: %d\n",
483  msg->idiag_tcpinfo.tcpi_backoff);
484  nl_dump(p, "\toptions: %s\n",
485  idiagnl_tcpopts2str(msg->idiag_tcpinfo.tcpi_options,
486  buf, sizeof(buf)));
487  nl_dump(p, "\tsnd_wscale: %d\n", msg->idiag_tcpinfo.tcpi_snd_wscale);
488  nl_dump(p, "\trcv_wscale: %d\n", msg->idiag_tcpinfo.tcpi_rcv_wscale);
489  nl_dump(p, "\trto: %d\n", msg->idiag_tcpinfo.tcpi_rto);
490  nl_dump(p, "\tato: %d\n", msg->idiag_tcpinfo.tcpi_ato);
491  nl_dump(p, "\tsnd_mss: %s\n", nl_size2str(msg->idiag_tcpinfo.tcpi_snd_mss,
492  buf, sizeof(buf)));
493  nl_dump(p, "\trcv_mss: %s\n", nl_size2str(msg->idiag_tcpinfo.tcpi_rcv_mss,
494  buf, sizeof(buf)));
495  nl_dump(p, "\tunacked: %d\n", msg->idiag_tcpinfo.tcpi_unacked);
496  nl_dump(p, "\tsacked: %d\n", msg->idiag_tcpinfo.tcpi_sacked);
497 
498  nl_dump(p, "\tlost: %d\n", msg->idiag_tcpinfo.tcpi_lost);
499  nl_dump(p, "\tretransmit segments: %d\n",
500  msg->idiag_tcpinfo.tcpi_retrans);
501  nl_dump(p, "\tfackets: %d\n",
502  msg->idiag_tcpinfo.tcpi_fackets);
503  nl_dump(p, "\tlast data sent: %s\n",
504  nl_msec2str(msg->idiag_tcpinfo.tcpi_last_data_sent, buf,
505  sizeof(buf)));
506  nl_dump(p, "\tlast ack sent: %s\n",
507  nl_msec2str(msg->idiag_tcpinfo.tcpi_last_ack_sent, buf, sizeof(buf)));
508  nl_dump(p, "\tlast data recv: %s\n",
509  nl_msec2str(msg->idiag_tcpinfo.tcpi_last_data_recv, buf,
510  sizeof(buf)));
511  nl_dump(p, "\tlast ack recv: %s\n",
512  nl_msec2str(msg->idiag_tcpinfo.tcpi_last_ack_recv, buf,
513  sizeof(buf)));
514  nl_dump(p, "\tpath mtu: %s\n",
515  nl_size2str(msg->idiag_tcpinfo.tcpi_pmtu, buf,
516  sizeof(buf)));
517  nl_dump(p, "\trcv ss threshold: %d\n",
518  msg->idiag_tcpinfo.tcpi_rcv_ssthresh);
519  nl_dump(p, "\tsmoothed round trip time: %d\n",
520  msg->idiag_tcpinfo.tcpi_rtt);
521  nl_dump(p, "\tround trip time variation: %d\n",
522  msg->idiag_tcpinfo.tcpi_rttvar);
523  nl_dump(p, "\tsnd ss threshold: %s\n",
524  nl_size2str(msg->idiag_tcpinfo.tcpi_snd_ssthresh, buf,
525  sizeof(buf)));
526  nl_dump(p, "\tsend congestion window: %d\n",
527  msg->idiag_tcpinfo.tcpi_snd_cwnd);
528  nl_dump(p, "\tadvertised mss: %s\n",
529  nl_size2str(msg->idiag_tcpinfo.tcpi_advmss, buf,
530  sizeof(buf)));
531  nl_dump(p, "\treordering: %d\n",
532  msg->idiag_tcpinfo.tcpi_reordering);
533  nl_dump(p, "\trcv rround trip time: %d\n",
534  msg->idiag_tcpinfo.tcpi_rcv_rtt);
535  nl_dump(p, "\treceive queue space: %s\n",
536  nl_size2str(msg->idiag_tcpinfo.tcpi_rcv_space, buf,
537  sizeof(buf)));
538  nl_dump(p, "\ttotal retransmits: %d\n",
539  msg->idiag_tcpinfo.tcpi_total_retrans);
540  nl_dump(p, "]\n");
541 
542  if (msg->idiag_meminfo) {
543  nl_dump(p, "meminfo: [\n");
544  nl_dump(p, "\trmem: %s\n",
545  nl_size2str(msg->idiag_meminfo->idiag_rmem,
546  buf,
547  sizeof(buf)));
548  nl_dump(p, "\twmem: %s\n",
549  nl_size2str(msg->idiag_meminfo->idiag_wmem,
550  buf,
551  sizeof(buf)));
552  nl_dump(p, "\tfmem: %s\n",
553  nl_size2str(msg->idiag_meminfo->idiag_fmem,
554  buf,
555  sizeof(buf)));
556  nl_dump(p, "\ttmem: %s\n",
557  nl_size2str(msg->idiag_meminfo->idiag_tmem,
558  buf,
559  sizeof(buf)));
560  nl_dump(p, "]\n");
561  }
562 
563  if (msg->idiag_vegasinfo) {
564  nl_dump(p, "vegasinfo: [\n");
565  nl_dump(p, "\tvegas enabled: %d\n",
566  msg->idiag_vegasinfo->tcpv_enabled);
567  if (msg->idiag_vegasinfo->tcpv_enabled) {
568  nl_dump(p, "\trtt cnt: %d",
569  msg->idiag_vegasinfo->tcpv_rttcnt);
570  nl_dump(p, "\trtt (propagation delay): %d",
571  msg->idiag_vegasinfo->tcpv_rtt);
572  nl_dump(p, "\tmin rtt: %d",
573  msg->idiag_vegasinfo->tcpv_minrtt);
574  }
575  nl_dump(p, "]\n");
576  }
577 
578  if (msg->ce_mask & IDIAGNL_ATTR_MEMINFO) {
579  nl_dump(p, "skmeminfo: [\n");
580  nl_dump(p, "\trmem alloc: %d\n",
581  msg->idiag_skmeminfo[SK_MEMINFO_RMEM_ALLOC]);
582  nl_dump(p, "\trcv buf: %s\n",
583  nl_size2str(msg->idiag_skmeminfo[SK_MEMINFO_RCVBUF],
584  buf, sizeof(buf)));
585  nl_dump(p, "\twmem alloc: %d\n",
586  msg->idiag_skmeminfo[SK_MEMINFO_WMEM_ALLOC]);
587  nl_dump(p, "\tsnd buf: %s\n",
588  nl_size2str(msg->idiag_skmeminfo[SK_MEMINFO_SNDBUF],
589  buf, sizeof(buf)));
590  nl_dump(p, "\tfwd alloc: %d\n",
591  msg->idiag_skmeminfo[SK_MEMINFO_FWD_ALLOC]);
592  nl_dump(p, "\twmem queued: %s\n",
593  nl_size2str(msg->idiag_skmeminfo[SK_MEMINFO_WMEM_QUEUED],
594  buf, sizeof(buf)));
595  nl_dump(p, "\topt mem: %d\n",
596  msg->idiag_skmeminfo[SK_MEMINFO_OPTMEM]);
597  nl_dump(p, "\tbacklog: %d\n",
598  msg->idiag_skmeminfo[SK_MEMINFO_BACKLOG]);
599  nl_dump(p, "]\n\n");
600  }
601 }
602 
603 static void idiagnl_msg_free(struct nl_object *a)
604 {
605  struct idiagnl_msg *msg = (struct idiagnl_msg *) a;
606  if (a == NULL)
607  return;
608 
609  free(msg->idiag_cong);
610  nl_addr_put(msg->idiag_src);
611  nl_addr_put(msg->idiag_dst);
612  idiagnl_meminfo_put(msg->idiag_meminfo);
613  idiagnl_vegasinfo_put(msg->idiag_vegasinfo);
614 }
615 
616 static int idiagnl_msg_clone(struct nl_object *_dst, struct nl_object *_src)
617 {
618  struct idiagnl_msg *dst = (struct idiagnl_msg *) _dst;
619  struct idiagnl_msg *src = (struct idiagnl_msg *) _src;
620 
621  dst->idiag_cong = NULL;
622  dst->idiag_src = NULL;
623  dst->idiag_dst = NULL;
624  dst->idiag_meminfo = NULL;
625  dst->idiag_vegasinfo = NULL;
626  dst->ce_mask &= ~(IDIAGNL_ATTR_CONG |
627  IDIAGNL_ATTR_SRC |
628  IDIAGNL_ATTR_DST |
629  IDIAGNL_ATTR_MEMINFO |
630  IDIAGNL_ATTR_VEGASINFO);
631 
632  if (src->idiag_cong) {
633  if (!(dst->idiag_cong = strdup(src->idiag_cong)))
634  return -NLE_NOMEM;
635  dst->ce_mask |= IDIAGNL_ATTR_CONG;
636  }
637 
638  if (src->idiag_src) {
639  if (!(dst->idiag_src = nl_addr_clone(src->idiag_src)))
640  return -NLE_NOMEM;
641  dst->ce_mask |= IDIAGNL_ATTR_SRC;
642  }
643 
644  if (src->idiag_dst) {
645  if (!(dst->idiag_dst = nl_addr_clone(src->idiag_dst)))
646  return -NLE_NOMEM;
647  dst->ce_mask |= IDIAGNL_ATTR_DST;
648  }
649 
650  if (src->idiag_meminfo) {
651  if (!(dst->idiag_meminfo = (struct idiagnl_meminfo *) nl_object_clone((struct nl_object *) src->idiag_meminfo)))
652  return -NLE_NOMEM;
653  dst->ce_mask |= IDIAGNL_ATTR_MEMINFO;
654  }
655 
656  if (src->idiag_vegasinfo) {
657  if (!(dst->idiag_vegasinfo = (struct idiagnl_vegasinfo *) nl_object_clone((struct nl_object *) src->idiag_vegasinfo)))
658  return -NLE_NOMEM;
659  dst->ce_mask |= IDIAGNL_ATTR_VEGASINFO;
660  }
661 
662  return 0;
663 }
664 
665 static struct nla_policy ext_policy[INET_DIAG_MAX+1] = {
666  [INET_DIAG_MEMINFO] = { .minlen = sizeof(struct inet_diag_meminfo) },
667  [INET_DIAG_INFO] = { .minlen = sizeof(struct tcp_info) },
668  [INET_DIAG_VEGASINFO] = { .minlen = sizeof(struct tcpvegas_info) },
669  [INET_DIAG_CONG] = { .type = NLA_STRING },
670  [INET_DIAG_TOS] = { .type = NLA_U8 },
671  [INET_DIAG_TCLASS] = { .type = NLA_U8 },
672  /* Older kernel doesn't have SK_MEMINFO_BACKLOG */
673  [INET_DIAG_SKMEMINFO] = { .minlen = (sizeof(uint32_t) * (SK_MEMINFO_OPTMEM + 1)) },
674  [INET_DIAG_SHUTDOWN] = { .type = NLA_U8 },
675 };
676 
677 int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result)
678 {
679  struct idiagnl_msg *msg = NULL;
680  struct inet_diag_msg *raw_msg = NULL;
681  struct nl_addr *src = NULL, *dst = NULL;
682  struct nlattr *tb[INET_DIAG_MAX+1];
683  int err = 0;
684 
685  msg = idiagnl_msg_alloc();
686  if (!msg)
687  goto errout_nomem;
688 
689  err = nlmsg_parse(nlh, sizeof(struct inet_diag_msg), tb, INET_DIAG_MAX,
690  ext_policy);
691  if (err < 0)
692  goto errout;
693 
694  raw_msg = nlmsg_data(nlh);
695  msg->idiag_family = raw_msg->idiag_family;
696  msg->idiag_state = raw_msg->idiag_state;
697  msg->idiag_timer = raw_msg->idiag_timer;
698  msg->idiag_retrans = raw_msg->idiag_retrans;
699  msg->idiag_expires = raw_msg->idiag_expires;
700  msg->idiag_rqueue = raw_msg->idiag_rqueue;
701  msg->idiag_wqueue = raw_msg->idiag_wqueue;
702  msg->idiag_uid = raw_msg->idiag_uid;
703  msg->idiag_inode = raw_msg->idiag_inode;
704  msg->idiag_sport = raw_msg->id.idiag_sport;
705  msg->idiag_dport = raw_msg->id.idiag_dport;
706  msg->idiag_ifindex = raw_msg->id.idiag_if;
707 
708  msg->ce_mask = (IDIAGNL_ATTR_FAMILY |
709  IDIAGNL_ATTR_STATE |
710  IDIAGNL_ATTR_TIMER |
711  IDIAGNL_ATTR_RETRANS |
712  IDIAGNL_ATTR_EXPIRES |
713  IDIAGNL_ATTR_RQUEUE |
714  IDIAGNL_ATTR_WQUEUE |
715  IDIAGNL_ATTR_UID |
716  IDIAGNL_ATTR_INODE |
717  IDIAGNL_ATTR_SPORT |
718  IDIAGNL_ATTR_DPORT |
719  IDIAGNL_ATTR_IFINDEX);
720 
721  dst = nl_addr_build(raw_msg->idiag_family, raw_msg->id.idiag_dst,
722  sizeof(raw_msg->id.idiag_dst));
723  if (!dst)
724  goto errout_nomem;
725 
726  err = idiagnl_msg_set_dst(msg, dst);
727  if (err < 0)
728  goto errout;
729 
730  nl_addr_put(dst);
731 
732  src = nl_addr_build(raw_msg->idiag_family, raw_msg->id.idiag_src,
733  sizeof(raw_msg->id.idiag_src));
734  if (!src)
735  goto errout_nomem;
736 
737  err = idiagnl_msg_set_src(msg, src);
738  if (err < 0)
739  goto errout;
740 
741  nl_addr_put(src);
742 
743  if (tb[INET_DIAG_TOS]) {
744  msg->idiag_tos = nla_get_u8(tb[INET_DIAG_TOS]);
745  msg->ce_mask |= IDIAGNL_ATTR_TOS;
746  }
747 
748  if (tb[INET_DIAG_TCLASS]) {
749  msg->idiag_tclass = nla_get_u8(tb[INET_DIAG_TCLASS]);
750  msg->ce_mask |= IDIAGNL_ATTR_TCLASS;
751  }
752 
753  if (tb[INET_DIAG_SHUTDOWN]) {
754  msg->idiag_shutdown = nla_get_u8(tb[INET_DIAG_SHUTDOWN]);
755  msg->ce_mask |= IDIAGNL_ATTR_SHUTDOWN;
756  }
757 
758  if (tb[INET_DIAG_CONG]) {
759  msg->idiag_cong = nla_strdup(tb[INET_DIAG_CONG]);
760  msg->ce_mask |= IDIAGNL_ATTR_CONG;
761  }
762 
763  if (tb[INET_DIAG_INFO]) {
764  nla_memcpy(&msg->idiag_tcpinfo, tb[INET_DIAG_INFO],
765  sizeof(msg->idiag_tcpinfo));
766  msg->ce_mask |= IDIAGNL_ATTR_TCPINFO;
767  }
768 
769  if (tb[INET_DIAG_MEMINFO]) {
770  struct idiagnl_meminfo *minfo = idiagnl_meminfo_alloc();
771  struct inet_diag_meminfo *raw_minfo = NULL;
772 
773  if (!minfo)
774  goto errout_nomem;
775 
776  raw_minfo = (struct inet_diag_meminfo *)
777  nla_data(tb[INET_DIAG_MEMINFO]);
778 
779  idiagnl_meminfo_set_rmem(minfo, raw_minfo->idiag_rmem);
780  idiagnl_meminfo_set_wmem(minfo, raw_minfo->idiag_wmem);
781  idiagnl_meminfo_set_fmem(minfo, raw_minfo->idiag_fmem);
782  idiagnl_meminfo_set_tmem(minfo, raw_minfo->idiag_tmem);
783 
784  msg->idiag_meminfo = minfo;
785  msg->ce_mask |= IDIAGNL_ATTR_MEMINFO;
786  }
787 
788  if (tb[INET_DIAG_VEGASINFO]) {
789  struct idiagnl_vegasinfo *vinfo = idiagnl_vegasinfo_alloc();
790  struct tcpvegas_info *raw_vinfo = NULL;
791 
792  if (!vinfo)
793  goto errout_nomem;
794 
795  raw_vinfo = (struct tcpvegas_info *)
796  nla_data(tb[INET_DIAG_VEGASINFO]);
797 
798  idiagnl_vegasinfo_set_enabled(vinfo, raw_vinfo->tcpv_enabled);
799  idiagnl_vegasinfo_set_rttcnt(vinfo, raw_vinfo->tcpv_rttcnt);
800  idiagnl_vegasinfo_set_rtt(vinfo, raw_vinfo->tcpv_rtt);
801  idiagnl_vegasinfo_set_minrtt(vinfo, raw_vinfo->tcpv_minrtt);
802 
803  msg->idiag_vegasinfo = vinfo;
804  msg->ce_mask |= IDIAGNL_ATTR_VEGASINFO;
805  }
806 
807  if (tb[INET_DIAG_SKMEMINFO]) {
808  nla_memcpy(&msg->idiag_skmeminfo, tb[INET_DIAG_SKMEMINFO],
809  sizeof(msg->idiag_skmeminfo));
810  msg->ce_mask |= IDIAGNL_ATTR_SKMEMINFO;
811  }
812 
813  *result = msg;
814  return 0;
815 
816 errout:
817  idiagnl_msg_put(msg);
818  return err;
819 
820 errout_nomem:
821  err = -NLE_NOMEM;
822  goto errout;
823 }
824 
825 static const struct trans_tbl idiagnl_attrs[] = {
826  __ADD(IDIAGNL_ATTR_FAMILY, family),
827  __ADD(IDIAGNL_ATTR_STATE, state),
828  __ADD(IDIAGNL_ATTR_TIMER, timer),
829  __ADD(IDIAGNL_ATTR_RETRANS, retrans),
830  __ADD(IDIAGNL_ATTR_SPORT, sport),
831  __ADD(IDIAGNL_ATTR_DPORT, dport),
832  __ADD(IDIAGNL_ATTR_SRC, src),
833  __ADD(IDIAGNL_ATTR_DST, dst),
834  __ADD(IDIAGNL_ATTR_IFINDEX, ifindex),
835  __ADD(IDIAGNL_ATTR_EXPIRES, expires),
836  __ADD(IDIAGNL_ATTR_RQUEUE, rqueue),
837  __ADD(IDIAGNL_ATTR_WQUEUE, wqueue),
838  __ADD(IDIAGNL_ATTR_UID, uid),
839  __ADD(IDIAGNL_ATTR_INODE, inode),
840  __ADD(IDIAGNL_ATTR_TOS, tos),
841  __ADD(IDIAGNL_ATTR_TCLASS, tclass),
842  __ADD(IDIAGNL_ATTR_SHUTDOWN, shutdown),
843  __ADD(IDIAGNL_ATTR_CONG, cong),
844  __ADD(IDIAGNL_ATTR_MEMINFO, meminfo),
845  __ADD(IDIAGNL_ATTR_VEGASINFO, vegasinfo),
846  __ADD(IDIAGNL_ATTR_TCPINFO, tcpinfo),
847  __ADD(IDIAGNL_ATTR_SKMEMINFO, skmeminfo),
848 };
849 
850 static char *_idiagnl_attrs2str(int attrs, char *buf, size_t len)
851 {
852  return __flags2str(attrs, buf, len, idiagnl_attrs,
853  ARRAY_SIZE(idiagnl_attrs));
854 }
855 
856 static uint64_t idiagnl_compare(struct nl_object *_a, struct nl_object *_b,
857  uint64_t attrs, int flags)
858 {
859  struct idiagnl_msg *a = (struct idiagnl_msg *) _a;
860  struct idiagnl_msg *b = (struct idiagnl_msg *) _b;
861  uint64_t diff = 0;
862 
863 #define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, IDIAGNL_ATTR_##ATTR, a, b, EXPR)
864  diff |= _DIFF(FAMILY, a->idiag_family != b->idiag_family);
865  diff |= _DIFF(STATE, a->idiag_state != b->idiag_state);
866  diff |= _DIFF(TIMER, a->idiag_timer != b->idiag_timer);
867  diff |= _DIFF(RETRANS, a->idiag_retrans != b->idiag_retrans);
868  diff |= _DIFF(SPORT, a->idiag_sport != b->idiag_sport);
869  diff |= _DIFF(DPORT, a->idiag_dport != b->idiag_dport);
870  diff |= _DIFF(SRC, nl_addr_cmp (a->idiag_src, b->idiag_src));
871  diff |= _DIFF(DST, nl_addr_cmp (a->idiag_dst, b->idiag_dst));
872  diff |= _DIFF(IFINDEX, a->idiag_ifindex != b->idiag_ifindex);
873  diff |= _DIFF(EXPIRES, a->idiag_expires != b->idiag_expires);
874  diff |= _DIFF(RQUEUE, a->idiag_rqueue != b->idiag_rqueue);
875  diff |= _DIFF(WQUEUE, a->idiag_wqueue != b->idiag_wqueue);
876  diff |= _DIFF(UID, a->idiag_uid != b->idiag_uid);
877  diff |= _DIFF(INODE, a->idiag_inode != b->idiag_inode);
878  diff |= _DIFF(TOS, a->idiag_tos != b->idiag_tos);
879  diff |= _DIFF(TCLASS, a->idiag_tclass != b->idiag_tclass);
880  diff |= _DIFF(SHUTDOWN, a->idiag_shutdown != b->idiag_shutdown);
881  diff |= _DIFF(CONG, strcmp(a->idiag_cong, b->idiag_cong));
882  diff |= _DIFF(MEMINFO, nl_object_diff((struct nl_object *) a->idiag_meminfo, (struct nl_object *) b->idiag_meminfo));
883  diff |= _DIFF(VEGASINFO, nl_object_diff((struct nl_object *) a->idiag_vegasinfo, (struct nl_object *) b->idiag_vegasinfo));
884  diff |= _DIFF(TCPINFO, memcmp(&a->idiag_tcpinfo, &b->idiag_tcpinfo, sizeof(a->idiag_tcpinfo)));
885  diff |= _DIFF(SKMEMINFO, memcmp(a->idiag_skmeminfo, b->idiag_skmeminfo, sizeof(a->idiag_skmeminfo)));
886 #undef _DIFF
887  return diff;
888 }
889 
890 static void idiagnl_keygen(struct nl_object *obj, uint32_t *hashkey,
891  uint32_t table_sz)
892 {
893  struct idiagnl_msg *msg = (struct idiagnl_msg *)obj;
894  unsigned int key_sz;
895  struct idiagnl_hash_key {
896  uint8_t family;
897  uint32_t src_hash;
898  uint32_t dst_hash;
899  uint16_t sport;
900  uint16_t dport;
901  } __attribute__((packed)) key;
902 
903  key_sz = sizeof(key);
904  key.family = msg->idiag_family;
905  key.src_hash = 0;
906  key.dst_hash = 0;
907  key.sport = msg->idiag_sport;
908  key.dport = msg->idiag_dport;
909 
910  if (msg->idiag_src) {
911  key.src_hash = nl_hash (nl_addr_get_binary_addr(msg->idiag_src),
912  nl_addr_get_len(msg->idiag_src), 0);
913  }
914  if (msg->idiag_dst) {
915  key.dst_hash = nl_hash (nl_addr_get_binary_addr(msg->idiag_dst),
916  nl_addr_get_len(msg->idiag_dst), 0);
917  }
918 
919  *hashkey = nl_hash(&key, key_sz, 0) % table_sz;
920 
921  NL_DBG(5, "idiagnl %p key (fam %d src_hash %d dst_hash %d sport %d dport %d) keysz %d, hash 0x%x\n",
922  msg, key.family, key.src_hash, key.dst_hash, key.sport, key.dport, key_sz, *hashkey);
923 
924  return;
925 }
926 
927 /** @cond SKIP */
928 struct nl_object_ops idiagnl_msg_obj_ops = {
929  .oo_name = "idiag/idiag_msg",
930  .oo_size = sizeof(struct idiagnl_msg),
931  .oo_free_data = idiagnl_msg_free,
932  .oo_clone = idiagnl_msg_clone,
933  .oo_dump = {
934  [NL_DUMP_LINE] = idiag_msg_dump_line,
935  [NL_DUMP_DETAILS] = idiag_msg_dump_details,
936  [NL_DUMP_STATS] = idiag_msg_dump_stats,
937  },
938  .oo_compare = idiagnl_compare,
939  .oo_keygen = idiagnl_keygen,
940  .oo_attrs2str = _idiagnl_attrs2str,
941  .oo_id_attrs = (IDIAGNL_ATTR_FAMILY |
942  IDIAGNL_ATTR_SRC |
943  IDIAGNL_ATTR_DST |
944  IDIAGNL_ATTR_SPORT |
945  IDIAGNL_ATTR_DPORT),
946 };
947 /** @endcond */
948 
949 /** @} */
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
Definition: addr.c:471
Dump object briefly on one line.
Definition: types.h:22
8 bit integer
Definition: attr.h:41
int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
Compare abstract addresses.
Definition: addr.c:563
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
Definition: msg.c:106
struct nl_object * nl_object_alloc(struct nl_object_ops *ops)
Allocate a new object of kind specified by the operations handle.
Definition: object.c:54
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Definition: cache_mngt.c:287
Attribute validation policy.
Definition: attr.h:69
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
Definition: attr.c:606
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
Definition: object.c:204
struct nl_addr * nl_addr_build(int family, const void *buf, size_t size)
Allocate abstract address based on a binary address.
Definition: addr.c:216
char * nl_msec2str(uint64_t msec, char *buf, size_t len)
Convert milliseconds to a character string.
Definition: utils.c:594
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, struct nla_policy *policy)
parse attributes of a netlink message
Definition: msg.c:214
struct nl_addr * nl_addr_get(struct nl_addr *addr)
Increase the reference counter of an abstract address.
Definition: addr.c:501
NUL terminated character string.
Definition: attr.h:45
Dump all attributes but no statistics.
Definition: types.h:23
int idiagnl_msg_alloc_cache(struct nl_sock *sk, int family, int states, struct nl_cache **result)
Build an inetdiag cache to hold socket state information.
char * nl_size2str(const size_t size, char *buf, const size_t len)
Convert a size toa character string.
Definition: utils.c:357
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition: cache_mngt.c:252
int idiagnl_send_simple(struct nl_sock *sk, int flags, uint8_t family, uint16_t states, uint16_t ext)
Send trivial idiag netlink message.
Definition: idiag.c:63
char * idiagnl_shutdown2str(uint8_t shutdown, char *buf, size_t len)
Convert shutdown state to string.
Definition: idiag.c:260
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
Definition: attr.c:353
char * idiagnl_tcpopts2str(uint8_t attrs, char *buf, size_t len)
Convert TCP option attributes to string.
Definition: idiag.c:246
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition: attr.c:120
uint16_t minlen
Minimal length of payload required.
Definition: attr.h:74
char * idiagnl_tcpstate2str(uint8_t state, char *buf, size_t len)
Convert inetdiag tcp states to strings.
Definition: idiag.c:224
int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
(Re)fill a cache with the contents in the kernel.
Definition: cache.c:1040
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition: object.c:215
char * idiagnl_timer2str(int timer, char *buf, size_t len)
Convert inet diag timer types to strings.
Definition: idiag.c:143
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition: addr.c:517
Dumping parameters.
Definition: types.h:33
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:961
struct nl_object * nl_object_clone(struct nl_object *obj)
Allocate a new object and copy all data from an existing object.
Definition: object.c:110
char * idiagnl_state2str(int state, char *buf, size_t len)
Convert inet diag socket states to strings.
Definition: idiag.c:108
unsigned int nl_addr_get_len(const struct nl_addr *addr)
Get length of binary address of abstract address object.
Definition: addr.c:917
Dump all attributes including statistics.
Definition: types.h:24
void * nl_addr_get_binary_addr(const struct nl_addr *addr)
Get binary address of abstract address object.
Definition: addr.c:905
struct nl_cache * nl_cache_alloc(struct nl_cache_ops *ops)
Allocate new cache.
Definition: cache.c:183
uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b)
Compute 32-bit bitmask representing difference in attribute values.
Definition: object.c:385
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
Definition: addr.c:963