From 2660b810d97bd162fbaf22e76a1193729d66142c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 16 Aug 2012 18:54:44 +0400 Subject: [PATCH] packet: Rings support There's no way (currently) to check that the ring got restored. Will do it once we implement mapping of a packet socket and tcpdump app test. Signed-off-by: Pavel Emelyanov --- include/sk-packet.h | 11 +++++ protobuf/packet-sock.proto | 13 ++++++ sk-packet.c | 91 ++++++++++++++++++++++++++++++++++++++ sockets.c | 2 +- 4 files changed, 116 insertions(+), 1 deletion(-) diff --git a/include/sk-packet.h b/include/sk-packet.h index db4d26ff8..721ef0770 100644 --- a/include/sk-packet.h +++ b/include/sk-packet.h @@ -21,5 +21,16 @@ extern int packet_receive_one(struct nlmsghdr *h, void *arg); #ifndef PACKET_FANOUT #define PACKET_FANOUT 18 + +struct tpacket_req3 { + unsigned int tp_block_size; + unsigned int tp_block_nr; + unsigned int tp_frame_size; + unsigned int tp_frame_nr; + unsigned int tp_retire_blk_tov; + unsigned int tp_sizeof_priv; + unsigned int tp_feature_req_word; +}; #endif + #endif diff --git a/protobuf/packet-sock.proto b/protobuf/packet-sock.proto index f6cfce7ab..030de2c25 100644 --- a/protobuf/packet-sock.proto +++ b/protobuf/packet-sock.proto @@ -7,6 +7,17 @@ message packet_mclist { required bytes addr = 3; } +message packet_ring { + required uint32 block_size = 1; + required uint32 block_nr = 2; + required uint32 frame_size = 3; + required uint32 frame_nr = 4; + + required uint32 retire_tmo = 5; + required uint32 sizeof_priv = 6; + required uint32 features = 7; +} + message packet_sock_entry { required uint32 id = 1; required uint32 type = 2; @@ -27,4 +38,6 @@ message packet_sock_entry { required uint32 copy_thresh = 15; repeated packet_mclist mclist = 16; optional uint32 fanout = 17 [ default = 0xffffffff ]; + optional packet_ring rx_ring = 18; + optional packet_ring tx_ring = 19; } diff --git a/sk-packet.c b/sk-packet.c index 32d3a4f34..cd0abada0 100644 --- a/sk-packet.c +++ b/sk-packet.c @@ -36,6 +36,7 @@ struct packet_sock_desc { int mreq_n; struct packet_diag_mclist *mreqs; unsigned int fanout; + struct packet_diag_ring *rx, *tx; }; #define NO_FANOUT ((unsigned int)-1) @@ -104,6 +105,44 @@ err: return -1; } +static PacketRing *dump_ring(struct packet_diag_ring *dr) +{ + PacketRing *ring; + + ring = xmalloc(sizeof(*ring)); + if (!ring) + return NULL; + + packet_ring__init(ring); + + ring->block_size = dr->pdr_block_size; + ring->block_nr = dr->pdr_block_nr; + ring->frame_size = dr->pdr_frame_size; + ring->frame_nr = dr->pdr_frame_nr; + ring->retire_tmo = dr->pdr_retire_tmo; + ring->sizeof_priv = dr->pdr_sizeof_priv; + ring->features = dr->pdr_features; + + return ring; +} + +static int dump_rings(PacketSockEntry *psk, struct packet_sock_desc *sd) +{ + if (sd->rx) { + psk->rx_ring = dump_ring(sd->rx); + if (!psk->rx_ring) + return -1; + } + + if (sd->tx) { + psk->tx_ring = dump_ring(sd->tx); + if (!psk->tx_ring) + return -1; + } + + return 0; +} + static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p) { PacketSockEntry psk = PACKET_SOCK_ENTRY__INIT; @@ -148,8 +187,14 @@ static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p) psk.fanout = sd->fanout; } + ret = dump_rings(&psk, sd); + if (ret) + goto out; + ret = pb_write_one(fdset_fd(glob_fdset, CR_FD_PACKETSK), &psk, PB_PACKETSK); out: + xfree(psk.rx_ring); + xfree(psk.tx_ring); for (i = 0; i < psk.n_mclist; i++) xfree(psk.mclist[i]->addr.data); xfree(psk.mclist); @@ -215,6 +260,18 @@ int packet_receive_one(struct nlmsghdr *hdr, void *arg) else sd->fanout = NO_FANOUT; + if (tb[PACKET_DIAG_RX_RING]) { + sd->rx = xmalloc(sizeof(*sd->rx)); + memcpy(sd->rx, RTA_DATA(tb[PACKET_DIAG_RX_RING]), sizeof(*sd->rx)); + } else + sd->rx = NULL; + + if (tb[PACKET_DIAG_TX_RING]) { + sd->tx = xmalloc(sizeof(*sd->tx)); + memcpy(sd->tx, RTA_DATA(tb[PACKET_DIAG_TX_RING]), sizeof(*sd->tx)); + } else + sd->tx = NULL; + return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd); } @@ -246,6 +303,37 @@ static int restore_mreqs(int sk, PacketSockEntry *pse) return 0; } +static int restore_ring(int sk, int type, PacketRing *ring) +{ + struct tpacket_req3 req; + + if (!ring) + return 0; + + pr_debug("\tRestoring %d ring\n", type); + + req.tp_block_size = ring->block_size; + req.tp_block_nr = ring->block_nr; + req.tp_frame_size = ring->frame_size; + req.tp_frame_nr = ring->frame_nr; + req.tp_retire_blk_tov = ring->retire_tmo; + req.tp_sizeof_priv = ring->sizeof_priv; + req.tp_feature_req_word = ring->features; + + return restore_opt(sk, SOL_PACKET, type, &req); +} + +static int restore_rings(int sk, PacketSockEntry *psk) +{ + if (restore_ring(sk, PACKET_RX_RING, psk->rx_ring)) + return -1; + + if (restore_ring(sk, PACKET_TX_RING, psk->tx_ring)) + return -1; + + return 0; +} + static int open_packet_sk(struct file_desc *d) { struct packet_sock_info *psi; @@ -312,6 +400,9 @@ static int open_packet_sk(struct file_desc *d) if (restore_mreqs(sk, pse)) goto err_cl; + if (restore_rings(sk, pse)) + goto err_cl; + if (pse->has_fanout) { pr_info("Restoring fanout %x\n", pse->fanout); if (restore_opt(sk, SOL_PACKET, PACKET_FANOUT, &pse->fanout)) diff --git a/sockets.c b/sockets.c index 9bdfc6e28..3d418a59d 100644 --- a/sockets.c +++ b/sockets.c @@ -274,7 +274,7 @@ int collect_sockets(int pid) req.r.p.sdiag_family = AF_PACKET; req.r.p.sdiag_protocol = 0; req.r.p.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MCLIST | - PACKET_SHOW_FANOUT; + PACKET_SHOW_FANOUT | PACKET_SHOW_RING_CFG; tmp = do_rtnl_req(nl, &req, sizeof(req), packet_receive_one, NULL); if (tmp) err = tmp;