aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorToke Høiland-Jørgensen <toke@redhat.com>2021-11-08 22:18:28 +0100
committerToke Høiland-Jørgensen <toke@redhat.com>2021-11-09 21:35:16 +0100
commitf88dc77e8d556abca484fb6dc9b6fc7517452af8 (patch)
tree8ddfe4402135169866430739b36f7db003cd4173
parent6805907f11a49512c2e6fb534df22784eb91d2ef (diff)
downloadlinux-f88dc77e8d556abca484fb6dc9b6fc7517452af8.tar.gz
net: add a page pool instance to the loopback device
This adds a page pool instance to the loopback device. This will be used in a subsequent patch to support proper XDP_REDIRECT in bpf_prog_run(), and is only initialised on the first use (so the memory overhead when it's not used is only a single pointer). Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
-rw-r--r--drivers/net/loopback.c48
-rw-r--r--include/linux/netdevice.h1
2 files changed, 48 insertions, 1 deletions
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index a1c77cc004165..b3514568890a9 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -54,6 +54,7 @@
#include <linux/net_tstamp.h>
#include <net/net_namespace.h>
#include <linux/u64_stats_sync.h>
+#include <net/page_pool.h>
/* blackhole_netdev - a device used for dsts that are marked expired!
* This is global device (instead of per-net-ns) since it's not needed
@@ -62,6 +63,10 @@
struct net_device *blackhole_netdev;
EXPORT_SYMBOL(blackhole_netdev);
+struct loopback_priv {
+ struct page_pool *page_pool;
+};
+
/* The higher levels take care of making this non-reentrant (it's
* called with bh's disabled).
*/
@@ -148,10 +153,51 @@ static int loopback_dev_init(struct net_device *dev)
static void loopback_dev_free(struct net_device *dev)
{
+ struct loopback_priv *priv = netdev_priv(dev);
+
+ if (priv->page_pool) {
+ page_pool_destroy(priv->page_pool);
+ priv->page_pool = NULL;
+ }
+
dev_net(dev)->loopback_dev = NULL;
free_percpu(dev->lstats);
}
+struct page_pool *dev_loopback_get_page_pool(struct net *net)
+{
+ struct net_device *dev = net->loopback_dev;
+ struct loopback_priv *priv = netdev_priv(dev);
+
+ if (!priv->page_pool) {
+ struct page_pool_params pp_params = {
+ .order = 0,
+ .flags = 0,
+ .pool_size = 128,
+ .nid = NUMA_NO_NODE,
+ .max_len = PAGE_SIZE - sizeof(struct skb_shared_info),
+ };
+ struct netdev_rx_queue *rxq;
+ struct page_pool *pp;
+ int err;
+
+ rxq = __netif_get_rx_queue(dev, 0);
+
+ pp = page_pool_create(&pp_params);
+ if (IS_ERR(pp))
+ return pp;
+
+ err = xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq, MEM_TYPE_PAGE_POOL, pp);
+ if (err) {
+ page_pool_destroy(pp);
+ return ERR_PTR(err);
+ }
+ priv->page_pool = pp;
+ }
+
+ return priv->page_pool;
+}
+
static const struct net_device_ops loopback_ops = {
.ndo_init = loopback_dev_init,
.ndo_start_xmit = loopback_xmit,
@@ -208,7 +254,7 @@ static __net_init int loopback_net_init(struct net *net)
int err;
err = -ENOMEM;
- dev = alloc_netdev(0, "lo", NET_NAME_UNKNOWN, loopback_setup);
+ dev = alloc_netdev(sizeof(struct loopback_priv), "lo", NET_NAME_UNKNOWN, loopback_setup);
if (!dev)
goto out;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 3ec42495a43a5..efce0f22b71ca 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2962,6 +2962,7 @@ void dev_close(struct net_device *dev);
void dev_close_many(struct list_head *head, bool unlink);
void dev_disable_lro(struct net_device *dev);
int dev_loopback_xmit(struct net *net, struct sock *sk, struct sk_buff *newskb);
+struct page_pool *dev_loopback_get_page_pool(struct net *net);
u16 dev_pick_tx_zero(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev);
u16 dev_pick_tx_cpu_id(struct net_device *dev, struct sk_buff *skb,