← Documents Documentation/networking/page_pool.rst GitHub 원문 ↗

Linux 6.18.37 · Networking

Page Pool API

Network RX용 page를 queue별 lockless cache에서 할당·DMA sync·재활용하는 Page Pool API입니다.

Source pathDocumentation/networking/page_pool.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

page_pool.rst:1-199

Page Pool은 hardware queue마다 독립 pool을 두고 NAPI의 직렬화 보장을 이용해 RX page를 lock 없이 빠르게 재사용합니다. DMA sync 범위는 전체 page 기준으로 지정하며 XDP·skb lifetime과 driver teardown에서 올바른 반환 helper를 선택해야 합니다.

Page Pool lifecycle 요약
Per-queue pool 생성fast cache allocationRX/XDP/SKB 사용direct 또는 deferred recycledriver unload 반환

할당부터 재활용·unload까지입니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 =============
4 Page Pool API
5 =============
6
7 .. kernel-doc:: include/net/page_pool/helpers.h
8 :doc: page_pool allocator
9
10 Architecture overview
11 =====================
12
13 .. code-block:: none
14
15 +------------------+
16 | Driver |
17 +------------------+
18 ^
19 |
20 |
21 |
22 v
23 +--------------------------------------------+
24 | request memory |
25 +--------------------------------------------+
26 ^ ^
27 | |
28 | Pool empty | Pool has entries
29 | |
30 v v
31 +-----------------------+ +------------------------+
32 | alloc (and map) pages | | get page from cache |
33 +-----------------------+ +------------------------+
34 ^ ^
35 | |
36 | cache available | No entries, refill
37 | | from ptr-ring
38 | |
39 v v
40 +-----------------+ +------------------+
41 | Fast cache | | ptr-ring cache |
42 +-----------------+ +------------------+
43
44 Monitoring
45 ==========
46 Information about page pools on the system can be accessed via the netdev
47 genetlink family (see Documentation/netlink/specs/netdev.yaml).
48
49 API interface
50 =============
51 The number of pools created **must** match the number of hardware queues
52 unless hardware restrictions make that impossible. This would otherwise beat the
53 purpose of page pool, which is allocate pages fast from cache without locking.
54 This lockless guarantee naturally comes from running under a NAPI softirq.
55 The protection doesn't strictly have to be NAPI, any guarantee that allocating
56 a page will cause no race conditions is enough.
57
58 .. kernel-doc:: net/core/page_pool.c
59 :identifiers: page_pool_create
60
61 .. kernel-doc:: include/net/page_pool/types.h
62 :identifiers: struct page_pool_params
63
64 .. kernel-doc:: include/net/page_pool/helpers.h
65 :identifiers: page_pool_put_page page_pool_put_full_page
66 page_pool_recycle_direct page_pool_free_va
67 page_pool_dev_alloc_pages page_pool_dev_alloc_frag
68 page_pool_dev_alloc page_pool_dev_alloc_va
69 page_pool_get_dma_addr page_pool_get_dma_dir
70
71 .. kernel-doc:: net/core/page_pool.c
72 :identifiers: page_pool_put_page_bulk page_pool_get_stats
73
74 DMA sync
75 --------
76 Driver is always responsible for syncing the pages for the CPU.
77 Drivers may choose to take care of syncing for the device as well
78 or set the ``PP_FLAG_DMA_SYNC_DEV`` flag to request that pages
79 allocated from the page pool are already synced for the device.
80
81 If ``PP_FLAG_DMA_SYNC_DEV`` is set, the driver must inform the core what portion
82 of the buffer has to be synced. This allows the core to avoid syncing the entire
83 page when the drivers knows that the device only accessed a portion of the page.
84
85 Most drivers will reserve headroom in front of the frame. This part
86 of the buffer is not touched by the device, so to avoid syncing
87 it drivers can set the ``offset`` field in struct page_pool_params
88 appropriately.
89
90 For pages recycled on the XDP xmit and skb paths the page pool will
91 use the ``max_len`` member of struct page_pool_params to decide how
92 much of the page needs to be synced (starting at ``offset``).
93 When directly freeing pages in the driver (page_pool_put_page())
94 the ``dma_sync_size`` argument specifies how much of the buffer needs
95 to be synced.
96
97 If in doubt set ``offset`` to 0, ``max_len`` to ``PAGE_SIZE`` and
98 pass -1 as ``dma_sync_size``. That combination of arguments is always
99 correct.
100
101 Note that the syncing parameters are for the entire page.
102 This is important to remember when using fragments (``PP_FLAG_PAGE_FRAG``),
103 where allocated buffers may be smaller than a full page.
104 Unless the driver author really understands page pool internals
105 it's recommended to always use ``offset = 0``, ``max_len = PAGE_SIZE``
106 with fragmented page pools.
107
108 Stats API and structures
109 ------------------------
110 If the kernel is configured with ``CONFIG_PAGE_POOL_STATS=y``, the API
111 page_pool_get_stats() and structures described below are available.
112 It takes a pointer to a ``struct page_pool`` and a pointer to a struct
113 page_pool_stats allocated by the caller.
114
115 Older drivers expose page pool statistics via ethtool or debugfs.
116 The same statistics are accessible via the netlink netdev family
117 in a driver-independent fashion.
118
119 .. kernel-doc:: include/net/page_pool/types.h
120 :identifiers: struct page_pool_recycle_stats
121 struct page_pool_alloc_stats
122 struct page_pool_stats
123
124 Coding examples
125 ===============
126
127 Registration
128 ------------
129
130 .. code-block:: c
131
132 /* Page pool registration */
133 struct page_pool_params pp_params = { 0 };
134 struct xdp_rxq_info xdp_rxq;
135 int err;
136
137 pp_params.order = 0;
138 /* internal DMA mapping in page_pool */
139 pp_params.flags = PP_FLAG_DMA_MAP;
140 pp_params.pool_size = DESC_NUM;
141 pp_params.nid = NUMA_NO_NODE;
142 pp_params.dev = priv->dev;
143 pp_params.napi = napi; /* only if locking is tied to NAPI */
144 pp_params.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
145 page_pool = page_pool_create(&pp_params);
146
147 err = xdp_rxq_info_reg(&xdp_rxq, ndev, 0);
148 if (err)
149 goto err_out;
150
151 err = xdp_rxq_info_reg_mem_model(&xdp_rxq, MEM_TYPE_PAGE_POOL, page_pool);
152 if (err)
153 goto err_out;
154
155 NAPI poller
156 -----------
157
158
159 .. code-block:: c
160
161 /* NAPI Rx poller */
162 enum dma_data_direction dma_dir;
163
164 dma_dir = page_pool_get_dma_dir(dring->page_pool);
165 while (done < budget) {
166 if (some error)
167 page_pool_recycle_direct(page_pool, page);
168 if (packet_is_xdp) {
169 if XDP_DROP:
170 page_pool_recycle_direct(page_pool, page);
171 } else (packet_is_skb) {
172 skb_mark_for_recycle(skb);
173 new_page = page_pool_dev_alloc_pages(page_pool);
174 }
175 }
176
177 Stats
178 -----
179
180 .. code-block:: c
181
182 #ifdef CONFIG_PAGE_POOL_STATS
183 /* retrieve stats */
184 struct page_pool_stats stats = { 0 };
185 if (page_pool_get_stats(page_pool, &stats)) {
186 /* perhaps the driver reports statistics with ethool */
187 ethtool_print_allocation_stats(&stats.alloc_stats);
188 ethtool_print_recycle_stats(&stats.recycle_stats);
189 }
190 #endif
191
192 Driver unload
193 -------------
194
195 .. code-block:: c
196
197 /* Driver unload */
198 page_pool_put_full_page(page_pool, page, false);
199 xdp_rxq_info_unreg(&xdp_rxq);
200

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

Allocator architecture와 두 cache

1-43

`include/net/page_pool/helpers.h`의 kernel-doc는 page-pool allocator 자체를 설명합니다. Page Pool은 network driver가 page 또는 fragment를 빠르게 재사용하도록 설계된 allocator입니다.

Driver가 memory를 요청했을 때 pool이 비어 있으면 새 page를 할당하고 필요하면 DMA mapping도 수행합니다. Pool에 entry가 있으면 cache에서 page를 가져옵니다. Fast cache에 entry가 있으면 바로 반환하고, 비어 있으면 ptr-ring cache에서 refill합니다.

이 구조의 목적은 hot allocation path를 fast cache에서 처리하고, 더 큰 ptr-ring을 refill source로 두며, 둘 다 비었을 때만 일반 page allocation·mapping 비용을 지불하는 것입니다.

Page Pool allocation architecture
Driver memory requestPool has entriesFast cache hitcached page 반환
Driver memory requestFast cache emptyptr-ring cache refillcached page 반환
Driver memory requestPool emptyallocate pageDMA map if requestedpage 반환

원문의 ASCII allocator 구조를 hit·refill·miss 경로로 재구성했습니다.

.. SPDX-License-Identifier: GPL-2.0

=============
Page Pool API
=============

.. kernel-doc:: include/net/page_pool/helpers.h
   :doc: page_pool allocator

