* [PATCH 11/17] gtp: consolidate gtp socket rx path
From: Andreas Schultz @ 2017-01-23 11:57 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
Add network device to gtp context in preparation for splitting
the TEID from the network device.
Use this to rework the socker rx path. Move the common RX part
of v0 and v1 into a helper. Also move the final rx part into
that helper as well.
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 92 ++++++++++++++++++++++++++++---------------------------
1 file changed, 47 insertions(+), 45 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 6600c92..868467d 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,7 @@ struct pdp_ctx {
struct in_addr ms_addr_ip4;
struct in_addr sgsn_addr_ip4;
+ struct net_device *dev;
struct sock *sk;
atomic_t tx_seq;
@@ -179,9 +180,42 @@ static bool gtp_check_src_ms(struct sk_buff *skb, struct pdp_ctx *pctx,
return false;
}
+static int gtp_rx(struct sk_buff *skb, struct pdp_ctx *pctx, unsigned int hdrlen)
+{
+ struct pcpu_sw_netstats *stats;
+
+ if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
+ pr_debug("No PDP ctx for this MS\n");
+ return -1;
+ }
+
+ /* Get rid of the GTP + UDP headers. */
+ if (iptunnel_pull_header(skb, hdrlen, skb->protocol,
+ !net_eq(sock_net(skb->sk), dev_net(pctx->dev))))
+ return -1;
+
+ pr_debug("forwarding packet from GGSN to uplink\n");
+
+ /* Now that the UDP and the GTP header have been removed, set up the
+ * new network header. This is required by the upper layer to
+ * calculate the transport header.
+ */
+ skb_reset_network_header(skb);
+
+ skb->dev = pctx->dev;
+
+ stats = this_cpu_ptr(pctx->dev->tstats);
+ u64_stats_update_begin(&stats->syncp);
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+ u64_stats_update_end(&stats->syncp);
+
+ netif_rx(skb);
+ return 0;
+}
+
/* 1 means pass up to the stack, -1 means drop and 0 means decapsulated. */
-static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
- bool xnet)
+static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
{
unsigned int hdrlen = sizeof(struct udphdr) +
sizeof(struct gtp0_header);
@@ -205,17 +239,10 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
return -1;
}
- if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
- netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
- return -1;
- }
-
- /* Get rid of the GTP + UDP headers. */
- return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
+ return gtp_rx(skb, pctx, hdrlen);
}
-static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
- bool xnet)
+static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
{
unsigned int hdrlen = sizeof(struct udphdr) +
sizeof(struct gtp1_header);
@@ -254,13 +281,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
return -1;
}
- if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
- netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
- return -1;
- }
-
- /* Get rid of the GTP + UDP headers. */
- return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
+ return gtp_rx(skb, pctx, hdrlen);
}
/* UDP encapsulation receive handler. See net/ipv4/udp.c.
@@ -268,10 +289,8 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
*/
static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
{
- struct pcpu_sw_netstats *stats;
struct gtp_dev *gtp;
- bool xnet;
- int ret;
+ int ret = 0;
gtp = rcu_dereference_sk_user_data(sk);
if (!gtp)
@@ -279,16 +298,14 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
- xnet = !net_eq(sock_net(sk), dev_net(gtp->dev));
-
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
netdev_dbg(gtp->dev, "received GTP0 packet\n");
- ret = gtp0_udp_encap_recv(gtp, skb, xnet);
+ ret = gtp0_udp_encap_recv(gtp, skb);
break;
case UDP_ENCAP_GTP1U:
netdev_dbg(gtp->dev, "received GTP1U packet\n");
- ret = gtp1u_udp_encap_recv(gtp, skb, xnet);
+ ret = gtp1u_udp_encap_recv(gtp, skb);
break;
default:
ret = -1; /* Shouldn't happen. */
@@ -297,33 +314,17 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
switch (ret) {
case 1:
netdev_dbg(gtp->dev, "pass up to the process\n");
- return 1;
+ break;
case 0:
- netdev_dbg(gtp->dev, "forwarding packet from GGSN to uplink\n");
break;
case -1:
netdev_dbg(gtp->dev, "GTP packet has been dropped\n");
kfree_skb(skb);
- return 0;
+ ret = 0;
+ break;
}
- /* Now that the UDP and the GTP header have been removed, set up the
- * new network header. This is required by the upper layer to
- * calculate the transport header.
- */
- skb_reset_network_header(skb);
-
- skb->dev = gtp->dev;
-
- stats = this_cpu_ptr(gtp->dev->tstats);
- u64_stats_update_begin(&stats->syncp);
- stats->rx_packets++;
- stats->rx_bytes += skb->len;
- u64_stats_update_end(&stats->syncp);
-
- netif_rx(skb);
-
- return 0;
+ return ret;
}
static void gtp_encap_destroy(struct sock *sk)
@@ -929,6 +930,7 @@ static int ipv4_pdp_add(struct net_device *dev, struct sock *sk,
sock_hold(sk);
pctx->sk = sk;
+ pctx->dev = dev;
ipv4_pdp_fill(pctx, info);
atomic_set(&pctx->tx_seq, 0);
--
2.10.2
^ permalink raw reply related
* [PATCH 07/17] gtp: remove unnecessary rcu_read_lock
From: Andreas Schultz @ 2017-01-23 11:56 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
The rcu read lock is hold by default in the ip input path. There
is no need to hold it twice in the socket recv decapsulate code path.
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 24 ++++--------------------
1 file changed, 4 insertions(+), 20 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index bc8734b7..f434f84 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -183,7 +183,6 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
sizeof(struct gtp0_header);
struct gtp0_header *gtp0;
struct pdp_ctx *pctx;
- int ret = 0;
if (!pskb_may_pull(skb, hdrlen))
return -1;
@@ -196,26 +195,19 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
if (gtp0->type != GTP_TPDU)
return 1;
- rcu_read_lock();
pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
if (IS_ERR(pctx)) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
- ret = -1;
- goto out_rcu;
+ return -1;
}
if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
- ret = -1;
- goto out_rcu;
+ return -1;
}
- rcu_read_unlock();
/* Get rid of the GTP + UDP headers. */
return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
-out_rcu:
- rcu_read_unlock();
- return ret;
}
static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
@@ -225,7 +217,6 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
sizeof(struct gtp1_header);
struct gtp1_header *gtp1;
struct pdp_ctx *pctx;
- int ret = 0;
if (!pskb_may_pull(skb, hdrlen))
return -1;
@@ -253,26 +244,19 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr));
- rcu_read_lock();
pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
if (IS_ERR(pctx)) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
- ret = -1;
- goto out_rcu;
+ return -1;
}
if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
netdev_dbg(gtp->dev, "No PDP ctx for this MS\n");
- ret = -1;
- goto out_rcu;
+ return -1;
}
- rcu_read_unlock();
/* Get rid of the GTP + UDP headers. */
return iptunnel_pull_header(skb, hdrlen, skb->protocol, xnet);
-out_rcu:
- rcu_read_unlock();
- return ret;
}
/* UDP encapsulation receive handler. See net/ipv4/udp.c.
--
2.10.2
^ permalink raw reply related
* [PATCH 16/17] gtp: add genl cmd to enable GTP encapsulation on UDP socket
From: Andreas Schultz @ 2017-01-23 11:57 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/gtp.h | 4 ++++
2 files changed, 52 insertions(+)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 55bf098..157cf40 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1240,6 +1240,46 @@ static int gtp_genl_dump_pdp(struct sk_buff *skb,
return skb->len;
}
+static int gtp_genl_enable_socket(struct sk_buff *skb, struct genl_info *info)
+{
+ u32 version, fd, hashsize;
+ struct socket *sock;
+
+ if (!info->attrs[GTPA_VERSION] ||
+ !info->attrs[GTPA_FD])
+ return -EINVAL;
+
+ if (!info->attrs[GTPA_PDP_HASHSIZE])
+ hashsize = 1024;
+ else
+ hashsize = nla_get_u32(info->attrs[IFLA_GTP_PDP_HASHSIZE]);
+
+ version = nla_get_u32(info->attrs[GTPA_VERSION]);
+ fd = nla_get_u32(info->attrs[GTPA_FD]);
+
+ switch (version) {
+ case GTP_V0:
+ sock = gtp_encap_enable_socket(fd, UDP_ENCAP_GTP0, hashsize);
+ break;
+
+ case GTP_V1:
+ sock = gtp_encap_enable_socket(fd, UDP_ENCAP_GTP1U, hashsize);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (!sock)
+ return -EINVAL;
+
+ if (IS_ERR(sock))
+ return PTR_ERR(sock);
+
+ sockfd_put(sock);
+ return 0;
+}
+
static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = {
[GTPA_LINK] = { .type = NLA_U32, },
[GTPA_VERSION] = { .type = NLA_U32, },
@@ -1250,6 +1290,8 @@ static struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = {
[GTPA_NET_NS_FD] = { .type = NLA_U32, },
[GTPA_I_TEI] = { .type = NLA_U32, },
[GTPA_O_TEI] = { .type = NLA_U32, },
+ [GTPA_PDP_HASHSIZE] = { .type = NLA_U32, },
+ [GTPA_FD] = { .type = NLA_U32, },
};
static const struct genl_ops gtp_genl_ops[] = {
@@ -1272,6 +1314,12 @@ static const struct genl_ops gtp_genl_ops[] = {
.policy = gtp_genl_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = GTP_CMD_ENABLE_SOCKET,
+ .doit = gtp_genl_enable_socket,
+ .policy = gtp_genl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
static struct genl_family gtp_genl_family __ro_after_init = {
diff --git a/include/uapi/linux/gtp.h b/include/uapi/linux/gtp.h
index 72a04a0..a9e9fe0 100644
--- a/include/uapi/linux/gtp.h
+++ b/include/uapi/linux/gtp.h
@@ -6,6 +6,8 @@ enum gtp_genl_cmds {
GTP_CMD_DELPDP,
GTP_CMD_GETPDP,
+ GTP_CMD_ENABLE_SOCKET,
+
GTP_CMD_MAX,
};
@@ -26,6 +28,8 @@ enum gtp_attrs {
GTPA_I_TEI, /* for GTPv1 only */
GTPA_O_TEI, /* for GTPv1 only */
GTPA_PAD,
+ GTPA_PDP_HASHSIZE,
+ GTPA_FD,
__GTPA_MAX,
};
#define GTPA_MAX (__GTPA_MAX + 1)
--
2.10.2
^ permalink raw reply related
* [PATCH 09/17] gtp: use addr_hash when traversing pdp contexts
From: Andreas Schultz @ 2017-01-23 11:56 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
This prepares for the removal of the tid_hash from the device.
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 5b35ebb..762dd6b 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -778,7 +778,7 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
int i;
for (i = 0; i < gtp->hash_size; i++)
- hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid)
+ hlist_for_each_entry_rcu(pctx, >p->addr_hash[i], hlist_addr)
pdp_context_delete(pctx);
synchronize_rcu();
@@ -1188,7 +1188,7 @@ static int gtp_genl_dump_pdp(struct sk_buff *skb,
last_gtp = NULL;
for (i = k; i < gtp->hash_size; i++) {
- hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid) {
+ hlist_for_each_entry_rcu(pctx, >p->addr_hash[i], hlist_addr) {
if (tid && tid != pctx->u.tid)
continue;
else
--
2.10.2
^ permalink raw reply related
* [PATCH 14/17] gtp: move TEID hash to per socket structure
From: Andreas Schultz @ 2017-01-23 11:57 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
Untangele the TEID information from the network device and move
it into a per socket structure.
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 100 ++++++++++++++++++++++++++++++++----------------------
1 file changed, 60 insertions(+), 40 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 276cc66..019e80f 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -75,10 +75,15 @@ struct gtp_dev {
struct net_device *dev;
unsigned int hash_size;
- struct hlist_head *tid_hash;
struct hlist_head *addr_hash;
};
+/* One instance of the GTP socket. */
+struct gtp_sock {
+ unsigned int hash_size;
+ struct hlist_head tid_hash[];
+};
+
static unsigned int gtp_net_id __read_mostly;
struct gtp_net {
@@ -106,12 +111,12 @@ static inline u32 ipv4_hashfn(__be32 ip)
}
/* Resolve a PDP context structure based on the 64bit TID. */
-static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, u64 tid)
+static struct pdp_ctx *gtp0_pdp_find(struct gtp_sock *gsk, u64 tid)
{
struct hlist_head *head;
struct pdp_ctx *pdp;
- head = >p->tid_hash[gtp0_hashfn(tid) % gtp->hash_size];
+ head = &gsk->tid_hash[gtp0_hashfn(tid) % gsk->hash_size];
hlist_for_each_entry_rcu(pdp, head, hlist_tid) {
if (pdp->gtp_version == GTP_V0 &&
@@ -122,12 +127,12 @@ static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, u64 tid)
}
/* Resolve a PDP context structure based on the 32bit TEI. */
-static struct pdp_ctx *gtp1_pdp_find(struct gtp_dev *gtp, u32 tid)
+static struct pdp_ctx *gtp1_pdp_find(struct gtp_sock *gsk, u32 tid)
{
struct hlist_head *head;
struct pdp_ctx *pdp;
- head = >p->tid_hash[gtp1u_hashfn(tid) % gtp->hash_size];
+ head = &gsk->tid_hash[gtp1u_hashfn(tid) % gsk->hash_size];
hlist_for_each_entry_rcu(pdp, head, hlist_tid) {
if (pdp->gtp_version == GTP_V1 &&
@@ -215,7 +220,7 @@ static int gtp_rx(struct sk_buff *skb, struct pdp_ctx *pctx, unsigned int hdrlen
}
/* 1 means pass up to the stack, -1 means drop and 0 means decapsulated. */
-static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
+static int gtp0_udp_encap_recv(struct gtp_sock *gsk, struct sk_buff *skb)
{
unsigned int hdrlen = sizeof(struct udphdr) +
sizeof(struct gtp0_header);
@@ -233,7 +238,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
if (gtp0->type != GTP_TPDU)
return 1;
- pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
+ pctx = gtp0_pdp_find(gsk, be64_to_cpu(gtp0->tid));
if (IS_ERR(pctx)) {
pr_debug("No PDP ctx to decap skb=%p\n", skb);
return 1;
@@ -242,7 +247,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
return gtp_rx(skb, pctx, hdrlen);
}
-static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
+static int gtp1u_udp_encap_recv(struct gtp_sock *gsk, struct sk_buff *skb)
{
unsigned int hdrlen = sizeof(struct udphdr) +
sizeof(struct gtp1_header);
@@ -275,7 +280,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr));
- pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
+ pctx = gtp1_pdp_find(gsk, ntohl(gtp1->tid));
if (IS_ERR(pctx)) {
pr_debug("No PDP ctx to decap skb=%p\n", skb);
return 1;
@@ -289,11 +294,11 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
*/
static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
{
- struct gtp_dev *gtp;
+ struct gtp_sock *gsk;
int ret = 0;
- gtp = rcu_dereference_sk_user_data(sk);
- if (!gtp)
+ gsk = rcu_dereference_sk_user_data(sk);
+ if (!gsk)
return 1;
pr_debug("encap_recv sk=%p\n", sk);
@@ -301,11 +306,11 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
pr_debug("received GTP0 packet\n");
- ret = gtp0_udp_encap_recv(gtp, skb);
+ ret = gtp0_udp_encap_recv(gsk, skb);
break;
case UDP_ENCAP_GTP1U:
pr_debug("received GTP1U packet\n");
- ret = gtp1u_udp_encap_recv(gtp, skb);
+ ret = gtp1u_udp_encap_recv(gsk, skb);
break;
default:
ret = -1; /* Shouldn't happen. */
@@ -329,12 +334,21 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
static void gtp_encap_destroy(struct sock *sk)
{
- struct gtp_dev *gtp;
+ struct gtp_sock *gsk;
+ struct pdp_ctx *pctx;
+ int i;
- gtp = rcu_dereference_sk_user_data(sk);
- if (gtp) {
+ gsk = rcu_dereference_sk_user_data(sk);
+ if (gsk) {
udp_sk(sk)->encap_type = 0;
rcu_assign_sk_user_data(sk, NULL);
+
+ for (i = 0; i < gsk->hash_size; i++)
+ hlist_for_each_entry_rcu(pctx, &gsk->tid_hash[i], hlist_tid)
+ pdp_context_delete(pctx);
+
+ synchronize_rcu();
+ kfree(gsk);
}
}
@@ -607,7 +621,7 @@ static void gtp_link_setup(struct net_device *dev)
static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
static void gtp_hashtable_free(struct gtp_dev *gtp);
static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
- struct nlattr *data[]);
+ int hsize, struct nlattr *data[]);
static void gtp_encap_disable(struct gtp_dev *gtp);
static int gtp_newlink(struct net *src_net, struct net_device *dev,
@@ -625,7 +639,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev,
hashsize = nla_get_u32(data[IFLA_GTP_PDP_HASHSIZE]);
if (data[IFLA_GTP_FD0] || data[IFLA_GTP_FD1]) {
- err = gtp_encap_enable(dev, gtp, data);
+ err = gtp_encap_enable(dev, gtp, hashsize, data);
if (err < 0)
goto out_err;
}
@@ -736,20 +750,12 @@ static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize)
if (gtp->addr_hash == NULL)
return -ENOMEM;
- gtp->tid_hash = kmalloc(sizeof(struct hlist_head) * hsize, GFP_KERNEL);
- if (gtp->tid_hash == NULL)
- goto err1;
-
gtp->hash_size = hsize;
- for (i = 0; i < hsize; i++) {
+ for (i = 0; i < hsize; i++)
INIT_HLIST_HEAD(>p->addr_hash[i]);
- INIT_HLIST_HEAD(>p->tid_hash[i]);
- }
+
return 0;
-err1:
- kfree(gtp->addr_hash);
- return -ENOMEM;
}
static void gtp_hashtable_free(struct gtp_dev *gtp)
@@ -763,15 +769,14 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
synchronize_rcu();
kfree(gtp->addr_hash);
- kfree(gtp->tid_hash);
}
-static struct socket *gtp_encap_enable_socket(int fd, int type,
- struct gtp_dev *gtp)
+static struct socket *gtp_encap_enable_socket(int fd, int type, int hsize)
{
struct udp_tunnel_sock_cfg tuncfg = {NULL};
+ struct gtp_sock *gsk;
struct socket *sock;
- int err;
+ int err, i;
pr_debug("enable gtp on %d, %d\n", fd, type);
@@ -787,7 +792,17 @@ static struct socket *gtp_encap_enable_socket(int fd, int type,
goto out_sock;
}
- tuncfg.sk_user_data = gtp;
+ gsk = kzalloc(sizeof(*gsk) + sizeof(struct hlist_head) * hsize, GFP_KERNEL);
+ if (!gsk) {
+ err = -ENOMEM;
+ goto out_sock;
+ }
+
+ gsk->hash_size = hsize;
+ for (i = 0; i < hsize; i++)
+ INIT_HLIST_HEAD(&gsk->tid_hash[i]);
+
+ tuncfg.sk_user_data = gsk;
tuncfg.encap_type = type;
tuncfg.encap_rcv = gtp_encap_recv;
tuncfg.encap_destroy = gtp_encap_destroy;
@@ -801,7 +816,7 @@ static struct socket *gtp_encap_enable_socket(int fd, int type,
}
static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
- struct nlattr *data[])
+ int hsize, struct nlattr *data[])
{
struct socket *sock0 = NULL;
struct socket *sock1u = NULL;
@@ -809,7 +824,7 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
if (data[IFLA_GTP_FD0]) {
u32 fd0 = nla_get_u32(data[IFLA_GTP_FD0]);
- sock0 = gtp_encap_enable_socket(fd0, UDP_ENCAP_GTP0, gtp);
+ sock0 = gtp_encap_enable_socket(fd0, UDP_ENCAP_GTP0, hsize);
if (IS_ERR(sock0))
return PTR_ERR(sock0);
}
@@ -817,7 +832,7 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
if (data[IFLA_GTP_FD1]) {
u32 fd1 = nla_get_u32(data[IFLA_GTP_FD1]);
- sock1u = gtp_encap_enable_socket(fd1, UDP_ENCAP_GTP1U, gtp);
+ sock1u = gtp_encap_enable_socket(fd1, UDP_ENCAP_GTP1U, hsize);
if (IS_ERR(sock1u)) {
if (sock0)
sockfd_put(sock0);
@@ -890,11 +905,16 @@ static int ipv4_pdp_add(struct net_device *dev, struct sock *sk,
struct genl_info *info)
{
struct gtp_dev *gtp = netdev_priv(dev);
+ struct gtp_sock *gsk;
u32 hash_ms, hash_tid = 0;
struct pdp_ctx *pctx;
bool found = false;
__be32 ms_addr;
+ gsk = rcu_dereference_sk_user_data(sk);
+ if (!gsk)
+ return -ENODEV;
+
ms_addr = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
hash_ms = ipv4_hashfn(ms_addr) % gtp->hash_size;
@@ -941,15 +961,15 @@ static int ipv4_pdp_add(struct net_device *dev, struct sock *sk,
* situation in which this doesn't unambiguosly identify the
* PDP context.
*/
- hash_tid = gtp0_hashfn(pctx->u.v0.tid) % gtp->hash_size;
+ hash_tid = gtp0_hashfn(pctx->u.v0.tid) % gsk->hash_size;
break;
case GTP_V1:
- hash_tid = gtp1u_hashfn(pctx->u.v1.i_tei) % gtp->hash_size;
+ hash_tid = gtp1u_hashfn(pctx->u.v1.i_tei) % gsk->hash_size;
break;
}
hlist_add_head_rcu(&pctx->hlist_addr, >p->addr_hash[hash_ms]);
- hlist_add_head_rcu(&pctx->hlist_tid, >p->tid_hash[hash_tid]);
+ hlist_add_head_rcu(&pctx->hlist_tid, &gsk->tid_hash[hash_tid]);
switch (pctx->gtp_version) {
case GTP_V0:
--
2.10.2
^ permalink raw reply related
* [PATCH 15/17] gtp: rename gtp hashtable helpers
From: Andreas Schultz @ 2017-01-23 11:57 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
The gtp_hashtable helper are now olny used for the per netdevice
address hashes. Rename them to make their purpose clearer.
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 019e80f..55bf098 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -618,8 +618,8 @@ static void gtp_link_setup(struct net_device *dev)
sizeof(struct gtp0_header);
}
-static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
-static void gtp_hashtable_free(struct gtp_dev *gtp);
+static int gtp_dev_hashtable_new(struct gtp_dev *gtp, int hsize);
+static void gtp_dev_hashtable_free(struct gtp_dev *gtp);
static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
int hsize, struct nlattr *data[]);
static void gtp_encap_disable(struct gtp_dev *gtp);
@@ -644,7 +644,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev,
goto out_err;
}
- err = gtp_hashtable_new(gtp, hashsize);
+ err = gtp_dev_hashtable_new(gtp, hashsize);
if (err < 0)
goto out_socket;
@@ -662,7 +662,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev,
return 0;
out_hashtable:
- gtp_hashtable_free(gtp);
+ gtp_dev_hashtable_free(gtp);
out_socket:
gtp_encap_disable(gtp);
out_err:
@@ -673,7 +673,7 @@ static void gtp_dellink(struct net_device *dev, struct list_head *head)
{
struct gtp_dev *gtp = netdev_priv(dev);
- gtp_hashtable_free(gtp);
+ gtp_dev_hashtable_free(gtp);
if (gtp->sock0)
sockfd_put(gtp->sock0);
if (gtp->sock1u)
@@ -742,7 +742,7 @@ static struct net *gtp_genl_get_net(struct net *src_net, struct nlattr *tb[])
return net;
}
-static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize)
+static int gtp_dev_hashtable_new(struct gtp_dev *gtp, int hsize)
{
int i;
@@ -758,7 +758,7 @@ static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize)
return 0;
}
-static void gtp_hashtable_free(struct gtp_dev *gtp)
+static void gtp_dev_hashtable_free(struct gtp_dev *gtp)
{
struct pdp_ctx *pctx;
int i;
--
2.10.2
^ permalink raw reply related
* [PATCH 08/17] gtp: consolidate pdp context destruction into helper
From: Andreas Schultz @ 2017-01-23 11:56 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index f434f84..5b35ebb 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -84,6 +84,8 @@ struct gtp_net {
static u32 gtp_h_initval;
+static void pdp_context_delete(struct pdp_ctx *pctx);
+
static inline u32 gtp0_hashfn(u64 tid)
{
u32 *tid32 = (u32 *) &tid;
@@ -775,13 +777,10 @@ static void gtp_hashtable_free(struct gtp_dev *gtp)
struct pdp_ctx *pctx;
int i;
- for (i = 0; i < gtp->hash_size; i++) {
- hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid) {
- hlist_del_rcu(&pctx->hlist_tid);
- hlist_del_rcu(&pctx->hlist_addr);
- kfree_rcu(pctx, rcu_head);
- }
- }
+ for (i = 0; i < gtp->hash_size; i++)
+ hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid)
+ pdp_context_delete(pctx);
+
synchronize_rcu();
kfree(gtp->addr_hash);
kfree(gtp->tid_hash);
@@ -984,6 +983,13 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
return 0;
}
+static void pdp_context_delete(struct pdp_ctx *pctx)
+{
+ hlist_del_rcu(&pctx->hlist_tid);
+ hlist_del_rcu(&pctx->hlist_addr);
+ kfree_rcu(pctx, rcu_head);
+}
+
static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
{
struct net_device *dev;
@@ -1082,10 +1088,7 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
pr_debug("GTPv1-U: deleting tunnel id = %x/%x (pdp %p)\n",
pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
- hlist_del_rcu(&pctx->hlist_tid);
- hlist_del_rcu(&pctx->hlist_addr);
- kfree_rcu(pctx, rcu_head);
-
+ pdp_context_delete(pctx);
return 0;
}
--
2.10.2
^ permalink raw reply related
* [PATCH 05/17] gtp: unify genl_find_pdp and prepare for per socket lookup
From: Andreas Schultz @ 2017-01-23 11:56 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
TEID are unique per socket and not per network device. Therefore
the API needs to be changed here.
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 99 +++++++++++++++++--------------------------------------
1 file changed, 31 insertions(+), 68 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index e95c856..7a3c5f6 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1044,56 +1044,61 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
return ipv4_pdp_add(dev, info);
}
-static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
+static struct pdp_ctx *gtp_genl_find_pdp_by_link(struct sk_buff *skb,
+ struct genl_info *info)
{
struct net_device *dev;
- struct pdp_ctx *pctx;
struct gtp_dev *gtp;
struct net *net;
+ __be32 ms_addr;
- if (!info->attrs[GTPA_VERSION] ||
- !info->attrs[GTPA_LINK])
- return -EINVAL;
+ if (!info->attrs[GTPA_MS_ADDRESS])
+ return ERR_PTR(-EINVAL);
+ ms_addr = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
if (IS_ERR(net))
- return PTR_ERR(net);
+ return ERR_PTR(PTR_ERR(net));
/* Check if there's an existing gtpX device to configure */
dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK]));
if (dev == NULL) {
put_net(net);
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
}
put_net(net);
gtp = netdev_priv(dev);
- switch (nla_get_u32(info->attrs[GTPA_VERSION])) {
- case GTP_V0:
- if (!info->attrs[GTPA_TID])
- return -EINVAL;
- pctx = gtp0_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_TID]));
- break;
- case GTP_V1:
- if (!info->attrs[GTPA_I_TEI])
- return -EINVAL;
- pctx = gtp1_pdp_find(gtp, nla_get_u64(info->attrs[GTPA_I_TEI]));
- break;
+ return ipv4_pdp_find(gtp, ms_addr);
+}
- default:
+static struct pdp_ctx *gtp_genl_find_pdp(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ if (info->attrs[GTPA_LINK])
+ return gtp_genl_find_pdp_by_link(skb, info);
+ else
+ return ERR_PTR(-EINVAL);
+}
+
+static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
+{
+ struct pdp_ctx *pctx;
+
+ if (!info->attrs[GTPA_VERSION])
return -EINVAL;
- }
+ pctx = gtp_genl_find_pdp(skb, info);
if (IS_ERR(pctx))
return PTR_ERR(pctx);
if (pctx->gtp_version == GTP_V0)
- netdev_dbg(dev, "GTPv0-U: deleting tunnel id = %llx (pdp %p)\n",
- pctx->u.v0.tid, pctx);
+ pr_debug("GTPv0-U: deleting tunnel id = %llx (pdp %p)\n",
+ pctx->u.v0.tid, pctx);
else if (pctx->gtp_version == GTP_V1)
- netdev_dbg(dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp %p)\n",
- pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
+ pr_debug("GTPv1-U: deleting tunnel id = %x/%x (pdp %p)\n",
+ pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx);
hlist_del_rcu(&pctx->hlist_tid);
hlist_del_rcu(&pctx->hlist_addr);
@@ -1143,57 +1148,15 @@ static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq,
static int gtp_genl_get_pdp(struct sk_buff *skb, struct genl_info *info)
{
struct pdp_ctx *pctx = NULL;
- struct net_device *dev;
struct sk_buff *skb2;
- struct gtp_dev *gtp;
- u32 gtp_version;
- struct net *net;
int err;
- if (!info->attrs[GTPA_VERSION] ||
- !info->attrs[GTPA_LINK])
- return -EINVAL;
-
- gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]);
- switch (gtp_version) {
- case GTP_V0:
- case GTP_V1:
- break;
- default:
+ if (!info->attrs[GTPA_VERSION])
return -EINVAL;
- }
-
- net = gtp_genl_get_net(sock_net(skb->sk), info->attrs);
- if (IS_ERR(net))
- return PTR_ERR(net);
-
- /* Check if there's an existing gtpX device to configure */
- dev = gtp_find_dev(net, nla_get_u32(info->attrs[GTPA_LINK]));
- if (dev == NULL) {
- put_net(net);
- return -ENODEV;
- }
- put_net(net);
-
- gtp = netdev_priv(dev);
rcu_read_lock();
- if (gtp_version == GTP_V0 &&
- info->attrs[GTPA_TID]) {
- u64 tid = nla_get_u64(info->attrs[GTPA_TID]);
-
- pctx = gtp0_pdp_find(gtp, tid);
- } else if (gtp_version == GTP_V1 &&
- info->attrs[GTPA_I_TEI]) {
- u32 tid = nla_get_u32(info->attrs[GTPA_I_TEI]);
-
- pctx = gtp1_pdp_find(gtp, tid);
- } else if (info->attrs[GTPA_MS_ADDRESS]) {
- __be32 ip = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
-
- pctx = ipv4_pdp_find(gtp, ip);
- }
+ pctx = gtp_genl_find_pdp(skb, info);
if (IS_ERR(pctx)) {
err = PTR_ERR(pctx);
goto err_unlock;
--
2.10.2
^ permalink raw reply related
* [PATCH 01/17] gtp: add genl family modules alias
From: Andreas Schultz @ 2017-01-23 11:56 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
Auto-load the module when userspace asks for the gtp netlink
family.
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 8b6810b..7580ccc 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1376,3 +1376,4 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <hwelte@sysmocom.de>");
MODULE_DESCRIPTION("Interface driver for GTP encapsulated traffic");
MODULE_ALIAS_RTNL_LINK("gtp");
+MODULE_ALIAS_GENL_FAMILY("gtp");
--
2.10.2
^ permalink raw reply related
* [PATCH 12/17] gtp: let userspace handle packets for invalid tunnels
From: Andreas Schultz @ 2017-01-23 11:57 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
enable userspace to send error replies for invalid tunnels
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 868467d..290c400 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -186,7 +186,7 @@ static int gtp_rx(struct sk_buff *skb, struct pdp_ctx *pctx, unsigned int hdrlen
if (!gtp_check_src_ms(skb, pctx, hdrlen)) {
pr_debug("No PDP ctx for this MS\n");
- return -1;
+ return 1;
}
/* Get rid of the GTP + UDP headers. */
@@ -236,7 +236,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
if (IS_ERR(pctx)) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
- return -1;
+ return 1;
}
return gtp_rx(skb, pctx, hdrlen);
@@ -278,7 +278,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
if (IS_ERR(pctx)) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
- return -1;
+ return 1;
}
return gtp_rx(skb, pctx, hdrlen);
--
2.10.2
^ permalink raw reply related
* [PATCH 04/17] gtp: return error ptr in find pdp helpers
From: Andreas Schultz @ 2017-01-23 11:56 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 60946b7..e95c856 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -114,7 +114,7 @@ static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, u64 tid)
pdp->u.v0.tid == tid)
return pdp;
}
- return NULL;
+ return ERR_PTR(-ENOENT);
}
/* Resolve a PDP context structure based on the 32bit TEI. */
@@ -130,7 +130,7 @@ static struct pdp_ctx *gtp1_pdp_find(struct gtp_dev *gtp, u32 tid)
pdp->u.v1.i_tei == tid)
return pdp;
}
- return NULL;
+ return ERR_PTR(-ENOENT);
}
/* Resolve a PDP context based on IPv4 address of MS. */
@@ -147,7 +147,7 @@ static struct pdp_ctx *ipv4_pdp_find(struct gtp_dev *gtp, __be32 ms_addr)
return pdp;
}
- return NULL;
+ return ERR_PTR(-ENOENT);
}
static bool gtp_check_src_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx,
@@ -199,7 +199,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
rcu_read_lock();
pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
- if (!pctx) {
+ if (IS_ERR(pctx)) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
ret = -1;
goto out_rcu;
@@ -256,7 +256,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb,
rcu_read_lock();
pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
- if (!pctx) {
+ if (IS_ERR(pctx)) {
netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
ret = -1;
goto out_rcu;
@@ -476,10 +476,10 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev,
*/
iph = ip_hdr(skb);
pctx = ipv4_pdp_find(gtp, iph->daddr);
- if (!pctx) {
+ if (IS_ERR(pctx)) {
netdev_dbg(dev, "no PDP ctx found for %pI4, skip\n",
&iph->daddr);
- return -ENOENT;
+ return PTR_ERR(pctx);
}
netdev_dbg(dev, "found PDP context %p\n", pctx);
@@ -1085,8 +1085,8 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
- if (pctx == NULL)
- return -ENOENT;
+ if (IS_ERR(pctx))
+ return PTR_ERR(pctx);
if (pctx->gtp_version == GTP_V0)
netdev_dbg(dev, "GTPv0-U: deleting tunnel id = %llx (pdp %p)\n",
@@ -1194,8 +1194,8 @@ static int gtp_genl_get_pdp(struct sk_buff *skb, struct genl_info *info)
pctx = ipv4_pdp_find(gtp, ip);
}
- if (pctx == NULL) {
- err = -ENOENT;
+ if (IS_ERR(pctx)) {
+ err = PTR_ERR(pctx);
goto err_unlock;
}
--
2.10.2
^ permalink raw reply related
* [PATCH 10/17] gtp: add socket to pdp context
From: Andreas Schultz @ 2017-01-23 11:56 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
Having the socket present in context simplifies the sending logic.
It also fixes the invalid assumtion that we have to use the same
sending socket for all client IP's on a specific gtp interface.
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 70 ++++++++++++++++++++++++++++++-------------------------
1 file changed, 38 insertions(+), 32 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 762dd6b..6600c92 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -58,6 +58,8 @@ struct pdp_ctx {
struct in_addr ms_addr_ip4;
struct in_addr sgsn_addr_ip4;
+ struct sock *sk;
+
atomic_t tx_seq;
struct rcu_head rcu_head;
};
@@ -353,8 +355,9 @@ static void gtp_dev_uninit(struct net_device *dev)
free_percpu(dev->tstats);
}
-static struct rtable *ip4_route_output_gtp(struct net *net, struct flowi4 *fl4,
- const struct sock *sk, __be32 daddr)
+static struct rtable *ip4_route_output_gtp(struct flowi4 *fl4,
+ const struct sock *sk,
+ __be32 daddr)
{
memset(fl4, 0, sizeof(*fl4));
fl4->flowi4_oif = sk->sk_bound_dev_if;
@@ -363,7 +366,7 @@ static struct rtable *ip4_route_output_gtp(struct net *net, struct flowi4 *fl4,
fl4->flowi4_tos = RT_CONN_FLAGS(sk);
fl4->flowi4_proto = sk->sk_protocol;
- return ip_route_output_key(net, fl4);
+ return ip_route_output_key(sock_net(sk), fl4);
}
static inline void gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)
@@ -452,7 +455,6 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev,
struct rtable *rt;
struct flowi4 fl4;
struct iphdr *iph;
- struct sock *sk;
__be16 df;
int mtu;
@@ -468,30 +470,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev,
}
netdev_dbg(dev, "found PDP context %p\n", pctx);
- switch (pctx->gtp_version) {
- case GTP_V0:
- if (gtp->sock0)
- sk = gtp->sock0->sk;
- else
- sk = NULL;
- break;
- case GTP_V1:
- if (gtp->sock1u)
- sk = gtp->sock1u->sk;
- else
- sk = NULL;
- break;
- default:
- return -ENOENT;
- }
-
- if (!sk) {
- netdev_dbg(dev, "no userspace socket is available, skip\n");
- return -ENOENT;
- }
-
- rt = ip4_route_output_gtp(sock_net(sk), &fl4, gtp->sock0->sk,
- pctx->sgsn_addr_ip4.s_addr);
+ rt = ip4_route_output_gtp(&fl4, pctx->sk, pctx->sgsn_addr_ip4.s_addr);
if (IS_ERR(rt)) {
netdev_dbg(dev, "no route to SSGN %pI4\n",
&pctx->sgsn_addr_ip4.s_addr);
@@ -536,7 +515,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev,
goto err_rt;
}
- gtp_set_pktinfo_ipv4(pktinfo, sk, iph, pctx, rt, &fl4, dev);
+ gtp_set_pktinfo_ipv4(pktinfo, pctx->sk, iph, pctx, rt, &fl4, dev);
gtp_push_header(skb, pktinfo);
return 0;
@@ -906,7 +885,8 @@ static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info)
}
}
-static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
+static int ipv4_pdp_add(struct net_device *dev, struct sock *sk,
+ struct genl_info *info)
{
struct gtp_dev *gtp = netdev_priv(dev);
u32 hash_ms, hash_tid = 0;
@@ -947,6 +927,8 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
if (pctx == NULL)
return -ENOMEM;
+ sock_hold(sk);
+ pctx->sk = sk;
ipv4_pdp_fill(pctx, info);
atomic_set(&pctx->tx_seq, 0);
@@ -985,15 +967,33 @@ static int ipv4_pdp_add(struct net_device *dev, struct genl_info *info)
static void pdp_context_delete(struct pdp_ctx *pctx)
{
+ sock_put(pctx->sk);
hlist_del_rcu(&pctx->hlist_tid);
hlist_del_rcu(&pctx->hlist_addr);
kfree_rcu(pctx, rcu_head);
}
+static struct socket *gtp_genl_new_pdp_select_socket(int version,
+ struct net_device *dev)
+{
+ struct gtp_dev *gtp = netdev_priv(dev);
+
+ switch (version) {
+ case GTP_V0:
+ return gtp->sock0;
+ case GTP_V1:
+ return gtp->sock1u;
+ default:
+ return NULL;
+ }
+}
+
static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
{
+ unsigned int version;
struct net_device *dev;
struct net *net;
+ struct socket *sock;
if (!info->attrs[GTPA_VERSION] ||
!info->attrs[GTPA_LINK] ||
@@ -1001,7 +1001,9 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
!info->attrs[GTPA_MS_ADDRESS])
return -EINVAL;
- switch (nla_get_u32(info->attrs[GTPA_VERSION])) {
+ version = nla_get_u32(info->attrs[GTPA_VERSION]);
+
+ switch (version) {
case GTP_V0:
if (!info->attrs[GTPA_TID] ||
!info->attrs[GTPA_FLOW])
@@ -1029,7 +1031,11 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
}
put_net(net);
- return ipv4_pdp_add(dev, info);
+ sock = gtp_genl_new_pdp_select_socket(version, dev);
+ if (!sock)
+ return -ENODEV;
+
+ return ipv4_pdp_add(dev, sock->sk, info);
}
static struct pdp_ctx *gtp_genl_find_pdp_by_link(struct sk_buff *skb,
--
2.10.2
^ permalink raw reply related
* [PATCH 06/17] gtp: fix cross netns recv on gtp socket
From: Andreas Schultz @ 2017-01-23 11:56 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
The use of the paassed through netlink src_net to check for a
cross netns operation was wrong. Using the GTP socket and the
GTP netdevice is always correct (even if the netdev has been
moved to new netns after link creation).
Remove the now obsolete net field from gtp_dev.
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 7a3c5f6..bc8734b7 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -69,7 +69,6 @@ struct gtp_dev {
struct socket *sock0;
struct socket *sock1u;
- struct net *net;
struct net_device *dev;
unsigned int hash_size;
@@ -292,7 +291,7 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
- xnet = !net_eq(gtp->net, dev_net(gtp->dev));
+ xnet = !net_eq(sock_net(sk), dev_net(gtp->dev));
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
@@ -642,7 +641,7 @@ static void gtp_link_setup(struct net_device *dev)
static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
static void gtp_hashtable_free(struct gtp_dev *gtp);
static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
- struct net *src_net, struct nlattr *data[]);
+ struct nlattr *data[]);
static void gtp_encap_disable(struct gtp_dev *gtp);
static int gtp_newlink(struct net *src_net, struct net_device *dev,
@@ -660,7 +659,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev,
hashsize = nla_get_u32(data[IFLA_GTP_PDP_HASHSIZE]);
if (data[IFLA_GTP_FD0] || data[IFLA_GTP_FD1]) {
- err = gtp_encap_enable(dev, gtp, src_net, data);
+ err = gtp_encap_enable(dev, gtp, data);
if (err < 0)
goto out_err;
}
@@ -839,7 +838,7 @@ static struct socket *gtp_encap_enable_socket(int fd, int type,
}
static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
- struct net *src_net, struct nlattr *data[])
+ struct nlattr *data[])
{
struct socket *sock0 = NULL;
struct socket *sock1u = NULL;
@@ -867,7 +866,6 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
gtp->sock0 = sock0;
gtp->sock1u = sock1u;
- gtp->net = src_net;
return 0;
}
--
2.10.2
^ permalink raw reply related
* [PATCH 13/17] gtp: replace netdev_dbg and KERN_DEBUG printk with pr_debug
From: Andreas Schultz @ 2017-01-23 11:57 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
pr_debug is more versatile for normal debugging.
Also replace netdev_dbg in in places where the network device
will be remove soon.
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 290c400..276cc66 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -235,7 +235,7 @@ static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid));
if (IS_ERR(pctx)) {
- netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
+ pr_debug("No PDP ctx to decap skb=%p\n", skb);
return 1;
}
@@ -277,7 +277,7 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
if (IS_ERR(pctx)) {
- netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb);
+ pr_debug("No PDP ctx to decap skb=%p\n", skb);
return 1;
}
@@ -296,15 +296,15 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
if (!gtp)
return 1;
- netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
+ pr_debug("encap_recv sk=%p\n", sk);
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
- netdev_dbg(gtp->dev, "received GTP0 packet\n");
+ pr_debug("received GTP0 packet\n");
ret = gtp0_udp_encap_recv(gtp, skb);
break;
case UDP_ENCAP_GTP1U:
- netdev_dbg(gtp->dev, "received GTP1U packet\n");
+ pr_debug("received GTP1U packet\n");
ret = gtp1u_udp_encap_recv(gtp, skb);
break;
default:
@@ -313,12 +313,12 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb)
switch (ret) {
case 1:
- netdev_dbg(gtp->dev, "pass up to the process\n");
+ pr_debug("pass up to the process\n");
break;
case 0:
break;
case -1:
- netdev_dbg(gtp->dev, "GTP packet has been dropped\n");
+ pr_debug("GTP packet has been dropped\n");
kfree_skb(skb);
ret = 0;
break;
--
2.10.2
^ permalink raw reply related
* [PATCH 02/17] gtp: clear DF bit on GTP packet tx
From: Andreas Schultz @ 2017-01-23 11:56 UTC (permalink / raw)
To: Pablo Neira; +Cc: netdev, Harald Welte, Lionel Gauthier, openbsc
In-Reply-To: <20170123115706.4354-1-aschultz@tpip.net>
3GPP TS 29.281 and 3GPP TS 29.060 imply that GTP-U packets should be
sent with the DF bit cleared. For example 3GPP TS 29.060, Release 8,
Section 13.2.2:
> Backbone router: Any router in the backbone may fragment the GTP
> packet if needed, according to IPv4.
Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
drivers/net/gtp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 7580ccc..1df54d6 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -612,7 +612,7 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct net_device *dev)
pktinfo.fl4.saddr, pktinfo.fl4.daddr,
pktinfo.iph->tos,
ip4_dst_hoplimit(&pktinfo.rt->dst),
- htons(IP_DF),
+ 0,
pktinfo.gtph_port, pktinfo.gtph_port,
true, false);
break;
--
2.10.2
^ permalink raw reply related
* RE: [PATCHv3 net-next 4/4] sctp: implement sender-side procedures for Add Incoming/Outgoing Streams Request Parameter
From: David Laight @ 2017-01-23 11:25 UTC (permalink / raw)
To: 'Xin Long', network dev, linux-sctp@vger.kernel.org
Cc: Marcelo Ricardo Leitner, Neil Horman, Vlad Yasevich,
davem@davemloft.net
In-Reply-To: <daa150a23548dda0a2fd513c622773f0ff9b2df3.1484845510.git.lucien.xin@gmail.com>
From: Xin Long
> Sent: 19 January 2017 17:19
> This patch is to implement Sender-Side Procedures for the Add
> Outgoing and Incoming Streams Request Parameter described in
> rfc6525 section 5.1.5-5.1.6.
>
> It is also to add sockopt SCTP_ADD_STREAMS in rfc6525 section
> 6.3.4 for users.
...
> + out = params->sas_outstrms;
> + in = params->sas_instrms;
> +
> + if (!out && !in)
> + goto out;
> +
> + if (out) {
> + __u16 nums = stream->outcnt + out;
Make nums 'unsigned int', the code will be smaller and you can
use the value for the overflow check.
> + /* Check for overflow, can't use nums here */
> + if (stream->outcnt + out > SCTP_MAX_STREAM)
> + goto out;
> +
> + /* Use ksize to check if stream array really needs to realloc */
> + if (ksize(stream->out) / sizeof(*stream->out) < nums) {
> + struct sctp_stream_out *streamout;
> +
> + streamout = kcalloc(nums, sizeof(*streamout),
> + GFP_KERNEL);
> + if (!streamout) {
> + retval = -ENOMEM;
> + goto out;
> + }
> +
> + memcpy(streamout, stream->out,
> + sizeof(*streamout) * stream->outcnt);
> +
> + kfree(stream->out);
> + stream->out = streamout;
> + }
Does kcalloc() zero the entire area, or just the length you ask for?
If the latter you need to zero the rest here.
...
David
^ permalink raw reply
* [net-next PATCH v7] net: dummy: Introduce dummy virtual functions
From: Phil Sutter @ 2017-01-23 11:17 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Sabrina Dubroca
The idea for this was born when testing VF support in iproute2 which was
impeded by hardware requirements. In fact, not every VF-capable hardware
driver implements all netdev ops, so testing the interface is still hard
to do even with a well-sorted hardware shelf.
To overcome this and allow for testing the user-kernel interface, this
patch allows to turn dummy into a PF with a configurable amount of VFs.
Since my patch series 'bus-agnostic-num-vf' has been accepted,
implementing the required interfaces is pretty straightforward: Iff
'num_vfs' module parameter was given a value >0, a dummy bus type is
being registered which implements the 'num_vf()' callback. Additionally,
a dummy parent device common to all dummy devices is registered which
sits on the above dummy bus.
Joint work with Sabrina Dubroca.
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
Changes since v6:
- Dropped ndo_get_vf_count callback since it wasn't accepted.
- Implemented dummy bus type and parent to allow for integration with
rtnetlink.
- Dropped 'num_vfs' field from struct dummy priv since having interfaces
with differing numbers of VFs is no longer possible anyway (due to
common parent device).
- Redefine pr_fmt to make use of pr_err() macro.
- Adjusted commit message to reflect code changes.
Changes since v5:
- Got rid of fake PCI parent hack altogether, implement ndo_get_vf_count
instead.
Changes since v4:
- Initialize pci_pdev.sriov at runtime - older gcc versions don't allow
initializing fields of anonymous unions at declaration time.
- Rebased onto current net-next/master.
Changes since v3:
- Changed type of vf_mac field from unsigned char to u8.
- Column-aligned structs' field names.
Changes since v2:
- Fixed oops on reboot (need to initialize parent device mutex).
- Got rid of potential mem leak noticed by Eric Dumazet.
- Dropped stray newline insertion.
Changes since v1:
- Fixed issues reported by kbuild test robot:
- pci_dev->sriov is only present if CONFIG_PCI_ATS is active.
- pci_bus_type does not exist if CONFIG_PCI is not defined.
---
drivers/net/dummy.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 215 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 1f2de4e8207c5..2c80611b94aef 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -41,7 +41,48 @@
#define DRV_NAME "dummy"
#define DRV_VERSION "1.0"
+#undef pr_fmt
+#define pr_fmt(fmt) DRV_NAME ": " fmt
+
static int numdummies = 1;
+static int num_vfs;
+
+struct vf_data_storage {
+ u8 vf_mac[ETH_ALEN];
+ u16 pf_vlan; /* When set, guest VLAN config not allowed. */
+ u16 pf_qos;
+ __be16 vlan_proto;
+ u16 min_tx_rate;
+ u16 max_tx_rate;
+ u8 spoofchk_enabled;
+ bool rss_query_enabled;
+ u8 trusted;
+ int link_state;
+};
+
+struct dummy_priv {
+ struct vf_data_storage *vfinfo;
+};
+
+static int dummy_num_vf(struct device *dev)
+{
+ return num_vfs;
+}
+
+static struct bus_type dummy_bus = {
+ .name = "dummy",
+ .num_vf = dummy_num_vf,
+};
+
+static void release_dummy_parent(struct device *dev)
+{
+}
+
+static struct device dummy_parent = {
+ .init_name = "dummy",
+ .bus = &dummy_bus,
+ .release = release_dummy_parent,
+};
/* fake multicast ability */
static void set_multicast_list(struct net_device *dev)
@@ -90,10 +131,25 @@ static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev)
static int dummy_dev_init(struct net_device *dev)
{
+ struct dummy_priv *priv = netdev_priv(dev);
+
dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats);
if (!dev->dstats)
return -ENOMEM;
+ priv->vfinfo = NULL;
+
+ if (!num_vfs)
+ return 0;
+
+ dev->dev.parent = &dummy_parent;
+ priv->vfinfo = kcalloc(num_vfs, sizeof(struct vf_data_storage),
+ GFP_KERNEL);
+ if (!priv->vfinfo) {
+ free_percpu(dev->dstats);
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -111,6 +167,117 @@ static int dummy_change_carrier(struct net_device *dev, bool new_carrier)
return 0;
}
+static int dummy_set_vf_mac(struct net_device *dev, int vf, u8 *mac)
+{
+ struct dummy_priv *priv = netdev_priv(dev);
+
+ if (!is_valid_ether_addr(mac) || (vf >= num_vfs))
+ return -EINVAL;
+
+ memcpy(priv->vfinfo[vf].vf_mac, mac, ETH_ALEN);
+
+ return 0;
+}
+
+static int dummy_set_vf_vlan(struct net_device *dev, int vf,
+ u16 vlan, u8 qos, __be16 vlan_proto)
+{
+ struct dummy_priv *priv = netdev_priv(dev);
+
+ if ((vf >= num_vfs) || (vlan > 4095) || (qos > 7))
+ return -EINVAL;
+
+ priv->vfinfo[vf].pf_vlan = vlan;
+ priv->vfinfo[vf].pf_qos = qos;
+ priv->vfinfo[vf].vlan_proto = vlan_proto;
+
+ return 0;
+}
+
+static int dummy_set_vf_rate(struct net_device *dev, int vf, int min, int max)
+{
+ struct dummy_priv *priv = netdev_priv(dev);
+
+ if (vf >= num_vfs)
+ return -EINVAL;
+
+ priv->vfinfo[vf].min_tx_rate = min;
+ priv->vfinfo[vf].max_tx_rate = max;
+
+ return 0;
+}
+
+static int dummy_set_vf_spoofchk(struct net_device *dev, int vf, bool val)
+{
+ struct dummy_priv *priv = netdev_priv(dev);
+
+ if (vf >= num_vfs)
+ return -EINVAL;
+
+ priv->vfinfo[vf].spoofchk_enabled = val;
+
+ return 0;
+}
+
+static int dummy_set_vf_rss_query_en(struct net_device *dev, int vf, bool val)
+{
+ struct dummy_priv *priv = netdev_priv(dev);
+
+ if (vf >= num_vfs)
+ return -EINVAL;
+
+ priv->vfinfo[vf].rss_query_enabled = val;
+
+ return 0;
+}
+
+static int dummy_set_vf_trust(struct net_device *dev, int vf, bool val)
+{
+ struct dummy_priv *priv = netdev_priv(dev);
+
+ if (vf >= num_vfs)
+ return -EINVAL;
+
+ priv->vfinfo[vf].trusted = val;
+
+ return 0;
+}
+
+static int dummy_get_vf_config(struct net_device *dev,
+ int vf, struct ifla_vf_info *ivi)
+{
+ struct dummy_priv *priv = netdev_priv(dev);
+
+ if (vf >= num_vfs)
+ return -EINVAL;
+
+ ivi->vf = vf;
+ memcpy(&ivi->mac, priv->vfinfo[vf].vf_mac, ETH_ALEN);
+ ivi->vlan = priv->vfinfo[vf].pf_vlan;
+ ivi->qos = priv->vfinfo[vf].pf_qos;
+ ivi->spoofchk = priv->vfinfo[vf].spoofchk_enabled;
+ ivi->linkstate = priv->vfinfo[vf].link_state;
+ ivi->min_tx_rate = priv->vfinfo[vf].min_tx_rate;
+ ivi->max_tx_rate = priv->vfinfo[vf].max_tx_rate;
+ ivi->rss_query_en = priv->vfinfo[vf].rss_query_enabled;
+ ivi->trusted = priv->vfinfo[vf].trusted;
+ ivi->vlan_proto = priv->vfinfo[vf].vlan_proto;
+
+ return 0;
+}
+
+static int dummy_set_vf_link_state(struct net_device *dev, int vf, int state)
+{
+ struct dummy_priv *priv = netdev_priv(dev);
+
+ if (vf >= num_vfs)
+ return -EINVAL;
+
+ priv->vfinfo[vf].link_state = state;
+
+ return 0;
+}
+
static const struct net_device_ops dummy_netdev_ops = {
.ndo_init = dummy_dev_init,
.ndo_uninit = dummy_dev_uninit,
@@ -120,6 +287,14 @@ static const struct net_device_ops dummy_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
.ndo_get_stats64 = dummy_get_stats64,
.ndo_change_carrier = dummy_change_carrier,
+ .ndo_set_vf_mac = dummy_set_vf_mac,
+ .ndo_set_vf_vlan = dummy_set_vf_vlan,
+ .ndo_set_vf_rate = dummy_set_vf_rate,
+ .ndo_set_vf_spoofchk = dummy_set_vf_spoofchk,
+ .ndo_set_vf_trust = dummy_set_vf_trust,
+ .ndo_get_vf_config = dummy_get_vf_config,
+ .ndo_set_vf_link_state = dummy_set_vf_link_state,
+ .ndo_set_vf_rss_query_en = dummy_set_vf_rss_query_en,
};
static void dummy_get_drvinfo(struct net_device *dev,
@@ -133,6 +308,14 @@ static const struct ethtool_ops dummy_ethtool_ops = {
.get_drvinfo = dummy_get_drvinfo,
};
+static void dummy_free_netdev(struct net_device *dev)
+{
+ struct dummy_priv *priv = netdev_priv(dev);
+
+ kfree(priv->vfinfo);
+ free_netdev(dev);
+}
+
static void dummy_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -140,7 +323,7 @@ static void dummy_setup(struct net_device *dev)
/* Initialize the device structure. */
dev->netdev_ops = &dummy_netdev_ops;
dev->ethtool_ops = &dummy_ethtool_ops;
- dev->destructor = free_netdev;
+ dev->destructor = dummy_free_netdev;
/* Fill in device structure with ethernet-generic values. */
dev->flags |= IFF_NOARP;
@@ -171,6 +354,7 @@ static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
static struct rtnl_link_ops dummy_link_ops __read_mostly = {
.kind = DRV_NAME,
+ .priv_size = sizeof(struct dummy_priv),
.setup = dummy_setup,
.validate = dummy_validate,
};
@@ -179,12 +363,16 @@ static struct rtnl_link_ops dummy_link_ops __read_mostly = {
module_param(numdummies, int, 0);
MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
+module_param(num_vfs, int, 0);
+MODULE_PARM_DESC(num_vfs, "Number of dummy VFs per dummy device");
+
static int __init dummy_init_one(void)
{
struct net_device *dev_dummy;
int err;
- dev_dummy = alloc_netdev(0, "dummy%d", NET_NAME_UNKNOWN, dummy_setup);
+ dev_dummy = alloc_netdev(sizeof(struct dummy_priv),
+ "dummy%d", NET_NAME_UNKNOWN, dummy_setup);
if (!dev_dummy)
return -ENOMEM;
@@ -203,6 +391,21 @@ static int __init dummy_init_module(void)
{
int i, err = 0;
+ if (num_vfs) {
+ err = bus_register(&dummy_bus);
+ if (err < 0) {
+ pr_err("registering dummy bus failed\n");
+ return err;
+ }
+
+ err = device_register(&dummy_parent);
+ if (err < 0) {
+ pr_err("registering dummy parent device failed\n");
+ bus_unregister(&dummy_bus);
+ return err;
+ }
+ }
+
rtnl_lock();
err = __rtnl_link_register(&dummy_link_ops);
if (err < 0)
@@ -218,12 +421,22 @@ static int __init dummy_init_module(void)
out:
rtnl_unlock();
+ if (err && num_vfs) {
+ device_unregister(&dummy_parent);
+ bus_unregister(&dummy_bus);
+ }
+
return err;
}
static void __exit dummy_cleanup_module(void)
{
rtnl_link_unregister(&dummy_link_ops);
+
+ if (num_vfs) {
+ device_unregister(&dummy_parent);
+ bus_unregister(&dummy_bus);
+ }
}
module_init(dummy_init_module);
--
2.11.0
^ permalink raw reply related
* Re: net: use-after-free in tw_timer_handler
From: Dmitry Vyukov @ 2017-01-23 10:23 UTC (permalink / raw)
To: David Miller, Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
Patrick McHardy, netdev, LKML, Eric Dumazet
Cc: syzkaller
In-Reply-To: <CACT4Y+a2t=Ev1-Mp6+aHzRkNPhWaY-dSYRdMeL2Hp7b37bnbUg@mail.gmail.com>
On Mon, Jan 23, 2017 at 11:19 AM, Dmitry Vyukov <dvyukov@google.com> wrote:
> Hello,
>
> While running syzkaller fuzzer I started seeing use-after-frees in
> tw_timer_handler. It happens with very low frequency, so far I've seen
> 22 of them. But all reports look consistent, so I would assume that it
> is real, just requires a very tricky race to happen. I've stared
> seeing it around Jan 17, however I did not update kernels for some
> time before that so potentially the issues was introduced somewhat
> earlier. Or maybe fuzzer just figured how to trigger it, and the bug
> is actually old. I am seeing it on all of torvalds/linux-next/mmotm,
> some commits if it matters: 7a308bb3016f57e5be11a677d15b821536419d36,
> 5cf7a0f3442b2312326c39f571d637669a478235,
> c497f8d17246720afe680ea1a8fa6e48e75af852.
> Majority of reports points to net_drop_ns as the offending free, but
> it may be red herring. Since the access happens in timer, it can
> happen long after free and the memory could have been reused. I've
> also seen few where the access in tw_timer_handler is reported as
> out-of-bounds on task_struct and on struct filename.
I've briefly skimmed through the code. Assuming that it requires a
very tricky race to be triggered, the most suspicious looks
inet_twsk_deschedule_put vs __inet_twsk_schedule:
void inet_twsk_deschedule_put(struct inet_timewait_sock *tw)
{
if (del_timer_sync(&tw->tw_timer))
inet_twsk_kill(tw);
inet_twsk_put(tw);
}
void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo, bool rearm)
{
tw->tw_kill = timeo <= 4*HZ;
if (!rearm) {
BUG_ON(mod_timer(&tw->tw_timer, jiffies + timeo));
atomic_inc(&tw->tw_dr->tw_count);
} else {
mod_timer_pending(&tw->tw_timer, jiffies + timeo);
}
}
Can't it somehow end up rearming already deleted timer? Or maybe the
first mod_timer happens after del_timer_sync?
> BUG: KASAN: use-after-free in tw_timer_handler+0xc3/0xd0
> net/ipv4/inet_timewait_sock.c:149 at addr ffff8801cb58c398
> Read of size 8 by task syz-executor0/24691
> CPU: 0 PID: 24691 Comm: syz-executor0 Not tainted 4.9.0 #3
> Hardware name: Google Google Compute Engine/Google Compute Engine,
> BIOS Google 01/01/2011
> ffff8801dc007328 ffffffff8234530f ffffffff00000000 1ffff1003b800df8
> ffffed003b800df0 0000000041b58ab3 ffffffff84b379b8 ffffffff82345021
> ffff8801d8ad8f60 ffff8801d8ad8f68 ffff8801d8ad8740 000000000000002e
> Call Trace:
> [<ffffffff819dd8fe>] __asan_report_load8_noabort+0x3e/0x40
> mm/kasan/report.c:329
> [<ffffffff8374fd93>] tw_timer_handler+0xc3/0xd0
> net/ipv4/inet_timewait_sock.c:149
> [<ffffffff815f5b21>] call_timer_fn+0x241/0x800 kernel/time/timer.c:1308
> [<ffffffff815f84b7>] expire_timers kernel/time/timer.c:1348 [inline]
> [<ffffffff815f84b7>] __run_timers+0x9e7/0xe90 kernel/time/timer.c:1641
> [<ffffffff815f8981>] run_timer_softirq+0x21/0x80 kernel/time/timer.c:1654
> [<ffffffff84372c7f>] __do_softirq+0x31f/0xbcd kernel/softirq.c:284
> [<ffffffff8143c18c>] invoke_softirq kernel/softirq.c:364 [inline]
> [<ffffffff8143c18c>] irq_exit+0x1cc/0x200 kernel/softirq.c:405
> [<ffffffff843723ee>] exiting_irq arch/x86/include/asm/apic.h:659 [inline]
> [<ffffffff843723ee>] smp_trace_apic_timer_interrupt+0x13e/0x6a8
> arch/x86/kernel/apic/apic.c:981
> [<ffffffff843713dc>] trace_apic_timer_interrupt+0x8c/0xa0
> arch/x86/entry/entry_64.S:709
> <EOI> [ 2916.083183] [<ffffffff8436ebe6>] ? arch_local_irq_enable
> arch/x86/include/asm/paravirt.h:777 [inline]
> <EOI> [ 2916.083183] [<ffffffff8436ebe6>] ? __raw_spin_unlock_irq
> include/linux/spinlock_api_smp.h:170 [inline]
> <EOI> [ 2916.083183] [<ffffffff8436ebe6>] ?
> _raw_spin_unlock_irq+0x56/0x70 kernel/locking/spinlock.c:199
> [<ffffffff814cbff2>] finish_lock_switch kernel/sched/sched.h:1157 [inline]
> [<ffffffff814cbff2>] finish_task_switch+0x1c2/0x710 kernel/sched/core.c:2769
> [<ffffffff84356654>] context_switch kernel/sched/core.c:2902 [inline]
> [<ffffffff84356654>] __schedule+0x724/0x1e90 kernel/sched/core.c:3402
> [<ffffffff84357ec8>] schedule+0x108/0x440 kernel/sched/core.c:3457
> [<ffffffff8100790f>] exit_to_usermode_loop+0x20f/0x2a0
> arch/x86/entry/common.c:149
> [<ffffffff81009413>] prepare_exit_to_usermode
> arch/x86/entry/common.c:190 [inline]
> [<ffffffff81009413>] syscall_return_slowpath+0x4d3/0x570
> arch/x86/entry/common.c:259
> [<ffffffff8436fa22>] entry_SYSCALL_64_fastpath+0xc0/0xc2
> Object at ffff8801cb58c1c0, in cache net_namespace size: 6656
> Allocated:
> PID = 3183
> [ 2916.342108] [<ffffffff819dcd92>] kasan_slab_alloc+0x12/0x20
> mm/kasan/kasan.c:537
> [ 2916.349322] [<ffffffff819d83e2>] kmem_cache_alloc+0x102/0x680 mm/slab.c:3565
> [ 2916.356776] [<ffffffff83549a86>] kmem_cache_zalloc
> include/linux/slab.h:626 [inline]
> [ 2916.356776] [<ffffffff83549a86>] net_alloc
> net/core/net_namespace.c:339 [inline]
> [ 2916.356776] [<ffffffff83549a86>] copy_net_ns+0x196/0x480
> net/core/net_namespace.c:379
> [ 2916.363783] [<ffffffff814b1349>] create_new_namespaces+0x409/0x860
> kernel/nsproxy.c:106
> [ 2916.371605] [<ffffffff814b1aed>] copy_namespaces+0x34d/0x420
> kernel/nsproxy.c:164
> [ 2916.379042] [<ffffffff814197f1>]
> copy_process.part.40+0x2281/0x4d30 kernel/fork.c:1659
> [ 2916.387013] [<ffffffff8141c7e0>] copy_process kernel/fork.c:1483 [inline]
> [ 2916.387013] [<ffffffff8141c7e0>] _do_fork+0x200/0xff0 kernel/fork.c:1937
> [ 2916.393730] [<ffffffff8141d6a7>] SYSC_clone kernel/fork.c:2047 [inline]
> [ 2916.393730] [<ffffffff8141d6a7>] SyS_clone+0x37/0x50 kernel/fork.c:2041
> [ 2916.400376] [<ffffffff81009798>] do_syscall_64+0x2e8/0x930
> arch/x86/entry/common.c:280
> [ 2916.407563] [<ffffffff8436fa49>] return_from_SYSCALL_64+0x0/0x7a
> Freed:
> PID = 15107
> [ 2916.441170] [<ffffffff819da1b1>] __cache_free mm/slab.c:3507 [inline]
> [ 2916.441170] [<ffffffff819da1b1>] kmem_cache_free+0x71/0x240 mm/slab.c:3767
> [ 2916.448408] [<ffffffff83548e3e>] net_free
> net/core/net_namespace.c:355 [inline]
> [ 2916.448408] [<ffffffff83548e3e>] net_drop_ns+0x11e/0x140
> net/core/net_namespace.c:362
> [ 2916.455370] [<ffffffff83549652>] cleanup_net+0x7f2/0xa90
> net/core/net_namespace.c:472
> [ 2916.462331] [<ffffffff81492960>] process_one_work+0xbd0/0x1c10
> kernel/workqueue.c:2096
> [ 2916.469877] [<ffffffff81493bc3>] worker_thread+0x223/0x1990
> kernel/workqueue.c:2230
> [ 2916.477155] [<ffffffff814abb33>] kthread+0x323/0x3e0 kernel/kthread.c:209
> [ 2916.483831] [<ffffffff8436fbea>] ret_from_fork+0x2a/0x40
> arch/x86/entry/entry_64.S:433
> Memory state around the buggy address:
> ffff8801cb58c280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff8801cb58c300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>>ffff8801cb58c380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ^
> ffff8801cb58c400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff8801cb58c480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ==================================================================
>
> BUG: KASAN: use-after-free in tw_timer_handler+0xc3/0xd0
> net/ipv4/inet_timewait_sock.c:149 at addr ffff8801cd4ec298
> Read of size 8 by task swapper/1/0
> CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.9.0 #3
> Hardware name: Google Google Compute Engine/Google Compute Engine,
> BIOS Google 01/01/2011
> ffff8801dc107468 ffffffff8234530f ffffffff00000001 1ffff1003b820e20
> ffffed003b820e18 0000000041b58ab3 ffffffff84b379b8 ffffffff82345021
> 1ffff1003b820e17 ffff8801daf0e2c0 0000000041b58ab3 ffffffff84af4170
> Call Trace:
> [<ffffffff819dd8fe>] __asan_report_load8_noabort+0x3e/0x40
> mm/kasan/report.c:329
> [<ffffffff8374fd93>] tw_timer_handler+0xc3/0xd0
> net/ipv4/inet_timewait_sock.c:149
> [<ffffffff815f5b21>] call_timer_fn+0x241/0x800 kernel/time/timer.c:1308
> [<ffffffff815f84b7>] expire_timers kernel/time/timer.c:1348 [inline]
> [<ffffffff815f84b7>] __run_timers+0x9e7/0xe90 kernel/time/timer.c:1641
> [<ffffffff815f8981>] run_timer_softirq+0x21/0x80 kernel/time/timer.c:1654
> [<ffffffff84372c7f>] __do_softirq+0x31f/0xbcd kernel/softirq.c:284
> [<ffffffff8143c18c>] invoke_softirq kernel/softirq.c:364 [inline]
> [<ffffffff8143c18c>] irq_exit+0x1cc/0x200 kernel/softirq.c:405
> [<ffffffff8437228b>] exiting_irq arch/x86/include/asm/apic.h:659 [inline]
> [<ffffffff8437228b>] smp_apic_timer_interrupt+0x7b/0xa0
> arch/x86/kernel/apic/apic.c:960
> [<ffffffff8437133c>] apic_timer_interrupt+0x8c/0xa0
> arch/x86/entry/entry_64.S:709
> <EOI> [ 1412.821824] [<ffffffff8436dbb6>] ?
> native_safe_halt+0x6/0x10 arch/x86/include/asm/irqflags.h:53
> [<ffffffff8436d08f>] arch_safe_halt
> arch/x86/include/asm/paravirt.h:103 [inline]
> [<ffffffff8436d08f>] default_idle+0xbf/0x440 arch/x86/kernel/process.c:308
> [<ffffffff8128a5ca>] arch_cpu_idle+0xa/0x10 arch/x86/kernel/process.c:299
> [<ffffffff8436e0d6>] default_idle_call+0x36/0x90 kernel/sched/idle.c:96
> [<ffffffff815549a7>] cpuidle_idle_call kernel/sched/idle.c:154 [inline]
> [<ffffffff815549a7>] cpu_idle_loop kernel/sched/idle.c:247 [inline]
> [<ffffffff815549a7>] cpu_startup_entry+0x327/0x4b0 kernel/sched/idle.c:302
> [<ffffffff812e47ac>] start_secondary+0x36c/0x460 arch/x86/kernel/smpboot.c:263
> Object at ffff8801cd4ec0c0, in cache net_namespace size: 6656
> Allocated:
> PID = 3131
> [ 1412.940699] [<ffffffff819d83e2>] kmem_cache_alloc+0x102/0x680 mm/slab.c:3565
> [ 1412.948084] [<ffffffff83549a86>] kmem_cache_zalloc
> include/linux/slab.h:626 [inline]
> [ 1412.948084] [<ffffffff83549a86>] net_alloc
> net/core/net_namespace.c:339 [inline]
> [ 1412.948084] [<ffffffff83549a86>] copy_net_ns+0x196/0x480
> net/core/net_namespace.c:379
> [ 1412.955019] [<ffffffff814b1349>] create_new_namespaces+0x409/0x860
> kernel/nsproxy.c:106
> [ 1412.962817] [<ffffffff814b1aed>] copy_namespaces+0x34d/0x420
> kernel/nsproxy.c:164
> [ 1412.970094] [<ffffffff814197f1>]
> copy_process.part.40+0x2281/0x4d30 kernel/fork.c:1659
> [ 1412.978004] [<ffffffff8141c7e0>] copy_process kernel/fork.c:1483 [inline]
> [ 1412.978004] [<ffffffff8141c7e0>] _do_fork+0x200/0xff0 kernel/fork.c:1937
> [ 1412.984677] [<ffffffff8141d6a7>] SYSC_clone kernel/fork.c:2047 [inline]
> [ 1412.984677] [<ffffffff8141d6a7>] SyS_clone+0x37/0x50 kernel/fork.c:2041
> [ 1412.991276] [<ffffffff81009798>] do_syscall_64+0x2e8/0x930
> arch/x86/entry/common.c:280
> [ 1412.998394] [<ffffffff8436fa49>] return_from_SYSCALL_64+0x0/0x7a
> Freed:
> PID = 9846
> [ 1413.031603] [<ffffffff819da1b1>] __cache_free mm/slab.c:3507 [inline]
> [ 1413.031603] [<ffffffff819da1b1>] kmem_cache_free+0x71/0x240 mm/slab.c:3767
> [ 1413.038796] [<ffffffff83548e3e>] net_free
> net/core/net_namespace.c:355 [inline]
> [ 1413.038796] [<ffffffff83548e3e>] net_drop_ns+0x11e/0x140
> net/core/net_namespace.c:362
> [ 1413.045734] [<ffffffff83549652>] cleanup_net+0x7f2/0xa90
> net/core/net_namespace.c:472
> [ 1413.052667] [<ffffffff81492960>] process_one_work+0xbd0/0x1c10
> kernel/workqueue.c:2096
> [ 1413.060120] [<ffffffff81493bc3>] worker_thread+0x223/0x1990
> kernel/workqueue.c:2230
> [ 1413.067357] [<ffffffff814abb33>] kthread+0x323/0x3e0 kernel/kthread.c:209
> [ 1413.073944] [<ffffffff8436fbea>] ret_from_fork+0x2a/0x40
> arch/x86/entry/entry_64.S:433
> Memory state around the buggy address:
> ffff8801cd4ec180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff8801cd4ec200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>>ffff8801cd4ec280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ^
> ffff8801cd4ec300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff8801cd4ec380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ==================================================================
>
> BUG: KASAN: use-after-free in tw_timer_handler+0xc3/0xd0
> net/ipv4/inet_timewait_sock.c:149 at addr ffff8801b7b50358
> Read of size 8 by task swapper/0/0
> CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.9.0 #3
> Hardware name: Google Google Compute Engine/Google Compute Engine,
> BIOS Google 01/01/2011
> ffff8801dc007468 ffffffff8234530f ffffffff00000000 1ffff1003b800e20
> ffffed003b800e18 0000000041b58ab3 ffffffff84b379b8 ffffffff82345021
> ffffffff84e2bba0 ffffffff84e2bba8 ffffffff84e2b380 000000000000002e
> Call Trace:
> [<ffffffff819dd8fe>] __asan_report_load8_noabort+0x3e/0x40
> mm/kasan/report.c:329
> [<ffffffff8374fd93>] tw_timer_handler+0xc3/0xd0
> net/ipv4/inet_timewait_sock.c:149
> [<ffffffff815f5b21>] call_timer_fn+0x241/0x800 kernel/time/timer.c:1308
> [<ffffffff815f84b7>] expire_timers kernel/time/timer.c:1348 [inline]
> [<ffffffff815f84b7>] __run_timers+0x9e7/0xe90 kernel/time/timer.c:1641
> [<ffffffff815f8981>] run_timer_softirq+0x21/0x80 kernel/time/timer.c:1654
> [<ffffffff84372c7f>] __do_softirq+0x31f/0xbcd kernel/softirq.c:284
> [<ffffffff8143c18c>] invoke_softirq kernel/softirq.c:364 [inline]
> [<ffffffff8143c18c>] irq_exit+0x1cc/0x200 kernel/softirq.c:405
> [<ffffffff8437228b>] exiting_irq arch/x86/include/asm/apic.h:659 [inline]
> [<ffffffff8437228b>] smp_apic_timer_interrupt+0x7b/0xa0
> arch/x86/kernel/apic/apic.c:960
> [<ffffffff8437133c>] apic_timer_interrupt+0x8c/0xa0
> arch/x86/entry/entry_64.S:709
> <EOI> [ 1965.936792] [<ffffffff8436dbb6>] ?
> native_safe_halt+0x6/0x10 arch/x86/include/asm/irqflags.h:53
> [<ffffffff8436d08f>] arch_safe_halt
> arch/x86/include/asm/paravirt.h:103 [inline]
> [<ffffffff8436d08f>] default_idle+0xbf/0x440 arch/x86/kernel/process.c:308
> [<ffffffff8128a5ca>] arch_cpu_idle+0xa/0x10 arch/x86/kernel/process.c:299
> [<ffffffff8436e0d6>] default_idle_call+0x36/0x90 kernel/sched/idle.c:96
> [<ffffffff815549a7>] cpuidle_idle_call kernel/sched/idle.c:154 [inline]
> [<ffffffff815549a7>] cpu_idle_loop kernel/sched/idle.c:247 [inline]
> [<ffffffff815549a7>] cpu_startup_entry+0x327/0x4b0 kernel/sched/idle.c:302
> [<ffffffff8434f05d>] rest_init+0x18d/0x1a0 init/main.c:408
> [<ffffffff85481b16>] start_kernel+0x7a0/0x7d2 init/main.c:660
> [<ffffffff854802e6>] x86_64_start_reservations+0x2a/0x2c
> arch/x86/kernel/head64.c:195
> [<ffffffff85480424>] x86_64_start_kernel+0x13c/0x149
> arch/x86/kernel/head64.c:176
> Object at ffff8801b7b50180, in cache net_namespace size: 6656
> Allocated:
> PID = 3169
> [ 1966.129951] [<ffffffff819d83e2>] kmem_cache_alloc+0x102/0x680 mm/slab.c:3565
> [ 1966.137357] [<ffffffff83549a86>] kmem_cache_zalloc
> include/linux/slab.h:626 [inline]
> [ 1966.137357] [<ffffffff83549a86>] net_alloc
> net/core/net_namespace.c:339 [inline]
> [ 1966.137357] [<ffffffff83549a86>] copy_net_ns+0x196/0x480
> net/core/net_namespace.c:379
> [ 1966.144350] [<ffffffff814b1349>] create_new_namespaces+0x409/0x860
> kernel/nsproxy.c:106
> [ 1966.152254] [<ffffffff814b1aed>] copy_namespaces+0x34d/0x420
> kernel/nsproxy.c:164
> [ 1966.159567] [<ffffffff814197f1>]
> copy_process.part.40+0x2281/0x4d30 kernel/fork.c:1659
> [ 1966.167484] [<ffffffff8141c7e0>] copy_process kernel/fork.c:1483 [inline]
> [ 1966.167484] [<ffffffff8141c7e0>] _do_fork+0x200/0xff0 kernel/fork.c:1937
> [ 1966.174207] [<ffffffff8141d6a7>] SYSC_clone kernel/fork.c:2047 [inline]
> [ 1966.174207] [<ffffffff8141d6a7>] SyS_clone+0x37/0x50 kernel/fork.c:2041
> [ 1966.180832] [<ffffffff81009798>] do_syscall_64+0x2e8/0x930
> arch/x86/entry/common.c:280
> [ 1966.187973] [<ffffffff8436fa49>] return_from_SYSCALL_64+0x0/0x7a
> Freed:
> PID = 8938
> [ 1966.221347] [<ffffffff819da1b1>] __cache_free mm/slab.c:3507 [inline]
> [ 1966.221347] [<ffffffff819da1b1>] kmem_cache_free+0x71/0x240 mm/slab.c:3767
> [ 1966.228568] [<ffffffff83548e3e>] net_free
> net/core/net_namespace.c:355 [inline]
> [ 1966.228568] [<ffffffff83548e3e>] net_drop_ns+0x11e/0x140
> net/core/net_namespace.c:362
> [ 1966.235564] [<ffffffff83549652>] cleanup_net+0x7f2/0xa90
> net/core/net_namespace.c:472
> [ 1966.242517] [<ffffffff81492960>] process_one_work+0xbd0/0x1c10
> kernel/workqueue.c:2096
> [ 1966.249995] [<ffffffff81493bc3>] worker_thread+0x223/0x1990
> kernel/workqueue.c:2230
> [ 1966.257258] [<ffffffff814abb33>] kthread+0x323/0x3e0 kernel/kthread.c:209
> [ 1966.263879] [<ffffffff8436fbea>] ret_from_fork+0x2a/0x40
> arch/x86/entry/entry_64.S:433
> Memory state around the buggy address:
> ffff8801b7b50200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff8801b7b50280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>>ffff8801b7b50300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ^
> ffff8801b7b50380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff8801b7b50400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ==================================================================
>
> BUG: KASAN: slab-out-of-bounds in tw_timer_handler+0xc3/0xd0
> net/ipv4/inet_timewait_sock.c:149 at addr ffff8801c98f43a0
> Read of size 8 by task syz-executor8/3423
> CPU: 0 PID: 3423 Comm: syz-executor8 Not tainted 4.10.0-rc5 #19
> Hardware name: Google Google Compute Engine/Google Compute Engine,
> BIOS Google 01/01/2011
> Call Trace:
> <IRQ>
> __dump_stack lib/dump_stack.c:15 [inline]
> dump_stack+0x2ee/0x3ef lib/dump_stack.c:51
> kasan_object_err+0x1c/0x70 mm/kasan/report.c:161
> print_address_description mm/kasan/report.c:199 [inline]
> kasan_report_error+0x1d1/0x4d0 mm/kasan/report.c:288
> kasan_report mm/kasan/report.c:308 [inline]
> __asan_report_load8_noabort+0x3e/0x40 mm/kasan/report.c:329
> tw_timer_handler+0xc3/0xd0 net/ipv4/inet_timewait_sock.c:149
> call_timer_fn+0x241/0x820 kernel/time/timer.c:1308
> expire_timers kernel/time/timer.c:1348 [inline]
> __run_timers+0x9e7/0xe90 kernel/time/timer.c:1642
> run_timer_softirq+0x21/0x80 kernel/time/timer.c:1655
> __do_softirq+0x31f/0xbe7 kernel/softirq.c:284
> invoke_softirq kernel/softirq.c:364 [inline]
> irq_exit+0x1cc/0x200 kernel/softirq.c:405
> exiting_irq arch/x86/include/asm/apic.h:658 [inline]
> smp_apic_timer_interrupt+0x76/0xa0 arch/x86/kernel/apic/apic.c:961
> apic_timer_interrupt+0x93/0xa0 arch/x86/entry/entry_64.S:707
> RIP: 0010:arch_local_save_flags arch/x86/include/asm/paravirt.h:762 [inline]
> RIP: 0010:arch_local_irq_save arch/x86/include/asm/paravirt.h:784 [inline]
> RIP: 0010:lock_is_held_type+0x124/0x310 kernel/locking/lockdep.c:3787
> RSP: 0018:ffff8801c946f558 EFLAGS: 00000286 ORIG_RAX: ffffffffffffff10
> RAX: 0000000000000286 RBX: 1ffff1003928deac RCX: 1ffff1003928deb0
> RDX: 1ffffffff0a18984 RSI: 00000000ffffffff RDI: ffffffff850c4c20
> RBP: ffff8801c946f6a8 R08: 0000000000000002 R09: 0000000000000001
> R10: 000000000000000a R11: 0000000000000000 R12: ffff8801c946f680
> R13: ffff8801c9492640 R14: ffffffff85130ec0 R15: 0000000000000bff
> </IRQ>
> lock_is_held include/linux/lockdep.h:348 [inline]
> ___might_sleep+0x5b3/0x650 kernel/sched/core.c:7748
> __might_sleep+0x95/0x1a0 kernel/sched/core.c:7739
> cache_alloc_debugcheck_before mm/slab.c:3071 [inline]
> slab_alloc mm/slab.c:3386 [inline]
> kmem_cache_alloc+0x273/0x680 mm/slab.c:3558
> shmem_alloc_inode+0x1b/0x40 mm/shmem.c:3647
> alloc_inode+0x61/0x180 fs/inode.c:207
> new_inode_pseudo+0x69/0x170 fs/inode.c:889
> new_inode+0x1c/0x40 fs/inode.c:918
> shmem_get_inode+0xd1/0x8a0 mm/shmem.c:2120
> shmem_mknod+0x58/0x1b0 mm/shmem.c:2824
> shmem_mkdir+0x29/0x50 mm/shmem.c:2875
> vfs_mkdir+0x3be/0x600 fs/namei.c:3738
> SYSC_mkdirat fs/namei.c:3761 [inline]
> SyS_mkdirat fs/namei.c:3745 [inline]
> SYSC_mkdir fs/namei.c:3772 [inline]
> SyS_mkdir+0x16e/0x290 fs/namei.c:3770
> entry_SYSCALL_64_fastpath+0x1f/0xc2
> RIP: 0033:0x44ec87
> RSP: 002b:0000000001a2fe40 EFLAGS: 00000212 ORIG_RAX: 0000000000000053
> RAX: ffffffffffffffda RBX: 0000000000000010 RCX: 000000000044ec87
> RDX: 0000000001a2fe6e RSI: 00000000000001ff RDI: 0000000001a2fe68
> RBP: 00000000000019ec R08: 0000000000000000 R09: 0000000000000006
> R10: 0000000000000064 R11: 0000000000000212 R12: 0000000001ef390c
> R13: 0000000000000000 R14: 00000000000a43b5 R15: 00000000000019ec
> Object at ffff8801c98f44c0, in cache task_struct size: 5696
> Allocated:
> PID = 3452
> [<ffffffff8129f656>] save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:57
> [<ffffffff819f6f53>] save_stack+0x43/0xd0 mm/kasan/kasan.c:502
> [<ffffffff819f71da>] set_track mm/kasan/kasan.c:514 [inline]
> [<ffffffff819f71da>] kasan_kmalloc+0xaa/0xd0 mm/kasan/kasan.c:605
> [<ffffffff819f77d2>] kasan_slab_alloc+0x12/0x20 mm/kasan/kasan.c:544
> [<ffffffff819f1652>] kmem_cache_alloc_node+0x122/0x690 mm/slab.c:3650
> [<ffffffff81421fe2>] alloc_task_struct_node kernel/fork.c:142 [inline]
> [<ffffffff81421fe2>] dup_task_struct kernel/fork.c:482 [inline]
> [<ffffffff81421fe2>] copy_process.part.42+0x1a32/0x5fd0 kernel/fork.c:1515
> [<ffffffff81426ac0>] copy_process kernel/fork.c:1486 [inline]
> [<ffffffff81426ac0>] _do_fork+0x200/0xff0 kernel/fork.c:1942
> [<ffffffff81427987>] SYSC_clone kernel/fork.c:2052 [inline]
> [<ffffffff81427987>] SyS_clone+0x37/0x50 kernel/fork.c:2046
> [<ffffffff81009798>] do_syscall_64+0x2e8/0x930 arch/x86/entry/common.c:280
> [<ffffffff8440fb09>] return_from_SYSCALL_64+0x0/0x7a
> Freed:
> PID = 29885
> [<ffffffff8129f656>] save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:57
> [<ffffffff819f6f53>] save_stack+0x43/0xd0 mm/kasan/kasan.c:502
> [<ffffffff819f784f>] set_track mm/kasan/kasan.c:514 [inline]
> [<ffffffff819f784f>] kasan_slab_free+0x6f/0xb0 mm/kasan/kasan.c:578
> [<ffffffff819f4bf1>] __cache_free mm/slab.c:3502 [inline]
> [<ffffffff819f4bf1>] kmem_cache_free+0x71/0x240 mm/slab.c:3762
> [<ffffffff8141f041>] free_task_struct kernel/fork.c:147 [inline]
> [<ffffffff8141f041>] free_task+0x151/0x1d0 kernel/fork.c:359
> [<ffffffff8141f30b>] __put_task_struct+0x24b/0x5f0 kernel/fork.c:396
> [<ffffffff81435baa>] put_task_struct include/linux/sched.h:2257 [inline]
> [<ffffffff81435baa>] delayed_put_task_struct+0xca/0x3f0 kernel/exit.c:173
> [<ffffffff815ef250>] __rcu_reclaim kernel/rcu/rcu.h:118 [inline]
> [<ffffffff815ef250>] rcu_do_batch.isra.70+0x9e0/0xdf0 kernel/rcu/tree.c:2780
> [<ffffffff815efad2>] invoke_rcu_callbacks kernel/rcu/tree.c:3043 [inline]
> [<ffffffff815efad2>] __rcu_process_callbacks kernel/rcu/tree.c:3010 [inline]
> [<ffffffff815efad2>] rcu_process_callbacks+0x472/0xc70 kernel/rcu/tree.c:3027
> [<ffffffff84412d7f>] __do_softirq+0x31f/0xbe7 kernel/softirq.c:284
> Memory state around the buggy address:
> ffff8801c98f4280: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> ffff8801c98f4300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>>ffff8801c98f4380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> ^
> ffff8801c98f4400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> ffff8801c98f4480: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
> ==================================================================
^ permalink raw reply
* net: use-after-free in tw_timer_handler
From: Dmitry Vyukov @ 2017-01-23 10:19 UTC (permalink / raw)
To: David Miller, Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
Patrick McHardy, netdev, LKML, Eric Dumazet
Cc: syzkaller
Hello,
While running syzkaller fuzzer I started seeing use-after-frees in
tw_timer_handler. It happens with very low frequency, so far I've seen
22 of them. But all reports look consistent, so I would assume that it
is real, just requires a very tricky race to happen. I've stared
seeing it around Jan 17, however I did not update kernels for some
time before that so potentially the issues was introduced somewhat
earlier. Or maybe fuzzer just figured how to trigger it, and the bug
is actually old. I am seeing it on all of torvalds/linux-next/mmotm,
some commits if it matters: 7a308bb3016f57e5be11a677d15b821536419d36,
5cf7a0f3442b2312326c39f571d637669a478235,
c497f8d17246720afe680ea1a8fa6e48e75af852.
Majority of reports points to net_drop_ns as the offending free, but
it may be red herring. Since the access happens in timer, it can
happen long after free and the memory could have been reused. I've
also seen few where the access in tw_timer_handler is reported as
out-of-bounds on task_struct and on struct filename.
BUG: KASAN: use-after-free in tw_timer_handler+0xc3/0xd0
net/ipv4/inet_timewait_sock.c:149 at addr ffff8801cb58c398
Read of size 8 by task syz-executor0/24691
CPU: 0 PID: 24691 Comm: syz-executor0 Not tainted 4.9.0 #3
Hardware name: Google Google Compute Engine/Google Compute Engine,
BIOS Google 01/01/2011
ffff8801dc007328 ffffffff8234530f ffffffff00000000 1ffff1003b800df8
ffffed003b800df0 0000000041b58ab3 ffffffff84b379b8 ffffffff82345021
ffff8801d8ad8f60 ffff8801d8ad8f68 ffff8801d8ad8740 000000000000002e
Call Trace:
[<ffffffff819dd8fe>] __asan_report_load8_noabort+0x3e/0x40
mm/kasan/report.c:329
[<ffffffff8374fd93>] tw_timer_handler+0xc3/0xd0
net/ipv4/inet_timewait_sock.c:149
[<ffffffff815f5b21>] call_timer_fn+0x241/0x800 kernel/time/timer.c:1308
[<ffffffff815f84b7>] expire_timers kernel/time/timer.c:1348 [inline]
[<ffffffff815f84b7>] __run_timers+0x9e7/0xe90 kernel/time/timer.c:1641
[<ffffffff815f8981>] run_timer_softirq+0x21/0x80 kernel/time/timer.c:1654
[<ffffffff84372c7f>] __do_softirq+0x31f/0xbcd kernel/softirq.c:284
[<ffffffff8143c18c>] invoke_softirq kernel/softirq.c:364 [inline]
[<ffffffff8143c18c>] irq_exit+0x1cc/0x200 kernel/softirq.c:405
[<ffffffff843723ee>] exiting_irq arch/x86/include/asm/apic.h:659 [inline]
[<ffffffff843723ee>] smp_trace_apic_timer_interrupt+0x13e/0x6a8
arch/x86/kernel/apic/apic.c:981
[<ffffffff843713dc>] trace_apic_timer_interrupt+0x8c/0xa0
arch/x86/entry/entry_64.S:709
<EOI> [ 2916.083183] [<ffffffff8436ebe6>] ? arch_local_irq_enable
arch/x86/include/asm/paravirt.h:777 [inline]
<EOI> [ 2916.083183] [<ffffffff8436ebe6>] ? __raw_spin_unlock_irq
include/linux/spinlock_api_smp.h:170 [inline]
<EOI> [ 2916.083183] [<ffffffff8436ebe6>] ?
_raw_spin_unlock_irq+0x56/0x70 kernel/locking/spinlock.c:199
[<ffffffff814cbff2>] finish_lock_switch kernel/sched/sched.h:1157 [inline]
[<ffffffff814cbff2>] finish_task_switch+0x1c2/0x710 kernel/sched/core.c:2769
[<ffffffff84356654>] context_switch kernel/sched/core.c:2902 [inline]
[<ffffffff84356654>] __schedule+0x724/0x1e90 kernel/sched/core.c:3402
[<ffffffff84357ec8>] schedule+0x108/0x440 kernel/sched/core.c:3457
[<ffffffff8100790f>] exit_to_usermode_loop+0x20f/0x2a0
arch/x86/entry/common.c:149
[<ffffffff81009413>] prepare_exit_to_usermode
arch/x86/entry/common.c:190 [inline]
[<ffffffff81009413>] syscall_return_slowpath+0x4d3/0x570
arch/x86/entry/common.c:259
[<ffffffff8436fa22>] entry_SYSCALL_64_fastpath+0xc0/0xc2
Object at ffff8801cb58c1c0, in cache net_namespace size: 6656
Allocated:
PID = 3183
[ 2916.342108] [<ffffffff819dcd92>] kasan_slab_alloc+0x12/0x20
mm/kasan/kasan.c:537
[ 2916.349322] [<ffffffff819d83e2>] kmem_cache_alloc+0x102/0x680 mm/slab.c:3565
[ 2916.356776] [<ffffffff83549a86>] kmem_cache_zalloc
include/linux/slab.h:626 [inline]
[ 2916.356776] [<ffffffff83549a86>] net_alloc
net/core/net_namespace.c:339 [inline]
[ 2916.356776] [<ffffffff83549a86>] copy_net_ns+0x196/0x480
net/core/net_namespace.c:379
[ 2916.363783] [<ffffffff814b1349>] create_new_namespaces+0x409/0x860
kernel/nsproxy.c:106
[ 2916.371605] [<ffffffff814b1aed>] copy_namespaces+0x34d/0x420
kernel/nsproxy.c:164
[ 2916.379042] [<ffffffff814197f1>]
copy_process.part.40+0x2281/0x4d30 kernel/fork.c:1659
[ 2916.387013] [<ffffffff8141c7e0>] copy_process kernel/fork.c:1483 [inline]
[ 2916.387013] [<ffffffff8141c7e0>] _do_fork+0x200/0xff0 kernel/fork.c:1937
[ 2916.393730] [<ffffffff8141d6a7>] SYSC_clone kernel/fork.c:2047 [inline]
[ 2916.393730] [<ffffffff8141d6a7>] SyS_clone+0x37/0x50 kernel/fork.c:2041
[ 2916.400376] [<ffffffff81009798>] do_syscall_64+0x2e8/0x930
arch/x86/entry/common.c:280
[ 2916.407563] [<ffffffff8436fa49>] return_from_SYSCALL_64+0x0/0x7a
Freed:
PID = 15107
[ 2916.441170] [<ffffffff819da1b1>] __cache_free mm/slab.c:3507 [inline]
[ 2916.441170] [<ffffffff819da1b1>] kmem_cache_free+0x71/0x240 mm/slab.c:3767
[ 2916.448408] [<ffffffff83548e3e>] net_free
net/core/net_namespace.c:355 [inline]
[ 2916.448408] [<ffffffff83548e3e>] net_drop_ns+0x11e/0x140
net/core/net_namespace.c:362
[ 2916.455370] [<ffffffff83549652>] cleanup_net+0x7f2/0xa90
net/core/net_namespace.c:472
[ 2916.462331] [<ffffffff81492960>] process_one_work+0xbd0/0x1c10
kernel/workqueue.c:2096
[ 2916.469877] [<ffffffff81493bc3>] worker_thread+0x223/0x1990
kernel/workqueue.c:2230
[ 2916.477155] [<ffffffff814abb33>] kthread+0x323/0x3e0 kernel/kthread.c:209
[ 2916.483831] [<ffffffff8436fbea>] ret_from_fork+0x2a/0x40
arch/x86/entry/entry_64.S:433
Memory state around the buggy address:
ffff8801cb58c280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8801cb58c300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff8801cb58c380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff8801cb58c400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8801cb58c480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
BUG: KASAN: use-after-free in tw_timer_handler+0xc3/0xd0
net/ipv4/inet_timewait_sock.c:149 at addr ffff8801cd4ec298
Read of size 8 by task swapper/1/0
CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.9.0 #3
Hardware name: Google Google Compute Engine/Google Compute Engine,
BIOS Google 01/01/2011
ffff8801dc107468 ffffffff8234530f ffffffff00000001 1ffff1003b820e20
ffffed003b820e18 0000000041b58ab3 ffffffff84b379b8 ffffffff82345021
1ffff1003b820e17 ffff8801daf0e2c0 0000000041b58ab3 ffffffff84af4170
Call Trace:
[<ffffffff819dd8fe>] __asan_report_load8_noabort+0x3e/0x40
mm/kasan/report.c:329
[<ffffffff8374fd93>] tw_timer_handler+0xc3/0xd0
net/ipv4/inet_timewait_sock.c:149
[<ffffffff815f5b21>] call_timer_fn+0x241/0x800 kernel/time/timer.c:1308
[<ffffffff815f84b7>] expire_timers kernel/time/timer.c:1348 [inline]
[<ffffffff815f84b7>] __run_timers+0x9e7/0xe90 kernel/time/timer.c:1641
[<ffffffff815f8981>] run_timer_softirq+0x21/0x80 kernel/time/timer.c:1654
[<ffffffff84372c7f>] __do_softirq+0x31f/0xbcd kernel/softirq.c:284
[<ffffffff8143c18c>] invoke_softirq kernel/softirq.c:364 [inline]
[<ffffffff8143c18c>] irq_exit+0x1cc/0x200 kernel/softirq.c:405
[<ffffffff8437228b>] exiting_irq arch/x86/include/asm/apic.h:659 [inline]
[<ffffffff8437228b>] smp_apic_timer_interrupt+0x7b/0xa0
arch/x86/kernel/apic/apic.c:960
[<ffffffff8437133c>] apic_timer_interrupt+0x8c/0xa0
arch/x86/entry/entry_64.S:709
<EOI> [ 1412.821824] [<ffffffff8436dbb6>] ?
native_safe_halt+0x6/0x10 arch/x86/include/asm/irqflags.h:53
[<ffffffff8436d08f>] arch_safe_halt
arch/x86/include/asm/paravirt.h:103 [inline]
[<ffffffff8436d08f>] default_idle+0xbf/0x440 arch/x86/kernel/process.c:308
[<ffffffff8128a5ca>] arch_cpu_idle+0xa/0x10 arch/x86/kernel/process.c:299
[<ffffffff8436e0d6>] default_idle_call+0x36/0x90 kernel/sched/idle.c:96
[<ffffffff815549a7>] cpuidle_idle_call kernel/sched/idle.c:154 [inline]
[<ffffffff815549a7>] cpu_idle_loop kernel/sched/idle.c:247 [inline]
[<ffffffff815549a7>] cpu_startup_entry+0x327/0x4b0 kernel/sched/idle.c:302
[<ffffffff812e47ac>] start_secondary+0x36c/0x460 arch/x86/kernel/smpboot.c:263
Object at ffff8801cd4ec0c0, in cache net_namespace size: 6656
Allocated:
PID = 3131
[ 1412.940699] [<ffffffff819d83e2>] kmem_cache_alloc+0x102/0x680 mm/slab.c:3565
[ 1412.948084] [<ffffffff83549a86>] kmem_cache_zalloc
include/linux/slab.h:626 [inline]
[ 1412.948084] [<ffffffff83549a86>] net_alloc
net/core/net_namespace.c:339 [inline]
[ 1412.948084] [<ffffffff83549a86>] copy_net_ns+0x196/0x480
net/core/net_namespace.c:379
[ 1412.955019] [<ffffffff814b1349>] create_new_namespaces+0x409/0x860
kernel/nsproxy.c:106
[ 1412.962817] [<ffffffff814b1aed>] copy_namespaces+0x34d/0x420
kernel/nsproxy.c:164
[ 1412.970094] [<ffffffff814197f1>]
copy_process.part.40+0x2281/0x4d30 kernel/fork.c:1659
[ 1412.978004] [<ffffffff8141c7e0>] copy_process kernel/fork.c:1483 [inline]
[ 1412.978004] [<ffffffff8141c7e0>] _do_fork+0x200/0xff0 kernel/fork.c:1937
[ 1412.984677] [<ffffffff8141d6a7>] SYSC_clone kernel/fork.c:2047 [inline]
[ 1412.984677] [<ffffffff8141d6a7>] SyS_clone+0x37/0x50 kernel/fork.c:2041
[ 1412.991276] [<ffffffff81009798>] do_syscall_64+0x2e8/0x930
arch/x86/entry/common.c:280
[ 1412.998394] [<ffffffff8436fa49>] return_from_SYSCALL_64+0x0/0x7a
Freed:
PID = 9846
[ 1413.031603] [<ffffffff819da1b1>] __cache_free mm/slab.c:3507 [inline]
[ 1413.031603] [<ffffffff819da1b1>] kmem_cache_free+0x71/0x240 mm/slab.c:3767
[ 1413.038796] [<ffffffff83548e3e>] net_free
net/core/net_namespace.c:355 [inline]
[ 1413.038796] [<ffffffff83548e3e>] net_drop_ns+0x11e/0x140
net/core/net_namespace.c:362
[ 1413.045734] [<ffffffff83549652>] cleanup_net+0x7f2/0xa90
net/core/net_namespace.c:472
[ 1413.052667] [<ffffffff81492960>] process_one_work+0xbd0/0x1c10
kernel/workqueue.c:2096
[ 1413.060120] [<ffffffff81493bc3>] worker_thread+0x223/0x1990
kernel/workqueue.c:2230
[ 1413.067357] [<ffffffff814abb33>] kthread+0x323/0x3e0 kernel/kthread.c:209
[ 1413.073944] [<ffffffff8436fbea>] ret_from_fork+0x2a/0x40
arch/x86/entry/entry_64.S:433
Memory state around the buggy address:
ffff8801cd4ec180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8801cd4ec200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff8801cd4ec280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff8801cd4ec300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8801cd4ec380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
BUG: KASAN: use-after-free in tw_timer_handler+0xc3/0xd0
net/ipv4/inet_timewait_sock.c:149 at addr ffff8801b7b50358
Read of size 8 by task swapper/0/0
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.9.0 #3
Hardware name: Google Google Compute Engine/Google Compute Engine,
BIOS Google 01/01/2011
ffff8801dc007468 ffffffff8234530f ffffffff00000000 1ffff1003b800e20
ffffed003b800e18 0000000041b58ab3 ffffffff84b379b8 ffffffff82345021
ffffffff84e2bba0 ffffffff84e2bba8 ffffffff84e2b380 000000000000002e
Call Trace:
[<ffffffff819dd8fe>] __asan_report_load8_noabort+0x3e/0x40
mm/kasan/report.c:329
[<ffffffff8374fd93>] tw_timer_handler+0xc3/0xd0
net/ipv4/inet_timewait_sock.c:149
[<ffffffff815f5b21>] call_timer_fn+0x241/0x800 kernel/time/timer.c:1308
[<ffffffff815f84b7>] expire_timers kernel/time/timer.c:1348 [inline]
[<ffffffff815f84b7>] __run_timers+0x9e7/0xe90 kernel/time/timer.c:1641
[<ffffffff815f8981>] run_timer_softirq+0x21/0x80 kernel/time/timer.c:1654
[<ffffffff84372c7f>] __do_softirq+0x31f/0xbcd kernel/softirq.c:284
[<ffffffff8143c18c>] invoke_softirq kernel/softirq.c:364 [inline]
[<ffffffff8143c18c>] irq_exit+0x1cc/0x200 kernel/softirq.c:405
[<ffffffff8437228b>] exiting_irq arch/x86/include/asm/apic.h:659 [inline]
[<ffffffff8437228b>] smp_apic_timer_interrupt+0x7b/0xa0
arch/x86/kernel/apic/apic.c:960
[<ffffffff8437133c>] apic_timer_interrupt+0x8c/0xa0
arch/x86/entry/entry_64.S:709
<EOI> [ 1965.936792] [<ffffffff8436dbb6>] ?
native_safe_halt+0x6/0x10 arch/x86/include/asm/irqflags.h:53
[<ffffffff8436d08f>] arch_safe_halt
arch/x86/include/asm/paravirt.h:103 [inline]
[<ffffffff8436d08f>] default_idle+0xbf/0x440 arch/x86/kernel/process.c:308
[<ffffffff8128a5ca>] arch_cpu_idle+0xa/0x10 arch/x86/kernel/process.c:299
[<ffffffff8436e0d6>] default_idle_call+0x36/0x90 kernel/sched/idle.c:96
[<ffffffff815549a7>] cpuidle_idle_call kernel/sched/idle.c:154 [inline]
[<ffffffff815549a7>] cpu_idle_loop kernel/sched/idle.c:247 [inline]
[<ffffffff815549a7>] cpu_startup_entry+0x327/0x4b0 kernel/sched/idle.c:302
[<ffffffff8434f05d>] rest_init+0x18d/0x1a0 init/main.c:408
[<ffffffff85481b16>] start_kernel+0x7a0/0x7d2 init/main.c:660
[<ffffffff854802e6>] x86_64_start_reservations+0x2a/0x2c
arch/x86/kernel/head64.c:195
[<ffffffff85480424>] x86_64_start_kernel+0x13c/0x149
arch/x86/kernel/head64.c:176
Object at ffff8801b7b50180, in cache net_namespace size: 6656
Allocated:
PID = 3169
[ 1966.129951] [<ffffffff819d83e2>] kmem_cache_alloc+0x102/0x680 mm/slab.c:3565
[ 1966.137357] [<ffffffff83549a86>] kmem_cache_zalloc
include/linux/slab.h:626 [inline]
[ 1966.137357] [<ffffffff83549a86>] net_alloc
net/core/net_namespace.c:339 [inline]
[ 1966.137357] [<ffffffff83549a86>] copy_net_ns+0x196/0x480
net/core/net_namespace.c:379
[ 1966.144350] [<ffffffff814b1349>] create_new_namespaces+0x409/0x860
kernel/nsproxy.c:106
[ 1966.152254] [<ffffffff814b1aed>] copy_namespaces+0x34d/0x420
kernel/nsproxy.c:164
[ 1966.159567] [<ffffffff814197f1>]
copy_process.part.40+0x2281/0x4d30 kernel/fork.c:1659
[ 1966.167484] [<ffffffff8141c7e0>] copy_process kernel/fork.c:1483 [inline]
[ 1966.167484] [<ffffffff8141c7e0>] _do_fork+0x200/0xff0 kernel/fork.c:1937
[ 1966.174207] [<ffffffff8141d6a7>] SYSC_clone kernel/fork.c:2047 [inline]
[ 1966.174207] [<ffffffff8141d6a7>] SyS_clone+0x37/0x50 kernel/fork.c:2041
[ 1966.180832] [<ffffffff81009798>] do_syscall_64+0x2e8/0x930
arch/x86/entry/common.c:280
[ 1966.187973] [<ffffffff8436fa49>] return_from_SYSCALL_64+0x0/0x7a
Freed:
PID = 8938
[ 1966.221347] [<ffffffff819da1b1>] __cache_free mm/slab.c:3507 [inline]
[ 1966.221347] [<ffffffff819da1b1>] kmem_cache_free+0x71/0x240 mm/slab.c:3767
[ 1966.228568] [<ffffffff83548e3e>] net_free
net/core/net_namespace.c:355 [inline]
[ 1966.228568] [<ffffffff83548e3e>] net_drop_ns+0x11e/0x140
net/core/net_namespace.c:362
[ 1966.235564] [<ffffffff83549652>] cleanup_net+0x7f2/0xa90
net/core/net_namespace.c:472
[ 1966.242517] [<ffffffff81492960>] process_one_work+0xbd0/0x1c10
kernel/workqueue.c:2096
[ 1966.249995] [<ffffffff81493bc3>] worker_thread+0x223/0x1990
kernel/workqueue.c:2230
[ 1966.257258] [<ffffffff814abb33>] kthread+0x323/0x3e0 kernel/kthread.c:209
[ 1966.263879] [<ffffffff8436fbea>] ret_from_fork+0x2a/0x40
arch/x86/entry/entry_64.S:433
Memory state around the buggy address:
ffff8801b7b50200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8801b7b50280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff8801b7b50300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff8801b7b50380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8801b7b50400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
BUG: KASAN: slab-out-of-bounds in tw_timer_handler+0xc3/0xd0
net/ipv4/inet_timewait_sock.c:149 at addr ffff8801c98f43a0
Read of size 8 by task syz-executor8/3423
CPU: 0 PID: 3423 Comm: syz-executor8 Not tainted 4.10.0-rc5 #19
Hardware name: Google Google Compute Engine/Google Compute Engine,
BIOS Google 01/01/2011
Call Trace:
<IRQ>
__dump_stack lib/dump_stack.c:15 [inline]
dump_stack+0x2ee/0x3ef lib/dump_stack.c:51
kasan_object_err+0x1c/0x70 mm/kasan/report.c:161
print_address_description mm/kasan/report.c:199 [inline]
kasan_report_error+0x1d1/0x4d0 mm/kasan/report.c:288
kasan_report mm/kasan/report.c:308 [inline]
__asan_report_load8_noabort+0x3e/0x40 mm/kasan/report.c:329
tw_timer_handler+0xc3/0xd0 net/ipv4/inet_timewait_sock.c:149
call_timer_fn+0x241/0x820 kernel/time/timer.c:1308
expire_timers kernel/time/timer.c:1348 [inline]
__run_timers+0x9e7/0xe90 kernel/time/timer.c:1642
run_timer_softirq+0x21/0x80 kernel/time/timer.c:1655
__do_softirq+0x31f/0xbe7 kernel/softirq.c:284
invoke_softirq kernel/softirq.c:364 [inline]
irq_exit+0x1cc/0x200 kernel/softirq.c:405
exiting_irq arch/x86/include/asm/apic.h:658 [inline]
smp_apic_timer_interrupt+0x76/0xa0 arch/x86/kernel/apic/apic.c:961
apic_timer_interrupt+0x93/0xa0 arch/x86/entry/entry_64.S:707
RIP: 0010:arch_local_save_flags arch/x86/include/asm/paravirt.h:762 [inline]
RIP: 0010:arch_local_irq_save arch/x86/include/asm/paravirt.h:784 [inline]
RIP: 0010:lock_is_held_type+0x124/0x310 kernel/locking/lockdep.c:3787
RSP: 0018:ffff8801c946f558 EFLAGS: 00000286 ORIG_RAX: ffffffffffffff10
RAX: 0000000000000286 RBX: 1ffff1003928deac RCX: 1ffff1003928deb0
RDX: 1ffffffff0a18984 RSI: 00000000ffffffff RDI: ffffffff850c4c20
RBP: ffff8801c946f6a8 R08: 0000000000000002 R09: 0000000000000001
R10: 000000000000000a R11: 0000000000000000 R12: ffff8801c946f680
R13: ffff8801c9492640 R14: ffffffff85130ec0 R15: 0000000000000bff
</IRQ>
lock_is_held include/linux/lockdep.h:348 [inline]
___might_sleep+0x5b3/0x650 kernel/sched/core.c:7748
__might_sleep+0x95/0x1a0 kernel/sched/core.c:7739
cache_alloc_debugcheck_before mm/slab.c:3071 [inline]
slab_alloc mm/slab.c:3386 [inline]
kmem_cache_alloc+0x273/0x680 mm/slab.c:3558
shmem_alloc_inode+0x1b/0x40 mm/shmem.c:3647
alloc_inode+0x61/0x180 fs/inode.c:207
new_inode_pseudo+0x69/0x170 fs/inode.c:889
new_inode+0x1c/0x40 fs/inode.c:918
shmem_get_inode+0xd1/0x8a0 mm/shmem.c:2120
shmem_mknod+0x58/0x1b0 mm/shmem.c:2824
shmem_mkdir+0x29/0x50 mm/shmem.c:2875
vfs_mkdir+0x3be/0x600 fs/namei.c:3738
SYSC_mkdirat fs/namei.c:3761 [inline]
SyS_mkdirat fs/namei.c:3745 [inline]
SYSC_mkdir fs/namei.c:3772 [inline]
SyS_mkdir+0x16e/0x290 fs/namei.c:3770
entry_SYSCALL_64_fastpath+0x1f/0xc2
RIP: 0033:0x44ec87
RSP: 002b:0000000001a2fe40 EFLAGS: 00000212 ORIG_RAX: 0000000000000053
RAX: ffffffffffffffda RBX: 0000000000000010 RCX: 000000000044ec87
RDX: 0000000001a2fe6e RSI: 00000000000001ff RDI: 0000000001a2fe68
RBP: 00000000000019ec R08: 0000000000000000 R09: 0000000000000006
R10: 0000000000000064 R11: 0000000000000212 R12: 0000000001ef390c
R13: 0000000000000000 R14: 00000000000a43b5 R15: 00000000000019ec
Object at ffff8801c98f44c0, in cache task_struct size: 5696
Allocated:
PID = 3452
[<ffffffff8129f656>] save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:57
[<ffffffff819f6f53>] save_stack+0x43/0xd0 mm/kasan/kasan.c:502
[<ffffffff819f71da>] set_track mm/kasan/kasan.c:514 [inline]
[<ffffffff819f71da>] kasan_kmalloc+0xaa/0xd0 mm/kasan/kasan.c:605
[<ffffffff819f77d2>] kasan_slab_alloc+0x12/0x20 mm/kasan/kasan.c:544
[<ffffffff819f1652>] kmem_cache_alloc_node+0x122/0x690 mm/slab.c:3650
[<ffffffff81421fe2>] alloc_task_struct_node kernel/fork.c:142 [inline]
[<ffffffff81421fe2>] dup_task_struct kernel/fork.c:482 [inline]
[<ffffffff81421fe2>] copy_process.part.42+0x1a32/0x5fd0 kernel/fork.c:1515
[<ffffffff81426ac0>] copy_process kernel/fork.c:1486 [inline]
[<ffffffff81426ac0>] _do_fork+0x200/0xff0 kernel/fork.c:1942
[<ffffffff81427987>] SYSC_clone kernel/fork.c:2052 [inline]
[<ffffffff81427987>] SyS_clone+0x37/0x50 kernel/fork.c:2046
[<ffffffff81009798>] do_syscall_64+0x2e8/0x930 arch/x86/entry/common.c:280
[<ffffffff8440fb09>] return_from_SYSCALL_64+0x0/0x7a
Freed:
PID = 29885
[<ffffffff8129f656>] save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:57
[<ffffffff819f6f53>] save_stack+0x43/0xd0 mm/kasan/kasan.c:502
[<ffffffff819f784f>] set_track mm/kasan/kasan.c:514 [inline]
[<ffffffff819f784f>] kasan_slab_free+0x6f/0xb0 mm/kasan/kasan.c:578
[<ffffffff819f4bf1>] __cache_free mm/slab.c:3502 [inline]
[<ffffffff819f4bf1>] kmem_cache_free+0x71/0x240 mm/slab.c:3762
[<ffffffff8141f041>] free_task_struct kernel/fork.c:147 [inline]
[<ffffffff8141f041>] free_task+0x151/0x1d0 kernel/fork.c:359
[<ffffffff8141f30b>] __put_task_struct+0x24b/0x5f0 kernel/fork.c:396
[<ffffffff81435baa>] put_task_struct include/linux/sched.h:2257 [inline]
[<ffffffff81435baa>] delayed_put_task_struct+0xca/0x3f0 kernel/exit.c:173
[<ffffffff815ef250>] __rcu_reclaim kernel/rcu/rcu.h:118 [inline]
[<ffffffff815ef250>] rcu_do_batch.isra.70+0x9e0/0xdf0 kernel/rcu/tree.c:2780
[<ffffffff815efad2>] invoke_rcu_callbacks kernel/rcu/tree.c:3043 [inline]
[<ffffffff815efad2>] __rcu_process_callbacks kernel/rcu/tree.c:3010 [inline]
[<ffffffff815efad2>] rcu_process_callbacks+0x472/0xc70 kernel/rcu/tree.c:3027
[<ffffffff84412d7f>] __do_softirq+0x31f/0xbe7 kernel/softirq.c:284
Memory state around the buggy address:
ffff8801c98f4280: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff8801c98f4300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff8801c98f4380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
^
ffff8801c98f4400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff8801c98f4480: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
==================================================================
^ permalink raw reply
* Re: [PATCH] net: stmicro: fix LS field mask in EEE configuration
From: Joao Pinto @ 2017-01-23 10:17 UTC (permalink / raw)
To: David Miller, Joao.Pinto; +Cc: rayagond, netdev
In-Reply-To: <20170122.164953.874236089744264438.davem@davemloft.net>
Hi David,
Às 9:49 PM de 1/22/2017, David Miller escreveu:
> From: Joao Pinto <Joao.Pinto@synopsys.com>
> Date: Fri, 20 Jan 2017 16:00:26 +0000
>
>> This patch fixes the LS mask when setting EEE timer.
>> LS field is 10 bits long and not 11 as currently.
>>
>> Signed-off-by: Joao Pinto <jpinto@synopsys.com>
>> Reported-By: Rayagond Kokatanur <rayagond@vayavyalabs.com>
>
> Please indicate the appropriate target tree of your patch in the
> subject line just like all other developers on this list do, don't
> make me guess.
Sorry, I will follow that rule also of course.
>
> This time I figured out that this is meant for the net-next tree,
> but I will not guess next time, I will just reject your patch
> instead.
>
> Thanks.
>
Thanks.
Joao
^ permalink raw reply
* [patch net] mlxsw: spectrum_router: Correctly reallocate adjacency entries
From: Jiri Pirko @ 2017-01-23 10:11 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, eladr
From: Ido Schimmel <idosch@mellanox.com>
mlxsw_sp_nexthop_group_mac_update() is called in one of two cases:
1) When the MAC of a nexthop needs to be updated
2) When the size of a nexthop group has changed
In the second case the adjacency entries for the nexthop group need to
be reallocated from the adjacency table. In this case we must write to
the entries the MAC addresses of all the nexthops that should be
offloaded and not only those whose MAC changed. Otherwise, these entries
would be filled with garbage data, resulting in packet loss.
Fixes: a7ff87acd995 ("mlxsw: spectrum_router: Implement next-hop routing")
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 01d0efa..9e494a4 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -1172,7 +1172,8 @@ static int mlxsw_sp_nexthop_mac_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
static int
mlxsw_sp_nexthop_group_mac_update(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_nexthop_group *nh_grp)
+ struct mlxsw_sp_nexthop_group *nh_grp,
+ bool reallocate)
{
u32 adj_index = nh_grp->adj_index; /* base */
struct mlxsw_sp_nexthop *nh;
@@ -1187,7 +1188,7 @@ mlxsw_sp_nexthop_group_mac_update(struct mlxsw_sp *mlxsw_sp,
continue;
}
- if (nh->update) {
+ if (nh->update || reallocate) {
err = mlxsw_sp_nexthop_mac_update(mlxsw_sp,
adj_index, nh);
if (err)
@@ -1248,7 +1249,8 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
/* Nothing was added or removed, so no need to reallocate. Just
* update MAC on existing adjacency indexes.
*/
- err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp);
+ err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp,
+ false);
if (err) {
dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n");
goto set_trap;
@@ -1276,7 +1278,7 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
nh_grp->adj_index_valid = 1;
nh_grp->adj_index = adj_index;
nh_grp->ecmp_size = ecmp_size;
- err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp);
+ err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp, true);
if (err) {
dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n");
goto set_trap;
--
2.7.4
^ permalink raw reply related
* [PATCH v3 2/3] xen: modify xenstore watch event interface
From: Juergen Gross @ 2017-01-23 10:09 UTC (permalink / raw)
To: linux-kernel, xen-devel
Cc: boris.ostrovsky, Juergen Gross, konrad.wilk, roger.pau, wei.liu2,
paul.durrant, netdev
In-Reply-To: <20170123100918.13523-1-jgross@suse.com>
Today a Xenstore watch event is delivered via a callback function
declared as:
void (*callback)(struct xenbus_watch *,
const char **vec, unsigned int len);
As all watch events only ever come with two parameters (path and token)
changing the prototype to:
void (*callback)(struct xenbus_watch *,
const char *path, const char *token);
is the natural thing to do.
Apply this change and adapt all users.
Cc: konrad.wilk@oracle.com
Cc: roger.pau@citrix.com
Cc: wei.liu2@citrix.com
Cc: paul.durrant@citrix.com
Cc: netdev@vger.kernel.org
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Paul Durrant <paul.durrant@citrix.com>
Reviewed-by: Wei Liu <wei.liu2@citrix.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
---
drivers/block/xen-blkback/xenbus.c | 6 +++---
drivers/net/xen-netback/xenbus.c | 8 ++++----
drivers/xen/cpu_hotplug.c | 5 ++---
drivers/xen/manage.c | 6 +++---
drivers/xen/xen-balloon.c | 2 +-
drivers/xen/xen-pciback/xenbus.c | 2 +-
drivers/xen/xenbus/xenbus.h | 6 +++---
drivers/xen/xenbus/xenbus_client.c | 4 ++--
drivers/xen/xenbus/xenbus_dev_frontend.c | 21 ++++++++-------------
drivers/xen/xenbus/xenbus_probe.c | 11 ++++-------
drivers/xen/xenbus/xenbus_probe_backend.c | 8 ++++----
drivers/xen/xenbus/xenbus_probe_frontend.c | 14 +++++++-------
drivers/xen/xenbus/xenbus_xs.c | 29 ++++++++++++++---------------
include/xen/xenbus.h | 6 +++---
14 files changed, 59 insertions(+), 69 deletions(-)
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
index 415e79b..8fe61b5 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -38,8 +38,8 @@ struct backend_info {
static struct kmem_cache *xen_blkif_cachep;
static void connect(struct backend_info *);
static int connect_ring(struct backend_info *);
-static void backend_changed(struct xenbus_watch *, const char **,
- unsigned int);
+static void backend_changed(struct xenbus_watch *, const char *,
+ const char *);
static void xen_blkif_free(struct xen_blkif *blkif);
static void xen_vbd_free(struct xen_vbd *vbd);
@@ -661,7 +661,7 @@ static int xen_blkbk_probe(struct xenbus_device *dev,
* ready, connect.
*/
static void backend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+ const char *path, const char *token)
{
int err;
unsigned major;
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index 3124eae..d8a40fa 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -723,7 +723,7 @@ static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
}
static void xen_net_rate_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+ const char *path, const char *token)
{
struct xenvif *vif = container_of(watch, struct xenvif, credit_watch);
struct xenbus_device *dev = xenvif_to_xenbus_device(vif);
@@ -780,7 +780,7 @@ static void xen_unregister_credit_watch(struct xenvif *vif)
}
static void xen_mcast_ctrl_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+ const char *path, const char *token)
{
struct xenvif *vif = container_of(watch, struct xenvif,
mcast_ctrl_watch);
@@ -855,8 +855,8 @@ static void unregister_hotplug_status_watch(struct backend_info *be)
}
static void hotplug_status_changed(struct xenbus_watch *watch,
- const char **vec,
- unsigned int vec_size)
+ const char *path,
+ const char *token)
{
struct backend_info *be = container_of(watch,
struct backend_info,
diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c
index 5676aef..7a4daa2 100644
--- a/drivers/xen/cpu_hotplug.c
+++ b/drivers/xen/cpu_hotplug.c
@@ -68,13 +68,12 @@ static void vcpu_hotplug(unsigned int cpu)
}
static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+ const char *path, const char *token)
{
unsigned int cpu;
char *cpustr;
- const char *node = vec[XS_WATCH_PATH];
- cpustr = strstr(node, "cpu/");
+ cpustr = strstr(path, "cpu/");
if (cpustr != NULL) {
sscanf(cpustr, "cpu/%u", &cpu);
vcpu_hotplug(cpu);
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
index 26e5e85..ca62c09 100644
--- a/drivers/xen/manage.c
+++ b/drivers/xen/manage.c
@@ -218,7 +218,7 @@ static struct shutdown_handler shutdown_handlers[] = {
};
static void shutdown_handler(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+ const char *path, const char *token)
{
char *str;
struct xenbus_transaction xbt;
@@ -266,8 +266,8 @@ static void shutdown_handler(struct xenbus_watch *watch,
}
#ifdef CONFIG_MAGIC_SYSRQ
-static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
- unsigned int len)
+static void sysrq_handler(struct xenbus_watch *watch, const char *path,
+ const char *token)
{
char sysrq_key = '\0';
struct xenbus_transaction xbt;
diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c
index 79865b8..e7715cb 100644
--- a/drivers/xen/xen-balloon.c
+++ b/drivers/xen/xen-balloon.c
@@ -55,7 +55,7 @@ static int register_balloon(struct device *dev);
/* React to a change in the target key */
static void watch_target(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+ const char *path, const char *token)
{
unsigned long long new_target;
int err;
diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c
index 3f0aee0..3814b44 100644
--- a/drivers/xen/xen-pciback/xenbus.c
+++ b/drivers/xen/xen-pciback/xenbus.c
@@ -652,7 +652,7 @@ static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev)
}
static void xen_pcibk_be_watch(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+ const char *path, const char *token)
{
struct xen_pcibk_device *pdev =
container_of(watch, struct xen_pcibk_device, be_watch);
diff --git a/drivers/xen/xenbus/xenbus.h b/drivers/xen/xenbus/xenbus.h
index a6b007d..5199527 100644
--- a/drivers/xen/xenbus/xenbus.h
+++ b/drivers/xen/xenbus/xenbus.h
@@ -40,8 +40,8 @@ struct xen_bus_type {
int (*get_bus_id)(char bus_id[XEN_BUS_ID_SIZE], const char *nodename);
int (*probe)(struct xen_bus_type *bus, const char *type,
const char *dir);
- void (*otherend_changed)(struct xenbus_watch *watch, const char **vec,
- unsigned int len);
+ void (*otherend_changed)(struct xenbus_watch *watch, const char *path,
+ const char *token);
struct bus_type bus;
};
@@ -84,7 +84,7 @@ int xenbus_dev_resume(struct device *dev);
int xenbus_dev_cancel(struct device *dev);
void xenbus_otherend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len,
+ const char *path, const char *token,
int ignore_on_shutdown);
int xenbus_read_otherend_details(struct xenbus_device *xendev,
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
index 23edf53..9586c24 100644
--- a/drivers/xen/xenbus/xenbus_client.c
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -115,7 +115,7 @@ EXPORT_SYMBOL_GPL(xenbus_strstate);
int xenbus_watch_path(struct xenbus_device *dev, const char *path,
struct xenbus_watch *watch,
void (*callback)(struct xenbus_watch *,
- const char **, unsigned int))
+ const char *, const char *))
{
int err;
@@ -153,7 +153,7 @@ EXPORT_SYMBOL_GPL(xenbus_watch_path);
int xenbus_watch_pathfmt(struct xenbus_device *dev,
struct xenbus_watch *watch,
void (*callback)(struct xenbus_watch *,
- const char **, unsigned int),
+ const char *, const char *),
const char *pathfmt, ...)
{
int err;
diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c
index e2bc9b3..e4b9847 100644
--- a/drivers/xen/xenbus/xenbus_dev_frontend.c
+++ b/drivers/xen/xenbus/xenbus_dev_frontend.c
@@ -258,26 +258,23 @@ static struct watch_adapter *alloc_watch_adapter(const char *path,
}
static void watch_fired(struct xenbus_watch *watch,
- const char **vec,
- unsigned int len)
+ const char *path,
+ const char *token)
{
struct watch_adapter *adap;
struct xsd_sockmsg hdr;
- const char *path, *token;
- int path_len, tok_len, body_len, data_len = 0;
+ const char *token_caller;
+ int path_len, tok_len, body_len;
int ret;
LIST_HEAD(staging_q);
adap = container_of(watch, struct watch_adapter, watch);
- path = vec[XS_WATCH_PATH];
- token = adap->token;
+ token_caller = adap->token;
path_len = strlen(path) + 1;
- tok_len = strlen(token) + 1;
- if (len > 2)
- data_len = vec[len] - vec[2] + 1;
- body_len = path_len + tok_len + data_len;
+ tok_len = strlen(token_caller) + 1;
+ body_len = path_len + tok_len;
hdr.type = XS_WATCH_EVENT;
hdr.len = body_len;
@@ -288,9 +285,7 @@ static void watch_fired(struct xenbus_watch *watch,
if (!ret)
ret = queue_reply(&staging_q, path, path_len);
if (!ret)
- ret = queue_reply(&staging_q, token, tok_len);
- if (!ret && len > 2)
- ret = queue_reply(&staging_q, vec[2], data_len);
+ ret = queue_reply(&staging_q, token_caller, tok_len);
if (!ret) {
/* success: pass reply list onto watcher */
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 6baffbb..74888ca 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -169,7 +169,7 @@ int xenbus_read_otherend_details(struct xenbus_device *xendev,
EXPORT_SYMBOL_GPL(xenbus_read_otherend_details);
void xenbus_otherend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len,
+ const char *path, const char *token,
int ignore_on_shutdown)
{
struct xenbus_device *dev =
@@ -180,18 +180,15 @@ void xenbus_otherend_changed(struct xenbus_watch *watch,
/* Protect us against watches firing on old details when the otherend
details change, say immediately after a resume. */
if (!dev->otherend ||
- strncmp(dev->otherend, vec[XS_WATCH_PATH],
- strlen(dev->otherend))) {
- dev_dbg(&dev->dev, "Ignoring watch at %s\n",
- vec[XS_WATCH_PATH]);
+ strncmp(dev->otherend, path, strlen(dev->otherend))) {
+ dev_dbg(&dev->dev, "Ignoring watch at %s\n", path);
return;
}
state = xenbus_read_driver_state(dev->otherend);
dev_dbg(&dev->dev, "state is %d, (%s), %s, %s\n",
- state, xenbus_strstate(state), dev->otherend_watch.node,
- vec[XS_WATCH_PATH]);
+ state, xenbus_strstate(state), dev->otherend_watch.node, path);
/*
* Ignore xenbus transitions during shutdown. This prevents us doing
diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c
index f46b4dc..b0bed4f 100644
--- a/drivers/xen/xenbus/xenbus_probe_backend.c
+++ b/drivers/xen/xenbus/xenbus_probe_backend.c
@@ -181,9 +181,9 @@ static int xenbus_probe_backend(struct xen_bus_type *bus, const char *type,
}
static void frontend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+ const char *path, const char *token)
{
- xenbus_otherend_changed(watch, vec, len, 0);
+ xenbus_otherend_changed(watch, path, token, 0);
}
static struct xen_bus_type xenbus_backend = {
@@ -204,11 +204,11 @@ static struct xen_bus_type xenbus_backend = {
};
static void backend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+ const char *path, const char *token)
{
DPRINTK("");
- xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
+ xenbus_dev_changed(path, &xenbus_backend);
}
static struct xenbus_watch be_watch = {
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
index d7b77a6..19e45ce 100644
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -86,9 +86,9 @@ static int xenbus_uevent_frontend(struct device *_dev,
static void backend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+ const char *path, const char *token)
{
- xenbus_otherend_changed(watch, vec, len, 1);
+ xenbus_otherend_changed(watch, path, token, 1);
}
static void xenbus_frontend_delayed_resume(struct work_struct *w)
@@ -153,11 +153,11 @@ static struct xen_bus_type xenbus_frontend = {
};
static void frontend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+ const char *path, const char *token)
{
DPRINTK("");
- xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend);
+ xenbus_dev_changed(path, &xenbus_frontend);
}
@@ -332,13 +332,13 @@ static DECLARE_WAIT_QUEUE_HEAD(backend_state_wq);
static int backend_state;
static void xenbus_reset_backend_state_changed(struct xenbus_watch *w,
- const char **v, unsigned int l)
+ const char *path, const char *token)
{
- if (xenbus_scanf(XBT_NIL, v[XS_WATCH_PATH], "", "%i",
+ if (xenbus_scanf(XBT_NIL, path, "", "%i",
&backend_state) != 1)
backend_state = XenbusStateUnknown;
printk(KERN_DEBUG "XENBUS: backend %s %s\n",
- v[XS_WATCH_PATH], xenbus_strstate(backend_state));
+ path, xenbus_strstate(backend_state));
wake_up(&backend_state_wq);
}
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
index 4c49d87..ebc768f 100644
--- a/drivers/xen/xenbus/xenbus_xs.c
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -64,8 +64,8 @@ struct xs_stored_msg {
/* Queued watch events. */
struct {
struct xenbus_watch *handle;
- char **vec;
- unsigned int vec_size;
+ const char *path;
+ const char *token;
} watch;
} u;
};
@@ -765,7 +765,7 @@ void unregister_xenbus_watch(struct xenbus_watch *watch)
if (msg->u.watch.handle != watch)
continue;
list_del(&msg->list);
- kfree(msg->u.watch.vec);
+ kfree(msg->u.watch.path);
kfree(msg);
}
spin_unlock(&watch_events_lock);
@@ -833,11 +833,10 @@ static int xenwatch_thread(void *unused)
if (ent != &watch_events) {
msg = list_entry(ent, struct xs_stored_msg, list);
- msg->u.watch.handle->callback(
- msg->u.watch.handle,
- (const char **)msg->u.watch.vec,
- msg->u.watch.vec_size);
- kfree(msg->u.watch.vec);
+ msg->u.watch.handle->callback(msg->u.watch.handle,
+ msg->u.watch.path,
+ msg->u.watch.token);
+ kfree(msg->u.watch.path);
kfree(msg);
}
@@ -903,24 +902,24 @@ static int process_msg(void)
body[msg->hdr.len] = '\0';
if (msg->hdr.type == XS_WATCH_EVENT) {
- msg->u.watch.vec = split(body, msg->hdr.len,
- &msg->u.watch.vec_size);
- if (IS_ERR(msg->u.watch.vec)) {
- err = PTR_ERR(msg->u.watch.vec);
+ if (count_strings(body, msg->hdr.len) != 2) {
+ err = -EINVAL;
kfree(msg);
+ kfree(body);
goto out;
}
+ msg->u.watch.path = (const char *)body;
+ msg->u.watch.token = (const char *)strchr(body, '\0') + 1;
spin_lock(&watches_lock);
- msg->u.watch.handle = find_watch(
- msg->u.watch.vec[XS_WATCH_TOKEN]);
+ msg->u.watch.handle = find_watch(msg->u.watch.token);
if (msg->u.watch.handle != NULL) {
spin_lock(&watch_events_lock);
list_add_tail(&msg->list, &watch_events);
wake_up(&watch_events_waitq);
spin_unlock(&watch_events_lock);
} else {
- kfree(msg->u.watch.vec);
+ kfree(body);
kfree(msg);
}
spin_unlock(&watches_lock);
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
index 98f73a2..869c816 100644
--- a/include/xen/xenbus.h
+++ b/include/xen/xenbus.h
@@ -61,7 +61,7 @@ struct xenbus_watch
/* Callback (executed in a process context with no locks held). */
void (*callback)(struct xenbus_watch *,
- const char **vec, unsigned int len);
+ const char *path, const char *token);
};
@@ -193,11 +193,11 @@ void xenbus_probe(struct work_struct *);
int xenbus_watch_path(struct xenbus_device *dev, const char *path,
struct xenbus_watch *watch,
void (*callback)(struct xenbus_watch *,
- const char **, unsigned int));
+ const char *, const char *));
__printf(4, 5)
int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
void (*callback)(struct xenbus_watch *,
- const char **, unsigned int),
+ const char *, const char *),
const char *pathfmt, ...);
int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state);
--
2.10.2
^ permalink raw reply related
* [PATCH v3 0/3] xen: optimize xenbus performance
From: Juergen Gross @ 2017-01-23 10:09 UTC (permalink / raw)
To: linux-kernel, xen-devel
Cc: boris.ostrovsky, Juergen Gross, konrad.wilk, roger.pau, wei.liu2,
paul.durrant, netdev
The xenbus driver used for communication with Xenstore (all kernel
accesses to Xenstore and in case of Xenstore living in another domain
all accesses of the local domain to Xenstore) is rather simple
especially regarding multiple concurrent accesses: they are just being
serialized in spite of Xenstore being capable to handle multiple
parallel accesses.
Clean up the external interface(s) of xenbus and optimize its
performance by allowing multiple concurrent accesses to Xenstore.
V3:
- patch 3: simplify coding as requested by Boris Ostrovsky
V2:
- patch 1: update commit message, re-add lost copyright
- patch 3: address comments of Boris Ostrovsky:
- guard xs_request_id by lock
- move state struct definitions to the place where they are being
used
- rate limit some warnings
- use barrier() instead of cpu_relax()
- add/remove some comments
- minor changes like naming of variables
Juergen Gross (3):
xen: clean up xenbus internal headers
xen: modify xenstore watch event interface
xen: optimize xenbus driver for multiple concurrent xenstore accesses
drivers/block/xen-blkback/xenbus.c | 6 +-
drivers/net/xen-netback/xenbus.c | 8 +-
drivers/xen/cpu_hotplug.c | 5 +-
drivers/xen/manage.c | 6 +-
drivers/xen/xen-balloon.c | 2 +-
drivers/xen/xen-pciback/xenbus.c | 2 +-
drivers/xen/xenbus/xenbus.h | 135 +++++++
drivers/xen/xenbus/xenbus_client.c | 6 +-
drivers/xen/xenbus/xenbus_comms.c | 315 +++++++++++++++--
drivers/xen/xenbus/xenbus_comms.h | 51 ---
drivers/xen/xenbus/xenbus_dev_backend.c | 2 +-
drivers/xen/xenbus/xenbus_dev_frontend.c | 213 ++++++-----
drivers/xen/xenbus/xenbus_probe.c | 14 +-
drivers/xen/xenbus/xenbus_probe.h | 88 -----
drivers/xen/xenbus/xenbus_probe_backend.c | 11 +-
drivers/xen/xenbus/xenbus_probe_frontend.c | 17 +-
drivers/xen/xenbus/xenbus_xs.c | 544 +++++++++++++----------------
drivers/xen/xenfs/super.c | 2 +-
drivers/xen/xenfs/xenstored.c | 2 +-
include/xen/xenbus.h | 18 +-
20 files changed, 835 insertions(+), 612 deletions(-)
create mode 100644 drivers/xen/xenbus/xenbus.h
delete mode 100644 drivers/xen/xenbus/xenbus_comms.h
delete mode 100644 drivers/xen/xenbus/xenbus_probe.h
Cc: konrad.wilk@oracle.com
Cc: roger.pau@citrix.com
Cc: wei.liu2@citrix.com
Cc: paul.durrant@citrix.com
Cc: netdev@vger.kernel.org
--
2.10.2
^ permalink raw reply
* [patch net-next v2 4/4] mlxsw: spectrum: Add packet sample offloading support
From: Jiri Pirko @ 2017-01-23 10:07 UTC (permalink / raw)
To: netdev
Cc: davem, yotamg, idosch, eladr, nogahf, ogerlitz, jhs,
geert+renesas, stephen, xiyou.wangcong, linux, roopa,
john.fastabend, simon.horman, mrv
In-Reply-To: <1485166031-4773-1-git-send-email-jiri@resnulli.us>
From: Yotam Gigi <yotamg@mellanox.com>
Using the MPSC register, add the functions that configure port-based
packet sampling in hardware and the necessary datatypes in the
mlxsw_sp_port struct. In addition, add the necessary trap for sampled
packets and integrate with matchall offloading to allow offloading of the
sample tc action.
The current offload support is for the tc command:
tc filter add dev <DEV> parent ffff: \
matchall skip_sw \
action sample rate <RATE> group <GROUP> [trunc <SIZE>]
Where only ingress qdiscs are supported, and only a combination of
matchall classifier and sample action will lead to activating hardware
packet sampling.
Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 111 +++++++++++++++++++++++++
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 10 +++
drivers/net/ethernet/mellanox/mlxsw/trap.h | 1 +
3 files changed, 122 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 3dbd82e..467aa52 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -57,6 +57,7 @@
#include <net/pkt_cls.h>
#include <net/tc_act/tc_mirred.h>
#include <net/netevent.h>
+#include <net/tc_act/tc_sample.h>
#include "spectrum.h"
#include "pci.h"
@@ -469,6 +470,16 @@ static void mlxsw_sp_span_mirror_remove(struct mlxsw_sp_port *from,
mlxsw_sp_span_inspected_port_unbind(from, span_entry, type);
}
+static int mlxsw_sp_port_sample_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ bool enable, u32 rate)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ char mpsc_pl[MLXSW_REG_MPSC_LEN];
+
+ mlxsw_reg_mpsc_pack(mpsc_pl, mlxsw_sp_port->local_port, enable, rate);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpsc), mpsc_pl);
+}
+
static int mlxsw_sp_port_admin_status_set(struct mlxsw_sp_port *mlxsw_sp_port,
bool is_up)
{
@@ -1218,6 +1229,51 @@ mlxsw_sp_port_del_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_span_mirror_remove(mlxsw_sp_port, to_port, span_type);
}
+static int
+mlxsw_sp_port_add_cls_matchall_sample(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct tc_cls_matchall_offload *cls,
+ const struct tc_action *a,
+ bool ingress)
+{
+ int err;
+
+ if (!mlxsw_sp_port->sample)
+ return -EOPNOTSUPP;
+ if (rtnl_dereference(mlxsw_sp_port->sample->psample_group)) {
+ netdev_err(mlxsw_sp_port->dev, "sample already active\n");
+ return -EEXIST;
+ }
+ if (tcf_sample_rate(a) > MLXSW_REG_MPSC_RATE_MAX) {
+ netdev_err(mlxsw_sp_port->dev, "sample rate not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ rcu_assign_pointer(mlxsw_sp_port->sample->psample_group,
+ tcf_sample_psample_group(a));
+ mlxsw_sp_port->sample->truncate = tcf_sample_truncate(a);
+ mlxsw_sp_port->sample->trunc_size = tcf_sample_trunc_size(a);
+ mlxsw_sp_port->sample->rate = tcf_sample_rate(a);
+
+ err = mlxsw_sp_port_sample_set(mlxsw_sp_port, true, tcf_sample_rate(a));
+ if (err)
+ goto err_port_sample_set;
+ return 0;
+
+err_port_sample_set:
+ RCU_INIT_POINTER(mlxsw_sp_port->sample->psample_group, NULL);
+ return err;
+}
+
+static void
+mlxsw_sp_port_del_cls_matchall_sample(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ if (!mlxsw_sp_port->sample)
+ return;
+
+ mlxsw_sp_port_sample_set(mlxsw_sp_port, false, 1);
+ RCU_INIT_POINTER(mlxsw_sp_port->sample->psample_group, NULL);
+}
+
static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
__be16 protocol,
struct tc_cls_matchall_offload *cls,
@@ -1248,6 +1304,10 @@ static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
mirror = &mall_tc_entry->mirror;
err = mlxsw_sp_port_add_cls_matchall_mirror(mlxsw_sp_port,
mirror, a, ingress);
+ } else if (is_tcf_sample(a) && protocol == htons(ETH_P_ALL)) {
+ mall_tc_entry->type = MLXSW_SP_PORT_MALL_SAMPLE;
+ err = mlxsw_sp_port_add_cls_matchall_sample(mlxsw_sp_port, cls,
+ a, ingress);
} else {
err = -EOPNOTSUPP;
}
@@ -1281,6 +1341,9 @@ static void mlxsw_sp_port_del_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_port_del_cls_matchall_mirror(mlxsw_sp_port,
&mall_tc_entry->mirror);
break;
+ case MLXSW_SP_PORT_MALL_SAMPLE:
+ mlxsw_sp_port_del_cls_matchall_sample(mlxsw_sp_port);
+ break;
default:
WARN_ON(1);
}
@@ -2259,6 +2322,13 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
goto err_alloc_stats;
}
+ mlxsw_sp_port->sample = kzalloc(sizeof(*mlxsw_sp_port->sample),
+ GFP_KERNEL);
+ if (!mlxsw_sp_port->sample) {
+ err = -ENOMEM;
+ goto err_alloc_sample;
+ }
+
mlxsw_sp_port->hw_stats.cache =
kzalloc(sizeof(*mlxsw_sp_port->hw_stats.cache), GFP_KERNEL);
@@ -2387,6 +2457,8 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
err_port_swid_set:
kfree(mlxsw_sp_port->hw_stats.cache);
err_alloc_hw_stats:
+ kfree(mlxsw_sp_port->sample);
+err_alloc_sample:
free_percpu(mlxsw_sp_port->pcpu_stats);
err_alloc_stats:
kfree(mlxsw_sp_port->untagged_vlans);
@@ -2433,6 +2505,7 @@ static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port);
kfree(mlxsw_sp_port->hw_stats.cache);
+ kfree(mlxsw_sp_port->sample);
free_percpu(mlxsw_sp_port->pcpu_stats);
kfree(mlxsw_sp_port->untagged_vlans);
kfree(mlxsw_sp_port->active_vlans);
@@ -2734,6 +2807,41 @@ static void mlxsw_sp_rx_listener_mark_func(struct sk_buff *skb, u8 local_port,
return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv);
}
+static void mlxsw_sp_rx_listener_sample_func(struct sk_buff *skb, u8 local_port,
+ void *priv)
+{
+ struct mlxsw_sp *mlxsw_sp = priv;
+ struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
+ struct psample_group *psample_group;
+ u32 size;
+
+ if (unlikely(!mlxsw_sp_port)) {
+ dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: sample skb received for non-existent port\n",
+ local_port);
+ goto out;
+ }
+ if (unlikely(!mlxsw_sp_port->sample)) {
+ dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: sample skb received on unsupported port\n",
+ local_port);
+ goto out;
+ }
+
+ size = mlxsw_sp_port->sample->truncate ?
+ mlxsw_sp_port->sample->trunc_size : skb->len;
+
+ rcu_read_lock();
+ psample_group = rcu_dereference(mlxsw_sp_port->sample->psample_group);
+ if (!psample_group)
+ goto out_unlock;
+ psample_sample_packet(psample_group, skb, size,
+ mlxsw_sp_port->dev->ifindex, 0,
+ mlxsw_sp_port->sample->rate);
+out_unlock:
+ rcu_read_unlock();
+out:
+ consume_skb(skb);
+}
+
#define MLXSW_SP_RXL_NO_MARK(_trap_id, _action, _trap_group, _is_ctrl) \
MLXSW_RXL(mlxsw_sp_rx_listener_no_mark_func, _trap_id, _action, \
_is_ctrl, SP_##_trap_group, DISCARD)
@@ -2769,6 +2877,9 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = {
MLXSW_SP_RXL_NO_MARK(RTR_INGRESS0, TRAP_TO_CPU, REMOTE_ROUTE, false),
MLXSW_SP_RXL_NO_MARK(HOST_MISS_IPV4, TRAP_TO_CPU, ARP_MISS, false),
MLXSW_SP_RXL_NO_MARK(BGP_IPV4, TRAP_TO_CPU, BGP_IPV4, false),
+ /* PKT Sample trap */
+ MLXSW_RXL(mlxsw_sp_rx_listener_sample_func, PKT_SAMPLE, MIRROR_TO_CPU,
+ false, SP_IP2ME, DISCARD)
};
static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index cc1af19..bc3efe1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -46,6 +46,7 @@
#include <linux/dcbnl.h>
#include <linux/in6.h>
#include <linux/notifier.h>
+#include <net/psample.h>
#include "port.h"
#include "core.h"
@@ -229,6 +230,7 @@ struct mlxsw_sp_span_entry {
enum mlxsw_sp_port_mall_action_type {
MLXSW_SP_PORT_MALL_MIRROR,
+ MLXSW_SP_PORT_MALL_SAMPLE,
};
struct mlxsw_sp_port_mall_mirror_tc_entry {
@@ -315,6 +317,13 @@ struct mlxsw_sp_port_pcpu_stats {
u32 tx_dropped;
};
+struct mlxsw_sp_port_sample {
+ struct psample_group __rcu *psample_group;
+ u32 trunc_size;
+ u32 rate;
+ bool truncate;
+};
+
struct mlxsw_sp_port {
struct net_device *dev;
struct mlxsw_sp_port_pcpu_stats __percpu *pcpu_stats;
@@ -361,6 +370,7 @@ struct mlxsw_sp_port {
struct rtnl_link_stats64 *cache;
struct delayed_work update_dw;
} hw_stats;
+ struct mlxsw_sp_port_sample *sample;
};
struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h
index 7ab275d..02ea48b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/trap.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h
@@ -54,6 +54,7 @@ enum {
MLXSW_TRAP_ID_IGMP_V2_REPORT = 0x32,
MLXSW_TRAP_ID_IGMP_V2_LEAVE = 0x33,
MLXSW_TRAP_ID_IGMP_V3_REPORT = 0x34,
+ MLXSW_TRAP_ID_PKT_SAMPLE = 0x38,
MLXSW_TRAP_ID_ARPBC = 0x50,
MLXSW_TRAP_ID_ARPUC = 0x51,
MLXSW_TRAP_ID_MTUERROR = 0x52,
--
2.7.4
^ permalink raw reply related
* [patch net-next v2 3/4] mlxsw: reg: add the Monitoring Packet Sampling Configuration Register
From: Jiri Pirko @ 2017-01-23 10:07 UTC (permalink / raw)
To: netdev
Cc: davem, yotamg, idosch, eladr, nogahf, ogerlitz, jhs,
geert+renesas, stephen, xiyou.wangcong, linux, roopa,
john.fastabend, simon.horman, mrv
In-Reply-To: <1485166031-4773-1-git-send-email-jiri@resnulli.us>
From: Yotam Gigi <yotamg@mellanox.com>
The MPSC register allows to configure ingress packet sampling on specific
port of the mlxsw device. The sampled packets are then trapped via
PKT_SAMPLE trap.
Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/reg.h | 41 +++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index 1357fe0..9fb0316 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -4965,6 +4965,46 @@ static inline void mlxsw_reg_mlcr_pack(char *payload, u8 local_port,
MLXSW_REG_MLCR_DURATION_MAX : 0);
}
+/* MPSC - Monitoring Packet Sampling Configuration Register
+ * --------------------------------------------------------
+ * MPSC Register is used to configure the Packet Sampling mechanism.
+ */
+#define MLXSW_REG_MPSC_ID 0x9080
+#define MLXSW_REG_MPSC_LEN 0x1C
+
+MLXSW_REG_DEFINE(mpsc, MLXSW_REG_MPSC_ID, MLXSW_REG_MPSC_LEN);
+
+/* reg_mpsc_local_port
+ * Local port number
+ * Not supported for CPU port
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, mpsc, local_port, 0x00, 16, 8);
+
+/* reg_mpsc_e
+ * Enable sampling on port local_port
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mpsc, e, 0x04, 30, 1);
+
+#define MLXSW_REG_MPSC_RATE_MAX 3500000000UL
+
+/* reg_mpsc_rate
+ * Sampling rate = 1 out of rate packets (with randomization around
+ * the point). Valid values are: 1 to MLXSW_REG_MPSC_RATE_MAX
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mpsc, rate, 0x08, 0, 32);
+
+static inline void mlxsw_reg_mpsc_pack(char *payload, u8 local_port, bool e,
+ u32 rate)
+{
+ MLXSW_REG_ZERO(mpsc, payload);
+ mlxsw_reg_mpsc_local_port_set(payload, local_port);
+ mlxsw_reg_mpsc_e_set(payload, e);
+ mlxsw_reg_mpsc_rate_set(payload, rate);
+}
+
/* SBPR - Shared Buffer Pools Register
* -----------------------------------
* The SBPR configures and retrieves the shared buffer pools and configuration.
@@ -5429,6 +5469,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(mpat),
MLXSW_REG(mpar),
MLXSW_REG(mlcr),
+ MLXSW_REG(mpsc),
MLXSW_REG(sbpr),
MLXSW_REG(sbcm),
MLXSW_REG(sbpm),
--
2.7.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox