summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/packet_diag.h2
-rw-r--r--net/packet/af_packet.c23
-rw-r--r--net/packet/diag.c20
-rw-r--r--net/packet/internal.h20
4 files changed, 44 insertions, 21 deletions
diff --git a/include/linux/packet_diag.h b/include/linux/packet_diag.h
index 34ade828979..93f5fa94a43 100644
--- a/include/linux/packet_diag.h
+++ b/include/linux/packet_diag.h
@@ -15,6 +15,7 @@ struct packet_diag_req {
#define PACKET_SHOW_INFO 0x00000001 /* Basic packet_sk information */
#define PACKET_SHOW_MCLIST 0x00000002 /* A set of packet_diag_mclist-s */
#define PACKET_SHOW_RING_CFG 0x00000004 /* Rings configuration parameters */
+#define PACKET_SHOW_FANOUT 0x00000008
struct packet_diag_msg {
__u8 pdiag_family;
@@ -30,6 +31,7 @@ enum {
PACKET_DIAG_MCLIST,
PACKET_DIAG_RX_RING,
PACKET_DIAG_TX_RING,
+ PACKET_DIAG_FANOUT,
PACKET_DIAG_MAX,
};
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 8a1605ae402..226b2cdfc33 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -207,24 +207,6 @@ static void prb_fill_vlan_info(struct tpacket_kbdq_core *,
struct tpacket3_hdr *);
static void packet_flush_mclist(struct sock *sk);
-#define PACKET_FANOUT_MAX 256
-
-struct packet_fanout {
-#ifdef CONFIG_NET_NS
- struct net *net;
-#endif
- unsigned int num_members;
- u16 id;
- u8 type;
- u8 defrag;
- atomic_t rr_cur;
- struct list_head list;
- struct sock *arr[PACKET_FANOUT_MAX];
- spinlock_t lock;
- atomic_t sk_ref;
- struct packet_type prot_hook ____cacheline_aligned_in_smp;
-};
-
struct packet_skb_cb {
unsigned int origlen;
union {
@@ -1148,7 +1130,8 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
return po->prot_hook.func(skb, dev, &po->prot_hook, orig_dev);
}
-static DEFINE_MUTEX(fanout_mutex);
+DEFINE_MUTEX(fanout_mutex);
+EXPORT_SYMBOL_GPL(fanout_mutex);
static LIST_HEAD(fanout_list);
static void __fanout_link(struct sock *sk, struct packet_sock *po)
@@ -1260,9 +1243,9 @@ static void fanout_release(struct sock *sk)
if (!f)
return;
+ mutex_lock(&fanout_mutex);
po->fanout = NULL;
- mutex_lock(&fanout_mutex);
if (atomic_dec_and_test(&f->sk_ref)) {
list_del(&f->list);
dev_remove_pack(&f->prot_hook);
diff --git a/net/packet/diag.c b/net/packet/diag.c
index e3975e4d458..bc33fbe8a5e 100644
--- a/net/packet/diag.c
+++ b/net/packet/diag.c
@@ -109,6 +109,22 @@ static int pdiag_put_rings_cfg(struct packet_sock *po, struct sk_buff *skb)
return ret;
}
+static int pdiag_put_fanout(struct packet_sock *po, struct sk_buff *nlskb)
+{
+ int ret = 0;
+
+ mutex_lock(&fanout_mutex);
+ if (po->fanout) {
+ u32 val;
+
+ val = (u32)po->fanout->id | ((u32)po->fanout->type << 16);
+ ret = nla_put_u32(nlskb, PACKET_DIAG_FANOUT, val);
+ }
+ mutex_unlock(&fanout_mutex);
+
+ return ret;
+}
+
static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct packet_diag_req *req,
u32 pid, u32 seq, u32 flags, int sk_ino)
{
@@ -139,6 +155,10 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct packet_diag
pdiag_put_rings_cfg(po, skb))
goto out_nlmsg_trim;
+ if ((req->pdiag_show & PACKET_SHOW_FANOUT) &&
+ pdiag_put_fanout(po, skb))
+ goto out_nlmsg_trim;
+
return nlmsg_end(skb, nlh);
out_nlmsg_trim:
diff --git a/net/packet/internal.h b/net/packet/internal.h
index 2c5fca28b24..44945f6b725 100644
--- a/net/packet/internal.h
+++ b/net/packet/internal.h
@@ -67,7 +67,25 @@ struct packet_ring_buffer {
atomic_t pending;
};
-struct packet_fanout;
+extern struct mutex fanout_mutex;
+#define PACKET_FANOUT_MAX 256
+
+struct packet_fanout {
+#ifdef CONFIG_NET_NS
+ struct net *net;
+#endif
+ unsigned int num_members;
+ u16 id;
+ u8 type;
+ u8 defrag;
+ atomic_t rr_cur;
+ struct list_head list;
+ struct sock *arr[PACKET_FANOUT_MAX];
+ spinlock_t lock;
+ atomic_t sk_ref;
+ struct packet_type prot_hook ____cacheline_aligned_in_smp;
+};
+
struct packet_sock {
/* struct sock has to be the first member of packet_sock */
struct sock sk;