Architecture overview
=====================

.. code-block:: none

    +------------------+
    |       Driver     |
    +------------------+
            ^
            |
            |
            |
            v
    +--------------------------------------------+
    |                request memory              |
    +--------------------------------------------+
        ^                                  ^
        |                                  |
        | Pool empty                       | Pool has entries
        |                                  |
        v                                  v
    +-----------------------+     +------------------------+
    | alloc (and map) pages |     |  get page from cache   |
    +-----------------------+     +------------------------+
                                    ^                    ^
                                    |                    |
                                    | cache available    | No entries, refill
                                    |                    | from ptr-ring
                                    |                    |
                                    v                    v
                          +-----------------+     +------------------+
                          |   Fast cache    |     |  ptr-ring cache  |
                          +-----------------+     +------------------+

Monitoring과 lockless queue 규칙

44-73

System의 page-pool 정보는 netdev Generic Netlink family로 조회할 수 있습니다. Protocol 정의는 `Documentation/netlink/specs/netdev.yaml`에 있습니다.

Hardware 제약 때문에 불가능한 경우를 제외하면 생성한 pool 수는 hardware queue 수와 반드시 같아야 합니다. 그렇지 않으면 locking 없이 cache에서 page를 빠르게 할당하려는 page-pool의 목적을 훼손합니다.

이 lockless 보장은 자연스럽게 NAPI softirq context에서 나옵니다. 반드시 NAPI여야 하는 것은 아니며 page allocation에 race가 없다는 다른 보장이 있어도 충분합니다.

문서는 `page_pool_create`, `struct page_pool_params`, page 반환·재활용 함수, page·fragment·VA allocation helper, DMA address·direction helper, bulk 반환과 stats API의 kernel-doc를 연결합니다. 함수명과 source path는 원문 directive에 그대로 보존되어 있습니다.

Page Pool API 묶음
역할주요 symbol
생성·설정page_pool_create, struct page_pool_params
반환·재활용page_pool_put_page, page_pool_put_full_page, page_pool_recycle_direct
할당page_pool_dev_alloc_pages, page_pool_dev_alloc_frag, page_pool_dev_alloc_va
DMA 조회page_pool_get_dma_addr, page_pool_get_dma_dir
Bulk·statspage_pool_put_page_bulk, page_pool_get_stats

Kernel-doc에서 연결하는 역할별 interface입니다.

Monitoring
==========
Information about page pools on the system can be accessed via the netdev
genetlink family (see Documentation/netlink/specs/netdev.yaml).

API interface
=============
The number of pools created **must** match the number of hardware queues
unless hardware restrictions make that impossible. This would otherwise beat the
purpose of page pool, which is allocate pages fast from cache without locking.
This lockless guarantee naturally comes from running under a NAPI softirq.
The protection doesn't strictly have to be NAPI, any guarantee that allocating
a page will cause no race conditions is enough.

.. kernel-doc:: net/core/page_pool.c
   :identifiers: page_pool_create

.. kernel-doc:: include/net/page_pool/types.h
   :identifiers: struct page_pool_params

.. kernel-doc:: include/net/page_pool/helpers.h
   :identifiers: page_pool_put_page page_pool_put_full_page
                 page_pool_recycle_direct page_pool_free_va
                 page_pool_dev_alloc_pages page_pool_dev_alloc_frag
                 page_pool_dev_alloc page_pool_dev_alloc_va
                 page_pool_get_dma_addr page_pool_get_dma_dir

.. kernel-doc:: net/core/page_pool.c
   :identifiers: page_pool_put_page_bulk page_pool_get_stats

DMA sync 범위와 fragment 주의

74-107

Page를 CPU용으로 sync하는 책임은 항상 driver에 있습니다. Device용 sync도 driver가 직접 할 수 있고, `PP_FLAG_DMA_SYNC_DEV`를 설정해 page pool에서 할당한 page가 이미 device용으로 sync되어 나오도록 요청할 수도 있습니다.

`PP_FLAG_DMA_SYNC_DEV`를 쓰면 buffer에서 sync해야 할 범위를 core에 알려야 합니다. Device가 page 일부만 접근하는 것을 driver가 알 때 전체 page sync를 피할 수 있습니다.

대부분의 driver는 frame 앞에 headroom을 예약하며 device는 이 부분을 건드리지 않습니다. 따라서 `struct page_pool_params.offset`을 적절히 설정하면 headroom sync를 생략할 수 있습니다.

