* Re: [PATCH v3 0/2] net/sctp: Avoid allocating high order memory with kmalloc()
From: David Miller @ 2018-08-11 19:36 UTC (permalink / raw)
To: khorenko
Cc: marcelo.leitner, oleg.babin, netdev, linux-sctp, vyasevich,
nhorman, lucien.xin, aryabinin
In-Reply-To: <20180810171143.21592-1-khorenko@virtuozzo.com>
From: Konstantin Khorenko <khorenko@virtuozzo.com>
Date: Fri, 10 Aug 2018 20:11:41 +0300
> Each SCTP association can have up to 65535 input and output streams.
> For each stream type an array of sctp_stream_in or sctp_stream_out
> structures is allocated using kmalloc_array() function. This function
> allocates physically contiguous memory regions, so this can lead
> to allocation of memory regions of very high order, i.e.:
>
> sizeof(struct sctp_stream_out) == 24,
> ((65535 * 24) / 4096) == 383 memory pages (4096 byte per page),
> which means 9th memory order.
>
> This can lead to a memory allocation failures on the systems
> under a memory stress.
>
> We actually do not need these arrays of memory to be physically
> contiguous. Possible simple solution would be to use kvmalloc()
> instread of kmalloc() as kvmalloc() can allocate physically scattered
> pages if contiguous pages are not available. But the problem
> is that the allocation can happed in a softirq context with
> GFP_ATOMIC flag set, and kvmalloc() cannot be used in this scenario.
>
> So the other possible solution is to use flexible arrays instead of
> contiguios arrays of memory so that the memory would be allocated
> on a per-page basis.
>
> This patchset replaces kvmalloc() with flex_array usage.
> It consists of two parts:
>
> * First patch is preparatory - it mechanically wraps all direct
> access to assoc->stream.out[] and assoc->stream.in[] arrays
> with SCTP_SO() and SCTP_SI() wrappers so that later a direct
> array access could be easily changed to an access to a
> flex_array (or any other possible alternative).
> * Second patch replaces kmalloc_array() with flex_array usage.
Looks good, series applied, thanks!
^ permalink raw reply
* Re: [PATCH net-next v2 00/15] Remove rtnl lock dependency from all action implementations
From: David Miller @ 2018-08-11 19:38 UTC (permalink / raw)
To: vladbu
Cc: netdev, jhs, xiyou.wangcong, jiri, pablo, kadlec, fw, ast, daniel,
edumazet, keescook, marcelo.leitner
In-Reply-To: <1533923515-5664-1-git-send-email-vladbu@mellanox.com>
From: Vlad Buslov <vladbu@mellanox.com>
Date: Fri, 10 Aug 2018 20:51:40 +0300
> The goal of this change is to update specific actions APIs that access
> action private state directly, in order to be independent from external
> locking. General approach is to re-use existing tcf_lock spinlock (used
> by some action implementation to synchronize control path with data
> path) to protect action private state from concurrent modification. If
> action has rcu-protected pointer, tcf spinlock is used to protect its
> update code, instead of relying on rtnl lock.
>
> Some actions need to determine rtnl mutex status in order to release it.
> For example, ife action can load additional kernel modules(meta ops) and
> must make sure that no locks are held during module load. In such cases
> 'rtnl_held' argument is used to conditionally release rtnl mutex.
...
I like these changes, nice work. If there are any bugs or whatever, we
can fix them on top.
Series applied to net-next, thanks.
^ permalink raw reply
* Re: [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling
From: David Miller @ 2018-08-11 19:19 UTC (permalink / raw)
To: g.nault; +Cc: netdev, jchapman
In-Reply-To: <cover.1533895306.git.g.nault@alphalink.fr>
From: Guillaume Nault <g.nault@alphalink.fr>
Date: Fri, 10 Aug 2018 13:21:54 +0200
> The current ioctl() handling code can be simplified. It tests for
> non-relevant conditions and uselessly holds sockets. Once useless
> code is removed, it becomes even simpler to let pppol2tp_ioctl() handle
> commands directly, rather than dispatch them to pppol2tp_tunnel_ioctl()
> or pppol2tp_session_ioctl(). That is the approach taken by this series.
>
> Patch #1 and #2 define helper functions aimed at simplifying the rest
> of the patch set.
>
> Patch #3 drops useless tests in pppol2p_ioctl() and avoid holding a
> refcount on the socket.
>
> Patches #4, #5 and #6 are the core of the series. They let
> pppol2tp_ioctl() handle all ioctls and drop the tunnel and session
> specific functions.
>
> Then patch #6 brings a little bit of consolidation.
>
> Finally, patch #7 takes advantage of the simplified code to make
> pppol2tp sockets compatible with dev_ioctl(). Certainly not a killer
> feature, but it is trivial and it is always nice to see l2tp getting
> better integration with the rest of the stack.
Very nice cleanups.
Let's leave the -ENOSYS stuff there for now, changing error return
codes seems to always break something :-/
Series applied, thanks!
^ permalink raw reply
* Re: [PATCH v1 net-next] lan743x: lan743x: Add PTP support
From: Richard Cochran @ 2018-08-11 19:28 UTC (permalink / raw)
To: Bryan Whitehead; +Cc: davem, netdev, UNGLinuxDriver
In-Reply-To: <1533843370-26315-1-git-send-email-Bryan.Whitehead@microchip.com>
On Thu, Aug 09, 2018 at 03:36:10PM -0400, Bryan Whitehead wrote:
> +static int lan743x_ptpci_adjfine(struct ptp_clock_info *ptpci, long scaled_ppm)
> +{
> + struct lan743x_ptp *ptp =
> + container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
> + struct lan743x_adapter *adapter =
> + container_of(ptp, struct lan743x_adapter, ptp);
> + u32 lan743x_rate_adj = 0;
> + bool positive = true;
> + u64 u64_delta = 0;
> +
> + if ((scaled_ppm < (-LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM)) ||
> + scaled_ppm > LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM) {
> + return -EINVAL;
Maybe ERANGE is better here.
> + }
> + if (scaled_ppm > 0) {
> + u64_delta = (u64)scaled_ppm;
> + positive = true;
> + } else {
> + u64_delta = (u64)(-scaled_ppm);
> + positive = false;
> + }
> + u64_delta = (u64_delta << 19);
> + lan743x_rate_adj = div_u64(u64_delta, 1000000);
> +
> + if (positive)
> + lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_;
> +
> + lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ,
> + lan743x_rate_adj);
> +
> + return 0;
> +}
> +
> +static int lan743x_ptpci_adjfreq(struct ptp_clock_info *ptpci, s32 delta_ppb)
> +{
Since you have adjfine, you can delete adjfreq. The core PTP code
does this in ptp_clock.c:
if (ops->adjfine)
err = ops->adjfine(ops, tx->freq);
else
err = ops->adjfreq(ops, ppb);
Thanks,
Richard
^ permalink raw reply
* Re: [PATCH net-next 0/4] new mechanism to ACK immediately
From: David Miller @ 2018-08-11 18:41 UTC (permalink / raw)
To: ycheng; +Cc: edumazet, netdev, ncardwell, brakmo, weiwan
In-Reply-To: <20180809163812.58365-1-ycheng@google.com>
From: Yuchung Cheng <ycheng@google.com>
Date: Thu, 9 Aug 2018 09:38:08 -0700
> This patch is a follow-up feature improvement to the recent fixes on
> the performance issues in ECN (delayed) ACKs. Many of the fixes use
> tcp_enter_quickack_mode routine to force immediate ACKs. However the
> routine also reset tracking interactive session. This is not ideal
> because these immediate ACKs are required by protocol specifics
> unrelated to the interactiveness nature of the application.
>
> This patch set introduces a new flag to send a one-time immediate ACK
> without changing the status of interactive session tracking. With this
> patch set the immediate ACKs are generated upon these protocol states:
>
> 1) When a hole is repaired
> 2) When CE status changes between subsequent data packets received
> 3) When a data packet carries CWR flag
This looks really nice, series applied.
Thanks!
^ permalink raw reply
* Re: [PATCH net-next 1/2] ip: add helpers to process in-order fragments faster.
From: David Miller @ 2018-08-11 19:22 UTC (permalink / raw)
To: posk; +Cc: netdev, edumazet, fw
In-Reply-To: <20180810162246.46805-1-posk@google.com>
From: Peter Oskolkov <posk@google.com>
Date: Fri, 10 Aug 2018 16:22:45 +0000
> This patch introduces several helper functions/macros that will be
> used in the follow-up patch. No runtime changes yet.
>
> The new logic (fully implemented in the second patch) is as follows:
>
> * Nodes in the rb-tree will now contain not single fragments, but lists
> of consecutive fragments ("runs").
>
> * At each point in time, the current "active" run at the tail is
> maintained/tracked. Fragments that arrive in-order, adjacent
> to the previous tail fragment, are added to this tail run without
> triggering the re-balancing of the rb-tree.
>
> * If a fragment arrives out of order with the offset _before_ the tail run,
> it is inserted into the rb-tree as a single fragment.
>
> * If a fragment arrives after the current tail fragment (with a gap),
> it starts a new "tail" run, as is inserted into the rb-tree
> at the end as the head of the new run.
>
> skb->cb is used to store additional information
> needed here (suggested by Eric Dumazet).
>
> Reported-by: Willem de Bruijn <willemb@google.com>
> Cc: Eric Dumazet <edumazet@google.com>
> Cc: Cc: Florian Westphal <fw@strlen.de>
You need to post these changes with proper Signed-off-by: tags.
^ permalink raw reply
* Re: [PATCH net-next 1/1] tc: Update README and add config
From: David Miller @ 2018-08-11 19:21 UTC (permalink / raw)
To: kleib; +Cc: netdev, jhs, xiyou.wangcong, jiri, lucasb
In-Reply-To: <1533910181-17214-1-git-send-email-kleib@mojatatu.com>
From: Keara Leibovitz <kleib@mojatatu.com>
Date: Fri, 10 Aug 2018 10:09:41 -0400
> Updated README.
>
> Added config file that contains the minimum required features enabled to
> run the tests currently present in the kernel.
> This must be updated when new unittests are created and require their own
> modules.
>
> Signed-off-by: Keara Leibovitz <kleib@mojatatu.com>
Applied, thank you.
^ permalink raw reply
* Re: [PATCH v1 net-next] lan743x: lan743x: Add PTP support
From: David Miller @ 2018-08-11 18:47 UTC (permalink / raw)
To: Bryan.Whitehead; +Cc: netdev, UNGLinuxDriver, richardcochran
In-Reply-To: <1533843370-26315-1-git-send-email-Bryan.Whitehead@microchip.com>
From: Bryan Whitehead <Bryan.Whitehead@microchip.com>
Date: Thu, 9 Aug 2018 15:36:10 -0400
> PTP support includes:
> Ingress, and egress timestamping.
> One step timestamping available.
> PTP clock support.
> Periodic output support.
>
> Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
Applied to net-next, thank you.
^ permalink raw reply
* Re: [PATCH net-next,v4] net/tls: Calculate nsg for zerocopy path without skb_cow_data.
From: David Miller @ 2018-08-11 18:54 UTC (permalink / raw)
To: doronrk; +Cc: davejwatson, vakul.garg, borisp, aviadye, netdev
In-Reply-To: <20180809224344.GA48089@doronrk-mbp.dhcp.thefacebook.com>
From: Doron Roberts-Kedes <doronrk@fb.com>
Date: Thu, 9 Aug 2018 15:43:44 -0700
> Taking a step back, is there an existing solution for what this function
> is trying to do? I was surprised to find that there did not seem to
> exist a function for determining the number of scatterlist elements
> required to map an skb without COW.
The reason is that we usually never need to "map" an SKB on receive,
and on transmit the SKB geometry is normalized by the destination
device features which means no frag_list.
And the other existing receive path doing SW crypto, IPSEC, always
COWs the data so get the number of SG array entries needed from
skb_cow_data().
Frag lists on RX should be pretty rare. They occur when GRO
segmentation encouters poorly arranged incoming SKBs. For example
this happens if the incoming frames use lots of tiny SKB page frags,
and therefore prevent accumulation into the page frag array of the
head GRO skb.
So yes it can happen, and we have to account for it.
So I guess you really do need to accomodate this situation. Why
don't you try to rearrange your new function with some likely()
and unlikely() tests so that the straight code path optimizes for
the non-frag-list case?
Thanks!
^ permalink raw reply
* Re: [PATCH v2 net-next 0/2] virtio_net: Expand affinity to arbitrary numbers of cpu and vq
From: David Miller @ 2018-08-11 19:03 UTC (permalink / raw)
To: caleb.raitto
Cc: herbert, mst, arei.gonglei, jasowang, netdev, linux-crypto,
caraitto
In-Reply-To: <20180810011828.199888-1-caleb.raitto@gmail.com>
From: Caleb Raitto <caleb.raitto@gmail.com>
Date: Thu, 9 Aug 2018 18:18:27 -0700
> Virtio-net tries to pin each virtual queue rx and tx interrupt to a cpu if
> there are as many queues as cpus.
>
> Expand this heuristic to configure a reasonable affinity setting also
> when the number of cpus != the number of virtual queues.
>
> Patch 1 allows vqs to take an affinity mask with more than 1 cpu.
> Patch 2 generalizes the algorithm in virtnet_set_affinity beyond
> the case where #cpus == #vqs.
>
> v2 changes:
> Renamed "virtio_net: Make vp_set_vq_affinity() take a mask." to
> "virtio: Make vp_set_vq_affinity() take a mask."
>
> Tested:
...
Yes, this is so much better than the NAPI module parameter thing!
I'll apply this, and we can adjust/tweak the logic if necessary
on top of these changes.
Thanks!
^ permalink raw reply
* Re: [PATCH 0/2] net/sched: Add hardware specific counters to TC actions
From: David Miller @ 2018-08-11 19:06 UTC (permalink / raw)
To: jakub.kicinski; +Cc: echaudro, netdev, jhs, xiyou.wangcong, jiri, simon.horman
In-Reply-To: <20180809202608.6b816326@cakuba.netronome.com>
From: Jakub Kicinski <jakub.kicinski@netronome.com>
Date: Thu, 9 Aug 2018 20:26:08 -0700
> It is not immediately clear why this is needed. The memory and
> updating two sets of counters won't come for free, so perhaps a
> stronger justification than troubleshooting is due? :S
>
> Netdev has counters for fallback vs forwarded traffic, so you'd know
> that traffic hits the SW datapath, plus the rules which are in_hw will
> most likely not match as of today for flower (assuming correctness).
>
> I'm slightly concerned about potential performance impact, would you
> be able to share some numbers for non-trivial number of flows (100k
> active?)?
Agreed, features used for diagnostics cannot have a harmful penalty for
fast path performance.
^ permalink raw reply
* [PATCH net-next v2 0/2] ip: faster in-order IP fragments
From: Peter Oskolkov @ 2018-08-11 20:27 UTC (permalink / raw)
To: David Miller, netdev; +Cc: Peter Oskolkov
Added "Signed-off-by" in v2.
Peter Oskolkov (2):
ip: add helpers to process in-order fragments faster.
ip: process in-order fragments efficiently
include/net/inet_frag.h | 6 ++
net/ipv4/inet_fragment.c | 2 +-
net/ipv4/ip_fragment.c | 183 ++++++++++++++++++++++++++++++---------
3 files changed, 149 insertions(+), 42 deletions(-)
--
2.18.0.597.ga71716f1ad-goog
^ permalink raw reply
* [PATCH net-next v2 1/2] ip: add helpers to process in-order fragments faster.
From: Peter Oskolkov @ 2018-08-11 20:27 UTC (permalink / raw)
To: David Miller, netdev; +Cc: Peter Oskolkov, Eric Dumazet, Florian Westphal
In-Reply-To: <20180811202725.242498-1-posk@google.com>
This patch introduces several helper functions/macros that will be
used in the follow-up patch. No runtime changes yet.
The new logic (fully implemented in the second patch) is as follows:
* Nodes in the rb-tree will now contain not single fragments, but lists
of consecutive fragments ("runs").
* At each point in time, the current "active" run at the tail is
maintained/tracked. Fragments that arrive in-order, adjacent
to the previous tail fragment, are added to this tail run without
triggering the re-balancing of the rb-tree.
* If a fragment arrives out of order with the offset _before_ the tail run,
it is inserted into the rb-tree as a single fragment.
* If a fragment arrives after the current tail fragment (with a gap),
it starts a new "tail" run, as is inserted into the rb-tree
at the end as the head of the new run.
skb->cb is used to store additional information
needed here (suggested by Eric Dumazet).
Reported-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Peter Oskolkov <posk@google.com>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Florian Westphal <fw@strlen.de>
---
include/net/inet_frag.h | 6 ++++
net/ipv4/ip_fragment.c | 73 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 79 insertions(+)
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index b86d14528188..1662cbc0b46b 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -57,7 +57,9 @@ struct frag_v6_compare_key {
* @lock: spinlock protecting this frag
* @refcnt: reference count of the queue
* @fragments: received fragments head
+ * @rb_fragments: received fragments rb-tree root
* @fragments_tail: received fragments tail
+ * @last_run_head: the head of the last "run". see ip_fragment.c
* @stamp: timestamp of the last received fragment
* @len: total length of the original datagram
* @meat: length of received fragments so far
@@ -78,6 +80,7 @@ struct inet_frag_queue {
struct sk_buff *fragments; /* Used in IPv6. */
struct rb_root rb_fragments; /* Used in IPv4. */
struct sk_buff *fragments_tail;
+ struct sk_buff *last_run_head;
ktime_t stamp;
int len;
int meat;
@@ -113,6 +116,9 @@ void inet_frag_kill(struct inet_frag_queue *q);
void inet_frag_destroy(struct inet_frag_queue *q);
struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, void *key);
+/* Free all skbs in the queue; return the sum of their truesizes. */
+unsigned int inet_frag_rbtree_purge(struct rb_root *root);
+
static inline void inet_frag_put(struct inet_frag_queue *q)
{
if (refcount_dec_and_test(&q->refcnt))
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 7cb7ed761d8c..26ace9d2d976 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -57,6 +57,57 @@
*/
static const char ip_frag_cache_name[] = "ip4-frags";
+/* Use skb->cb to track consecutive/adjacent fragments coming at
+ * the end of the queue. Nodes in the rb-tree queue will
+ * contain "runs" of one or more adjacent fragments.
+ *
+ * Invariants:
+ * - next_frag is NULL at the tail of a "run";
+ * - the head of a "run" has the sum of all fragment lengths in frag_run_len.
+ */
+struct ipfrag_skb_cb {
+ struct inet_skb_parm h;
+ struct sk_buff *next_frag;
+ int frag_run_len;
+};
+
+#define FRAG_CB(skb) ((struct ipfrag_skb_cb *)((skb)->cb))
+
+static void ip4_frag_init_run(struct sk_buff *skb)
+{
+ BUILD_BUG_ON(sizeof(struct ipfrag_skb_cb) > sizeof(skb->cb));
+
+ FRAG_CB(skb)->next_frag = NULL;
+ FRAG_CB(skb)->frag_run_len = skb->len;
+}
+
+/* Append skb to the last "run". */
+static void ip4_frag_append_to_last_run(struct inet_frag_queue *q,
+ struct sk_buff *skb)
+{
+ RB_CLEAR_NODE(&skb->rbnode);
+ FRAG_CB(skb)->next_frag = NULL;
+
+ FRAG_CB(q->last_run_head)->frag_run_len += skb->len;
+ FRAG_CB(q->fragments_tail)->next_frag = skb;
+ q->fragments_tail = skb;
+}
+
+/* Create a new "run" with the skb. */
+static void ip4_frag_create_run(struct inet_frag_queue *q, struct sk_buff *skb)
+{
+ if (q->last_run_head)
+ rb_link_node(&skb->rbnode, &q->last_run_head->rbnode,
+ &q->last_run_head->rbnode.rb_right);
+ else
+ rb_link_node(&skb->rbnode, NULL, &q->rb_fragments.rb_node);
+ rb_insert_color(&skb->rbnode, &q->rb_fragments);
+
+ ip4_frag_init_run(skb);
+ q->fragments_tail = skb;
+ q->last_run_head = skb;
+}
+
/* Describe an entry in the "incomplete datagrams" queue. */
struct ipq {
struct inet_frag_queue q;
@@ -654,6 +705,28 @@ struct sk_buff *ip_check_defrag(struct net *net, struct sk_buff *skb, u32 user)
}
EXPORT_SYMBOL(ip_check_defrag);
+unsigned int inet_frag_rbtree_purge(struct rb_root *root)
+{
+ struct rb_node *p = rb_first(root);
+ unsigned int sum = 0;
+
+ while (p) {
+ struct sk_buff *skb = rb_entry(p, struct sk_buff, rbnode);
+
+ p = rb_next(p);
+ rb_erase(&skb->rbnode, root);
+ while (skb) {
+ struct sk_buff *next = FRAG_CB(skb)->next_frag;
+
+ sum += skb->truesize;
+ kfree_skb(skb);
+ skb = next;
+ }
+ }
+ return sum;
+}
+EXPORT_SYMBOL(inet_frag_rbtree_purge);
+
#ifdef CONFIG_SYSCTL
static int dist_min;
--
2.18.0.597.ga71716f1ad-goog
^ permalink raw reply related
* [PATCH net-next v2 2/2] ip: process in-order fragments efficiently
From: Peter Oskolkov @ 2018-08-11 20:27 UTC (permalink / raw)
To: David Miller, netdev; +Cc: Peter Oskolkov, Eric Dumazet, Florian Westphal
In-Reply-To: <20180811202725.242498-1-posk@google.com>
This patch changes the runtime behavior of IP defrag queue:
incoming in-order fragments are added to the end of the current
list/"run" of in-order fragments at the tail.
On some workloads, UDP stream performance is substantially improved:
RX: ./udp_stream -F 10 -T 2 -l 60
TX: ./udp_stream -c -H <host> -F 10 -T 5 -l 60
with this patchset applied on a 10Gbps receiver:
throughput=9524.18
throughput_units=Mbit/s
upstream (net-next):
throughput=4608.93
throughput_units=Mbit/s
Reported-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Peter Oskolkov <posk@google.com>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Florian Westphal <fw@strlen.de>
---
net/ipv4/inet_fragment.c | 2 +-
net/ipv4/ip_fragment.c | 110 ++++++++++++++++++++++++---------------
2 files changed, 70 insertions(+), 42 deletions(-)
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 6d258a5669e7..bcb11f3a27c0 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -146,7 +146,7 @@ void inet_frag_destroy(struct inet_frag_queue *q)
fp = xp;
} while (fp);
} else {
- sum_truesize = skb_rbtree_purge(&q->rb_fragments);
+ sum_truesize = inet_frag_rbtree_purge(&q->rb_fragments);
}
sum = sum_truesize + f->qsize;
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 26ace9d2d976..88281fbce88c 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -126,8 +126,8 @@ static u8 ip4_frag_ecn(u8 tos)
static struct inet_frags ip4_frags;
-static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
- struct net_device *dev);
+static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
+ struct sk_buff *prev_tail, struct net_device *dev);
static void ip4_frag_init(struct inet_frag_queue *q, const void *a)
@@ -219,7 +219,12 @@ static void ip_expire(struct timer_list *t)
head = skb_rb_first(&qp->q.rb_fragments);
if (!head)
goto out;
- rb_erase(&head->rbnode, &qp->q.rb_fragments);
+ if (FRAG_CB(head)->next_frag)
+ rb_replace_node(&head->rbnode,
+ &FRAG_CB(head)->next_frag->rbnode,
+ &qp->q.rb_fragments);
+ else
+ rb_erase(&head->rbnode, &qp->q.rb_fragments);
memset(&head->rbnode, 0, sizeof(head->rbnode));
barrier();
}
@@ -320,7 +325,7 @@ static int ip_frag_reinit(struct ipq *qp)
return -ETIMEDOUT;
}
- sum_truesize = skb_rbtree_purge(&qp->q.rb_fragments);
+ sum_truesize = inet_frag_rbtree_purge(&qp->q.rb_fragments);
sub_frag_mem_limit(qp->q.net, sum_truesize);
qp->q.flags = 0;
@@ -329,6 +334,7 @@ static int ip_frag_reinit(struct ipq *qp)
qp->q.fragments = NULL;
qp->q.rb_fragments = RB_ROOT;
qp->q.fragments_tail = NULL;
+ qp->q.last_run_head = NULL;
qp->iif = 0;
qp->ecn = 0;
@@ -340,7 +346,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
{
struct net *net = container_of(qp->q.net, struct net, ipv4.frags);
struct rb_node **rbn, *parent;
- struct sk_buff *skb1;
+ struct sk_buff *skb1, *prev_tail;
struct net_device *dev;
unsigned int fragsize;
int flags, offset;
@@ -418,38 +424,41 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
*/
/* Find out where to put this fragment. */
- skb1 = qp->q.fragments_tail;
- if (!skb1) {
- /* This is the first fragment we've received. */
- rb_link_node(&skb->rbnode, NULL, &qp->q.rb_fragments.rb_node);
- qp->q.fragments_tail = skb;
- } else if ((skb1->ip_defrag_offset + skb1->len) < end) {
- /* This is the common/special case: skb goes to the end. */
+ prev_tail = qp->q.fragments_tail;
+ if (!prev_tail)
+ ip4_frag_create_run(&qp->q, skb); /* First fragment. */
+ else if (prev_tail->ip_defrag_offset + prev_tail->len < end) {
+ /* This is the common case: skb goes to the end. */
/* Detect and discard overlaps. */
- if (offset < (skb1->ip_defrag_offset + skb1->len))
+ if (offset < prev_tail->ip_defrag_offset + prev_tail->len)
goto discard_qp;
- /* Insert after skb1. */
- rb_link_node(&skb->rbnode, &skb1->rbnode, &skb1->rbnode.rb_right);
- qp->q.fragments_tail = skb;
+ if (offset == prev_tail->ip_defrag_offset + prev_tail->len)
+ ip4_frag_append_to_last_run(&qp->q, skb);
+ else
+ ip4_frag_create_run(&qp->q, skb);
} else {
- /* Binary search. Note that skb can become the first fragment, but
- * not the last (covered above). */
+ /* Binary search. Note that skb can become the first fragment,
+ * but not the last (covered above).
+ */
rbn = &qp->q.rb_fragments.rb_node;
do {
parent = *rbn;
skb1 = rb_to_skb(parent);
if (end <= skb1->ip_defrag_offset)
rbn = &parent->rb_left;
- else if (offset >= skb1->ip_defrag_offset + skb1->len)
+ else if (offset >= skb1->ip_defrag_offset +
+ FRAG_CB(skb1)->frag_run_len)
rbn = &parent->rb_right;
else /* Found an overlap with skb1. */
goto discard_qp;
} while (*rbn);
/* Here we have parent properly set, and rbn pointing to
- * one of its NULL left/right children. Insert skb. */
+ * one of its NULL left/right children. Insert skb.
+ */
+ ip4_frag_init_run(skb);
rb_link_node(&skb->rbnode, parent, rbn);
+ rb_insert_color(&skb->rbnode, &qp->q.rb_fragments);
}
- rb_insert_color(&skb->rbnode, &qp->q.rb_fragments);
if (dev)
qp->iif = dev->ifindex;
@@ -476,7 +485,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
unsigned long orefdst = skb->_skb_refdst;
skb->_skb_refdst = 0UL;
- err = ip_frag_reasm(qp, skb, dev);
+ err = ip_frag_reasm(qp, skb, prev_tail, dev);
skb->_skb_refdst = orefdst;
return err;
}
@@ -495,7 +504,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
/* Build a new IP datagram from all its fragments. */
static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
- struct net_device *dev)
+ struct sk_buff *prev_tail, struct net_device *dev)
{
struct net *net = container_of(qp->q.net, struct net, ipv4.frags);
struct iphdr *iph;
@@ -519,10 +528,16 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
fp = skb_clone(skb, GFP_ATOMIC);
if (!fp)
goto out_nomem;
- rb_replace_node(&skb->rbnode, &fp->rbnode, &qp->q.rb_fragments);
+ FRAG_CB(fp)->next_frag = FRAG_CB(skb)->next_frag;
+ if (RB_EMPTY_NODE(&skb->rbnode))
+ FRAG_CB(prev_tail)->next_frag = fp;
+ else
+ rb_replace_node(&skb->rbnode, &fp->rbnode,
+ &qp->q.rb_fragments);
if (qp->q.fragments_tail == skb)
qp->q.fragments_tail = fp;
skb_morph(skb, head);
+ FRAG_CB(skb)->next_frag = FRAG_CB(head)->next_frag;
rb_replace_node(&head->rbnode, &skb->rbnode,
&qp->q.rb_fragments);
consume_skb(head);
@@ -558,7 +573,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
for (i = 0; i < skb_shinfo(head)->nr_frags; i++)
plen += skb_frag_size(&skb_shinfo(head)->frags[i]);
clone->len = clone->data_len = head->data_len - plen;
- skb->truesize += clone->truesize;
+ head->truesize += clone->truesize;
clone->csum = 0;
clone->ip_summed = head->ip_summed;
add_frag_mem_limit(qp->q.net, clone->truesize);
@@ -571,24 +586,36 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
skb_push(head, head->data - skb_network_header(head));
/* Traverse the tree in order, to build frag_list. */
+ fp = FRAG_CB(head)->next_frag;
rbn = rb_next(&head->rbnode);
rb_erase(&head->rbnode, &qp->q.rb_fragments);
- while (rbn) {
- struct rb_node *rbnext = rb_next(rbn);
- fp = rb_to_skb(rbn);
- rb_erase(rbn, &qp->q.rb_fragments);
- rbn = rbnext;
- *nextp = fp;
- nextp = &fp->next;
- fp->prev = NULL;
- memset(&fp->rbnode, 0, sizeof(fp->rbnode));
- head->data_len += fp->len;
- head->len += fp->len;
- if (head->ip_summed != fp->ip_summed)
- head->ip_summed = CHECKSUM_NONE;
- else if (head->ip_summed == CHECKSUM_COMPLETE)
- head->csum = csum_add(head->csum, fp->csum);
- head->truesize += fp->truesize;
+ while (rbn || fp) {
+ /* fp points to the next sk_buff in the current run;
+ * rbn points to the next run.
+ */
+ /* Go through the current run. */
+ while (fp) {
+ *nextp = fp;
+ nextp = &fp->next;
+ fp->prev = NULL;
+ memset(&fp->rbnode, 0, sizeof(fp->rbnode));
+ head->data_len += fp->len;
+ head->len += fp->len;
+ if (head->ip_summed != fp->ip_summed)
+ head->ip_summed = CHECKSUM_NONE;
+ else if (head->ip_summed == CHECKSUM_COMPLETE)
+ head->csum = csum_add(head->csum, fp->csum);
+ head->truesize += fp->truesize;
+ fp = FRAG_CB(fp)->next_frag;
+ }
+ /* Move to the next run. */
+ if (rbn) {
+ struct rb_node *rbnext = rb_next(rbn);
+
+ fp = rb_to_skb(rbn);
+ rb_erase(rbn, &qp->q.rb_fragments);
+ rbn = rbnext;
+ }
}
sub_frag_mem_limit(qp->q.net, head->truesize);
@@ -624,6 +651,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
qp->q.fragments = NULL;
qp->q.rb_fragments = RB_ROOT;
qp->q.fragments_tail = NULL;
+ qp->q.last_run_head = NULL;
return 0;
out_nomem:
--
2.18.0.597.ga71716f1ad-goog
^ permalink raw reply related
* [GIT] Networking
From: David Miller @ 2018-08-11 18:20 UTC (permalink / raw)
To: torvalds; +Cc: akpm, netdev, linux-kernel
Last bit of straggler fixes...
1) Fix btf library licensing to LGPL, from Martin KaFai lau.
2) Fix error handling in bpf sockmap code, from Daniel Borkmann.
3) XDP cpumap teardown handling wrt. execution contexts, from
Jesper Dangaard Brouer.
4) Fix loss of runtime PM on failed vlan add/del, from Ivan
Khoronzhuk.
5) xen-netfront caches skb_shinfo(skb) across a __pskb_pull_tail()
call, which potentially changes the skb's data buffer, and thus
skb_shinfo(). Fix from Juergen Gross.
Please pull, thanks a lot!
The following changes since commit 112cbae26d18e75098d95cc234cfa5059de8d479:
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6 (2018-08-09 10:00:15 -0700)
are available in the Git repository at:
gitolite@ra.kernel.org:/pub/scm/linux/kernel/git/davem/net.git
for you to fetch changes up to d472b3a6cf63cd31cae1ed61930f07e6cd6671b5:
xen/netfront: don't cache skb_shinfo() (2018-08-11 09:41:58 -0700)
----------------------------------------------------------------
Alexei Starovoitov (1):
Merge branch 'sockmap-fixes'
Daniel Borkmann (4):
bpf, sockmap: fix bpf_tcp_sendmsg sock error handling
bpf, sockmap: fix leak in bpf_tcp_sendmsg wait for mem path
bpf, sockmap: fix cork timeout for select due to epipe
Merge branch 'bpf-fix-cpu-and-devmap-teardown'
David S. Miller (2):
Merge git://git.kernel.org/.../bpf/bpf
Merge branch 'cpsw-runtime-pm-fix'
Ivan Khoronzhuk (2):
net: ethernet: ti: cpsw: clear all entries when delete vid
net: ethernet: ti: cpsw: fix runtime_pm while add/kill vlan
Jesper Dangaard Brouer (3):
xdp: fix bug in cpumap teardown code path
samples/bpf: xdp_redirect_cpu adjustment to reproduce teardown race easier
xdp: fix bug in devmap teardown code path
Juergen Gross (1):
xen/netfront: don't cache skb_shinfo()
Martin KaFai Lau (1):
bpf: btf: Change tools/lib/bpf/btf to LGPL
drivers/net/ethernet/ti/cpsw.c | 25 +++++++++++--------------
drivers/net/ethernet/ti/cpsw_ale.c | 2 +-
drivers/net/xen-netfront.c | 8 ++++----
kernel/bpf/cpumap.c | 15 +++++++++------
kernel/bpf/devmap.c | 14 +++++++++-----
kernel/bpf/sockmap.c | 9 ++++++---
samples/bpf/xdp_redirect_cpu_kern.c | 2 +-
samples/bpf/xdp_redirect_cpu_user.c | 4 ++--
tools/lib/bpf/btf.c | 2 +-
tools/lib/bpf/btf.h | 2 +-
tools/testing/selftests/bpf/test_sockmap.c | 2 +-
11 files changed, 46 insertions(+), 39 deletions(-)
^ permalink raw reply
* Re: [PATCH net-next] rds: avoid lock hierarchy violation between m_rs_lock and rs_recv_lock
From: David Miller @ 2018-08-11 18:22 UTC (permalink / raw)
To: sowmini.varadhan; +Cc: netdev, rds-devel, santosh.shilimkar
In-Reply-To: <1533761833-106379-1-git-send-email-sowmini.varadhan@oracle.com>
From: Sowmini Varadhan <sowmini.varadhan@oracle.com>
Date: Wed, 8 Aug 2018 13:57:13 -0700
> The following deadlock, reported by syzbot, can occur if CPU0 is in
> rds_send_remove_from_sock() while CPU1 is in rds_clear_recv_queue()
>
> CPU0 CPU1
> ---- ----
> lock(&(&rm->m_rs_lock)->rlock);
> lock(&rs->rs_recv_lock);
> lock(&(&rm->m_rs_lock)->rlock);
> lock(&rs->rs_recv_lock);
>
> The deadlock should be avoided by moving the messages from the
> rs_recv_queue into a tmp_list in rds_clear_recv_queue() under
> the rs_recv_lock, and then dropping the refcnt on the messages
> in the tmp_list (potentially resulting in rds_message_purge())
> after dropping the rs_recv_lock.
>
> The same lock hierarchy violation also exists in rds_still_queued()
> and should be avoided in a similar manner
>
> Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
> Reported-by: syzbot+52140d69ac6dc6b927a9@syzkaller.appspotmail.com
I'm putting this in deferred state for now.
Sowmini, once you and Santosh agree on what exactly to do, please
resubmit.
Thank you.
^ permalink raw reply
* [net-next:master 540/547] drivers/net/ethernet/microchip/lan743x_ethtool.c:558:18: error: 'struct lan743x_ptp' has no member named 'ptp_clock'; did you mean 'tx_ts_lock'?
From: kbuild test robot @ 2018-08-11 22:18 UTC (permalink / raw)
To: Bryan Whitehead; +Cc: kbuild-all, netdev
[-- Attachment #1: Type: text/plain, Size: 3064 bytes --]
tree: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master
head: 9a95d9c6429bb58905fdfc95da2e1b7cc3fb55b7
commit: 07624df1c9efd4b7f2f6762581587c590b03c7a2 [540/547] lan743x: lan743x: Add PTP support
config: x86_64-randconfig-ne0-08120429 (attached as .config)
compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026
reproduce:
git checkout 07624df1c9efd4b7f2f6762581587c590b03c7a2
# save the attached .config to linux build tree
make ARCH=x86_64
All errors (new ones prefixed by >>):
drivers/net/ethernet/microchip/lan743x_ethtool.c: In function 'lan743x_ethtool_get_ts_info':
>> drivers/net/ethernet/microchip/lan743x_ethtool.c:558:18: error: 'struct lan743x_ptp' has no member named 'ptp_clock'; did you mean 'tx_ts_lock'?
if (adapter->ptp.ptp_clock)
^
drivers/net/ethernet/microchip/lan743x_ethtool.c:559:52: error: 'struct lan743x_ptp' has no member named 'ptp_clock'; did you mean 'tx_ts_lock'?
ts_info->phc_index = ptp_clock_index(adapter->ptp.ptp_clock);
^
--
drivers/net/ethernet/microchip/lan743x_ptp.c: In function 'lan743x_ptp_isr':
>> drivers/net/ethernet/microchip/lan743x_ptp.c:781:26: error: 'struct lan743x_ptp' has no member named 'ptp_clock'; did you mean 'tx_ts_lock'?
ptp_schedule_worker(ptp->ptp_clock, 0);
^~
drivers/net/ethernet/microchip/lan743x_ptp.c: In function 'lan743x_ptp_open':
drivers/net/ethernet/microchip/lan743x_ptp.c:879:6: warning: unused variable 'ret' [-Wunused-variable]
int ret = -ENODEV;
^~~
At top level:
drivers/net/ethernet/microchip/lan743x_ptp.c:63:13: warning: 'lan743x_ptp_tx_ts_enqueue_ts' defined but not used [-Wunused-function]
static void lan743x_ptp_tx_ts_enqueue_ts(struct lan743x_adapter *adapter,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +558 drivers/net/ethernet/microchip/lan743x_ethtool.c
545
546 static int lan743x_ethtool_get_ts_info(struct net_device *netdev,
547 struct ethtool_ts_info *ts_info)
548 {
549 struct lan743x_adapter *adapter = netdev_priv(netdev);
550
551 ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
552 SOF_TIMESTAMPING_RX_SOFTWARE |
553 SOF_TIMESTAMPING_SOFTWARE |
554 SOF_TIMESTAMPING_TX_HARDWARE |
555 SOF_TIMESTAMPING_RX_HARDWARE |
556 SOF_TIMESTAMPING_RAW_HARDWARE;
557
> 558 if (adapter->ptp.ptp_clock)
559 ts_info->phc_index = ptp_clock_index(adapter->ptp.ptp_clock);
560 else
561 ts_info->phc_index = -1;
562
563 ts_info->tx_types = BIT(HWTSTAMP_TX_OFF) |
564 BIT(HWTSTAMP_TX_ON) |
565 BIT(HWTSTAMP_TX_ONESTEP_SYNC);
566 ts_info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
567 BIT(HWTSTAMP_FILTER_ALL);
568 return 0;
569 }
570
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 29434 bytes --]
^ permalink raw reply
* [net-next:master 1999/2033] drivers/net/virtio_net.c:1916:10: error: implicit declaration of function 'cpumask_next_wrap'
From: kbuild test robot @ 2018-08-11 22:29 UTC (permalink / raw)
To: Caleb Raitto; +Cc: kbuild-all, netdev, Willem de Bruijn
[-- Attachment #1: Type: text/plain, Size: 2336 bytes --]
tree: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master
head: 9a95d9c6429bb58905fdfc95da2e1b7cc3fb55b7
commit: 2ca653d607ce59f2729173a7ea56dbfa6330ec88 [1999/2033] virtio_net: Stripe queue affinities across cores.
config: x86_64-randconfig-s1-08120449 (attached as .config)
compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026
reproduce:
git checkout 2ca653d607ce59f2729173a7ea56dbfa6330ec88
# save the attached .config to linux build tree
make ARCH=x86_64
All errors (new ones prefixed by >>):
drivers/net/virtio_net.c: In function 'virtnet_set_affinity':
>> drivers/net/virtio_net.c:1916:10: error: implicit declaration of function 'cpumask_next_wrap' [-Werror=implicit-function-declaration]
cpu = cpumask_next_wrap(cpu, cpu_online_mask,
^~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/cpumask_next_wrap +1916 drivers/net/virtio_net.c
1889
1890 static void virtnet_set_affinity(struct virtnet_info *vi)
1891 {
1892 cpumask_var_t mask;
1893 int stragglers;
1894 int group_size;
1895 int i, j, cpu;
1896 int num_cpu;
1897 int stride;
1898
1899 if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
1900 virtnet_clean_affinity(vi, -1);
1901 return;
1902 }
1903
1904 num_cpu = num_online_cpus();
1905 stride = max_t(int, num_cpu / vi->curr_queue_pairs, 1);
1906 stragglers = num_cpu >= vi->curr_queue_pairs ?
1907 num_cpu % vi->curr_queue_pairs :
1908 0;
1909 cpu = cpumask_next(-1, cpu_online_mask);
1910
1911 for (i = 0; i < vi->curr_queue_pairs; i++) {
1912 group_size = stride + (i < stragglers ? 1 : 0);
1913
1914 for (j = 0; j < group_size; j++) {
1915 cpumask_set_cpu(cpu, mask);
> 1916 cpu = cpumask_next_wrap(cpu, cpu_online_mask,
1917 nr_cpu_ids, false);
1918 }
1919 virtqueue_set_affinity(vi->rq[i].vq, mask);
1920 virtqueue_set_affinity(vi->sq[i].vq, mask);
1921 __netif_set_xps_queue(vi->dev, cpumask_bits(mask), i, false);
1922 cpumask_clear(mask);
1923 }
1924
1925 vi->affinity_hint_set = true;
1926 free_cpumask_var(mask);
1927 }
1928
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 26618 bytes --]
^ permalink raw reply
* [net-next:master 1999/2033] drivers//net/virtio_net.c:1916:10: error: implicit declaration of function 'cpumask_next_wrap'; did you mean 'cpumask_next_and'?
From: kbuild test robot @ 2018-08-11 23:11 UTC (permalink / raw)
To: Caleb Raitto; +Cc: kbuild-all, netdev, Willem de Bruijn
[-- Attachment #1: Type: text/plain, Size: 2533 bytes --]
tree: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master
head: 9a95d9c6429bb58905fdfc95da2e1b7cc3fb55b7
commit: 2ca653d607ce59f2729173a7ea56dbfa6330ec88 [1999/2033] virtio_net: Stripe queue affinities across cores.
config: sh-allyesconfig (attached as .config)
compiler: sh4-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout 2ca653d607ce59f2729173a7ea56dbfa6330ec88
# save the attached .config to linux build tree
GCC_VERSION=7.2.0 make.cross ARCH=sh
All errors (new ones prefixed by >>):
drivers//net/virtio_net.c: In function 'virtnet_set_affinity':
>> drivers//net/virtio_net.c:1916:10: error: implicit declaration of function 'cpumask_next_wrap'; did you mean 'cpumask_next_and'? [-Werror=implicit-function-declaration]
cpu = cpumask_next_wrap(cpu, cpu_online_mask,
^~~~~~~~~~~~~~~~~
cpumask_next_and
cc1: some warnings being treated as errors
vim +1916 drivers//net/virtio_net.c
1889
1890 static void virtnet_set_affinity(struct virtnet_info *vi)
1891 {
1892 cpumask_var_t mask;
1893 int stragglers;
1894 int group_size;
1895 int i, j, cpu;
1896 int num_cpu;
1897 int stride;
1898
1899 if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
1900 virtnet_clean_affinity(vi, -1);
1901 return;
1902 }
1903
1904 num_cpu = num_online_cpus();
1905 stride = max_t(int, num_cpu / vi->curr_queue_pairs, 1);
1906 stragglers = num_cpu >= vi->curr_queue_pairs ?
1907 num_cpu % vi->curr_queue_pairs :
1908 0;
1909 cpu = cpumask_next(-1, cpu_online_mask);
1910
1911 for (i = 0; i < vi->curr_queue_pairs; i++) {
1912 group_size = stride + (i < stragglers ? 1 : 0);
1913
1914 for (j = 0; j < group_size; j++) {
1915 cpumask_set_cpu(cpu, mask);
> 1916 cpu = cpumask_next_wrap(cpu, cpu_online_mask,
1917 nr_cpu_ids, false);
1918 }
1919 virtqueue_set_affinity(vi->rq[i].vq, mask);
1920 virtqueue_set_affinity(vi->sq[i].vq, mask);
1921 __netif_set_xps_queue(vi->dev, cpumask_bits(mask), i, false);
1922 cpumask_clear(mask);
1923 }
1924
1925 vi->affinity_hint_set = true;
1926 free_cpumask_var(mask);
1927 }
1928
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 49014 bytes --]
^ permalink raw reply
* [PATCH bpf-next] bpf: decouple btf from seq bpf fs dump and enable more maps
From: Daniel Borkmann @ 2018-08-11 23:59 UTC (permalink / raw)
To: ast; +Cc: netdev, yhs, kafai, Daniel Borkmann
Commit a26ca7c982cb ("bpf: btf: Add pretty print support to
the basic arraymap") and 699c86d6ec21 ("bpf: btf: add pretty
print for hash/lru_hash maps") enabled support for BTF and
dumping via BPF fs for array and hash/lru map. However, both
can be decoupled from each other such that regular BPF maps
can be supported for attaching BTF key/value information,
while not all maps necessarily need to dump via map_seq_show_elem()
callback.
The basic sanity check which is a prerequisite for all maps
is that key/value size has to match in any case, and some maps
can have extra checks via map_check_btf() callback, e.g.
probing certain types or indicating no support in general. With
that we can also enable retrieving BTF info for per-cpu map
types and lpm.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
---
include/linux/bpf.h | 13 +++++++++----
kernel/bpf/arraymap.c | 26 ++++++++++++--------------
kernel/bpf/cpumap.c | 1 +
kernel/bpf/devmap.c | 1 +
kernel/bpf/hashtab.c | 20 +-------------------
kernel/bpf/inode.c | 3 ++-
kernel/bpf/local_storage.c | 1 +
kernel/bpf/lpm_trie.c | 12 ++++++++++++
kernel/bpf/sockmap.c | 2 ++
kernel/bpf/stackmap.c | 1 +
kernel/bpf/syscall.c | 36 ++++++++++++++++++++++++++++++++----
kernel/bpf/xskmap.c | 3 +--
12 files changed, 75 insertions(+), 44 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index db11662..523481a 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -23,7 +23,7 @@ struct bpf_prog;
struct bpf_map;
struct sock;
struct seq_file;
-struct btf;
+struct btf_type;
/* map is generic key/value storage optionally accesible by eBPF programs */
struct bpf_map_ops {
@@ -48,8 +48,9 @@ struct bpf_map_ops {
u32 (*map_fd_sys_lookup_elem)(void *ptr);
void (*map_seq_show_elem)(struct bpf_map *map, void *key,
struct seq_file *m);
- int (*map_check_btf)(const struct bpf_map *map, const struct btf *btf,
- u32 key_type_id, u32 value_type_id);
+ int (*map_check_btf)(const struct bpf_map *map,
+ const struct btf_type *key_type,
+ const struct btf_type *value_type);
};
struct bpf_map {
@@ -118,9 +119,13 @@ static inline bool bpf_map_offload_neutral(const struct bpf_map *map)
static inline bool bpf_map_support_seq_show(const struct bpf_map *map)
{
- return map->ops->map_seq_show_elem && map->ops->map_check_btf;
+ return map->btf && map->ops->map_seq_show_elem;
}
+int map_check_no_btf(const struct bpf_map *map,
+ const struct btf_type *key_type,
+ const struct btf_type *value_type);
+
extern const struct bpf_map_ops bpf_map_offload_ops;
/* function argument constraints */
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index f6ca3e7..0c17aab 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -358,27 +358,20 @@ static void array_map_seq_show_elem(struct bpf_map *map, void *key,
rcu_read_unlock();
}
-static int array_map_check_btf(const struct bpf_map *map, const struct btf *btf,
- u32 btf_key_id, u32 btf_value_id)
+static int array_map_check_btf(const struct bpf_map *map,
+ const struct btf_type *key_type,
+ const struct btf_type *value_type)
{
- const struct btf_type *key_type, *value_type;
- u32 key_size, value_size;
u32 int_data;
- key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
- if (!key_type || BTF_INFO_KIND(key_type->info) != BTF_KIND_INT)
+ if (BTF_INFO_KIND(key_type->info) != BTF_KIND_INT)
return -EINVAL;
int_data = *(u32 *)(key_type + 1);
- /* bpf array can only take a u32 key. This check makes
- * sure that the btf matches the attr used during map_create.
+ /* bpf array can only take a u32 key. This check makes sure
+ * that the btf matches the attr used during map_create.
*/
- if (BTF_INT_BITS(int_data) != 32 || key_size != 4 ||
- BTF_INT_OFFSET(int_data))
- return -EINVAL;
-
- value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
- if (!value_type || value_size != map->value_size)
+ if (BTF_INT_BITS(int_data) != 32 || BTF_INT_OFFSET(int_data))
return -EINVAL;
return 0;
@@ -405,6 +398,7 @@ const struct bpf_map_ops percpu_array_map_ops = {
.map_lookup_elem = percpu_array_map_lookup_elem,
.map_update_elem = array_map_update_elem,
.map_delete_elem = array_map_delete_elem,
+ .map_check_btf = array_map_check_btf,
};
static int fd_array_map_alloc_check(union bpf_attr *attr)
@@ -546,6 +540,7 @@ const struct bpf_map_ops prog_array_map_ops = {
.map_fd_put_ptr = prog_fd_array_put_ptr,
.map_fd_sys_lookup_elem = prog_fd_array_sys_lookup_elem,
.map_release_uref = bpf_fd_array_map_clear,
+ .map_check_btf = map_check_no_btf,
};
static struct bpf_event_entry *bpf_event_entry_gen(struct file *perf_file,
@@ -634,6 +629,7 @@ const struct bpf_map_ops perf_event_array_map_ops = {
.map_fd_get_ptr = perf_event_fd_array_get_ptr,
.map_fd_put_ptr = perf_event_fd_array_put_ptr,
.map_release = perf_event_fd_array_release,
+ .map_check_btf = map_check_no_btf,
};
#ifdef CONFIG_CGROUPS
@@ -665,6 +661,7 @@ const struct bpf_map_ops cgroup_array_map_ops = {
.map_delete_elem = fd_array_map_delete_elem,
.map_fd_get_ptr = cgroup_fd_array_get_ptr,
.map_fd_put_ptr = cgroup_fd_array_put_ptr,
+ .map_check_btf = map_check_no_btf,
};
#endif
@@ -749,4 +746,5 @@ const struct bpf_map_ops array_of_maps_map_ops = {
.map_fd_put_ptr = bpf_map_fd_put_ptr,
.map_fd_sys_lookup_elem = bpf_map_fd_sys_lookup_elem,
.map_gen_lookup = array_of_map_gen_lookup,
+ .map_check_btf = map_check_no_btf,
};
diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c
index e0918d1..3b49494 100644
--- a/kernel/bpf/cpumap.c
+++ b/kernel/bpf/cpumap.c
@@ -555,6 +555,7 @@ const struct bpf_map_ops cpu_map_ops = {
.map_update_elem = cpu_map_update_elem,
.map_lookup_elem = cpu_map_lookup_elem,
.map_get_next_key = cpu_map_get_next_key,
+ .map_check_btf = map_check_no_btf,
};
static int bq_flush_to_queue(struct bpf_cpu_map_entry *rcpu,
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index d361fc1..a7c6620 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -484,6 +484,7 @@ const struct bpf_map_ops dev_map_ops = {
.map_lookup_elem = dev_map_lookup_elem,
.map_update_elem = dev_map_update_elem,
.map_delete_elem = dev_map_delete_elem,
+ .map_check_btf = map_check_no_btf,
};
static int dev_map_notification(struct notifier_block *notifier,
diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
index d611004..04b8eda 100644
--- a/kernel/bpf/hashtab.c
+++ b/kernel/bpf/hashtab.c
@@ -1185,23 +1185,6 @@ static void htab_map_seq_show_elem(struct bpf_map *map, void *key,
rcu_read_unlock();
}
-static int htab_map_check_btf(const struct bpf_map *map, const struct btf *btf,
- u32 btf_key_id, u32 btf_value_id)
-{
- const struct btf_type *key_type, *value_type;
- u32 key_size, value_size;
-
- key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
- if (!key_type || key_size != map->key_size)
- return -EINVAL;
-
- value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
- if (!value_type || value_size != map->value_size)
- return -EINVAL;
-
- return 0;
-}
-
const struct bpf_map_ops htab_map_ops = {
.map_alloc_check = htab_map_alloc_check,
.map_alloc = htab_map_alloc,
@@ -1212,7 +1195,6 @@ const struct bpf_map_ops htab_map_ops = {
.map_delete_elem = htab_map_delete_elem,
.map_gen_lookup = htab_map_gen_lookup,
.map_seq_show_elem = htab_map_seq_show_elem,
- .map_check_btf = htab_map_check_btf,
};
const struct bpf_map_ops htab_lru_map_ops = {
@@ -1225,7 +1207,6 @@ const struct bpf_map_ops htab_lru_map_ops = {
.map_delete_elem = htab_lru_map_delete_elem,
.map_gen_lookup = htab_lru_map_gen_lookup,
.map_seq_show_elem = htab_map_seq_show_elem,
- .map_check_btf = htab_map_check_btf,
};
/* Called from eBPF program */
@@ -1452,4 +1433,5 @@ const struct bpf_map_ops htab_of_maps_map_ops = {
.map_fd_put_ptr = bpf_map_fd_put_ptr,
.map_fd_sys_lookup_elem = bpf_map_fd_sys_lookup_elem,
.map_gen_lookup = htab_of_map_gen_lookup,
+ .map_check_btf = map_check_no_btf,
};
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index fc5b103..2ada5e2 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -334,7 +334,8 @@ static int bpf_mkmap(struct dentry *dentry, umode_t mode, void *arg)
struct bpf_map *map = arg;
return bpf_mkobj_ops(dentry, mode, arg, &bpf_map_iops,
- map->btf ? &bpffs_map_fops : &bpffs_obj_fops);
+ bpf_map_support_seq_show(map) ?
+ &bpffs_map_fops : &bpffs_obj_fops);
}
static struct dentry *
diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c
index fc4e37f..22ad967 100644
--- a/kernel/bpf/local_storage.c
+++ b/kernel/bpf/local_storage.c
@@ -246,6 +246,7 @@ const struct bpf_map_ops cgroup_storage_map_ops = {
.map_lookup_elem = cgroup_storage_lookup_elem,
.map_update_elem = cgroup_storage_update_elem,
.map_delete_elem = cgroup_storage_delete_elem,
+ .map_check_btf = map_check_no_btf,
};
int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *_map)
diff --git a/kernel/bpf/lpm_trie.c b/kernel/bpf/lpm_trie.c
index 1603492..9058317 100644
--- a/kernel/bpf/lpm_trie.c
+++ b/kernel/bpf/lpm_trie.c
@@ -10,11 +10,13 @@
*/
#include <linux/bpf.h>
+#include <linux/btf.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/vmalloc.h>
#include <net/ipv6.h>
+#include <uapi/linux/btf.h>
/* Intermediate node */
#define LPM_TREE_NODE_FLAG_IM BIT(0)
@@ -686,6 +688,15 @@ static int trie_get_next_key(struct bpf_map *map, void *_key, void *_next_key)
return err;
}
+static int trie_check_btf(const struct bpf_map *map,
+ const struct btf_type *key_type,
+ const struct btf_type *value_type)
+{
+ /* Keys must have struct bpf_lpm_trie_key embedded. */
+ return BTF_INFO_KIND(key_type->info) != BTF_KIND_STRUCT ?
+ -EINVAL : 0;
+}
+
const struct bpf_map_ops trie_map_ops = {
.map_alloc = trie_alloc,
.map_free = trie_free,
@@ -693,4 +704,5 @@ const struct bpf_map_ops trie_map_ops = {
.map_lookup_elem = trie_lookup_elem,
.map_update_elem = trie_update_elem,
.map_delete_elem = trie_delete_elem,
+ .map_check_btf = trie_check_btf,
};
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
index 0b38be5..e376fff 100644
--- a/kernel/bpf/sockmap.c
+++ b/kernel/bpf/sockmap.c
@@ -2495,6 +2495,7 @@ const struct bpf_map_ops sock_map_ops = {
.map_update_elem = sock_map_update_elem,
.map_delete_elem = sock_map_delete_elem,
.map_release_uref = sock_map_release,
+ .map_check_btf = map_check_no_btf,
};
const struct bpf_map_ops sock_hash_ops = {
@@ -2505,6 +2506,7 @@ const struct bpf_map_ops sock_hash_ops = {
.map_update_elem = sock_hash_update_elem,
.map_delete_elem = sock_hash_delete_elem,
.map_release_uref = sock_map_release,
+ .map_check_btf = map_check_no_btf,
};
BPF_CALL_4(bpf_sock_map_update, struct bpf_sock_ops_kern *, bpf_sock,
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index b675a3f..8061a43 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -607,6 +607,7 @@ const struct bpf_map_ops stack_map_ops = {
.map_lookup_elem = stack_map_lookup_elem,
.map_update_elem = stack_map_update_elem,
.map_delete_elem = stack_map_delete_elem,
+ .map_check_btf = map_check_no_btf,
};
static int __init stack_map_init(void)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 57f4d07..43727ed 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -103,6 +103,7 @@ int bpf_check_uarg_tail_zero(void __user *uaddr,
const struct bpf_map_ops bpf_map_offload_ops = {
.map_alloc = bpf_map_offload_map_alloc,
.map_free = bpf_map_offload_map_free,
+ .map_check_btf = map_check_no_btf,
};
static struct bpf_map *find_and_alloc_map(union bpf_attr *attr)
@@ -455,6 +456,34 @@ static int bpf_obj_name_cpy(char *dst, const char *src)
return 0;
}
+int map_check_no_btf(const struct bpf_map *map,
+ const struct btf_type *key_type,
+ const struct btf_type *value_type)
+{
+ return -ENOTSUPP;
+}
+
+static int map_check_btf(const struct bpf_map *map, const struct btf *btf,
+ u32 btf_key_id, u32 btf_value_id)
+{
+ const struct btf_type *key_type, *value_type;
+ u32 key_size, value_size;
+ int ret = 0;
+
+ key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
+ if (!key_type || key_size != map->key_size)
+ return -EINVAL;
+
+ value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
+ if (!value_type || value_size != map->value_size)
+ return -EINVAL;
+
+ if (map->ops->map_check_btf)
+ ret = map->ops->map_check_btf(map, key_type, value_type);
+
+ return ret;
+}
+
#define BPF_MAP_CREATE_LAST_FIELD btf_value_type_id
/* called via syscall */
static int map_create(union bpf_attr *attr)
@@ -489,8 +518,7 @@ static int map_create(union bpf_attr *attr)
atomic_set(&map->refcnt, 1);
atomic_set(&map->usercnt, 1);
- if (bpf_map_support_seq_show(map) &&
- (attr->btf_key_type_id || attr->btf_value_type_id)) {
+ if (attr->btf_key_type_id || attr->btf_value_type_id) {
struct btf *btf;
if (!attr->btf_key_type_id || !attr->btf_value_type_id) {
@@ -504,8 +532,8 @@ static int map_create(union bpf_attr *attr)
goto free_map_nouncharge;
}
- err = map->ops->map_check_btf(map, btf, attr->btf_key_type_id,
- attr->btf_value_type_id);
+ err = map_check_btf(map, btf, attr->btf_key_type_id,
+ attr->btf_value_type_id);
if (err) {
btf_put(btf);
goto free_map_nouncharge;
diff --git a/kernel/bpf/xskmap.c b/kernel/bpf/xskmap.c
index b3c5574..4ddf61e1 100644
--- a/kernel/bpf/xskmap.c
+++ b/kernel/bpf/xskmap.c
@@ -227,6 +227,5 @@ const struct bpf_map_ops xsk_map_ops = {
.map_lookup_elem = xsk_map_lookup_elem,
.map_update_elem = xsk_map_update_elem,
.map_delete_elem = xsk_map_delete_elem,
+ .map_check_btf = map_check_no_btf,
};
-
-
--
2.9.5
^ permalink raw reply related
* Re: [PATCH net-next v2 0/2] ip: faster in-order IP fragments
From: David Miller @ 2018-08-12 0:54 UTC (permalink / raw)
To: posk; +Cc: netdev
In-Reply-To: <20180811202725.242498-1-posk@google.com>
From: Peter Oskolkov <posk@google.com>
Date: Sat, 11 Aug 2018 20:27:23 +0000
> Added "Signed-off-by" in v2.
Series applied, thank you.
^ permalink raw reply
* your photo needs
From: Jeff @ 2018-08-11 8:55 UTC (permalink / raw)
To: netdev
We would like to check if your photos need editing. We can do it for you.
Our image editing is for web store photos, jewelries images and beauty and
portrait photos etc.
It is including cut out and clipping path , and also retouching if it is
needed.
We can do test on your photos. Just send us a photo we will start to work
on it,
Thanks,
Jeff Allen
^ permalink raw reply
* Re: [RFC/RFT, net-next, 00/17] net: Convert neighbor tables to per-namespace
From: Vasily Averin @ 2018-08-12 6:46 UTC (permalink / raw)
To: dsahern, netdev
Cc: nikita.leshchenko, roopa, stephen, idosch, jiri, saeedm,
alex.aring, linux-wpan, netfilter-devel, linux-kernel,
David Ahern
In-Reply-To: <20180717120651.15748-1-dsahern@kernel.org>
On 07/17/2018 03:06 PM, dsahern@kernel.org wrote:
> From: David Ahern <dsahern@gmail.com>
>
> Nikita Leshenko reported that neighbor entries in one namespace can
> evict neighbor entries in another. The problem is that the neighbor
> tables have entries across all namespaces without separate accounting
> and with global limits on when to scan for entries to evict.
>
> Resolve by making the neighbor tables for ipv4, ipv6 and decnet per
> namespace and making the accounting and threshold limits per namespace.
Dear David,
I prepared own patch set to fix this problem and found your one.
It looks perfect for me, and I hope David Miller will merge it soon,
however I have found a few drawbacks:
1) I know that if net_device exist it always have correct net reference,
so dev_net(dev) will be always correct.
However I afraid that device reference itself is correct in some places.
For example,
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
@@ -376,9 +377,10 @@ mlxsw_sp_span_entry_gretap4_parms(const struct net_device *to_dev,
return mlxsw_sp_span_entry_unoffloadable(sparmsp);
l3edev = mlxsw_sp_span_gretap4_route(to_dev, &saddr.addr4, &gw.addr4);
+ tbl = ipv4_neigh_table(dev_net(l3edev));
return mlxsw_sp_span_entry_tunnel_parms_common(l3edev, saddr, daddr, gw,
tparm.iph.ttl,
- &arp_tbl, sparmsp);
+ tbl, sparmsp);
}
mlxsw_sp_span_entry_tunnel_parms_common() have "if (!edev)" check inside,
so it seems l3edev can be set to NULL here and lead to crash inside dev_net(l3edev).
There are few other suspicious places and I think they should be carefully re-checked.
2) modified arp_net_init() does not check return value neigh_sysctl_register() and lacks correct rollback.
It was acceptable in arp_init, because it was called only once on boot, but now it will be called
for each new net namespace, it can have real chances to fail lead to memory crash/memory corruption.
3) modified neigh_table_init() is called many times per netns but it can panic in case failed memory allocation.
I think it should be reworked to return errors in such cases, its callers should check it and add correct rollbacks.
4) currently neigh_table_clear() always return 0, I think it makes sense to change it to return void.
Thank you,
Vasily Averin
^ permalink raw reply
* Re: [PATCH bpf-next] bpf: decouple btf from seq bpf fs dump and enable more maps
From: Y Song @ 2018-08-12 6:43 UTC (permalink / raw)
To: Daniel Borkmann
Cc: Alexei Starovoitov, netdev, Yonghong Song, Martin KaFai Lau
In-Reply-To: <20180811235917.2969-1-daniel@iogearbox.net>
On Sat, Aug 11, 2018 at 4:59 PM, Daniel Borkmann <daniel@iogearbox.net> wrote:
> Commit a26ca7c982cb ("bpf: btf: Add pretty print support to
> the basic arraymap") and 699c86d6ec21 ("bpf: btf: add pretty
> print for hash/lru_hash maps") enabled support for BTF and
> dumping via BPF fs for array and hash/lru map. However, both
> can be decoupled from each other such that regular BPF maps
> can be supported for attaching BTF key/value information,
> while not all maps necessarily need to dump via map_seq_show_elem()
> callback.
>
> The basic sanity check which is a prerequisite for all maps
> is that key/value size has to match in any case, and some maps
> can have extra checks via map_check_btf() callback, e.g.
> probing certain types or indicating no support in general. With
> that we can also enable retrieving BTF info for per-cpu map
> types and lpm.
>
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> Acked-by: Alexei Starovoitov <ast@kernel.org>
Thanks for the fix. Looks good to me.
For bpftool, BTF pretty print support is missing
for per-cpu maps. bpffs print for per-cpu hash/array maps
need to be added as well. Will add them later.
Acked-by: Yonghong Song <yhs@fb.com>
^ permalink raw reply
* Re: [PATCH bpf-next 4/4] selftests/bpf: Selftest for bpf_skb_ancestor_cgroup_id
From: Yonghong Song @ 2018-08-12 6:58 UTC (permalink / raw)
To: Andrey Ignatov, netdev; +Cc: ast, daniel, tj, guro, kernel-team
In-Reply-To: <fd9428a9f03598da21caa2bb0e49c958f9c8daf3.1533965421.git.rdna@fb.com>
On 8/10/18 10:35 PM, Andrey Ignatov wrote:
> Add selftests for bpf_skb_ancestor_cgroup_id helper.
>
> test_skb_cgroup_id.sh prepares testing interface and adds tc qdisc and
> filter for it using BPF object compiled from test_skb_cgroup_id_kern.c
> program.
>
> BPF program in test_skb_cgroup_id_kern.c gets ancestor cgroup id using
> the new helper at different levels of cgroup hierarchy that skb belongs
> to, including root level and non-existing level, and saves it to the map
> where the key is the level of corresponding cgroup and the value is its
> id.
>
> To trigger BPF program, user space program test_skb_cgroup_id_user is
> run. It adds itself into testing cgroup and sends UDP datagram to
> link-local multicast address of testing interface. Then it reads cgroup
> ids saved in kernel for different levels from the BPF map and compares
> them with those in user space. They must be equal for every level of
> ancestry.
>
> Example of run:
> # ./test_skb_cgroup_id.sh
> Wait for testing link-local IP to become available ... OK
> Note: 8 bytes struct bpf_elf_map fixup performed due to size mismatch!
> [PASS]
I am not able to run the test on my FC27 based VM with the latest
bpf-next and the patch set.
[yhs@localhost bpf]$ sudo ./test_skb_cgroup_id.sh
Wait for testing link-local IP to become available .....ERROR: Timeout
waiting for test IP to become available.
[yhs@localhost bpf]$
I am able to run test_sock_addr.sh successfully.
$ sudo ./test_sock_addr.sh
Wait for testing IPv4/IPv6 to become available .
.. OK
Test case: bind4: load prog with wrong expected attach type .. [PASS]
Test case: bind4: attach prog with wrong attach type .. [PASS]
...
Test case: sendmsg6: deny call .. [PASS]
Summary: 27 PASSED, 0 FAILED
Maybe some issues in this addr ff02::1%${TEST_IF}?
>
> Signed-off-by: Andrey Ignatov <rdna@fb.com>
> ---
> tools/testing/selftests/bpf/Makefile | 9 +-
> .../selftests/bpf/test_skb_cgroup_id.sh | 61 ++++++
> .../selftests/bpf/test_skb_cgroup_id_kern.c | 47 +++++
> .../selftests/bpf/test_skb_cgroup_id_user.c | 187 ++++++++++++++++++
> 4 files changed, 301 insertions(+), 3 deletions(-)
> create mode 100755 tools/testing/selftests/bpf/test_skb_cgroup_id.sh
> create mode 100644 tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c
> create mode 100644 tools/testing/selftests/bpf/test_skb_cgroup_id_user.c
>
> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index daed162043c2..fff7fb1285fc 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
> @@ -34,7 +34,8 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test
> test_btf_haskv.o test_btf_nokv.o test_sockmap_kern.o test_tunnel_kern.o \
> test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \
> test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \
> - get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o
> + get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \
> + test_skb_cgroup_id_kern.o
>
> # Order correspond to 'make run_tests' order
> TEST_PROGS := test_kmod.sh \
> @@ -45,10 +46,11 @@ TEST_PROGS := test_kmod.sh \
> test_sock_addr.sh \
> test_tunnel.sh \
> test_lwt_seg6local.sh \
> - test_lirc_mode2.sh
> + test_lirc_mode2.sh \
> + test_skb_cgroup_id.sh
>
> # Compile but not part of 'make run_tests'
> -TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr
> +TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user
>
> include ../lib.mk
>
> @@ -59,6 +61,7 @@ $(TEST_GEN_PROGS): $(BPFOBJ)
> $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a
>
> $(OUTPUT)/test_dev_cgroup: cgroup_helpers.c
> +$(OUTPUT)/test_skb_cgroup_id_user: cgroup_helpers.c
> $(OUTPUT)/test_sock: cgroup_helpers.c
> $(OUTPUT)/test_sock_addr: cgroup_helpers.c
> $(OUTPUT)/test_socket_cookie: cgroup_helpers.c
> diff --git a/tools/testing/selftests/bpf/test_skb_cgroup_id.sh b/tools/testing/selftests/bpf/test_skb_cgroup_id.sh
> new file mode 100755
> index 000000000000..b75e9b52f06f
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/test_skb_cgroup_id.sh
> @@ -0,0 +1,61 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2018 Facebook
> +
> +set -eu
> +
> +wait_for_ip()
> +{
> + local _i
> + echo -n "Wait for testing link-local IP to become available "
> + for _i in $(seq ${MAX_PING_TRIES}); do
> + echo -n "."
> + if ping -6 -q -c 1 -W 1 ff02::1%${TEST_IF} >/dev/null 2>&1; then
> + echo " OK"
> + return
> + fi
> + done
> + echo 1>&2 "ERROR: Timeout waiting for test IP to become available."
> + exit 1
> +}
> +
> +setup()
> +{
> + # Create testing interfaces not to interfere with current environment.
> + ip link add dev ${TEST_IF} type veth peer name ${TEST_IF_PEER}
> + ip link set ${TEST_IF} up
> + ip link set ${TEST_IF_PEER} up
> +
> + wait_for_ip
> +
> + tc qdisc add dev ${TEST_IF} clsact
> + tc filter add dev ${TEST_IF} egress bpf obj ${BPF_PROG_OBJ} \
> + sec ${BPF_PROG_SECTION} da
> +
> + BPF_PROG_ID=$(tc filter show dev ${TEST_IF} egress | \
> + awk '/ id / {sub(/.* id /, "", $0); print($1)}')
> +}
> +
> +cleanup()
> +{
> + ip link del ${TEST_IF} 2>/dev/null || :
> + ip link del ${TEST_IF_PEER} 2>/dev/null || :
> +}
> +
> +main()
> +{
> + trap cleanup EXIT 2 3 6 15
> + setup
> + ${PROG} ${TEST_IF} ${BPF_PROG_ID}
> +}
> +
> +DIR=$(dirname $0)
> +TEST_IF="test_cgid_1"
> +TEST_IF_PEER="test_cgid_2"
> +MAX_PING_TRIES=5
> +BPF_PROG_OBJ="${DIR}/test_skb_cgroup_id_kern.o"
> +BPF_PROG_SECTION="cgroup_id_logger"
> +BPF_PROG_ID=0
> +PROG="${DIR}/test_skb_cgroup_id_user"
> +
> +main
> diff --git a/tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c b/tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c
> new file mode 100644
> index 000000000000..68cf9829f5a7
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c
> @@ -0,0 +1,47 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2018 Facebook
> +
> +#include <linux/bpf.h>
> +#include <linux/pkt_cls.h>
> +
> +#include <string.h>
> +
> +#include "bpf_helpers.h"
> +
> +#define NUM_CGROUP_LEVELS 4
> +
> +struct bpf_map_def SEC("maps") cgroup_ids = {
> + .type = BPF_MAP_TYPE_ARRAY,
> + .key_size = sizeof(__u32),
> + .value_size = sizeof(__u64),
> + .max_entries = NUM_CGROUP_LEVELS,
> +};
> +
> +static __always_inline void log_nth_level(struct __sk_buff *skb, __u32 level)
> +{
> + __u64 id;
> +
> + /* [1] &level passed to external function that may change it, it's
> + * incompatible with loop unroll.
> + */
> + id = bpf_skb_ancestor_cgroup_id(skb, level);
> + bpf_map_update_elem(&cgroup_ids, &level, &id, 0);
> +}
> +
> +SEC("cgroup_id_logger")
> +int log_cgroup_id(struct __sk_buff *skb)
> +{
> + /* Loop unroll can't be used here due to [1]. Unrolling manually.
> + * Number of calls should be in sync with NUM_CGROUP_LEVELS.
> + */
> + log_nth_level(skb, 0);
> + log_nth_level(skb, 1);
> + log_nth_level(skb, 2);
> + log_nth_level(skb, 3);
> +
> + return TC_ACT_OK;
> +}
> +
> +int _version SEC("version") = 1;
> +
> +char _license[] SEC("license") = "GPL";
> diff --git a/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c b/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c
> new file mode 100644
> index 000000000000..c121cc59f314
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c
> @@ -0,0 +1,187 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2018 Facebook
> +
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#include <arpa/inet.h>
> +#include <net/if.h>
> +#include <netinet/in.h>
> +#include <sys/socket.h>
> +#include <sys/types.h>
> +
> +
> +#include <bpf/bpf.h>
> +#include <bpf/libbpf.h>
> +
> +#include "bpf_rlimit.h"
> +#include "cgroup_helpers.h"
> +
> +#define CGROUP_PATH "/skb_cgroup_test"
> +#define NUM_CGROUP_LEVELS 4
> +
> +/* RFC 4291, Section 2.7.1 */
> +#define LINKLOCAL_MULTICAST "ff02::1"
> +
> +static int mk_dst_addr(const char *ip, const char *iface,
> + struct sockaddr_in6 *dst)
> +{
> + memset(dst, 0, sizeof(*dst));
> +
> + dst->sin6_family = AF_INET6;
> + dst->sin6_port = htons(1025);
> +
> + if (inet_pton(AF_INET6, ip, &dst->sin6_addr) != 1) {
> + log_err("Invalid IPv6: %s", ip);
> + return -1;
> + }
> +
> + dst->sin6_scope_id = if_nametoindex(iface);
> + if (!dst->sin6_scope_id) {
> + log_err("Failed to get index of iface: %s", iface);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int send_packet(const char *iface)
> +{
> + struct sockaddr_in6 dst;
> + char msg[] = "msg";
> + int err = 0;
> + int fd = -1;
> +
> + if (mk_dst_addr(LINKLOCAL_MULTICAST, iface, &dst))
> + goto err;
> +
> + fd = socket(AF_INET6, SOCK_DGRAM, 0);
> + if (fd == -1) {
> + log_err("Failed to create UDP socket");
> + goto err;
> + }
> +
> + if (sendto(fd, &msg, sizeof(msg), 0, (const struct sockaddr *)&dst,
> + sizeof(dst)) == -1) {
> + log_err("Failed to send datagram");
> + goto err;
> + }
> +
> + goto out;
> +err:
> + err = -1;
> +out:
> + if (fd >= 0)
> + close(fd);
> + return err;
> +}
> +
> +int get_map_fd_by_prog_id(int prog_id)
> +{
> + struct bpf_prog_info info = {};
> + __u32 info_len = sizeof(info);
> + __u32 map_ids[1];
> + int prog_fd = -1;
> + int map_fd = -1;
> +
> + prog_fd = bpf_prog_get_fd_by_id(prog_id);
> + if (prog_fd < 0) {
> + log_err("Failed to get fd by prog id %d", prog_id);
> + goto err;
> + }
> +
> + info.nr_map_ids = 1;
> + info.map_ids = (__u64) (unsigned long) map_ids;
> +
> + if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) {
> + log_err("Failed to get info by prog fd %d", prog_fd);
> + goto err;
> + }
> +
> + if (!info.nr_map_ids) {
> + log_err("No maps found for prog fd %d", prog_fd);
> + goto err;
> + }
> +
> + map_fd = bpf_map_get_fd_by_id(map_ids[0]);
> + if (map_fd < 0)
> + log_err("Failed to get fd by map id %d", map_ids[0]);
> +err:
> + if (prog_fd >= 0)
> + close(prog_fd);
> + return map_fd;
> +}
> +
> +int check_ancestor_cgroup_ids(int prog_id)
> +{
> + __u64 actual_ids[NUM_CGROUP_LEVELS], expected_ids[NUM_CGROUP_LEVELS];
> + __u32 level;
> + int err = 0;
> + int map_fd;
> +
> + expected_ids[0] = 0x100000001; /* root cgroup */
> + expected_ids[1] = get_cgroup_id("");
> + expected_ids[2] = get_cgroup_id(CGROUP_PATH);
> + expected_ids[3] = 0; /* non-existent cgroup */
> +
> + map_fd = get_map_fd_by_prog_id(prog_id);
> + if (map_fd < 0)
> + goto err;
> +
> + for (level = 0; level < NUM_CGROUP_LEVELS; ++level) {
> + if (bpf_map_lookup_elem(map_fd, &level, &actual_ids[level])) {
> + log_err("Failed to lookup key %d", level);
> + goto err;
> + }
> + if (actual_ids[level] != expected_ids[level]) {
> + log_err("%llx (actual) != %llx (expected), level: %u\n",
> + actual_ids[level], expected_ids[level], level);
> + goto err;
> + }
> + }
> +
> + goto out;
> +err:
> + err = -1;
> +out:
> + if (map_fd >= 0)
> + close(map_fd);
> + return err;
> +}
> +
> +int main(int argc, char **argv)
> +{
> + int cgfd = -1;
> + int err = 0;
> +
> + if (argc < 3) {
> + fprintf(stderr, "Usage: %s iface prog_id\n", argv[0]);
> + exit(EXIT_FAILURE);
> + }
> +
> + if (setup_cgroup_environment())
> + goto err;
> +
> + cgfd = create_and_get_cgroup(CGROUP_PATH);
> + if (!cgfd)
> + goto err;
> +
> + if (join_cgroup(CGROUP_PATH))
> + goto err;
> +
> + if (send_packet(argv[1]))
> + goto err;
> +
> + if (check_ancestor_cgroup_ids(atoi(argv[2])))
> + goto err;
> +
> + goto out;
> +err:
> + err = -1;
> +out:
> + close(cgfd);
> + cleanup_cgroup_environment();
> + printf("[%s]\n", err ? "FAIL" : "PASS");
> + return err;
> +}
>
^ permalink raw reply
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