From 4ff60cd870c8ad7c8afd2afddb18120de6fdcbbe Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 15 Aug 2012 17:39:21 +0400 Subject: [PATCH] packet: Switch to use packet diag module It's in net-next already and does provide all we currently need (and more). Implementation is like for inet and unix sockets. Signed-off-by: Pavel Emelyanov --- include/packet_diag.h | 60 +++++++++++++++++++++++++++ include/sk-packet.h | 2 + sk-packet.c | 95 +++++++++++++++++++++++++------------------ sockets.c | 10 +++++ 4 files changed, 127 insertions(+), 40 deletions(-) create mode 100644 include/packet_diag.h diff --git a/include/packet_diag.h b/include/packet_diag.h new file mode 100644 index 000000000..895ca02dc --- /dev/null +++ b/include/packet_diag.h @@ -0,0 +1,60 @@ +#ifndef __PACKET_DIAG_H__ +#define __PACKET_DIAG_H__ + +#include + +struct packet_diag_req { + __u8 sdiag_family; + __u8 sdiag_protocol; + __u16 pad; + __u32 pdiag_ino; + __u32 pdiag_show; + __u32 pdiag_cookie[2]; +}; + +#define PACKET_SHOW_INFO 0x00000001 /* Basic packet_sk information */ +#define PACKET_SHOW_MCLIST 0x00000002 /* A set of packet_diag_mclist-s */ + +struct packet_diag_msg { + __u8 pdiag_family; + __u8 pdiag_type; + __u16 pdiag_num; + + __u32 pdiag_ino; + __u32 pdiag_cookie[2]; +}; + +enum { + PACKET_DIAG_INFO, + PACKET_DIAG_MCLIST, + + PACKET_DIAG_MAX, +}; + +struct packet_diag_info { + __u32 pdi_index; + __u32 pdi_version; + __u32 pdi_reserve; + __u32 pdi_copy_thresh; + __u32 pdi_tstamp; + __u32 pdi_flags; + +#define PDI_RUNNING 0x1 +#define PDI_AUXDATA 0x2 +#define PDI_ORIGDEV 0x4 +#define PDI_VNETHDR 0x8 +#define PDI_LOSS 0x10 +}; + +#ifndef MAX_ADDR_LEN +#define MAX_ADDR_LEN 32 +#endif + +struct packet_diag_mclist { + __u32 pdmc_index; + __u16 pdmc_type; + __u16 pdmc_alen; + __u8 pdmc_addr[MAX_ADDR_LEN]; +}; + +#endif diff --git a/include/sk-packet.h b/include/sk-packet.h index a2d3e60f4..1166691cd 100644 --- a/include/sk-packet.h +++ b/include/sk-packet.h @@ -13,6 +13,8 @@ int dump_one_packet_sk(struct fd_parms *p, int lfd, const struct cr_fdset *fds); int collect_packet_sockets(void); void show_packetsk(int fd, struct cr_options *); +extern int packet_receive_one(struct nlmsghdr *h, void *arg); + #ifndef PACKET_VNET_HDR #define PACKET_VNET_HDR 15 #endif diff --git a/sk-packet.c b/sk-packet.c index 66180695c..d36e37952 100644 --- a/sk-packet.c +++ b/sk-packet.c @@ -1,12 +1,16 @@ #include #include +#include +#include #include #include #include "crtools.h" #include "types.h" #include "files.h" #include "sockets.h" +#include "libnetlink.h" #include "sk-packet.h" +#include "packet_diag.h" #include "protobuf.h" #include "protobuf/packet-sock.pb-c.h" @@ -17,6 +21,13 @@ struct packet_sock_info { struct file_desc d; }; +struct packet_sock_desc { + struct socket_desc sd; + unsigned int type; + unsigned short proto; + struct packet_diag_info nli; +}; + void show_packetsk(int fd, struct cr_options *o) { pb_show_plain(fd, PB_PACKETSK); @@ -24,19 +35,20 @@ void show_packetsk(int fd, struct cr_options *o) static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p) { - int type, yes; PacketSockEntry psk = PACKET_SOCK_ENTRY__INIT; SkOptsEntry skopts = SK_OPTS_ENTRY__INIT; - struct sockaddr_ll addr; - socklen_t alen; + struct packet_sock_desc *sd; - pr_info("Dumping packet socket fd %d id %#x\n", lfd, id); - - if (dump_opt(lfd, SOL_SOCKET, SO_TYPE, &type)) + sd = (struct packet_sock_desc *)lookup_socket(p->stat.st_ino); + if (sd < 0) return -1; + pr_info("Dumping packet socket fd %d id %#x\n", lfd, id); + BUG_ON(sd->sd.already_dumped); + sd->sd.already_dumped = 1; + psk.id = id; - psk.type = type; + psk.type = sd->type; psk.flags = p->flags; psk.fown = (FownEntry *)&p->fown; psk.opts = &skopts; @@ -44,39 +56,15 @@ static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p) if (dump_socket_opts(lfd, &skopts)) return -1; - alen = sizeof(addr); - if (getsockname(lfd, (struct sockaddr *)&addr, &alen) < 0) { - pr_perror("Can't get packet sock name"); - return -1; - } - - psk.protocol = addr.sll_protocol; - psk.ifindex = addr.sll_ifindex; - - if (dump_opt(lfd, SOL_PACKET, PACKET_VERSION, &psk.version)) - return -1; - - if (dump_opt(lfd, SOL_PACKET, PACKET_RESERVE, &psk.reserve)) - return -1; - - if (dump_opt(lfd, SOL_PACKET, PACKET_TIMESTAMP, &psk.timestamp)) - return -1; - - if (dump_opt(lfd, SOL_PACKET, PACKET_AUXDATA, &yes)) - return -1; - psk.aux_data = (yes ? true : false); - - if (dump_opt(lfd, SOL_PACKET, PACKET_ORIGDEV, &yes)) - return 1; - psk.orig_dev = (yes ? true : false); - - if (dump_opt(lfd, SOL_PACKET, PACKET_VNET_HDR, &yes)) - return 1; - psk.vnet_hdr = (yes ? true : false); - - if (dump_opt(lfd, SOL_PACKET, PACKET_LOSS, &yes)) - return 1; - psk.loss = (yes ? true : false); + psk.protocol = sd->proto; + psk.ifindex = sd->nli.pdi_index; + psk.version = sd->nli.pdi_version; + psk.reserve = sd->nli.pdi_reserve; + psk.timestamp = sd->nli.pdi_tstamp; + psk.aux_data = (sd->nli.pdi_flags & PDI_AUXDATA ? true : false); + psk.orig_dev = (sd->nli.pdi_flags & PDI_ORIGDEV ? true : false); + psk.vnet_hdr = (sd->nli.pdi_flags & PDI_VNETHDR ? true : false); + psk.loss = (sd->nli.pdi_flags & PDI_LOSS ? true : false); return pb_write_one(fdset_fd(glob_fdset, CR_FD_PACKETSK), &psk, PB_PACKETSK); } @@ -91,6 +79,33 @@ int dump_one_packet_sk(struct fd_parms *p, int lfd, const struct cr_fdset *fds) return do_dump_gen_file(p, lfd, &packet_dump_ops, fds); } +int packet_receive_one(struct nlmsghdr *hdr, void *arg) +{ + struct packet_diag_msg *m; + struct rtattr *tb[PACKET_DIAG_MAX + 1]; + struct packet_sock_desc *sd; + + m = NLMSG_DATA(hdr); + parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr *)(m + 1), + hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*m))); + pr_msg("Collect packet sock %u %u\n", m->pdiag_ino, (unsigned int)m->pdiag_num); + + if (!tb[PACKET_DIAG_INFO]) { + pr_err("No packet sock info in nlm\n"); + return -1; + } + + sd = xmalloc(sizeof(*sd)); + if (!sd) + return -1; + + sd->type = m->pdiag_type; + sd->proto = htons(m->pdiag_num); + memcpy(&sd->nli, RTA_DATA(tb[PACKET_DIAG_INFO]), sizeof(sd->nli)); + + return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd); +} + static int open_packet_sk(struct file_desc *d) { struct packet_sock_info *psi; diff --git a/sockets.c b/sockets.c index 361ac2911..e6bcbcd87 100644 --- a/sockets.c +++ b/sockets.c @@ -8,6 +8,7 @@ #include "sockets.h" #include "unix_diag.h" #include "inet_diag.h" +#include "packet_diag.h" #include "files.h" #include "util-net.h" #include "sk-packet.h" @@ -46,6 +47,7 @@ int sk_collect_one(int ino, int family, struct socket_desc *d) d->ino = ino; d->family = family; + d->already_dumped = 0; chain = &sockets[ino % SK_HASH_SIZE]; d->next = *chain; @@ -174,6 +176,7 @@ int collect_sockets(int pid) union { struct unix_diag_req u; struct inet_diag_req_v2 i; + struct packet_diag_req p; } r; } req; @@ -263,6 +266,13 @@ int collect_sockets(int pid) if (tmp) err = tmp; + req.r.p.sdiag_family = AF_PACKET; + req.r.p.sdiag_protocol = 0; + req.r.p.pdiag_show = PACKET_SHOW_INFO; + tmp = do_rtnl_req(nl, &req, sizeof(req), packet_receive_one, NULL); + if (tmp) + err = tmp; + close(nl); out: if (rst > 0 && restore_ns(rst, CLONE_NEWNET) < 0)