XDP xmit과 skb path에서 재활용하는 page는 `offset`부터 `struct page_pool_params.max_len`만큼 sync합니다. Driver가 `page_pool_put_page()`로 직접 page를 해제할 때는 `dma_sync_size` argument가 sync할 buffer 길이를 정합니다.

확신이 없으면 `offset=0`, `max_len=PAGE_SIZE`, `dma_sync_size=-1`을 사용하면 항상 정확합니다. Sync parameter는 fragment 크기가 아니라 전체 page 기준입니다. `PP_FLAG_PAGE_FRAG`로 full page보다 작은 buffer를 할당하는 경우 특히 중요합니다. Page-pool 내부를 충분히 이해하지 못했다면 fragmented pool에서도 `offset=0`, `max_len=PAGE_SIZE`를 권장합니다.

DMA sync 범위
상황범위
XDP xmit·skb recycleoffset부터 max_len
page_pool_put_page 직접 반환dma_sync_size argument
안전한 기본값offset=0, max_len=PAGE_SIZE, dma_sync_size=-1
Fragment pool 권장값offset=0, max_len=PAGE_SIZE

Page Pool에서 core와 driver가 사용하는 범위 설정입니다.

DMA sync
--------
Driver is always responsible for syncing the pages for the CPU.
Drivers may choose to take care of syncing for the device as well
or set the ``PP_FLAG_DMA_SYNC_DEV`` flag to request that pages
allocated from the page pool are already synced for the device.

If ``PP_FLAG_DMA_SYNC_DEV`` is set, the driver must inform the core what portion
of the buffer has to be synced. This allows the core to avoid syncing the entire
page when the drivers knows that the device only accessed a portion of the page.

Most drivers will reserve headroom in front of the frame. This part
of the buffer is not touched by the device, so to avoid syncing
it drivers can set the ``offset`` field in struct page_pool_params
appropriately.

For pages recycled on the XDP xmit and skb paths the page pool will
use the ``max_len`` member of struct page_pool_params to decide how
much of the page needs to be synced (starting at ``offset``).
When directly freeing pages in the driver (page_pool_put_page())
the ``dma_sync_size`` argument specifies how much of the buffer needs
to be synced.

If in doubt set ``offset`` to 0, ``max_len`` to ``PAGE_SIZE`` and
pass -1 as ``dma_sync_size``. That combination of arguments is always
correct.

Note that the syncing parameters are for the entire page.
This is important to remember when using fragments (``PP_FLAG_PAGE_FRAG``),
where allocated buffers may be smaller than a full page.
Unless the driver author really understands page pool internals
it's recommended to always use ``offset = 0``, ``max_len = PAGE_SIZE``
with fragmented page pools.

Stats 설정과 driver-independent Netlink

108-123

Kernel이 `CONFIG_PAGE_POOL_STATS=y`로 구성되면 `page_pool_get_stats()`와 관련 구조체를 사용할 수 있습니다. Caller가 할당한 `struct page_pool_stats`와 대상 `struct page_pool` pointer를 함수에 전달합니다.

예전 driver는 page-pool 통계를 ethtool 또는 debugfs로 노출했습니다. 같은 통계를 이제 driver와 무관한 방식으로 netlink netdev family에서 조회할 수 있습니다.

문서는 `struct page_pool_recycle_stats`, `struct page_pool_alloc_stats`, `struct page_pool_stats`의 kernel-doc를 포함합니다.

Stats API and structures
------------------------
If the kernel is configured with ``CONFIG_PAGE_POOL_STATS=y``, the API
page_pool_get_stats() and structures described below are available.
It takes a  pointer to a ``struct page_pool`` and a pointer to a struct
page_pool_stats allocated by the caller.

Older drivers expose page pool statistics via ethtool or debugfs.
The same statistics are accessible via the netlink netdev family
in a driver-independent fashion.

.. kernel-doc:: include/net/page_pool/types.h
   :identifiers: struct page_pool_recycle_stats
                 struct page_pool_alloc_stats
                 struct page_pool_stats

Pool과 XDP RX queue 등록

124-154

등록 예제는 `struct page_pool_params`와 `struct xdp_rxq_info`를 준비합니다. `order=0`, internal DMA mapping을 위한 `PP_FLAG_DMA_MAP`, descriptor 수와 같은 `pool_size`, `NUMA_NO_NODE`, device, NAPI pointer를 지정합니다. Locking 보장이 NAPI에 묶일 때만 `napi`를 설정합니다.

DMA direction은 XDP program이 있으면 `DMA_BIDIRECTIONAL`, 없으면 `DMA_FROM_DEVICE`를 선택하고 `page_pool_create()`로 pool을 만듭니다.

그 뒤 `xdp_rxq_info_reg()`로 RX queue를 network device에 등록하고, `xdp_rxq_info_reg_mem_model(..., MEM_TYPE_PAGE_POOL, page_pool)`로 memory model과 pool을 연결합니다. 각 단계의 error는 `err_out`으로 이동합니다. 전체 C code를 그대로 보존했습니다.

Page Pool registration
page_pool_params 채우기page_pool_createxdp_rxq_info_regxdp_rxq_info_reg_mem_model(MEM_TYPE_PAGE_POOL)RX path 준비

Driver setup의 호출 순서입니다.

Coding examples
===============

Registration
------------

.. code-block:: c

    /* Page pool registration */
    struct page_pool_params pp_params = { 0 };
    struct xdp_rxq_info xdp_rxq;
    int err;

    pp_params.order = 0;
    /* internal DMA mapping in page_pool */
    pp_params.flags = PP_FLAG_DMA_MAP;
    pp_params.pool_size = DESC_NUM;
    pp_params.nid = NUMA_NO_NODE;
    pp_params.dev = priv->dev;
    pp_params.napi = napi; /* only if locking is tied to NAPI */
    pp_params.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
    page_pool = page_pool_create(&pp_params);

    err = xdp_rxq_info_reg(&xdp_rxq, ndev, 0);
    if (err)
        goto err_out;

    err = xdp_rxq_info_reg_mem_model(&xdp_rxq, MEM_TYPE_PAGE_POOL, page_pool);
    if (err)
        goto err_out;

NAPI RX poller의 recycle·allocation

155-176

NAPI RX poller 예제는 `page_pool_get_dma_dir()`로 pool의 DMA direction을 얻고 budget까지 packet을 처리합니다.

오류가 나거나 XDP packet이 `XDP_DROP` 결과를 받으면 `page_pool_recycle_direct(page_pool, page)`로 현재 NAPI context에서 즉시 recycle합니다. SKB path에서는 `skb_mark_for_recycle(skb)`로 page가 나중에 pool로 돌아오게 표시하고 `page_pool_dev_alloc_pages(page_pool)`로 새 RX page를 얻습니다.

NAPI page 처리
경로동작
RX errorpage_pool_recycle_direct
XDP_DROPpage_pool_recycle_direct
SKBskb_mark_for_recycle + 새 page_pool_dev_alloc_pages

Packet 경로별 page lifetime입니다.

NAPI poller
-----------


.. code-block:: c

    /* NAPI Rx poller */
    enum dma_data_direction dma_dir;

    dma_dir = page_pool_get_dma_dir(dring->page_pool);
    while (done < budget) {
        if (some error)
            page_pool_recycle_direct(page_pool, page);
        if (packet_is_xdp) {
            if XDP_DROP:
                page_pool_recycle_direct(page_pool, page);
        } else (packet_is_skb) {
            skb_mark_for_recycle(skb);
            new_page = page_pool_dev_alloc_pages(page_pool);
        }
    }

Allocation·recycle 통계 조회

177-191

Stats 예제는 `CONFIG_PAGE_POOL_STATS`일 때 `struct page_pool_stats`를 0으로 초기화하고 `page_pool_get_stats(page_pool, &stats)`를 호출합니다.

통계를 얻으면 driver가 ethtool로 노출하는 경우처럼 `alloc_stats`와 `recycle_stats`를 각각 출력합니다. Compile-time guard와 example symbol은 원문 code에 보존되어 있습니다.

Stats
-----

.. code-block:: c

        #ifdef CONFIG_PAGE_POOL_STATS
        /* retrieve stats */
        struct page_pool_stats stats = { 0 };
        if (page_pool_get_stats(page_pool, &stats)) {
                /* perhaps the driver reports statistics with ethool */
                ethtool_print_allocation_stats(&stats.alloc_stats);
                ethtool_print_recycle_stats(&stats.recycle_stats);
        }
        #endif

Driver unload와 resource 해제

192-199

Driver unload 예제는 남아 있는 page를 `page_pool_put_full_page(page_pool, page, false)`로 pool에 반환하고 `xdp_rxq_info_unreg(&xdp_rxq)`로 XDP RX queue 정보를 해제합니다.

Driver lifecycle
page_pool_create + xdp_rxq registerNAPI allocate/recycleput_full_pagexdp_rxq_info_unreg

등록·운영·해제의 대응 관계입니다.

Driver unload
-------------

.. code-block:: c

    /* Driver unload */
    page_pool_put_full_page(page_pool, page, false);
    xdp_rxq_info_unreg(&xdp_rxq);