From david at redhat.com Mon Sep 1 11:35:05 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 13:35:05 +0200 Subject: [PATCH v1 18/36] mm/gup: drop nth_page() usage within folio when recording subpages In-Reply-To: <8a26ae97-9a78-4db5-be98-9c1f6e4fb403@lucifer.local> References: <20250827220141.262669-1-david@redhat.com> <20250827220141.262669-19-david@redhat.com> <632fea32-28aa-4993-9eff-99fc291c64f2@redhat.com> <8a26ae97-9a78-4db5-be98-9c1f6e4fb403@lucifer.local> Message-ID: <44072455-fc68-430d-ad38-0b9ce6a10b8d@redhat.com> >> >> >> The nice thing is that we only record pages in the array if they actually passed our tests. > > Yeah that's nice actually. > > This is fine (not the meme :P) :D > > So yes let's do this! That leaves us with the following on top of this patch: From 4533c6e3590cab0c53e81045624d5949e0ad9015 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 29 Aug 2025 15:41:45 +0200 Subject: [PATCH] mm/gup: remove record_subpages() We can just cleanup the code by calculating the #refs earlier, so we can just inline what remains of record_subpages(). Calculate the number of references/pages ahead of times, and record them only once all our tests passed. Signed-off-by: David Hildenbrand --- mm/gup.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/mm/gup.c b/mm/gup.c index 89ca0813791ab..5a72a135ec70b 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -484,19 +484,6 @@ static inline void mm_set_has_pinned_flag(struct mm_struct *mm) #ifdef CONFIG_MMU #ifdef CONFIG_HAVE_GUP_FAST -static int record_subpages(struct page *page, unsigned long sz, - unsigned long addr, unsigned long end, - struct page **pages) -{ - int nr; - - page += (addr & (sz - 1)) >> PAGE_SHIFT; - for (nr = 0; addr != end; nr++, addr += PAGE_SIZE) - pages[nr] = page++; - - return nr; -} - /** * try_grab_folio_fast() - Attempt to get or pin a folio in fast path. * @page: pointer to page to be grabbed @@ -2963,8 +2950,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, if (pmd_special(orig)) return 0; - page = pmd_page(orig); - refs = record_subpages(page, PMD_SIZE, addr, end, pages + *nr); + refs = (end - addr) >> PAGE_SHIFT; + page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); folio = try_grab_folio_fast(page, refs, flags); if (!folio) @@ -2985,6 +2972,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, } *nr += refs; + for (; refs; refs--) + *(pages++) = page++; folio_set_referenced(folio); return 1; } @@ -3003,8 +2992,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, if (pud_special(orig)) return 0; - page = pud_page(orig); - refs = record_subpages(page, PUD_SIZE, addr, end, pages + *nr); + refs = (end - addr) >> PAGE_SHIFT; + page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT); folio = try_grab_folio_fast(page, refs, flags); if (!folio) @@ -3026,6 +3015,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, } *nr += refs; + for (; refs; refs--) + *(pages++) = page++; folio_set_referenced(folio); return 1; } -- 2.50.1 -- Cheers David / dhildenb From david at redhat.com Mon Sep 1 15:03:28 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:28 +0200 Subject: [PATCH v2 07/37] mm/memremap: reject unreasonable folio/compound page sizes in memremap_pages() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-8-david@redhat.com> Let's reject unreasonable folio sizes early, where we can still fail. We'll add sanity checks to prepare_compound_head/prepare_compound_page next. Is there a way to configure a system such that unreasonable folio sizes would be possible? It would already be rather questionable. If so, we'd probably want to bail out earlier, where we can avoid a WARN and just report a proper error message that indicates where something went wrong such that we messed up. Acked-by: SeongJae Park Reviewed-by: Lorenzo Stoakes Reviewed-by: Liam R. Howlett Signed-off-by: David Hildenbrand --- mm/memremap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/memremap.c b/mm/memremap.c index b0ce0d8254bd8..a2d4bb88f64b6 100644 --- a/mm/memremap.c +++ b/mm/memremap.c @@ -275,6 +275,9 @@ void *memremap_pages(struct dev_pagemap *pgmap, int nid) if (WARN_ONCE(!nr_range, "nr_range must be specified\n")) return ERR_PTR(-EINVAL); + if (WARN_ONCE(pgmap->vmemmap_shift > MAX_FOLIO_ORDER, + "requested folio size unsupported\n")) + return ERR_PTR(-EINVAL); switch (pgmap->type) { case MEMORY_DEVICE_PRIVATE: -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:29 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:29 +0200 Subject: [PATCH v2 08/37] mm/hugetlb: check for unreasonable folio sizes when registering hstate In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-9-david@redhat.com> Let's check that no hstate that corresponds to an unreasonable folio size is registered by an architecture. If we were to succeed registering, we could later try allocating an unsupported gigantic folio size. Further, let's add a BUILD_BUG_ON() for checking that HUGETLB_PAGE_ORDER is sane at build time. As HUGETLB_PAGE_ORDER is dynamic on powerpc, we have to use a BUILD_BUG_ON_INVALID() to make it compile. No existing kernel configuration should be able to trigger this check: either SPARSEMEM without SPARSEMEM_VMEMMAP cannot be configured or gigantic folios will not exceed a memory section (the case on sparse). Reviewed-by: Zi Yan Reviewed-by: Lorenzo Stoakes Reviewed-by: Liam R. Howlett Signed-off-by: David Hildenbrand --- mm/hugetlb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 1e777cc51ad04..d3542e92a712e 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -4657,6 +4657,7 @@ static int __init hugetlb_init(void) BUILD_BUG_ON(sizeof_field(struct page, private) * BITS_PER_BYTE < __NR_HPAGEFLAGS); + BUILD_BUG_ON_INVALID(HUGETLB_PAGE_ORDER > MAX_FOLIO_ORDER); if (!hugepages_supported()) { if (hugetlb_max_hstate || default_hstate_max_huge_pages) @@ -4740,6 +4741,7 @@ void __init hugetlb_add_hstate(unsigned int order) } BUG_ON(hugetlb_max_hstate >= HUGE_MAX_HSTATE); BUG_ON(order < order_base_2(__NR_USED_SUBPAGE)); + WARN_ON(order > MAX_FOLIO_ORDER); h = &hstates[hugetlb_max_hstate++]; __mutex_init(&h->resize_lock, "resize mutex", &h->resize_key); h->order = order; -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:30 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:30 +0200 Subject: [PATCH v2 09/37] mm/mm_init: make memmap_init_compound() look more like prep_compound_page() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-10-david@redhat.com> Grepping for "prep_compound_page" leaves on clueless how devdax gets its compound pages initialized. Let's add a comment that might help finding this open-coded prep_compound_page() initialization more easily. Further, let's be less smart about the ordering of initialization and just perform the prep_compound_head() call after all tail pages were initialized: just like prep_compound_page() does. No need for a comment to describe the initialization order: again, just like prep_compound_page(). Reviewed-by: Mike Rapoport (Microsoft) Reviewed-by: Wei Yang Reviewed-by: Lorenzo Stoakes Acked-by: Liam R. Howlett Signed-off-by: David Hildenbrand --- mm/mm_init.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/mm/mm_init.c b/mm/mm_init.c index 5c21b3af216b2..df614556741a4 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -1091,6 +1091,12 @@ static void __ref memmap_init_compound(struct page *head, unsigned long pfn, end_pfn = head_pfn + nr_pages; unsigned int order = pgmap->vmemmap_shift; + /* + * We have to initialize the pages, including setting up page links. + * prep_compound_page() does not take care of that, so instead we + * open-code prep_compound_page() so we can take care of initializing + * the pages in the same go. + */ __SetPageHead(head); for (pfn = head_pfn + 1; pfn < end_pfn; pfn++) { struct page *page = pfn_to_page(pfn); @@ -1098,15 +1104,8 @@ static void __ref memmap_init_compound(struct page *head, __init_zone_device_page(page, pfn, zone_idx, nid, pgmap); prep_compound_tail(head, pfn - head_pfn); set_page_count(page, 0); - - /* - * The first tail page stores important compound page info. - * Call prep_compound_head() after the first tail page has - * been initialized, to not have the data overwritten. - */ - if (pfn == head_pfn + 1) - prep_compound_head(head, order); } + prep_compound_head(head, order); } void __ref memmap_init_zone_device(struct zone *zone, -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:31 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:31 +0200 Subject: [PATCH v2 10/37] mm: sanity-check maximum folio size in folio_set_order() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-11-david@redhat.com> Let's sanity-check in folio_set_order() whether we would be trying to create a folio with an order that would make it exceed MAX_FOLIO_ORDER. This will enable the check whenever a folio/compound page is initialized through prepare_compound_head() / prepare_compound_page() with CONFIG_DEBUG_VM set. Reviewed-by: Zi Yan Reviewed-by: Wei Yang Reviewed-by: Lorenzo Stoakes Reviewed-by: Liam R. Howlett Signed-off-by: David Hildenbrand --- mm/internal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/internal.h b/mm/internal.h index 45da9ff5694f6..9b0129531d004 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -755,6 +755,7 @@ static inline void folio_set_order(struct folio *folio, unsigned int order) { if (WARN_ON_ONCE(!order || !folio_test_large(folio))) return; + VM_WARN_ON_ONCE(order > MAX_FOLIO_ORDER); folio->_flags_1 = (folio->_flags_1 & ~0xffUL) | order; #ifdef NR_PAGES_IN_LARGE_FOLIO -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:32 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:32 +0200 Subject: [PATCH v2 11/37] mm: limit folio/compound page sizes in problematic kernel configs In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-12-david@redhat.com> Let's limit the maximum folio size in problematic kernel config where the memmap is allocated per memory section (SPARSEMEM without SPARSEMEM_VMEMMAP) to a single memory section. Currently, only a single architectures supports ARCH_HAS_GIGANTIC_PAGE but not SPARSEMEM_VMEMMAP: sh. Fortunately, the biggest hugetlb size sh supports is 64 MiB (HUGETLB_PAGE_SIZE_64MB) and the section size is at least 64 MiB (SECTION_SIZE_BITS == 26), so their use case is not degraded. As folios and memory sections are naturally aligned to their order-2 size in memory, consequently a single folio can no longer span multiple memory sections on these problematic kernel configs. nth_page() is no longer required when operating within a single compound page / folio. Reviewed-by: Zi Yan Acked-by: Mike Rapoport (Microsoft) Reviewed-by: Wei Yang Reviewed-by: Lorenzo Stoakes Reviewed-by: Liam R. Howlett Signed-off-by: David Hildenbrand --- include/linux/mm.h | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 77737cbf2216a..2dee79fa2efcf 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2053,11 +2053,25 @@ static inline long folio_nr_pages(const struct folio *folio) return folio_large_nr_pages(folio); } -/* Only hugetlbfs can allocate folios larger than MAX_ORDER */ -#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE -#define MAX_FOLIO_ORDER PUD_ORDER -#else +#if !defined(CONFIG_ARCH_HAS_GIGANTIC_PAGE) +/* + * We don't expect any folios that exceed buddy sizes (and consequently + * memory sections). + */ #define MAX_FOLIO_ORDER MAX_PAGE_ORDER +#elif defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP) +/* + * Only pages within a single memory section are guaranteed to be + * contiguous. By limiting folios to a single memory section, all folio + * pages are guaranteed to be contiguous. + */ +#define MAX_FOLIO_ORDER PFN_SECTION_SHIFT +#else +/* + * There is no real limit on the folio size. We limit them to the maximum we + * currently expect (e.g., hugetlb, dax). + */ +#define MAX_FOLIO_ORDER PUD_ORDER #endif #define MAX_FOLIO_NR_PAGES (1UL << MAX_FOLIO_ORDER) -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:33 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:33 +0200 Subject: [PATCH v2 12/37] mm: simplify folio_page() and folio_page_idx() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-13-david@redhat.com> Now that a single folio/compound page can no longer span memory sections in problematic kernel configurations, we can stop using nth_page() in folio_page() and folio_page_idx(). While at it, turn both macros into static inline functions and add kernel doc for folio_page_idx(). Reviewed-by: Zi Yan Reviewed-by: Wei Yang Reviewed-by: Lorenzo Stoakes Signed-off-by: David Hildenbrand --- include/linux/mm.h | 16 ++++++++++++++-- include/linux/page-flags.h | 5 ++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 2dee79fa2efcf..f6880e3225c5c 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -210,10 +210,8 @@ extern unsigned long sysctl_admin_reserve_kbytes; #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP) #define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n)) -#define folio_page_idx(folio, p) (page_to_pfn(p) - folio_pfn(folio)) #else #define nth_page(page,n) ((page) + (n)) -#define folio_page_idx(folio, p) ((p) - &(folio)->page) #endif /* to align the pointer to the (next) page boundary */ @@ -225,6 +223,20 @@ extern unsigned long sysctl_admin_reserve_kbytes; /* test whether an address (unsigned long or pointer) is aligned to PAGE_SIZE */ #define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE) +/** + * folio_page_idx - Return the number of a page in a folio. + * @folio: The folio. + * @page: The folio page. + * + * This function expects that the page is actually part of the folio. + * The returned number is relative to the start of the folio. + */ +static inline unsigned long folio_page_idx(const struct folio *folio, + const struct page *page) +{ + return page - &folio->page; +} + static inline struct folio *lru_to_folio(struct list_head *head) { return list_entry((head)->prev, struct folio, lru); diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 5ee6ffbdbf831..faf17ca211b4f 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -316,7 +316,10 @@ static __always_inline unsigned long _compound_head(const struct page *page) * check that the page number lies within @folio; the caller is presumed * to have a reference to the page. */ -#define folio_page(folio, n) nth_page(&(folio)->page, n) +static inline struct page *folio_page(struct folio *folio, unsigned long n) +{ + return &folio->page + n; +} static __always_inline int PageTail(const struct page *page) { -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:34 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:34 +0200 Subject: [PATCH v2 13/37] mm/hugetlb: cleanup hugetlb_folio_init_tail_vmemmap() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-14-david@redhat.com> We can now safely iterate over all pages in a folio, so no need for the pfn_to_page(). Also, as we already force the refcount in __init_single_page() to 1 through init_page_count(), we can just set the refcount to 0 and avoid page_ref_freeze() + VM_BUG_ON. Likely, in the future, we would just want to tell __init_single_page() to which value to initialize the refcount. Further, adjust the comments to highlight that we are dealing with an open-coded prep_compound_page() variant, and add another comment explaining why we really need the __init_single_page() only on the tail pages. Note that the current code was likely problematic, but we never ran into it: prep_compound_tail() would have been called with an offset that might exceed a memory section, and prep_compound_tail() would have simply added that offset to the page pointer -- which would not have done the right thing on sparsemem without vmemmap. Reviewed-by: Mike Rapoport (Microsoft) Reviewed-by: Lorenzo Stoakes Acked-by: Liam R. Howlett Signed-off-by: David Hildenbrand --- mm/hugetlb.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index d3542e92a712e..56e6d2af08434 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3237,17 +3237,18 @@ static void __init hugetlb_folio_init_tail_vmemmap(struct folio *folio, { enum zone_type zone = zone_idx(folio_zone(folio)); int nid = folio_nid(folio); + struct page *page = folio_page(folio, start_page_number); unsigned long head_pfn = folio_pfn(folio); unsigned long pfn, end_pfn = head_pfn + end_page_number; - int ret; - - for (pfn = head_pfn + start_page_number; pfn < end_pfn; pfn++) { - struct page *page = pfn_to_page(pfn); + /* + * As we marked all tail pages with memblock_reserved_mark_noinit(), + * we must initialize them ourselves here. + */ + for (pfn = head_pfn + start_page_number; pfn < end_pfn; page++, pfn++) { __init_single_page(page, pfn, zone, nid); prep_compound_tail((struct page *)folio, pfn - head_pfn); - ret = page_ref_freeze(page, 1); - VM_BUG_ON(!ret); + set_page_count(page, 0); } } @@ -3257,12 +3258,15 @@ static void __init hugetlb_folio_init_vmemmap(struct folio *folio, { int ret; - /* Prepare folio head */ + /* + * This is an open-coded prep_compound_page() whereby we avoid + * walking pages twice by initializing/preparing+freezing them in the + * same go. + */ __folio_clear_reserved(folio); __folio_set_head(folio); ret = folio_ref_freeze(folio, 1); VM_BUG_ON(!ret); - /* Initialize the necessary tail struct pages */ hugetlb_folio_init_tail_vmemmap(folio, 1, nr_pages); prep_compound_head((struct page *)folio, huge_page_order(h)); } -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:35 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:35 +0200 Subject: [PATCH v2 14/37] mm/mm/percpu-km: drop nth_page() usage within single allocation In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-15-david@redhat.com> We're allocating a higher-order page from the buddy. For these pages (that are guaranteed to not exceed a single memory section) there is no need to use nth_page(). Reviewed-by: Lorenzo Stoakes Acked-by: Liam R. Howlett Signed-off-by: David Hildenbrand --- mm/percpu-km.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/percpu-km.c b/mm/percpu-km.c index fe31aa19db81a..4efa74a495cb6 100644 --- a/mm/percpu-km.c +++ b/mm/percpu-km.c @@ -69,7 +69,7 @@ static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp) } for (i = 0; i < nr_pages; i++) - pcpu_set_page_chunk(nth_page(pages, i), chunk); + pcpu_set_page_chunk(pages + i, chunk); chunk->data = pages; chunk->base_addr = page_address(pages); -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:36 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:36 +0200 Subject: [PATCH v2 15/37] fs: hugetlbfs: remove nth_page() usage within folio in adjust_range_hwpoison() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-16-david@redhat.com> The nth_page() is not really required anymore, so let's remove it. Reviewed-by: Zi Yan Reviewed-by: Lorenzo Stoakes Signed-off-by: David Hildenbrand --- fs/hugetlbfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 34d496a2b7de6..c5a46d10afaa0 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -217,7 +217,7 @@ static size_t adjust_range_hwpoison(struct folio *folio, size_t offset, break; offset += n; if (offset == PAGE_SIZE) { - page = nth_page(page, 1); + page++; offset = 0; } } -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:37 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:37 +0200 Subject: [PATCH v2 16/37] fs: hugetlbfs: cleanup folio in adjust_range_hwpoison() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-17-david@redhat.com> Let's cleanup and simplify the function a bit. Reviewed-by: Zi Yan Reviewed-by: Lorenzo Stoakes Signed-off-by: David Hildenbrand --- fs/hugetlbfs/inode.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index c5a46d10afaa0..3cfdf4091001f 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -192,37 +192,25 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, * Someone wants to read @bytes from a HWPOISON hugetlb @folio from @offset. * Returns the maximum number of bytes one can read without touching the 1st raw * HWPOISON page. - * - * The implementation borrows the iteration logic from copy_page_to_iter*. */ static size_t adjust_range_hwpoison(struct folio *folio, size_t offset, size_t bytes) { - struct page *page; - size_t n = 0; - size_t res = 0; - - /* First page to start the loop. */ - page = folio_page(folio, offset / PAGE_SIZE); - offset %= PAGE_SIZE; - while (1) { - if (is_raw_hwpoison_page_in_hugepage(page)) - break; + struct page *page = folio_page(folio, offset / PAGE_SIZE); + size_t safe_bytes; + + if (is_raw_hwpoison_page_in_hugepage(page)) + return 0; + /* Safe to read the remaining bytes in this page. */ + safe_bytes = PAGE_SIZE - (offset % PAGE_SIZE); + page++; - /* Safe to read n bytes without touching HWPOISON subpage. */ - n = min(bytes, (size_t)PAGE_SIZE - offset); - res += n; - bytes -= n; - if (!bytes || !n) + /* Check each remaining page as long as we are not done yet. */ + for (; safe_bytes < bytes; safe_bytes += PAGE_SIZE, page++) + if (is_raw_hwpoison_page_in_hugepage(page)) break; - offset += n; - if (offset == PAGE_SIZE) { - page++; - offset = 0; - } - } - return res; + return min(safe_bytes, bytes); } /* -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:38 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:38 +0200 Subject: [PATCH v2 17/37] mm/pagewalk: drop nth_page() usage within folio in folio_walk_start() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-18-david@redhat.com> It's no longer required to use nth_page() within a folio, so let's just drop the nth_page() in folio_walk_start(). Reviewed-by: Lorenzo Stoakes Reviewed-by: Liam R. Howlett Signed-off-by: David Hildenbrand --- mm/pagewalk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/pagewalk.c b/mm/pagewalk.c index c6753d370ff4e..9e4225e5fcf5c 100644 --- a/mm/pagewalk.c +++ b/mm/pagewalk.c @@ -1004,7 +1004,7 @@ struct folio *folio_walk_start(struct folio_walk *fw, found: if (expose_page) /* Note: Offset from the mapped page, not the folio start. */ - fw->page = nth_page(page, (addr & (entry_size - 1)) >> PAGE_SHIFT); + fw->page = page + ((addr & (entry_size - 1)) >> PAGE_SHIFT); else fw->page = NULL; fw->ptl = ptl; -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:39 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:39 +0200 Subject: [PATCH v2 18/37] mm/gup: drop nth_page() usage within folio when recording subpages In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-19-david@redhat.com> nth_page() is no longer required when iterating over pages within a single folio, so let's just drop it when recording subpages. Reviewed-by: Lorenzo Stoakes Signed-off-by: David Hildenbrand --- mm/gup.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mm/gup.c b/mm/gup.c index 8157197a19f77..c10cd969c1a3b 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -488,12 +488,11 @@ static int record_subpages(struct page *page, unsigned long sz, unsigned long addr, unsigned long end, struct page **pages) { - struct page *start_page; int nr; - start_page = nth_page(page, (addr & (sz - 1)) >> PAGE_SHIFT); + page += (addr & (sz - 1)) >> PAGE_SHIFT; for (nr = 0; addr != end; nr++, addr += PAGE_SIZE) - pages[nr] = nth_page(start_page, nr); + pages[nr] = page++; return nr; } @@ -1512,7 +1511,7 @@ static long __get_user_pages(struct mm_struct *mm, } for (j = 0; j < page_increm; j++) { - subpage = nth_page(page, j); + subpage = page + j; pages[i + j] = subpage; flush_anon_page(vma, subpage, start + j * PAGE_SIZE); flush_dcache_page(subpage); -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:40 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:40 +0200 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-20-david@redhat.com> We can just cleanup the code by calculating the #refs earlier, so we can just inline what remains of record_subpages(). Calculate the number of references/pages ahead of times, and record them only once all our tests passed. Signed-off-by: David Hildenbrand --- mm/gup.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/mm/gup.c b/mm/gup.c index c10cd969c1a3b..f0f4d1a68e094 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -484,19 +484,6 @@ static inline void mm_set_has_pinned_flag(struct mm_struct *mm) #ifdef CONFIG_MMU #ifdef CONFIG_HAVE_GUP_FAST -static int record_subpages(struct page *page, unsigned long sz, - unsigned long addr, unsigned long end, - struct page **pages) -{ - int nr; - - page += (addr & (sz - 1)) >> PAGE_SHIFT; - for (nr = 0; addr != end; nr++, addr += PAGE_SIZE) - pages[nr] = page++; - - return nr; -} - /** * try_grab_folio_fast() - Attempt to get or pin a folio in fast path. * @page: pointer to page to be grabbed @@ -2967,8 +2954,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, if (pmd_special(orig)) return 0; - page = pmd_page(orig); - refs = record_subpages(page, PMD_SIZE, addr, end, pages + *nr); + refs = (end - addr) >> PAGE_SHIFT; + page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); folio = try_grab_folio_fast(page, refs, flags); if (!folio) @@ -2989,6 +2976,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, } *nr += refs; + for (; refs; refs--) + *(pages++) = page++; folio_set_referenced(folio); return 1; } @@ -3007,8 +2996,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, if (pud_special(orig)) return 0; - page = pud_page(orig); - refs = record_subpages(page, PUD_SIZE, addr, end, pages + *nr); + refs = (end - addr) >> PAGE_SHIFT; + page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT); folio = try_grab_folio_fast(page, refs, flags); if (!folio) @@ -3030,6 +3019,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, } *nr += refs; + for (; refs; refs--) + *(pages++) = page++; folio_set_referenced(folio); return 1; } -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:41 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:41 +0200 Subject: [PATCH v2 20/37] io_uring/zcrx: remove nth_page() usage within folio In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-21-david@redhat.com> Within a folio/compound page, nth_page() is no longer required. Given that we call folio_test_partial_kmap()+kmap_local_page(), the code would already be problematic if the pages would span multiple folios. So let's just assume that all src pages belong to a single folio/compound page and can be iterated ordinarily. The dst page is currently always a single page, so we're not actually iterating anything. Reviewed-by: Pavel Begunkov Reviewed-by: Lorenzo Stoakes Cc: Jens Axboe Cc: Pavel Begunkov Signed-off-by: David Hildenbrand --- io_uring/zcrx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c index e5ff49f3425e0..18c12f4b56b6c 100644 --- a/io_uring/zcrx.c +++ b/io_uring/zcrx.c @@ -975,9 +975,9 @@ static ssize_t io_copy_page(struct io_copy_cache *cc, struct page *src_page, if (folio_test_partial_kmap(page_folio(dst_page)) || folio_test_partial_kmap(page_folio(src_page))) { - dst_page = nth_page(dst_page, dst_offset / PAGE_SIZE); + dst_page += dst_offset / PAGE_SIZE; dst_offset = offset_in_page(dst_offset); - src_page = nth_page(src_page, src_offset / PAGE_SIZE); + src_page += src_offset / PAGE_SIZE; src_offset = offset_in_page(src_offset); n = min(PAGE_SIZE - src_offset, PAGE_SIZE - dst_offset); n = min(n, len); -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:42 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:42 +0200 Subject: [PATCH v2 21/37] mips: mm: convert __flush_dcache_pages() to __flush_dcache_folio_pages() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-22-david@redhat.com> Let's make it clearer that we are operating within a single folio by providing both the folio and the page. This implies that for flush_dcache_folio() we'll now avoid one more page->folio lookup, and that we can safely drop the "nth_page" usage. While at it, drop the "extern" from the function declaration. Cc: Thomas Bogendoerfer Signed-off-by: David Hildenbrand --- arch/mips/include/asm/cacheflush.h | 11 +++++++---- arch/mips/mm/cache.c | 8 ++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h index 5d283ef89d90d..5099c1b65a584 100644 --- a/arch/mips/include/asm/cacheflush.h +++ b/arch/mips/include/asm/cacheflush.h @@ -50,13 +50,14 @@ extern void (*flush_cache_mm)(struct mm_struct *mm); extern void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn); -extern void __flush_dcache_pages(struct page *page, unsigned int nr); +void __flush_dcache_folio_pages(struct folio *folio, struct page *page, unsigned int nr); #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 static inline void flush_dcache_folio(struct folio *folio) { if (cpu_has_dc_aliases) - __flush_dcache_pages(&folio->page, folio_nr_pages(folio)); + __flush_dcache_folio_pages(folio, folio_page(folio, 0), + folio_nr_pages(folio)); else if (!cpu_has_ic_fills_f_dc) folio_set_dcache_dirty(folio); } @@ -64,10 +65,12 @@ static inline void flush_dcache_folio(struct folio *folio) static inline void flush_dcache_page(struct page *page) { + struct folio *folio = page_folio(page); + if (cpu_has_dc_aliases) - __flush_dcache_pages(page, 1); + __flush_dcache_folio_pages(folio, page, 1); else if (!cpu_has_ic_fills_f_dc) - folio_set_dcache_dirty(page_folio(page)); + folio_set_dcache_dirty(folio); } #define flush_dcache_mmap_lock(mapping) do { } while (0) diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index bf9a37c60e9f0..e3b4224c9a406 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -99,9 +99,9 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, return 0; } -void __flush_dcache_pages(struct page *page, unsigned int nr) +void __flush_dcache_folio_pages(struct folio *folio, struct page *page, + unsigned int nr) { - struct folio *folio = page_folio(page); struct address_space *mapping = folio_flush_mapping(folio); unsigned long addr; unsigned int i; @@ -117,12 +117,12 @@ void __flush_dcache_pages(struct page *page, unsigned int nr) * get faulted into the tlb (and thus flushed) anyways. */ for (i = 0; i < nr; i++) { - addr = (unsigned long)kmap_local_page(nth_page(page, i)); + addr = (unsigned long)kmap_local_page(page + i); flush_data_cache_page(addr); kunmap_local((void *)addr); } } -EXPORT_SYMBOL(__flush_dcache_pages); +EXPORT_SYMBOL(__flush_dcache_folio_pages); void __flush_anon_page(struct page *page, unsigned long vmaddr) { -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:43 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:43 +0200 Subject: [PATCH v2 22/37] mm/cma: refuse handing out non-contiguous page ranges In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-23-david@redhat.com> Let's disallow handing out PFN ranges with non-contiguous pages, so we can remove the nth-page usage in __cma_alloc(), and so any callers don't have to worry about that either when wanting to blindly iterate pages. This is really only a problem in configs with SPARSEMEM but without SPARSEMEM_VMEMMAP, and only when we would cross memory sections in some cases. Will this cause harm? Probably not, because it's mostly 32bit that does not support SPARSEMEM_VMEMMAP. If this ever becomes a problem we could look into allocating the memmap for the memory sections spanned by a single CMA region in one go from memblock. Reviewed-by: Alexandru Elisei Reviewed-by: Lorenzo Stoakes Signed-off-by: David Hildenbrand --- include/linux/mm.h | 6 ++++++ mm/cma.c | 39 ++++++++++++++++++++++++--------------- mm/util.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 15 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index f6880e3225c5c..2ca1eb2db63ec 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -209,9 +209,15 @@ extern unsigned long sysctl_user_reserve_kbytes; extern unsigned long sysctl_admin_reserve_kbytes; #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP) +bool page_range_contiguous(const struct page *page, unsigned long nr_pages); #define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n)) #else #define nth_page(page,n) ((page) + (n)) +static inline bool page_range_contiguous(const struct page *page, + unsigned long nr_pages) +{ + return true; +} #endif /* to align the pointer to the (next) page boundary */ diff --git a/mm/cma.c b/mm/cma.c index e56ec64d0567e..813e6dc7b0954 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -780,10 +780,8 @@ static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr, unsigned long count, unsigned int align, struct page **pagep, gfp_t gfp) { - unsigned long mask, offset; - unsigned long pfn = -1; - unsigned long start = 0; unsigned long bitmap_maxno, bitmap_no, bitmap_count; + unsigned long start, pfn, mask, offset; int ret = -EBUSY; struct page *page = NULL; @@ -795,7 +793,7 @@ static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr, if (bitmap_count > bitmap_maxno) goto out; - for (;;) { + for (start = 0; ; start = bitmap_no + mask + 1) { spin_lock_irq(&cma->lock); /* * If the request is larger than the available number @@ -812,6 +810,22 @@ static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr, spin_unlock_irq(&cma->lock); break; } + + pfn = cmr->base_pfn + (bitmap_no << cma->order_per_bit); + page = pfn_to_page(pfn); + + /* + * Do not hand out page ranges that are not contiguous, so + * callers can just iterate the pages without having to worry + * about these corner cases. + */ + if (!page_range_contiguous(page, count)) { + spin_unlock_irq(&cma->lock); + pr_warn_ratelimited("%s: %s: skipping incompatible area [0x%lx-0x%lx]", + __func__, cma->name, pfn, pfn + count - 1); + continue; + } + bitmap_set(cmr->bitmap, bitmap_no, bitmap_count); cma->available_count -= count; /* @@ -821,29 +835,24 @@ static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr, */ spin_unlock_irq(&cma->lock); - pfn = cmr->base_pfn + (bitmap_no << cma->order_per_bit); mutex_lock(&cma->alloc_mutex); ret = alloc_contig_range(pfn, pfn + count, ACR_FLAGS_CMA, gfp); mutex_unlock(&cma->alloc_mutex); - if (ret == 0) { - page = pfn_to_page(pfn); + if (!ret) break; - } cma_clear_bitmap(cma, cmr, pfn, count); if (ret != -EBUSY) break; pr_debug("%s(): memory range at pfn 0x%lx %p is busy, retrying\n", - __func__, pfn, pfn_to_page(pfn)); + __func__, pfn, page); - trace_cma_alloc_busy_retry(cma->name, pfn, pfn_to_page(pfn), - count, align); - /* try again with a bit different memory target */ - start = bitmap_no + mask + 1; + trace_cma_alloc_busy_retry(cma->name, pfn, page, count, align); } out: - *pagep = page; + if (!ret) + *pagep = page; return ret; } @@ -882,7 +891,7 @@ static struct page *__cma_alloc(struct cma *cma, unsigned long count, */ if (page) { for (i = 0; i < count; i++) - page_kasan_tag_reset(nth_page(page, i)); + page_kasan_tag_reset(page + i); } if (ret && !(gfp & __GFP_NOWARN)) { diff --git a/mm/util.c b/mm/util.c index d235b74f7aff7..fbdb73aaf35fe 100644 --- a/mm/util.c +++ b/mm/util.c @@ -1280,4 +1280,39 @@ unsigned int folio_pte_batch(struct folio *folio, pte_t *ptep, pte_t pte, { return folio_pte_batch_flags(folio, NULL, ptep, &pte, max_nr, 0); } + +#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP) +/** + * page_range_contiguous - test whether the page range is contiguous + * @page: the start of the page range. + * @nr_pages: the number of pages in the range. + * + * Test whether the page range is contiguous, such that they can be iterated + * naively, corresponding to iterating a contiguous PFN range. + * + * This function should primarily only be used for debug checks, or when + * working with page ranges that are not naturally contiguous (e.g., pages + * within a folio are). + * + * Returns true if contiguous, otherwise false. + */ +bool page_range_contiguous(const struct page *page, unsigned long nr_pages) +{ + const unsigned long start_pfn = page_to_pfn(page); + const unsigned long end_pfn = start_pfn + nr_pages; + unsigned long pfn; + + /* + * The memmap is allocated per memory section, so no need to check + * within the first section. However, we need to check each other + * spanned memory section once, making sure the first page in a + * section could similarly be reached by just iterating pages. + */ + for (pfn = ALIGN(start_pfn, PAGES_PER_SECTION); + pfn < end_pfn; pfn += PAGES_PER_SECTION) + if (unlikely(page + (pfn - start_pfn) != pfn_to_page(pfn))) + return false; + return true; +} +#endif #endif /* CONFIG_MMU */ -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:44 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:44 +0200 Subject: [PATCH v2 23/37] dma-remap: drop nth_page() in dma_common_contiguous_remap() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-24-david@redhat.com> dma_common_contiguous_remap() is used to remap an "allocated contiguous region". Within a single allocation, there is no need to use nth_page() anymore. Neither the buddy, nor hugetlb, nor CMA will hand out problematic page ranges. Acked-by: Marek Szyprowski Reviewed-by: Lorenzo Stoakes Cc: Robin Murphy Signed-off-by: David Hildenbrand --- kernel/dma/remap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/dma/remap.c b/kernel/dma/remap.c index 9e2afad1c6152..b7c1c0c92d0c8 100644 --- a/kernel/dma/remap.c +++ b/kernel/dma/remap.c @@ -49,7 +49,7 @@ void *dma_common_contiguous_remap(struct page *page, size_t size, if (!pages) return NULL; for (i = 0; i < count; i++) - pages[i] = nth_page(page, i); + pages[i] = page++; vaddr = vmap(pages, count, VM_DMA_COHERENT, prot); kvfree(pages); -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:45 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:45 +0200 Subject: [PATCH v2 24/37] scatterlist: disallow non-contigous page ranges in a single SG entry In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-25-david@redhat.com> The expectation is that there is currently no user that would pass in non-contigous page ranges: no allocator, not even VMA, will hand these out. The only problematic part would be if someone would provide a range obtained directly from memblock, or manually merge problematic ranges. If we find such cases, we should fix them to create separate SG entries. Let's check in sg_set_page() that this is really the case. No need to check in sg_set_folio(), as pages in a folio are guaranteed to be contiguous. As sg_set_page() gets inlined into modules, we have to export the page_range_contiguous() helper -- use EXPORT_SYMBOL, there is nothing special about this helper such that we would want to enforce GPL-only modules. We can now drop the nth_page() usage in sg_page_iter_page(). Acked-by: Marek Szyprowski Reviewed-by: Lorenzo Stoakes Signed-off-by: David Hildenbrand --- include/linux/scatterlist.h | 3 ++- mm/util.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index 6f8a4965f9b98..29f6ceb98d74b 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h @@ -158,6 +158,7 @@ static inline void sg_assign_page(struct scatterlist *sg, struct page *page) static inline void sg_set_page(struct scatterlist *sg, struct page *page, unsigned int len, unsigned int offset) { + VM_WARN_ON_ONCE(!page_range_contiguous(page, ALIGN(len + offset, PAGE_SIZE) / PAGE_SIZE)); sg_assign_page(sg, page); sg->offset = offset; sg->length = len; @@ -600,7 +601,7 @@ void __sg_page_iter_start(struct sg_page_iter *piter, */ static inline struct page *sg_page_iter_page(struct sg_page_iter *piter) { - return nth_page(sg_page(piter->sg), piter->sg_pgoffset); + return sg_page(piter->sg) + piter->sg_pgoffset; } /** diff --git a/mm/util.c b/mm/util.c index fbdb73aaf35fe..bb4b47cd67091 100644 --- a/mm/util.c +++ b/mm/util.c @@ -1314,5 +1314,6 @@ bool page_range_contiguous(const struct page *page, unsigned long nr_pages) return false; return true; } +EXPORT_SYMBOL(page_range_contiguous); #endif #endif /* CONFIG_MMU */ -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:55 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:55 +0200 Subject: [PATCH v2 34/37] mm/gup: drop nth_page() usage in unpin_user_page_range_dirty_lock() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-35-david@redhat.com> There is the concern that unpin_user_page_range_dirty_lock() might do some weird merging of PFN ranges -- either now or in the future -- such that PFN range is contiguous but the page range might not be. Let's sanity-check for that and drop the nth_page() usage. Reviewed-by: Lorenzo Stoakes Signed-off-by: David Hildenbrand --- mm/gup.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mm/gup.c b/mm/gup.c index f0f4d1a68e094..010fe56f6e132 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -237,7 +237,7 @@ void folio_add_pin(struct folio *folio) static inline struct folio *gup_folio_range_next(struct page *start, unsigned long npages, unsigned long i, unsigned int *ntails) { - struct page *next = nth_page(start, i); + struct page *next = start + i; struct folio *folio = page_folio(next); unsigned int nr = 1; @@ -342,6 +342,10 @@ EXPORT_SYMBOL(unpin_user_pages_dirty_lock); * "gup-pinned page range" refers to a range of pages that has had one of the * pin_user_pages() variants called on that page. * + * The page range must be truly physically contiguous: the page range + * corresponds to a contiguous PFN range and all pages can be iterated + * naturally. + * * For the page ranges defined by [page .. page+npages], make that range (or * its head pages, if a compound page) dirty, if @make_dirty is true, and if the * page range was previously listed as clean. @@ -359,6 +363,8 @@ void unpin_user_page_range_dirty_lock(struct page *page, unsigned long npages, struct folio *folio; unsigned int nr; + VM_WARN_ON_ONCE(!page_range_contiguous(page, npages)); + for (i = 0; i < npages; i += nr) { folio = gup_folio_range_next(page, npages, i, &nr); if (make_dirty && !folio_test_dirty(folio)) { -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:56 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:56 +0200 Subject: [PATCH v2 35/37] kfence: drop nth_page() usage In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-36-david@redhat.com> We want to get rid of nth_page(), and kfence init code is the last user. Unfortunately, we might actually walk a PFN range where the pages are not contiguous, because we might be allocating an area from memblock that could span memory sections in problematic kernel configs (SPARSEMEM without SPARSEMEM_VMEMMAP). We could check whether the page range is contiguous using page_range_contiguous() and failing kfence init, or making kfence incompatible these problemtic kernel configs. Let's keep it simple and simply use pfn_to_page() by iterating PFNs. Reviewed-by: Marco Elver Reviewed-by: Lorenzo Stoakes Cc: Alexander Potapenko Cc: Dmitry Vyukov Signed-off-by: David Hildenbrand --- mm/kfence/core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 0ed3be100963a..727c20c94ac59 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -594,15 +594,14 @@ static void rcu_guarded_free(struct rcu_head *h) */ static unsigned long kfence_init_pool(void) { - unsigned long addr; - struct page *pages; + unsigned long addr, start_pfn; int i; if (!arch_kfence_init_pool()) return (unsigned long)__kfence_pool; addr = (unsigned long)__kfence_pool; - pages = virt_to_page(__kfence_pool); + start_pfn = PHYS_PFN(virt_to_phys(__kfence_pool)); /* * Set up object pages: they must have PGTY_slab set to avoid freeing @@ -613,11 +612,12 @@ static unsigned long kfence_init_pool(void) * enters __slab_free() slow-path. */ for (i = 0; i < KFENCE_POOL_SIZE / PAGE_SIZE; i++) { - struct slab *slab = page_slab(nth_page(pages, i)); + struct slab *slab; if (!i || (i % 2)) continue; + slab = page_slab(pfn_to_page(start_pfn + i)); __folio_set_slab(slab_folio(slab)); #ifdef CONFIG_MEMCG slab->obj_exts = (unsigned long)&kfence_metadata_init[i / 2 - 1].obj_exts | @@ -665,10 +665,12 @@ static unsigned long kfence_init_pool(void) reset_slab: for (i = 0; i < KFENCE_POOL_SIZE / PAGE_SIZE; i++) { - struct slab *slab = page_slab(nth_page(pages, i)); + struct slab *slab; if (!i || (i % 2)) continue; + + slab = page_slab(pfn_to_page(start_pfn + i)); #ifdef CONFIG_MEMCG slab->obj_exts = 0; #endif -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:57 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:57 +0200 Subject: [PATCH v2 36/37] block: update comment of "struct bio_vec" regarding nth_page() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-37-david@redhat.com> Ever since commit 858c708d9efb ("block: move the bi_size update out of __bio_try_merge_page"), page_is_mergeable() no longer exists, and the logic in bvec_try_merge_page() is now a simple page pointer comparison. Reviewed-by: Lorenzo Stoakes Signed-off-by: David Hildenbrand --- include/linux/bvec.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/linux/bvec.h b/include/linux/bvec.h index 0a80e1f9aa201..3fc0efa0825b1 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -22,11 +22,8 @@ struct page; * @bv_len: Number of bytes in the address range. * @bv_offset: Start of the address range relative to the start of @bv_page. * - * The following holds for a bvec if n * PAGE_SIZE < bv_offset + bv_len: - * - * nth_page(@bv_page, n) == @bv_page + n - * - * This holds because page_is_mergeable() checks the above property. + * All pages within a bio_vec starting from @bv_page are contiguous and + * can simply be iterated (see bvec_advance()). */ struct bio_vec { struct page *bv_page; -- 2.50.1 From david at redhat.com Mon Sep 1 15:03:58 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 1 Sep 2025 17:03:58 +0200 Subject: [PATCH v2 37/37] mm: remove nth_page() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-38-david@redhat.com> Now that all users are gone, let's remove it. Reviewed-by: Lorenzo Stoakes Signed-off-by: David Hildenbrand --- include/linux/mm.h | 2 -- tools/testing/scatterlist/linux/mm.h | 1 - 2 files changed, 3 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 2ca1eb2db63ec..b26ca8b2162d9 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -210,9 +210,7 @@ extern unsigned long sysctl_admin_reserve_kbytes; #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP) bool page_range_contiguous(const struct page *page, unsigned long nr_pages); -#define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n)) #else -#define nth_page(page,n) ((page) + (n)) static inline bool page_range_contiguous(const struct page *page, unsigned long nr_pages) { diff --git a/tools/testing/scatterlist/linux/mm.h b/tools/testing/scatterlist/linux/mm.h index 5bd9e6e806254..121ae78d6e885 100644 --- a/tools/testing/scatterlist/linux/mm.h +++ b/tools/testing/scatterlist/linux/mm.h @@ -51,7 +51,6 @@ static inline unsigned long page_to_phys(struct page *page) #define page_to_pfn(page) ((unsigned long)(page) / PAGE_SIZE) #define pfn_to_page(pfn) (void *)((pfn) * PAGE_SIZE) -#define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n)) #define __min(t1, t2, min1, min2, x, y) ({ \ t1 min1 = (x); \ -- 2.50.1 From kuba at kernel.org Mon Sep 1 18:50:41 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Mon, 1 Sep 2025 11:50:41 -0700 Subject: [PATCH net 1/4] netlink: specs: fou: change local-v6/peer-v6 check In-Reply-To: <20250901145034.525518-2-ast@fiberby.net> References: <20250901145034.525518-1-ast@fiberby.net> <20250901145034.525518-2-ast@fiberby.net> Message-ID: <20250901115041.03d661fa@kernel.org> On Mon, 1 Sep 2025 14:50:20 +0000 Asbj?rn Sloth T?nnesen wrote: > While fixing the binary min-len implementaion, I noticed that > the only user, should AFAICT be using exact-len instead. > > In net/ipv4/fou_core.c FOU_ATTR_LOCAL_V6 and FOU_ATTR_PEER_V6 > are only used for singular IPv6 addresses, a exact-len policy, > therefore seams like a better fit. > > AFAICT this was caused by lacking support for the exact-len check > at the time of the blamed commit, which was later remedied by > c63ad379526 ("tools: ynl-gen: add support for exact-len validation"). No, take a look at 1d562c32e43. The intention was to keep the code before and after the same. I agree that the check is not ideal but it's not really a bug to ignore some input. So if you want to clean this up -- net-next and no Fixes tag.. > This patch therefore changes the local-v6/peer-v6 attributes to > use an exact-len check, instead of a min-len check. From kuba at kernel.org Mon Sep 1 18:52:08 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Mon, 1 Sep 2025 11:52:08 -0700 Subject: [PATCH net 2/4] tools: ynl-gen: use macro for binary min-len check In-Reply-To: <20250901145034.525518-3-ast@fiberby.net> References: <20250901145034.525518-1-ast@fiberby.net> <20250901145034.525518-3-ast@fiberby.net> Message-ID: <20250901115208.0cc7e9a6@kernel.org> On Mon, 1 Sep 2025 14:50:21 +0000 Asbj?rn Sloth T?nnesen wrote: > This patch changes the generated min-len check for binary > attributes to use the NLA_POLICY_MIN_LEN() macro, and thereby > ensures that .validation_type is not left at NLA_VALIDATE_NONE. Please test this well and include the results in the commit message. I'm pretty sure it's fine as is. From kuba at kernel.org Mon Sep 1 18:56:50 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Mon, 1 Sep 2025 11:56:50 -0700 Subject: [PATCH net 3/4] tools: ynl-gen: fix nested array counting In-Reply-To: <20250901145034.525518-4-ast@fiberby.net> References: <20250901145034.525518-1-ast@fiberby.net> <20250901145034.525518-4-ast@fiberby.net> Message-ID: <20250901115650.107e078e@kernel.org> On Mon, 1 Sep 2025 14:50:22 +0000 Asbj?rn Sloth T?nnesen wrote: > The blamed commit introduced the concept of split attribute > counting, and later allocating an array to hold them, however > TypeArrayNest wasn't updated to use the new counting variable. > > Abbreviated example from tools/net/ynl/generated/nl80211-user.c: > nl80211_if_combination_attributes_parse(...): > unsigned int n_limits = 0; > [...] > ynl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len) > if (type == NL80211_IFACE_COMB_LIMITS) > ynl_attr_for_each_nested(attr2, attr) > dst->_count.limits++; > if (n_limits) { > dst->_count.limits = n_limits; > /* allocate and parse attributes */ > } > > In the above example n_limits is guaranteed to always be 0, > hence the conditional is unsatisfiable and is optimized out. > > This patch changes the attribute counting to use n_limits++ in the > attribute counting loop in the above example. Looks good, thanks! Reviewed-by: Jakub Kicinski From kuba at kernel.org Mon Sep 1 18:57:40 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Mon, 1 Sep 2025 11:57:40 -0700 Subject: [PATCH net 4/4] genetlink: fix typo in comment In-Reply-To: <20250901145034.525518-5-ast@fiberby.net> References: <20250901145034.525518-1-ast@fiberby.net> <20250901145034.525518-5-ast@fiberby.net> Message-ID: <20250901115740.686152b9@kernel.org> On Mon, 1 Sep 2025 14:50:23 +0000 Asbj?rn Sloth T?nnesen wrote: > In this context "not that ..." should properly be "note that ...". > > Fixes: b8fd60c36a44 ("genetlink: allow families to use split ops directly") Looks good, but this is not a fix, please repost without the Fixes tag and for net-next. From david at redhat.com Fri Sep 5 06:41:23 2025 From: david at redhat.com (David Hildenbrand) Date: Fri, 5 Sep 2025 08:41:23 +0200 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <20250901150359.867252-20-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> Message-ID: <5090355d-546a-4d06-99e1-064354d156b5@redhat.com> On 01.09.25 17:03, David Hildenbrand wrote: > We can just cleanup the code by calculating the #refs earlier, > so we can just inline what remains of record_subpages(). > > Calculate the number of references/pages ahead of times, and record them > only once all our tests passed. > > Signed-off-by: David Hildenbrand > --- > mm/gup.c | 25 ++++++++----------------- > 1 file changed, 8 insertions(+), 17 deletions(-) > > diff --git a/mm/gup.c b/mm/gup.c > index c10cd969c1a3b..f0f4d1a68e094 100644 > --- a/mm/gup.c > +++ b/mm/gup.c > @@ -484,19 +484,6 @@ static inline void mm_set_has_pinned_flag(struct mm_struct *mm) > #ifdef CONFIG_MMU > > #ifdef CONFIG_HAVE_GUP_FAST > -static int record_subpages(struct page *page, unsigned long sz, > - unsigned long addr, unsigned long end, > - struct page **pages) > -{ > - int nr; > - > - page += (addr & (sz - 1)) >> PAGE_SHIFT; > - for (nr = 0; addr != end; nr++, addr += PAGE_SIZE) > - pages[nr] = page++; > - > - return nr; > -} > - > /** > * try_grab_folio_fast() - Attempt to get or pin a folio in fast path. > * @page: pointer to page to be grabbed > @@ -2967,8 +2954,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > if (pmd_special(orig)) > return 0; > > - page = pmd_page(orig); > - refs = record_subpages(page, PMD_SIZE, addr, end, pages + *nr); > + refs = (end - addr) >> PAGE_SHIFT; > + page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); > > folio = try_grab_folio_fast(page, refs, flags); > if (!folio) > @@ -2989,6 +2976,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > } > > *nr += refs; > + for (; refs; refs--) > + *(pages++) = page++; > folio_set_referenced(folio); > return 1; > } > @@ -3007,8 +2996,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > if (pud_special(orig)) > return 0; > > - page = pud_page(orig); > - refs = record_subpages(page, PUD_SIZE, addr, end, pages + *nr); > + refs = (end - addr) >> PAGE_SHIFT; > + page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT); > > folio = try_grab_folio_fast(page, refs, flags); > if (!folio) > @@ -3030,6 +3019,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > } > > *nr += refs; > + for (; refs; refs--) > + *(pages++) = page++; > folio_set_referenced(folio); > return 1; > } Okay, this code is nasty. We should rework this code to just return the nr and receive a the proper pages pointer, getting rid of the "*nr" parameter. For the time being, the following should do the trick: commit bfd07c995814354f6b66c5b6a72e96a7aa9fb73b (HEAD -> nth_page) Author: David Hildenbrand Date: Fri Sep 5 08:38:43 2025 +0200 fixup: mm/gup: remove record_subpages() pages is not adjusted by the caller, but idnexed by existing *nr. Signed-off-by: David Hildenbrand diff --git a/mm/gup.c b/mm/gup.c index 010fe56f6e132..22420f2069ee1 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -2981,6 +2981,7 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, return 0; } + pages += *nr; *nr += refs; for (; refs; refs--) *(pages++) = page++; @@ -3024,6 +3025,7 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, return 0; } + pages += *nr; *nr += refs; for (; refs; refs--) *(pages++) = page++; -- Cheers David / dhildenb From axboe at kernel.dk Fri Sep 5 11:26:53 2025 From: axboe at kernel.dk (Jens Axboe) Date: Fri, 5 Sep 2025 05:26:53 -0600 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <5090355d-546a-4d06-99e1-064354d156b5@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <5090355d-546a-4d06-99e1-064354d156b5@redhat.com> Message-ID: <1513d5fd-14ef-4cd0-a9a5-1016e9be6540@kernel.dk> On 9/5/25 12:41 AM, David Hildenbrand wrote: > On 01.09.25 17:03, David Hildenbrand wrote: >> We can just cleanup the code by calculating the #refs earlier, >> so we can just inline what remains of record_subpages(). >> >> Calculate the number of references/pages ahead of times, and record them >> only once all our tests passed. >> >> Signed-off-by: David Hildenbrand >> --- >> mm/gup.c | 25 ++++++++----------------- >> 1 file changed, 8 insertions(+), 17 deletions(-) >> >> diff --git a/mm/gup.c b/mm/gup.c >> index c10cd969c1a3b..f0f4d1a68e094 100644 >> --- a/mm/gup.c >> +++ b/mm/gup.c >> @@ -484,19 +484,6 @@ static inline void mm_set_has_pinned_flag(struct mm_struct *mm) >> #ifdef CONFIG_MMU >> #ifdef CONFIG_HAVE_GUP_FAST >> -static int record_subpages(struct page *page, unsigned long sz, >> - unsigned long addr, unsigned long end, >> - struct page **pages) >> -{ >> - int nr; >> - >> - page += (addr & (sz - 1)) >> PAGE_SHIFT; >> - for (nr = 0; addr != end; nr++, addr += PAGE_SIZE) >> - pages[nr] = page++; >> - >> - return nr; >> -} >> - >> /** >> * try_grab_folio_fast() - Attempt to get or pin a folio in fast path. >> * @page: pointer to page to be grabbed >> @@ -2967,8 +2954,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, >> if (pmd_special(orig)) >> return 0; >> - page = pmd_page(orig); >> - refs = record_subpages(page, PMD_SIZE, addr, end, pages + *nr); >> + refs = (end - addr) >> PAGE_SHIFT; >> + page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); >> folio = try_grab_folio_fast(page, refs, flags); >> if (!folio) >> @@ -2989,6 +2976,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, >> } >> *nr += refs; >> + for (; refs; refs--) >> + *(pages++) = page++; >> folio_set_referenced(folio); >> return 1; >> } >> @@ -3007,8 +2996,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, >> if (pud_special(orig)) >> return 0; >> - page = pud_page(orig); >> - refs = record_subpages(page, PUD_SIZE, addr, end, pages + *nr); >> + refs = (end - addr) >> PAGE_SHIFT; >> + page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT); >> folio = try_grab_folio_fast(page, refs, flags); >> if (!folio) >> @@ -3030,6 +3019,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, >> } >> *nr += refs; >> + for (; refs; refs--) >> + *(pages++) = page++; >> folio_set_referenced(folio); >> return 1; >> } > > Okay, this code is nasty. We should rework this code to just return the nr and receive a the proper > pages pointer, getting rid of the "*nr" parameter. > > For the time being, the following should do the trick: > > commit bfd07c995814354f6b66c5b6a72e96a7aa9fb73b (HEAD -> nth_page) > Author: David Hildenbrand > Date: Fri Sep 5 08:38:43 2025 +0200 > > fixup: mm/gup: remove record_subpages() > pages is not adjusted by the caller, but idnexed by existing *nr. > Signed-off-by: David Hildenbrand > > diff --git a/mm/gup.c b/mm/gup.c > index 010fe56f6e132..22420f2069ee1 100644 > --- a/mm/gup.c > +++ b/mm/gup.c > @@ -2981,6 +2981,7 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > return 0; > } > > + pages += *nr; > *nr += refs; > for (; refs; refs--) > *(pages++) = page++; > @@ -3024,6 +3025,7 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > return 0; > } > > + pages += *nr; > *nr += refs; > for (; refs; refs--) > *(pages++) = page++; > Tested as fixing the issue for me, thanks. -- Jens Axboe From david at redhat.com Fri Sep 5 11:38:32 2025 From: david at redhat.com (David Hildenbrand) Date: Fri, 5 Sep 2025 13:38:32 +0200 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <5090355d-546a-4d06-99e1-064354d156b5@redhat.com> Message-ID: <9fe9f8c7-f59d-4a4b-9668-d3cd2c5a5fc9@redhat.com> On 05.09.25 13:34, Lorenzo Stoakes wrote: > On Fri, Sep 05, 2025 at 08:41:23AM +0200, David Hildenbrand wrote: >> On 01.09.25 17:03, David Hildenbrand wrote: >>> We can just cleanup the code by calculating the #refs earlier, >>> so we can just inline what remains of record_subpages(). >>> >>> Calculate the number of references/pages ahead of times, and record them >>> only once all our tests passed. >>> >>> Signed-off-by: David Hildenbrand > > So strange I thought I looked at this...! > >>> --- >>> mm/gup.c | 25 ++++++++----------------- >>> 1 file changed, 8 insertions(+), 17 deletions(-) >>> >>> diff --git a/mm/gup.c b/mm/gup.c >>> index c10cd969c1a3b..f0f4d1a68e094 100644 >>> --- a/mm/gup.c >>> +++ b/mm/gup.c >>> @@ -484,19 +484,6 @@ static inline void mm_set_has_pinned_flag(struct mm_struct *mm) >>> #ifdef CONFIG_MMU >>> #ifdef CONFIG_HAVE_GUP_FAST >>> -static int record_subpages(struct page *page, unsigned long sz, >>> - unsigned long addr, unsigned long end, >>> - struct page **pages) >>> -{ >>> - int nr; >>> - >>> - page += (addr & (sz - 1)) >> PAGE_SHIFT; >>> - for (nr = 0; addr != end; nr++, addr += PAGE_SIZE) >>> - pages[nr] = page++; >>> - >>> - return nr; >>> -} >>> - >>> /** >>> * try_grab_folio_fast() - Attempt to get or pin a folio in fast path. >>> * @page: pointer to page to be grabbed >>> @@ -2967,8 +2954,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, >>> if (pmd_special(orig)) >>> return 0; >>> - page = pmd_page(orig); >>> - refs = record_subpages(page, PMD_SIZE, addr, end, pages + *nr); >>> + refs = (end - addr) >> PAGE_SHIFT; >>> + page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); >>> folio = try_grab_folio_fast(page, refs, flags); >>> if (!folio) >>> @@ -2989,6 +2976,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, >>> } >>> *nr += refs; >>> + for (; refs; refs--) >>> + *(pages++) = page++; >>> folio_set_referenced(folio); >>> return 1; >>> } >>> @@ -3007,8 +2996,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, >>> if (pud_special(orig)) >>> return 0; >>> - page = pud_page(orig); >>> - refs = record_subpages(page, PUD_SIZE, addr, end, pages + *nr); >>> + refs = (end - addr) >> PAGE_SHIFT; >>> + page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT); >>> folio = try_grab_folio_fast(page, refs, flags); >>> if (!folio) >>> @@ -3030,6 +3019,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, >>> } >>> *nr += refs; >>> + for (; refs; refs--) >>> + *(pages++) = page++; >>> folio_set_referenced(folio); >>> return 1; >>> } >> >> Okay, this code is nasty. We should rework this code to just return the nr and receive a the proper >> pages pointer, getting rid of the "*nr" parameter. >> >> For the time being, the following should do the trick: >> >> commit bfd07c995814354f6b66c5b6a72e96a7aa9fb73b (HEAD -> nth_page) >> Author: David Hildenbrand >> Date: Fri Sep 5 08:38:43 2025 +0200 >> >> fixup: mm/gup: remove record_subpages() >> pages is not adjusted by the caller, but idnexed by existing *nr. >> Signed-off-by: David Hildenbrand >> >> diff --git a/mm/gup.c b/mm/gup.c >> index 010fe56f6e132..22420f2069ee1 100644 >> --- a/mm/gup.c >> +++ b/mm/gup.c >> @@ -2981,6 +2981,7 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, >> return 0; >> } >> + pages += *nr; >> *nr += refs; >> for (; refs; refs--) >> *(pages++) = page++; >> @@ -3024,6 +3025,7 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, >> return 0; >> } >> + pages += *nr; >> *nr += refs; >> for (; refs; refs--) >> *(pages++) = page++; > > This looks correct. > > But. > > This is VERY nasty. Before we'd call record_subpages() with pages + *nr, where > it was clear we were offsetting by this, now we're making things imo way more > confusing. > > This makes me less in love with this approach to be honest. > > But perhaps it's the least worst thing for now until we can do a bigger > refactor... > > So since this seems correct to me, and for the sake of moving things forward > (was this one patch dropped from mm-new or does mm-new just have an old version? > Confused): > > Reviewed-by: Lorenzo Stoakes > > For this patch obviously with the fix applied. > > But can we PLEASE revisit this :) Yeah, I already asked someone internally if he would have time to do some refactorings in mm/gup.c. If that won't work out I shall do it at some point (and the same time reworking follow_page_mask() to just consume the array as well like gup does) -- Cheers David / dhildenb From wireguard at asbjorn.st Fri Sep 5 19:51:49 2025 From: wireguard at asbjorn.st (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Fri, 5 Sep 2025 19:51:49 +0000 Subject: [PATCH] ipc: linux: filter netdevices kernel-side Message-ID: <20250905195150.1134769-1-wireguard@asbjorn.st> Tell the kernel that we are only interested in wireguard netdevices, so that the kernel don't have to tells us about all the other netdevices. Tested with 10000 netdevices (common with ISP BNG setups), out of which 1 was a wireguard netdevice. Baseline: # time ./src/wg show real 0m0.342s user 0m0.013s sys 0m0.290s With patch: # time ./src/wg show real 0m0.006s user 0m0.000s sys 0m0.005s Signed-off-by: Asbj?rn Sloth T?nnesen --- NB: Since this email has been on the list a long-time, then maybe it will avoid moderation. src/ipc-linux.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ipc-linux.h b/src/ipc-linux.h index 01247f1..c56fede 100644 --- a/src/ipc-linux.h +++ b/src/ipc-linux.h @@ -80,6 +80,7 @@ static int kernel_get_wireguard_interfaces(struct string_list *list) int ret = 0; struct nlmsghdr *nlh; struct ifinfomsg *ifm; + struct nlattr *linkinfo_nest; ret = -ENOMEM; rtnl_buffer = calloc(SOCKET_BUFFER_SIZE, 1); @@ -105,6 +106,11 @@ static int kernel_get_wireguard_interfaces(struct string_list *list) nlh->nlmsg_seq = seq; ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm)); ifm->ifi_family = AF_UNSPEC; + + linkinfo_nest = mnl_attr_nest_start(nlh, IFLA_LINKINFO); + mnl_attr_put_strz(nlh, IFLA_INFO_KIND, WG_GENL_NAME); + mnl_attr_nest_end(nlh, linkinfo_nest); + message_len = nlh->nlmsg_len; if (mnl_socket_sendto(nl, rtnl_buffer, message_len) < 0) { -- 2.51.0 From ebiggers at kernel.org Fri Sep 5 23:00:06 2025 From: ebiggers at kernel.org (Eric Biggers) Date: Fri, 5 Sep 2025 16:00:06 -0700 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <5090355d-546a-4d06-99e1-064354d156b5@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <5090355d-546a-4d06-99e1-064354d156b5@redhat.com> Message-ID: <20250905230006.GA1776@sol> On Fri, Sep 05, 2025 at 08:41:23AM +0200, David Hildenbrand wrote: > On 01.09.25 17:03, David Hildenbrand wrote: > > We can just cleanup the code by calculating the #refs earlier, > > so we can just inline what remains of record_subpages(). > > > > Calculate the number of references/pages ahead of times, and record them > > only once all our tests passed. > > > > Signed-off-by: David Hildenbrand > > --- > > mm/gup.c | 25 ++++++++----------------- > > 1 file changed, 8 insertions(+), 17 deletions(-) > > > > diff --git a/mm/gup.c b/mm/gup.c > > index c10cd969c1a3b..f0f4d1a68e094 100644 > > --- a/mm/gup.c > > +++ b/mm/gup.c > > @@ -484,19 +484,6 @@ static inline void mm_set_has_pinned_flag(struct mm_struct *mm) > > #ifdef CONFIG_MMU > > #ifdef CONFIG_HAVE_GUP_FAST > > -static int record_subpages(struct page *page, unsigned long sz, > > - unsigned long addr, unsigned long end, > > - struct page **pages) > > -{ > > - int nr; > > - > > - page += (addr & (sz - 1)) >> PAGE_SHIFT; > > - for (nr = 0; addr != end; nr++, addr += PAGE_SIZE) > > - pages[nr] = page++; > > - > > - return nr; > > -} > > - > > /** > > * try_grab_folio_fast() - Attempt to get or pin a folio in fast path. > > * @page: pointer to page to be grabbed > > @@ -2967,8 +2954,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > > if (pmd_special(orig)) > > return 0; > > - page = pmd_page(orig); > > - refs = record_subpages(page, PMD_SIZE, addr, end, pages + *nr); > > + refs = (end - addr) >> PAGE_SHIFT; > > + page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); > > folio = try_grab_folio_fast(page, refs, flags); > > if (!folio) > > @@ -2989,6 +2976,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > > } > > *nr += refs; > > + for (; refs; refs--) > > + *(pages++) = page++; > > folio_set_referenced(folio); > > return 1; > > } > > @@ -3007,8 +2996,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > > if (pud_special(orig)) > > return 0; > > - page = pud_page(orig); > > - refs = record_subpages(page, PUD_SIZE, addr, end, pages + *nr); > > + refs = (end - addr) >> PAGE_SHIFT; > > + page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT); > > folio = try_grab_folio_fast(page, refs, flags); > > if (!folio) > > @@ -3030,6 +3019,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > > } > > *nr += refs; > > + for (; refs; refs--) > > + *(pages++) = page++; > > folio_set_referenced(folio); > > return 1; > > } > > Okay, this code is nasty. We should rework this code to just return the nr and receive a the proper > pages pointer, getting rid of the "*nr" parameter. > > For the time being, the following should do the trick: > > commit bfd07c995814354f6b66c5b6a72e96a7aa9fb73b (HEAD -> nth_page) > Author: David Hildenbrand > Date: Fri Sep 5 08:38:43 2025 +0200 > > fixup: mm/gup: remove record_subpages() > pages is not adjusted by the caller, but idnexed by existing *nr. > Signed-off-by: David Hildenbrand > > diff --git a/mm/gup.c b/mm/gup.c > index 010fe56f6e132..22420f2069ee1 100644 > --- a/mm/gup.c > +++ b/mm/gup.c > @@ -2981,6 +2981,7 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > return 0; > } > + pages += *nr; > *nr += refs; > for (; refs; refs--) > *(pages++) = page++; > @@ -3024,6 +3025,7 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > return 0; > } > + pages += *nr; > *nr += refs; > for (; refs; refs--) > *(pages++) = page++; Can this get folded in soon? This bug is causing crashes in AF_ALG too. Thanks, - Eric From kuba at kernel.org Sat Sep 6 00:07:25 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 5 Sep 2025 17:07:25 -0700 Subject: [PATCH net-next 01/11] tools: ynl-gen: allow overriding name-prefix for constants In-Reply-To: <20250904220156.1006541-1-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-1-ast@fiberby.net> Message-ID: <20250905170725.20387dc6@kernel.org> On Thu, 4 Sep 2025 22:01:24 +0000 Asbj?rn Sloth T?nnesen wrote: > Allow using custom name-prefix with constants, > just like it is for enum and flags declarations. > > This is needed for generating WG_KEY_LEN in > include/uapi/linux/wireguard.h from a spec. Reviewed-by: Jakub Kicinski From kuba at kernel.org Sat Sep 6 00:09:56 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 5 Sep 2025 17:09:56 -0700 Subject: [PATCH net-next 02/11] tools: ynl-gen: generate nested array policies In-Reply-To: <20250904220156.1006541-2-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-2-ast@fiberby.net> Message-ID: <20250905170956.64fa623b@kernel.org> On Thu, 4 Sep 2025 22:01:25 +0000 Asbj?rn Sloth T?nnesen wrote: > This patch adds support for NLA_POLICY_NESTED_ARRAY() policies. > > Example spec (from future wireguard.yaml): > - > name: wgpeer > attributes: > - > name: allowedips > type: indexed-array > sub-type: nest > nested-attributes: wgallowedip > > yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy). > > This doesn't change any currently generated code, as it isn't > used in any specs currently used for generating code. Reviewed-by: Jakub Kicinski From kuba at kernel.org Sat Sep 6 00:12:04 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 5 Sep 2025 17:12:04 -0700 Subject: [PATCH net-next 03/11] tools: ynl-gen: add sub-type check In-Reply-To: <20250904220156.1006541-3-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-3-ast@fiberby.net> Message-ID: <20250905171204.483b5f4f@kernel.org> On Thu, 4 Sep 2025 22:01:26 +0000 Asbj?rn Sloth T?nnesen wrote: > Add a check to verify that the sub-type is "nest", and throw an > exception if no policy could be generated, as a guard to prevent > against generating a bad policy. > > This is a trivial patch with no behavioural changes intended. I _think_ the expectation was that one of the other methods which validate the types more thoroughly has to be called if this one is. But either way: Reviewed-by: Jakub Kicinski From kuba at kernel.org Sat Sep 6 00:13:38 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 5 Sep 2025 17:13:38 -0700 Subject: [PATCH net-next 04/11] tools: ynl-gen: define count iterator in print_dump() In-Reply-To: <20250904220156.1006541-4-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-4-ast@fiberby.net> Message-ID: <20250905171338.046e35f2@kernel.org> On Thu, 4 Sep 2025 22:01:27 +0000 Asbj?rn Sloth T?nnesen wrote: > In wireguard_get_device_dump(), as generated by print_dump(), > it didn't generate a declaration of `unsigned int i`: > > $ make -C tools/net/ynl/generated wireguard-user.o > -e CC wireguard-user.o > wireguard-user.c: In function ?wireguard_get_device_dump?: > wireguard-user.c:502:22: error: ?i? undeclared (first use in this fn) > 502 | for (i = 0; i < req->_count.peers; i++) > | ^ > > Copy the logic from print_req() as it correctly generated the > iterator in wireguard_set_device(). Reviewed-by: Jakub Kicinski From jacob.e.keller at intel.com Sat Sep 6 00:15:54 2025 From: jacob.e.keller at intel.com (Jacob Keller) Date: Fri, 5 Sep 2025 17:15:54 -0700 Subject: [PATCH net-next 01/11] tools: ynl-gen: allow overriding name-prefix for constants In-Reply-To: <20250904220156.1006541-1-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-1-ast@fiberby.net> Message-ID: On 9/4/2025 3:01 PM, Asbj?rn Sloth T?nnesen wrote: > Allow using custom name-prefix with constants, > just like it is for enum and flags declarations. > > This is needed for generating WG_KEY_LEN in > include/uapi/linux/wireguard.h from a spec. > > Signed-off-by: Asbj?rn Sloth T?nnesen > --- > tools/net/ynl/pyynl/ynl_gen_c.py | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py > index fb7e03805a11..1543d4911bf5 100755 > --- a/tools/net/ynl/pyynl/ynl_gen_c.py > +++ b/tools/net/ynl/pyynl/ynl_gen_c.py > @@ -3211,8 +3211,9 @@ def render_uapi(family, cw): > cw.block_end(line=';') > cw.nl() > elif const['type'] == 'const': > + name_pfx = const.get('name-prefix', f"{family.ident_name}-") Previously we always used "{family.ident_name}-", but now we get the name-prefix and use that, falling back to the default if it doesn't exist. Good. Reviewed-by: Jacob Keller > defines.append([c_upper(family.get('c-define-name', > - f"{family.ident_name}-{const['name']}")), > + f"{name_pfx}{const['name']}")), > const['value']]) > > if defines: -------------- next part -------------- A non-text attachment was scrubbed... Name: OpenPGP_signature.asc Type: application/pgp-signature Size: 236 bytes Desc: OpenPGP digital signature URL: From kuba at kernel.org Sat Sep 6 00:18:09 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 5 Sep 2025 17:18:09 -0700 Subject: [PATCH net-next 05/11] tools: ynl-gen: define nlattr *array in a block scope In-Reply-To: <20250904220156.1006541-5-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-5-ast@fiberby.net> Message-ID: <20250905171809.694562c6@kernel.org> On Thu, 4 Sep 2025 22:01:28 +0000 Asbj?rn Sloth T?nnesen wrote: > Instead of trying to define "struct nlattr *array;" in the all > the right places, then simply define it in a block scope, > as it's only used here. > > Before this patch it was generated for attribute set _put() > functions, like wireguard_wgpeer_put(), but missing and caused a > compile error for the command function wireguard_set_device(). > > $ make -C tools/net/ynl/generated wireguard-user.o > -e CC wireguard-user.o > wireguard-user.c: In function ?wireguard_set_device?: > wireguard-user.c:548:9: error: ?array? undeclared (first use in ..) > 548 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); > | ^~~~~ Dunno about this one. In patch 4 you basically add another instance of the "let's declare local vars at function level" approach. And here you're going the other way. This patch will certainly work, but I felt like I wouldn't have written it this way if I was typing in the parsers by hand. From jacob.e.keller at intel.com Sat Sep 6 00:19:33 2025 From: jacob.e.keller at intel.com (Jacob Keller) Date: Fri, 5 Sep 2025 17:19:33 -0700 Subject: [PATCH net-next 02/11] tools: ynl-gen: generate nested array policies In-Reply-To: <20250904220156.1006541-2-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-2-ast@fiberby.net> Message-ID: On 9/4/2025 3:01 PM, Asbj?rn Sloth T?nnesen wrote: > This patch adds support for NLA_POLICY_NESTED_ARRAY() policies. > > Example spec (from future wireguard.yaml): > - > name: wgpeer > attributes: > - > name: allowedips > type: indexed-array > sub-type: nest > nested-attributes: wgallowedip > > yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy). > > This doesn't change any currently generated code, as it isn't > used in any specs currently used for generating code. > > Signed-off-by: Asbj?rn Sloth T?nnesen > --- Is this keyed of off the sub-type? Does you mean that all the existing uses of 'sub-type: nest' don't generate code today? Or that this _attr_policy implementation is not called yet? I checked and we have quite a number of uses: > $ rg 'sub-type: nest' > Documentation/netlink/specs/nlctrl.yaml > 69: sub-type: nest > 74: sub-type: nest > > Documentation/netlink/specs/tc.yaml > 2045: sub-type: nest > 2065: sub-type: nest > 2190: sub-type: nest > 2304: sub-type: nest > 2494: sub-type: nest > 3021: sub-type: nest > 3181: sub-type: nest > 3567: sub-type: nest > 3799: sub-type: nest > > Documentation/netlink/specs/rt-link.yaml > 2203: sub-type: nest > > Documentation/netlink/specs/nl80211.yaml > 610: sub-type: nest > 1309: sub-type: nest > 1314: sub-type: nest > 1337: sub-type: nest > 1420: sub-type: nest > 1476: sub-type: nest > 1615: sub-type: nest > -------------- next part -------------- A non-text attachment was scrubbed... Name: OpenPGP_signature.asc Type: application/pgp-signature Size: 236 bytes Desc: OpenPGP digital signature URL: From jacob.e.keller at intel.com Sat Sep 6 00:20:20 2025 From: jacob.e.keller at intel.com (Jacob Keller) Date: Fri, 5 Sep 2025 17:20:20 -0700 Subject: [PATCH net-next 03/11] tools: ynl-gen: add sub-type check In-Reply-To: <20250904220156.1006541-3-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-3-ast@fiberby.net> Message-ID: On 9/4/2025 3:01 PM, Asbj?rn Sloth T?nnesen wrote: > Add a check to verify that the sub-type is "nest", and throw an > exception if no policy could be generated, as a guard to prevent > against generating a bad policy. > > This is a trivial patch with no behavioural changes intended. > > Signed-off-by: Asbj?rn Sloth T?nnesen > --- Reviewed-by: Jacob Keller > tools/net/ynl/pyynl/ynl_gen_c.py | 4 +++- > 1 file changed, 3 insertions(+), 1 deletion(-) > > diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py > index b7de7f6b1fc7..04c26ed92ca3 100755 > --- a/tools/net/ynl/pyynl/ynl_gen_c.py > +++ b/tools/net/ynl/pyynl/ynl_gen_c.py > @@ -826,8 +826,10 @@ class TypeArrayNest(Type): > return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, ' > elif self.attr['sub-type'] == 'binary' and 'exact-len' in self.checks: > return f'.type = YNL_PT_BINARY, .len = {self.checks["exact-len"]}, ' > - else: > + elif self.attr['sub-type'] == 'nest': > return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' > + else: > + raise Exception(f"Typol for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") > > def _attr_get(self, ri, var): > local_vars = ['const struct nlattr *attr2;'] -------------- next part -------------- A non-text attachment was scrubbed... Name: OpenPGP_signature.asc Type: application/pgp-signature Size: 236 bytes Desc: OpenPGP digital signature URL: From jacob.e.keller at intel.com Sat Sep 6 00:20:58 2025 From: jacob.e.keller at intel.com (Jacob Keller) Date: Fri, 5 Sep 2025 17:20:58 -0700 Subject: [PATCH net-next 04/11] tools: ynl-gen: define count iterator in print_dump() In-Reply-To: <20250904220156.1006541-4-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-4-ast@fiberby.net> Message-ID: <1aaf9978-5bac-451e-8670-905809e7d1bf@intel.com> On 9/4/2025 3:01 PM, Asbj?rn Sloth T?nnesen wrote: > In wireguard_get_device_dump(), as generated by print_dump(), > it didn't generate a declaration of `unsigned int i`: > > $ make -C tools/net/ynl/generated wireguard-user.o > -e CC wireguard-user.o > wireguard-user.c: In function ?wireguard_get_device_dump?: > wireguard-user.c:502:22: error: ?i? undeclared (first use in this fn) > 502 | for (i = 0; i < req->_count.peers; i++) > | ^ > > Copy the logic from print_req() as it correctly generated the > iterator in wireguard_set_device(). > > Signed-off-by: Asbj?rn Sloth T?nnesen > --- Reviewed-by: Jacob Keller > tools/net/ynl/pyynl/ynl_gen_c.py | 5 +++++ > 1 file changed, 5 insertions(+) > > diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py > index 04c26ed92ca3..b0eeedfca2f2 100755 > --- a/tools/net/ynl/pyynl/ynl_gen_c.py > +++ b/tools/net/ynl/pyynl/ynl_gen_c.py > @@ -2425,6 +2425,11 @@ def print_dump(ri): > local_vars += ['size_t hdr_len;', > 'void *hdr;'] > > + for _, attr in ri.struct['request'].member_list(): > + if attr.presence_type() == 'count': > + local_vars += ['unsigned int i;'] > + break > + > ri.cw.write_func_lvar(local_vars) > > ri.cw.p('yds.yarg.ys = ys;') -------------- next part -------------- A non-text attachment was scrubbed... Name: OpenPGP_signature.asc Type: application/pgp-signature Size: 236 bytes Desc: OpenPGP digital signature URL: From kuba at kernel.org Sat Sep 6 00:23:34 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 5 Sep 2025 17:23:34 -0700 Subject: [PATCH net-next 06/11] tools: ynl-gen: don't validate nested array attribute types In-Reply-To: <20250904220156.1006541-6-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-6-ast@fiberby.net> Message-ID: <20250905172334.0411e05e@kernel.org> On Thu, 4 Sep 2025 22:01:29 +0000 Asbj?rn Sloth T?nnesen wrote: > In nested arrays don't require that the intermediate > attribute type should be a valid attribute type, it > might just be an index or simple 0, it is often not > even used. > > See include/net/netlink.h about NLA_NESTED_ARRAY: > > The difference to NLA_NESTED is the structure: > > NLA_NESTED has the nested attributes directly inside > > while an array has the nested attributes at another > > level down and the attribute types directly in the > > nesting don't matter. I don't understand, please provide more details. This is an ArrayNest, right? [ARRAY-ATTR] [ENTRY] [MEMBER1] [MEMBER2] [ENTRY] [MEMBER1] [MEMBER2] Which level are you saying doesn't matter? If entry is a nest it must be a valid nest. What the comment you're quoting is saying is that the nla_type of ENTRY doesn't matter. From jacob.e.keller at intel.com Sat Sep 6 00:24:02 2025 From: jacob.e.keller at intel.com (Jacob Keller) Date: Fri, 5 Sep 2025 17:24:02 -0700 Subject: [PATCH net-next 06/11] tools: ynl-gen: don't validate nested array attribute types In-Reply-To: <20250904220156.1006541-6-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-6-ast@fiberby.net> Message-ID: On 9/4/2025 3:01 PM, Asbj?rn Sloth T?nnesen wrote: > In nested arrays don't require that the intermediate > attribute type should be a valid attribute type, it > might just be an index or simple 0, it is often not > even used. > > See include/net/netlink.h about NLA_NESTED_ARRAY: >> The difference to NLA_NESTED is the structure: >> NLA_NESTED has the nested attributes directly inside >> while an array has the nested attributes at another >> level down and the attribute types directly in the >> nesting don't matter. > To me, it would seem like it makes more sense to define these (even if thats defined per family?) than to just say they aren't defined at all? Hm. > Signed-off-by: Asbj?rn Sloth T?nnesen > --- > tools/net/ynl/pyynl/ynl_gen_c.py | 11 ++++++----- > 1 file changed, 6 insertions(+), 5 deletions(-) > > diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py > index e6a84e13ec0a..3c0b158c4da8 100755 > --- a/tools/net/ynl/pyynl/ynl_gen_c.py > +++ b/tools/net/ynl/pyynl/ynl_gen_c.py > @@ -834,11 +834,12 @@ class TypeArrayNest(Type): > def _attr_get(self, ri, var): > local_vars = ['const struct nlattr *attr2;'] > get_lines = [f'attr_{self.c_name} = attr;', > - 'ynl_attr_for_each_nested(attr2, attr) {', > - '\tif (ynl_attr_validate(yarg, attr2))', > - '\t\treturn YNL_PARSE_CB_ERROR;', > - f'\tn_{self.c_name}++;', > - '}'] > + 'ynl_attr_for_each_nested(attr2, attr) {'] > + if self.attr['sub-type'] != 'nest': > + get_lines.append('\tif (ynl_attr_validate(yarg, attr2))') > + get_lines.append('\t\treturn YNL_PARSE_CB_ERROR;') > + get_lines.append(f'\tn_{self.c_name}++;') > + get_lines.append('}') > return get_lines, None, local_vars > > def attr_put(self, ri, var): -------------- next part -------------- A non-text attachment was scrubbed... Name: OpenPGP_signature.asc Type: application/pgp-signature Size: 236 bytes Desc: OpenPGP digital signature URL: From kuba at kernel.org Sat Sep 6 00:25:08 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 5 Sep 2025 17:25:08 -0700 Subject: [PATCH net-next 07/11] tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray In-Reply-To: <20250904220156.1006541-7-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-7-ast@fiberby.net> Message-ID: <20250905172508.45bbb3ef@kernel.org> On Thu, 4 Sep 2025 22:01:30 +0000 Asbj?rn Sloth T?nnesen wrote: > As TypeArrayNest can now be used with many other sub-types > than nest, then rename it to TypeIndexedArray, to reduce > confusion. You need to also find all the local comments and variables which allude to the name. From jacob.e.keller at intel.com Sat Sep 6 00:27:46 2025 From: jacob.e.keller at intel.com (Jacob Keller) Date: Fri, 5 Sep 2025 17:27:46 -0700 Subject: [PATCH net-next 10/11] tools: ynl: decode hex input In-Reply-To: References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-10-ast@fiberby.net> Message-ID: <410d69e5-d1f8-40e0-84b1-b5d56e0d9366@intel.com> On 9/5/2025 3:51 AM, Donald Hunter wrote: > Asbj?rn Sloth T?nnesen writes: > >> This patch add support for decoding hex input, so >> that binary attributes can be read through --json. >> >> Example (using future wireguard.yaml): >> $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ >> --do set-device --json '{"ifindex":3, >> "private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}' >> >> Signed-off-by: Asbj?rn Sloth T?nnesen > > Reviewed-by: Donald Hunter > > FWIW, the hex can include spaces or not when using bytes.fromhex(). When > formatting hex for output, I chose to include spaces, but I don't really > know if that was a good choice or not. I also prefer the spaces for readability. -------------- next part -------------- A non-text attachment was scrubbed... Name: OpenPGP_signature.asc Type: application/pgp-signature Size: 236 bytes Desc: OpenPGP digital signature URL: From david at redhat.com Sat Sep 6 06:56:48 2025 From: david at redhat.com (David Hildenbrand) Date: Sat, 6 Sep 2025 08:56:48 +0200 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <016307ba-427d-4646-8e4d-1ffefd2c1968@nvidia.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <016307ba-427d-4646-8e4d-1ffefd2c1968@nvidia.com> Message-ID: <85e760cf-b994-40db-8d13-221feee55c60@redhat.com> On 06.09.25 03:05, John Hubbard wrote: > On 9/1/25 8:03 AM, David Hildenbrand wrote: >> We can just cleanup the code by calculating the #refs earlier, >> so we can just inline what remains of record_subpages(). >> >> Calculate the number of references/pages ahead of times, and record them >> only once all our tests passed. >> >> Signed-off-by: David Hildenbrand >> --- >> mm/gup.c | 25 ++++++++----------------- >> 1 file changed, 8 insertions(+), 17 deletions(-) >> >> diff --git a/mm/gup.c b/mm/gup.c >> index c10cd969c1a3b..f0f4d1a68e094 100644 >> --- a/mm/gup.c >> +++ b/mm/gup.c >> @@ -484,19 +484,6 @@ static inline void mm_set_has_pinned_flag(struct mm_struct *mm) >> #ifdef CONFIG_MMU >> >> #ifdef CONFIG_HAVE_GUP_FAST >> -static int record_subpages(struct page *page, unsigned long sz, >> - unsigned long addr, unsigned long end, >> - struct page **pages) >> -{ >> - int nr; >> - >> - page += (addr & (sz - 1)) >> PAGE_SHIFT; >> - for (nr = 0; addr != end; nr++, addr += PAGE_SIZE) >> - pages[nr] = page++; >> - >> - return nr; >> -} >> - >> /** >> * try_grab_folio_fast() - Attempt to get or pin a folio in fast path. >> * @page: pointer to page to be grabbed >> @@ -2967,8 +2954,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, >> if (pmd_special(orig)) >> return 0; >> >> - page = pmd_page(orig); >> - refs = record_subpages(page, PMD_SIZE, addr, end, pages + *nr); >> + refs = (end - addr) >> PAGE_SHIFT; >> + page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); >> >> folio = try_grab_folio_fast(page, refs, flags); >> if (!folio) >> @@ -2989,6 +2976,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, >> } >> >> *nr += refs; >> + for (; refs; refs--) >> + *(pages++) = page++; >> folio_set_referenced(folio); >> return 1; >> } >> @@ -3007,8 +2996,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, >> if (pud_special(orig)) >> return 0; >> >> - page = pud_page(orig); >> - refs = record_subpages(page, PUD_SIZE, addr, end, pages + *nr); >> + refs = (end - addr) >> PAGE_SHIFT; >> + page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT); >> >> folio = try_grab_folio_fast(page, refs, flags); >> if (!folio) >> @@ -3030,6 +3019,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, >> } >> >> *nr += refs; >> + for (; refs; refs--) >> + *(pages++) = page++; > > Hi David, Hi! > > Probably a similar sentiment as Lorenzo here...the above diffs make the code > *worse* to read. In fact, I recall adding record_subpages() here long ago, > specifically to help clarify what was going on. Well, there is a lot I dislike about record_subpages() to go back there. Starting with "as Willy keeps explaining, the concept of subpages do not exist and ending with "why do we fill out the array even on failure". :) > > Now it's been returned to it's original, cryptic form. > The code in the caller was so uncryptic that both me and Lorenzo missed that magical addition. :P > Just my take on it, for whatever that's worth. :) As always, appreciated. I could of course keep the simple loop in some "record_folio_pages" function and clean up what I dislike about record_subpages(). But I much rather want the call chain to be cleaned up instead, if possible. Roughly, what I am thinking (limiting it to pte+pmd case) about is the following: From d6d6d21dbf435d8030782a627175e36e6c7b2dfb Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Sat, 6 Sep 2025 08:33:42 +0200 Subject: [PATCH] tmp Signed-off-by: David Hildenbrand --- mm/gup.c | 79 ++++++++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/mm/gup.c b/mm/gup.c index 22420f2069ee1..98907ead749c0 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -2845,12 +2845,11 @@ static void __maybe_unused gup_fast_undo_dev_pagemap(int *nr, int nr_start, * also check pmd here to make sure pmd doesn't change (corresponds to * pmdp_collapse_flush() in the THP collapse code path). */ -static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, - unsigned long end, unsigned int flags, struct page **pages, - int *nr) +static unsigned long gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, + unsigned long end, unsigned int flags, struct page **pages) { struct dev_pagemap *pgmap = NULL; - int ret = 0; + unsigned long nr_pages = 0; pte_t *ptep, *ptem; ptem = ptep = pte_offset_map(&pmd, addr); @@ -2908,24 +2907,20 @@ static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, * details. */ if (flags & FOLL_PIN) { - ret = arch_make_folio_accessible(folio); - if (ret) { + if (arch_make_folio_accessible(folio)) { gup_put_folio(folio, 1, flags); goto pte_unmap; } } folio_set_referenced(folio); - pages[*nr] = page; - (*nr)++; + pages[nr_pages++] = page; } while (ptep++, addr += PAGE_SIZE, addr != end); - ret = 1; - pte_unmap: if (pgmap) put_dev_pagemap(pgmap); pte_unmap(ptem); - return ret; + return nr_pages; } #else @@ -2938,21 +2933,24 @@ static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, * get_user_pages_fast_only implementation that can pin pages. Thus it's still * useful to have gup_fast_pmd_leaf even if we can't operate on ptes. */ -static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, - unsigned long end, unsigned int flags, struct page **pages, - int *nr) +static unsigned long gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, + unsigned long end, unsigned int flags, struct page **pages) { return 0; } #endif /* CONFIG_ARCH_HAS_PTE_SPECIAL */ -static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, - unsigned long end, unsigned int flags, struct page **pages, - int *nr) +static unsigned long gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, + unsigned long end, unsigned int flags, struct page **pages) { + const unsigned long nr_pages = (end - addr) >> PAGE_SHIFT; struct page *page; struct folio *folio; - int refs; + unsigned long i; + + /* See gup_fast_pte_range() */ + if (pmd_protnone(orig)) + return 0; if (!pmd_access_permitted(orig, flags & FOLL_WRITE)) return 0; @@ -2960,33 +2958,30 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, if (pmd_special(orig)) return 0; - refs = (end - addr) >> PAGE_SHIFT; page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); - folio = try_grab_folio_fast(page, refs, flags); + folio = try_grab_folio_fast(page, nr_pages, flags); if (!folio) return 0; if (unlikely(pmd_val(orig) != pmd_val(*pmdp))) { - gup_put_folio(folio, refs, flags); + gup_put_folio(folio, nr_pages, flags); return 0; } if (!gup_fast_folio_allowed(folio, flags)) { - gup_put_folio(folio, refs, flags); + gup_put_folio(folio, nr_pages, flags); return 0; } if (!pmd_write(orig) && gup_must_unshare(NULL, flags, &folio->page)) { - gup_put_folio(folio, refs, flags); + gup_put_folio(folio, nr_pages, flags); return 0; } - pages += *nr; - *nr += refs; - for (; refs; refs--) + for (i = 0; i < nr_pages; i++) *(pages++) = page++; folio_set_referenced(folio); - return 1; + return nr_pages; } static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, @@ -3033,11 +3028,11 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, return 1; } -static int gup_fast_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr, - unsigned long end, unsigned int flags, struct page **pages, - int *nr) +static unsigned long gup_fast_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr, + unsigned long end, unsigned int flags, struct page **pages) { - unsigned long next; + unsigned long cur_nr_pages, next; + unsigned long nr_pages = 0; pmd_t *pmdp; pmdp = pmd_offset_lockless(pudp, pud, addr); @@ -3046,23 +3041,21 @@ static int gup_fast_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr, next = pmd_addr_end(addr, end); if (!pmd_present(pmd)) - return 0; + break; - if (unlikely(pmd_leaf(pmd))) { - /* See gup_fast_pte_range() */ - if (pmd_protnone(pmd)) - return 0; + if (unlikely(pmd_leaf(pmd))) + cur_nr_pages = gup_fast_pmd_leaf(pmd, pmdp, addr, next, flags, pages); + else + cur_nr_pages = gup_fast_pte_range(pmd, pmdp, addr, next, flags, pages); - if (!gup_fast_pmd_leaf(pmd, pmdp, addr, next, flags, - pages, nr)) - return 0; + nr_pages += cur_nr_pages; + pages += cur_nr_pages; - } else if (!gup_fast_pte_range(pmd, pmdp, addr, next, flags, - pages, nr)) - return 0; + if (nr_pages != (next - addr) >> PAGE_SIZE) + break; } while (pmdp++, addr = next, addr != end); - return 1; + return nr_pages; } static int gup_fast_pud_range(p4d_t *p4dp, p4d_t p4d, unsigned long addr, -- 2.50.1 Oh, I might even have found a bug moving away from that questionable "ret==1 means success" handling in gup_fast_pte_range()? Will have to double-check, but likely the following is the right thing to do. From 8f48b25ef93e7ef98611fd58ec89384ad5171782 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Sat, 6 Sep 2025 08:46:45 +0200 Subject: [PATCH] mm/gup: fix handling of errors from arch_make_folio_accessible() in follow_page_pte() In case we call arch_make_folio_accessible() and it fails, we would incorrectly return a value that is "!= 0" to the caller, indicating that we pinned all requested pages and that the caller can keep going. follow_page_pte() is not supposed to return error values, but instead 0 on failure and 1 on success. That is of course wrong, because the caller will just keep going pinning more pages. If we happen to pin a page afterwards, we're in trouble, because we essentially skipped some pages. Fixes: f28d43636d6f ("mm/gup/writeback: add callbacks for inaccessible pages") Signed-off-by: David Hildenbrand --- mm/gup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mm/gup.c b/mm/gup.c index 22420f2069ee1..cff226ec0ee7d 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -2908,8 +2908,7 @@ static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, * details. */ if (flags & FOLL_PIN) { - ret = arch_make_folio_accessible(folio); - if (ret) { + if (arch_make_folio_accessible(folio)) { gup_put_folio(folio, 1, flags); goto pte_unmap; } -- 2.50.1 -- Cheers David / dhildenb From david at redhat.com Sat Sep 6 06:57:37 2025 From: david at redhat.com (David Hildenbrand) Date: Sat, 6 Sep 2025 08:57:37 +0200 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <20250905230006.GA1776@sol> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <5090355d-546a-4d06-99e1-064354d156b5@redhat.com> <20250905230006.GA1776@sol> Message-ID: <64fe4c61-f9cc-4a5a-9c33-07bd0f089e94@redhat.com> On 06.09.25 01:00, Eric Biggers wrote: > On Fri, Sep 05, 2025 at 08:41:23AM +0200, David Hildenbrand wrote: >> On 01.09.25 17:03, David Hildenbrand wrote: >>> We can just cleanup the code by calculating the #refs earlier, >>> so we can just inline what remains of record_subpages(). >>> >>> Calculate the number of references/pages ahead of times, and record them >>> only once all our tests passed. >>> >>> Signed-off-by: David Hildenbrand >>> --- >>> mm/gup.c | 25 ++++++++----------------- >>> 1 file changed, 8 insertions(+), 17 deletions(-) >>> >>> diff --git a/mm/gup.c b/mm/gup.c >>> index c10cd969c1a3b..f0f4d1a68e094 100644 >>> --- a/mm/gup.c >>> +++ b/mm/gup.c >>> @@ -484,19 +484,6 @@ static inline void mm_set_has_pinned_flag(struct mm_struct *mm) >>> #ifdef CONFIG_MMU >>> #ifdef CONFIG_HAVE_GUP_FAST >>> -static int record_subpages(struct page *page, unsigned long sz, >>> - unsigned long addr, unsigned long end, >>> - struct page **pages) >>> -{ >>> - int nr; >>> - >>> - page += (addr & (sz - 1)) >> PAGE_SHIFT; >>> - for (nr = 0; addr != end; nr++, addr += PAGE_SIZE) >>> - pages[nr] = page++; >>> - >>> - return nr; >>> -} >>> - >>> /** >>> * try_grab_folio_fast() - Attempt to get or pin a folio in fast path. >>> * @page: pointer to page to be grabbed >>> @@ -2967,8 +2954,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, >>> if (pmd_special(orig)) >>> return 0; >>> - page = pmd_page(orig); >>> - refs = record_subpages(page, PMD_SIZE, addr, end, pages + *nr); >>> + refs = (end - addr) >> PAGE_SHIFT; >>> + page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); >>> folio = try_grab_folio_fast(page, refs, flags); >>> if (!folio) >>> @@ -2989,6 +2976,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, >>> } >>> *nr += refs; >>> + for (; refs; refs--) >>> + *(pages++) = page++; >>> folio_set_referenced(folio); >>> return 1; >>> } >>> @@ -3007,8 +2996,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, >>> if (pud_special(orig)) >>> return 0; >>> - page = pud_page(orig); >>> - refs = record_subpages(page, PUD_SIZE, addr, end, pages + *nr); >>> + refs = (end - addr) >> PAGE_SHIFT; >>> + page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT); >>> folio = try_grab_folio_fast(page, refs, flags); >>> if (!folio) >>> @@ -3030,6 +3019,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, >>> } >>> *nr += refs; >>> + for (; refs; refs--) >>> + *(pages++) = page++; >>> folio_set_referenced(folio); >>> return 1; >>> } >> >> Okay, this code is nasty. We should rework this code to just return the nr and receive a the proper >> pages pointer, getting rid of the "*nr" parameter. >> >> For the time being, the following should do the trick: >> >> commit bfd07c995814354f6b66c5b6a72e96a7aa9fb73b (HEAD -> nth_page) >> Author: David Hildenbrand >> Date: Fri Sep 5 08:38:43 2025 +0200 >> >> fixup: mm/gup: remove record_subpages() >> pages is not adjusted by the caller, but idnexed by existing *nr. >> Signed-off-by: David Hildenbrand >> >> diff --git a/mm/gup.c b/mm/gup.c >> index 010fe56f6e132..22420f2069ee1 100644 >> --- a/mm/gup.c >> +++ b/mm/gup.c >> @@ -2981,6 +2981,7 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, >> return 0; >> } >> + pages += *nr; >> *nr += refs; >> for (; refs; refs--) >> *(pages++) = page++; >> @@ -3024,6 +3025,7 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, >> return 0; >> } >> + pages += *nr; >> *nr += refs; >> for (; refs; refs--) >> *(pages++) = page++; > > Can this get folded in soon? This bug is causing crashes in AF_ALG too. Andrew immediately dropped the original patch, so it's gone from mm-unstable and should be gone from next soon (today?). -- Cheers David / dhildenb From david at redhat.com Sat Sep 6 07:00:54 2025 From: david at redhat.com (David Hildenbrand) Date: Sat, 6 Sep 2025 09:00:54 +0200 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <85e760cf-b994-40db-8d13-221feee55c60@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <016307ba-427d-4646-8e4d-1ffefd2c1968@nvidia.com> <85e760cf-b994-40db-8d13-221feee55c60@redhat.com> Message-ID: <815cbde4-a56d-446d-b517-c63e12e473de@redhat.com> > pmdp = pmd_offset_lockless(pudp, pud, addr); > @@ -3046,23 +3041,21 @@ static int gup_fast_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr, > > next = pmd_addr_end(addr, end); > if (!pmd_present(pmd)) > - return 0; > + break; > > - if (unlikely(pmd_leaf(pmd))) { > - /* See gup_fast_pte_range() */ > - if (pmd_protnone(pmd)) > - return 0; > + if (unlikely(pmd_leaf(pmd))) > + cur_nr_pages = gup_fast_pmd_leaf(pmd, pmdp, addr, next, flags, pages); > + else > + cur_nr_pages = gup_fast_pte_range(pmd, pmdp, addr, next, flags, pages); > > - if (!gup_fast_pmd_leaf(pmd, pmdp, addr, next, flags, > - pages, nr)) > - return 0; > + nr_pages += cur_nr_pages; > + pages += cur_nr_pages; > > - } else if (!gup_fast_pte_range(pmd, pmdp, addr, next, flags, > - pages, nr)) > - return 0; > + if (nr_pages != (next - addr) >> PAGE_SIZE) > + break; ^ cur_nr_pages. Open for suggestions on how to make that thing here even better. -- Cheers David / dhildenb From kuba at kernel.org Sat Sep 6 19:07:54 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Sat, 6 Sep 2025 12:07:54 -0700 Subject: [PATCH net-next 05/11] tools: ynl-gen: define nlattr *array in a block scope In-Reply-To: <4eda9c57-bde0-43c3-b8a0-3e45f2e672ac@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-5-ast@fiberby.net> <20250905171809.694562c6@kernel.org> <4eda9c57-bde0-43c3-b8a0-3e45f2e672ac@fiberby.net> Message-ID: <20250906120754.7b90c718@kernel.org> On Sat, 6 Sep 2025 13:13:29 +0000 Asbj?rn Sloth T?nnesen wrote: > In patch 4, it is about a variable used by multiple Type classes having > presence_type() = 'count', which is currently 3 classes: > - TypeBinaryScalarArray > - TypeMultiAttr > - TypeArrayNest (later renamed to TypeIndexedArray) > > In patch 5, I move code for a special variable used by one Type class, > to be contained within that class. It makes it easier to ensure that the > variable is only defined, when used, and vice versa. This comes at the > cost of the generated code looking generated. So you're agreeing? > If we should make the generated code look like it was written by humans, > then I would move the definition of these local variables into a class > method, so `i` can be generated by the generic implementation, and `array` > can be implemented in it's class. I will take a stab at this, but it might > be too much refactoring for this series, eg. `len` is also defined local > to conditional blocks multiple branches in a row. > > tools/net/ynl/generated/nl80211-user.c: > nl80211_iftype_data_attrs_parse(..) { > [..] > ynl_attr_for_each_nested(attr, nested) { > unsigned int type = ynl_attr_type(attr); > > if (type == NL80211_BAND_IFTYPE_ATTR_IFTYPES) { > unsigned int len; > [..] > } else if (type == NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC) { > unsigned int len; > [..] > [same pattern 8 times, so 11 times in total] > } else if (type == NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE) { > unsigned int len; > [..] > } > } > return 0; > } It's pretty easily doable, I already gave up on not calling _attr_get() for sub-messages. > That looks very generated, I would have `len` defined together with `type`, > and a switch statement would also look a lot more natural, but maybe leave > the if->switch conversion for the compiler to detect. diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index fb7e03805a11..8a1f8a477566 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -243,7 +243,7 @@ from lib import SpecSubMessage, SpecSubMessageFormat raise Exception(f"Attr get not implemented for class type {self.type}") def attr_get(self, ri, var, first): - lines, init_lines, local_vars = self._attr_get(ri, var) + lines, init_lines, _ = self._attr_get(ri, var) if type(lines) is str: lines = [lines] if type(init_lines) is str: @@ -251,10 +251,6 @@ from lib import SpecSubMessage, SpecSubMessageFormat kw = 'if' if first else 'else if' ri.cw.block_start(line=f"{kw} (type == {self.enum_name})") - if local_vars: - for local in local_vars: - ri.cw.p(local) - ri.cw.nl() if not self.is_multi_val(): ri.cw.p("if (ynl_attr_validate(yarg, attr))") @@ -2101,6 +2097,7 @@ _C_KW = { else: raise Exception(f"Per-op fixed header not supported, yet") + var_set = set() array_nests = set() multi_attrs = set() needs_parg = False @@ -2118,6 +2115,13 @@ _C_KW = { multi_attrs.add(arg) needs_parg |= 'nested-attributes' in aspec needs_parg |= 'sub-message' in aspec + + try: + _, _, l_vars = aspec._attr_get(ri, '') + var_set |= set(l_vars) if l_vars else set() + except: + pass # _attr_get() not implemented by simple types, ignore + local_vars += list(var_set) if array_nests or multi_attrs: local_vars.append('int i;') if needs_parg: From kuba at kernel.org Sat Sep 6 19:29:38 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Sat, 6 Sep 2025 12:29:38 -0700 Subject: [PATCH net-next 06/11] tools: ynl-gen: don't validate nested array attribute types In-Reply-To: <0a9a7c41-7deb-4078-8cc9-aee8f8784443@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-6-ast@fiberby.net> <20250905172334.0411e05e@kernel.org> <0a9a7c41-7deb-4078-8cc9-aee8f8784443@fiberby.net> Message-ID: <20250906122938.30566de3@kernel.org> On Sat, 6 Sep 2025 13:22:01 +0000 Asbj?rn Sloth T?nnesen wrote: > > I don't understand, please provide more details. > > This is an ArrayNest, right? > > > > [ARRAY-ATTR] > > [ENTRY] > > [MEMBER1] > > [MEMBER2] > > [ENTRY] > > [MEMBER1] > > [MEMBER2] > > > > Which level are you saying doesn't matter? > > If entry is a nest it must be a valid nest. > > What the comment you're quoting is saying is that the nla_type of ENTRY > > doesn't matter. > > I will expand this in v2, but the gist of it is that this is part of the > "split attribute counting, and later allocating an array to hold them" code. > > The check that I remove for nested arrays, is an early exit during the > counting phase. Later in the allocation and parse phase it validates the > nested payload. > > In include/uapi/linux/wireguard.h: > > WGDEVICE_A_PEERS: NLA_NESTED > > 0: NLA_NESTED > > WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN > > [..] > > 0: NLA_NESTED > > ... > > ... > > The current check requires that the nested type is valid in the nested > attribute set, which in this case resolves to WGDEVICE_A_UNSPEC, which is > YNL_PT_REJECT, and it takes the early exit and returns YNL_PARSE_CB_ERROR. I see your point now. We're validating ENTRY as an attribute in the parent attribute set, but it's just a meaningless id. I think we need more fixing here. The real parsing loop will only validate what's _inside_ the [MEMBER]. Which doesn't matter all that much to nests, but look at what happens if subtype is a scalar. We'll just call ynl_attr_get_u32(), type is never really validate. I think we need this, and make the codegen feed in the ARRAY-ATTR type to validate ENTRY? diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 2a169c3c0797..e43167398c69 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -360,15 +360,15 @@ static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) /* Attribute validation */ -int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) +int __ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr, + unsigned int type) { const struct ynl_policy_attr *policy; - unsigned int type, len; unsigned char *data; + unsigned int len; data = ynl_attr_data(attr); len = ynl_attr_data_len(attr); - type = ynl_attr_type(attr); if (type > yarg->rsp_policy->max_attr) { yerr(yarg->ys, YNL_ERROR_INTERNAL, "Internal error, validating unknown attribute"); @@ -450,6 +450,11 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) return 0; } +int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) +{ + return __ynl_attr_validate(yarg, attr, ynl_attr_type(attr)); +} + int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, const char *sel_name) { From wg-lists at bluematt.me Sat Sep 6 21:12:02 2025 From: wg-lists at bluematt.me (Matt Corallo) Date: Sat, 6 Sep 2025 17:12:02 -0400 Subject: Leaving skb->priority alone when encapsulating? Message-ID: <043598bd-198a-4d79-8749-789e578e07fe@bluematt.me> Its (I presume) fairly common to have multiple wireguard links on a single machine which ultimately has its outbound interface shaped with some tc qdisc. While wg_reset_packet leaves the skb hash flag alone to allow that qdisc to have visibility into the header hash, it wipes all other skb headers with a `memset(&skb->headers...)`. This makes it (I believe) impossible to allow the primary qdisc to operate on the DSCP of the inner packet (which wireguard reasonably wipes, but could otherwise be copied into skb->priority, which is generally an appropriate place for it). This appears to differ from every other tunneling protocol (the only instances of `memset.*headers` in the entire tree are in wireguard and the mellanox drivers) and other encapsulation protocols appear to rely on iptunnel_xmit's clearing of the relevant flags, rather than doing it themselves. While most of the fields in a skb's headers are perfectly reasonable to clear, I do wonder why wireguard is special here, but in any case it would be very nice to allow at least priority to propagate past wg_reset_packet. From johannes at sipsolutions.net Mon Sep 8 07:54:03 2025 From: johannes at sipsolutions.net (Johannes Berg) Date: Mon, 08 Sep 2025 09:54:03 +0200 Subject: [PATCH net-next 02/11] tools: ynl-gen: generate nested array policies In-Reply-To: <6e31a9e0-5450-4b45-a557-2aa08d23c25a@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-2-ast@fiberby.net> <6e31a9e0-5450-4b45-a557-2aa08d23c25a@fiberby.net> Message-ID: On Sat, 2025-09-06 at 14:13 +0000, Asbj?rn Sloth T?nnesen wrote: > > Johannes introduced NLA_NESTED_ARRAY and the NLA_POLICY_NESTED_ARRAY() > macro in commit 1501d13596b9 for use in nl80211, and it's therefore > used in net/wireless/nl80211.c, but outside of that the macro is > only sparsely adopted (only by mac80211_hwsim.c and nf_tables_api.c). > > Wireguard adopts the macro in this RFC patch: > https://lore.kernel.org/netdev/20250904220255.1006675-2-ast at fiberby.net/ I think the general consensus now is that preference should be towards arrays being expressed by giving the attribute holding the array multiple times, i.e. each occurrence of an attribute holds a single entry of the array: [header][type1:a1][type2:b][type1:a2][type1:a3] resulting in an array [a1, a2, a3] and a separate value "b", rather than a nested array: [header][type1:[1:a1][2:a2][3:a3]][type2:b] Of course if each entry has multiple values, then you'd still need nesting: [header][type1:[subtype1:x1][subtype2:x2]][type1:[subtype1:y1][subtype2:y2]] would be an array [[x1, x2], [y1, y2]]. I can't get rid of the nested array types in nl80211 though, of course. I'm not sure the nl80211 ynl code was ever merged, but it wasn't authoritative anyway, just for some limited userspace generation, so I'm not sure the whole ynl handling this is needed at all? johannes From johannes at sipsolutions.net Mon Sep 8 07:55:31 2025 From: johannes at sipsolutions.net (Johannes Berg) Date: Mon, 08 Sep 2025 09:55:31 +0200 Subject: [PATCH net-next 06/11] tools: ynl-gen: don't validate nested array attribute types In-Reply-To: References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-6-ast@fiberby.net> Message-ID: <96db85326505785727bcfe45b99ae12fdbfb548a.camel@sipsolutions.net> On Sat, 2025-09-06 at 15:10 +0000, Asbj?rn Sloth T?nnesen wrote: > > For the other families, I don't know how well defined it is, Johannes have > stated that nl80211 doesn't care which types are used, but I have no idea > how consistent clients have abused that statement to send random data, > or do they all just send zeros? I think most clients probably send incrementing numbers (1, 2, 3, ...), but maybe some start at 0, some sometimes might use band numbers and thus have sparse values, etc. But as I just wrote, I'm not really sure it should be used at all. joahnnes From david at redhat.com Mon Sep 8 08:00:05 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 8 Sep 2025 10:00:05 +0200 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <0a28adde-acaf-4d55-96ba-c32d6113285f@nvidia.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <016307ba-427d-4646-8e4d-1ffefd2c1968@nvidia.com> <85e760cf-b994-40db-8d13-221feee55c60@redhat.com> <0a28adde-acaf-4d55-96ba-c32d6113285f@nvidia.com> Message-ID: <28fc8fb3-f16b-4efb-b8e3-24081f035c73@redhat.com> >> Roughly, what I am thinking (limiting it to pte+pmd case) about is the >> following: > > The code below looks much cleaner, that's great! Great, I (or Aristeu if he has capacity) will clean this all up soon. -- Cheers David / dhildenb From david at redhat.com Mon Sep 8 12:53:00 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 8 Sep 2025 14:53:00 +0200 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <727cabec-5ee8-4793-926b-8d78febcd623@lucifer.local> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <016307ba-427d-4646-8e4d-1ffefd2c1968@nvidia.com> <85e760cf-b994-40db-8d13-221feee55c60@redhat.com> <727cabec-5ee8-4793-926b-8d78febcd623@lucifer.local> Message-ID: <7ee0b58a-8fe4-46fe-bfef-f04f900f3040@redhat.com> On 08.09.25 14:25, Lorenzo Stoakes wrote: > On Sat, Sep 06, 2025 at 08:56:48AM +0200, David Hildenbrand wrote: >> On 06.09.25 03:05, John Hubbard wrote: >>> >>> Probably a similar sentiment as Lorenzo here...the above diffs make the code >>> *worse* to read. In fact, I recall adding record_subpages() here long ago, >>> specifically to help clarify what was going on. >> >> Well, there is a lot I dislike about record_subpages() to go back there. >> Starting with "as Willy keeps explaining, the concept of subpages do >> not exist and ending with "why do we fill out the array even on failure". > > Yes > >> >> :) >> >>> >>> Now it's been returned to it's original, cryptic form. >>> >> >> The code in the caller was so uncryptic that both me and Lorenzo missed >> that magical addition. :P > > :'( > >> >>> Just my take on it, for whatever that's worth. :) >> >> As always, appreciated. >> >> I could of course keep the simple loop in some "record_folio_pages" >> function and clean up what I dislike about record_subpages(). >> >> But I much rather want the call chain to be cleaned up instead, if possible. >> >> >> Roughly, what I am thinking (limiting it to pte+pmd case) about is the following: > > I cannot get the below to apply even with the original patch here applied + fix. > > It looks like (in mm-new :) commit e73f43a66d5f ("mm/gup: remove dead pgmap > refcounting code") by Alastair has conflicted here, but even then I can't make > it apply, with/without your fix...! To be clear: it was never intended to be applied, because it wouldn't even compile in the current form. It was based on this nth_page submission + fix. [...] >> } >> static int gup_fast_pud_range(p4d_t *p4dp, p4d_t p4d, unsigned long addr, > > OK I guess you intentionally left the rest as a TODO :) > > So I'll wait for you to post it before reviewing in-depth. > > This generally LGTM as an approach, getting rid of *nr is important that's > really horrible. Yes. Expect a cleanup in that direction soonish (again, either from me or someone else I poke) > >> -- >> 2.50.1 >> >> >> >> Oh, I might even have found a bug moving away from that questionable >> "ret==1 means success" handling in gup_fast_pte_range()? Will >> have to double-check, but likely the following is the right thing to do. >> >> >> >> From 8f48b25ef93e7ef98611fd58ec89384ad5171782 Mon Sep 17 00:00:00 2001 >> From: David Hildenbrand >> Date: Sat, 6 Sep 2025 08:46:45 +0200 >> Subject: [PATCH] mm/gup: fix handling of errors from >> arch_make_folio_accessible() in follow_page_pte() >> >> In case we call arch_make_folio_accessible() and it fails, we would >> incorrectly return a value that is "!= 0" to the caller, indicating that >> we pinned all requested pages and that the caller can keep going. >> >> follow_page_pte() is not supposed to return error values, but instead >> 0 on failure and 1 on success. >> >> That is of course wrong, because the caller will just keep going pinning >> more pages. If we happen to pin a page afterwards, we're in trouble, >> because we essentially skipped some pages. >> >> Fixes: f28d43636d6f ("mm/gup/writeback: add callbacks for inaccessible pages") >> Signed-off-by: David Hildenbrand >> --- >> mm/gup.c | 3 +-- >> 1 file changed, 1 insertion(+), 2 deletions(-) >> >> diff --git a/mm/gup.c b/mm/gup.c >> index 22420f2069ee1..cff226ec0ee7d 100644 >> --- a/mm/gup.c >> +++ b/mm/gup.c >> @@ -2908,8 +2908,7 @@ static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, >> * details. >> */ >> if (flags & FOLL_PIN) { >> - ret = arch_make_folio_accessible(folio); >> - if (ret) { >> + if (arch_make_folio_accessible(folio)) { > > Oh Lord above. Lol. Yikes. > > Yeah I think your fix is valid... I sent it out earlier today. Fortunately that function shouldn't usually really fail IIUC. -- Cheers David / dhildenb From johannes at sipsolutions.net Mon Sep 8 13:22:40 2025 From: johannes at sipsolutions.net (Johannes Berg) Date: Mon, 08 Sep 2025 15:22:40 +0200 Subject: [PATCH net-next 02/11] tools: ynl-gen: generate nested array policies In-Reply-To: References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-2-ast@fiberby.net> <6e31a9e0-5450-4b45-a557-2aa08d23c25a@fiberby.net> Message-ID: <4ef5406d68805d6b176a0078ed0bf21b00052264.camel@sipsolutions.net> On Mon, 2025-09-08 at 09:08 +0000, Asbj?rn Sloth T?nnesen wrote: > > Thank you for the consensus write up. Should we prohibit indexed-array with sub-type > nest for families with a genetlink protocol? > > It is currently only used in families with a netlink-raw or genetlink-legacy protocol. I have no strong opinion on that, but I guess maybe so? At least print out a warning for anyone who's trying to add such a new thing perhaps, so that new stuff that isn't just a port (to ynl) or annotation of existing APIs doesn't add it. > > I can't get rid of the nested array types in nl80211 though, of course. > > Wireguard is already in the same boat. [...] Oh, sorry. I didn't look at the linked patch and thought it was adding such a new thing. Looking now, I see it just makes the policy validate it instead of (only) doing it in the code. (FWIW, in the code you could then also set the policy argument for nla_parse_nested() calls to NULL.) > Given that, as Jacob pointed out, there are more families with nested arrays in > their YNL spec, than those using NLA_NESTED_ARRAY, then it appears that there > are more families already in the boat. Right. johannes From broonie at kernel.org Mon Sep 8 15:16:13 2025 From: broonie at kernel.org (Mark Brown) Date: Mon, 8 Sep 2025 16:16:13 +0100 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <20250901150359.867252-20-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> Message-ID: On Mon, Sep 01, 2025 at 05:03:40PM +0200, David Hildenbrand wrote: > We can just cleanup the code by calculating the #refs earlier, > so we can just inline what remains of record_subpages(). > > Calculate the number of references/pages ahead of times, and record them > only once all our tests passed. I'm seeing failures in kselftest-mm in -next on at least Raspberry Pi 4 and Orion O6 which bisect to this patch. I'm seeing a NULL pointer dereference during the GUP test (which isn't actually doing anything as I'm just using a standard defconfig rather than one with the mm fragment): # # # [RUN] R/O longterm GUP-fast pin in MAP_SHARED file mapping .[ 92.209804] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008 ... [ 92.443816] Call trace: [ 92.446284] io_check_coalesce_buffer+0xd4/0x160 (P) [ 92.451306] io_sqe_buffers_register+0x1b0/0x22c [ 92.455976] __arm64_sys_io_uring_register+0x330/0xe74 [ 92.461176] invoke_syscall+0x48/0x104 [ 92.464966] el0_svc_common.constprop.0+0x40/0xe0 Full log: https://lava.sirena.org.uk/scheduler/job/1778528#L1985 The bisect looks to converge reasonably clearly, I didn't make much more effort to diagnose: # bad: [be5d4872e528796df9d7425f2bd9b3893eb3a42c] Add linux-next specific files for 20250905 # good: [5fe42852269dc659c8d511864410bd5cf3393e91] Merge branch 'for-linux-next-fixes' of https://gitlab.freedesktop.org/drm/misc/kernel.git # good: [0ccc1eeda155c947d88ef053e0b54e434e218ee2] ASoC: dt-bindings: wlf,wm8960: Document routing strings (pin names) # good: [7748328c2fd82efed24257b2bfd796eb1fa1d09b] ASoC: dt-bindings: qcom,lpass-va-macro: Update bindings for clocks to support ADSP # good: [dd7ae5b8b3c291c0206f127a564ae1e316705ca0] ASoC: cs42l43: Shutdown jack detection on suspend # good: [ce1a46b2d6a8465a86f7a6f71beb4c6de83bce5c] ASoC: codecs: lpass-wsa-macro: add Codev version 2.9 # good: [ce57b718006a069226b5e5d3afe7969acd59154e] ASoC: Intel: avs: ssm4567: Adjust platform name # good: [94b39cb3ad6db935b585988b36378884199cd5fc] spi: mxs: fix "transfered"->"transferred" # good: [5cc49b5a36b32a2dba41441ea13b93fb5ea21cfd] spi: spi-fsl-dspi: Report FIFO overflows as errors # good: [3279052eab235bfb7130b1fabc74029c2260ed8d] ASoC: SOF: ipc4-topology: Fix a less than zero check on a u32 # good: [8f57dcf39fd0864f5f3e6701fe885e55f45d0d3a] ASoC: qcom: audioreach: convert to cpu endainess type before accessing # good: [9d35d068fb138160709e04e3ee97fe29a6f8615b] regulator: scmi: Use int type to store negative error codes # good: [8a9772ec08f87c9e45ab1ad2c8d2b8c1763836eb] ASoC: soc-dapm: rename snd_soc_kcontrol_component() to snd_soc_kcontrol_to_component() # good: [07752abfa5dbf7cb4d9ce69fa94dc3b12bc597d9] ASoC: SOF: sof-client: Introduce sof_client_dev_entry structure # good: [d57d27171c92e9049d5301785fb38de127b28fbf] ASoC: SOF: sof-client-probes: Add available points_info(), IPC4 only # good: [f7c41911ad744177d8289820f01009dc93d8f91c] ASoC: SOF: ipc4-topology: Add support for float sample type # good: [3d439e1ec3368fae17db379354bd7a9e568ca0ab] ASoC: sof: ipc4-topology: Add support to sched_domain attribute # good: [5c39bc498f5ff7ef016abf3f16698f3e8db79677] ASoC: SOF: Intel: only detect codecs when HDA DSP probe # good: [f522da9ab56c96db8703b2ea0f09be7cdc3bffeb] ASoC: doc: Internally link to Writing an ALSA Driver docs # good: [f4672dc6e9c07643c8c755856ba8e9eb9ca95d0c] regmap: use int type to store negative error codes # good: [b088b6189a4066b97cef459afd312fd168a76dea] ASoC: mediatek: common: Switch to for_each_available_child_of_node_scoped() # good: [c42e36a488c7e01f833fc9f4814f735b66b2d494] spi: Drop dev_pm_domain_detach() call # good: [a37280daa4d583c7212681c49b285de9464a5200] ASoC: Intel: avs: Allow i2s test and non-test boards to coexist # good: [ff9a7857b7848227788f113d6dc6a72e989084e0] spi: rb4xx: use devm for clk_prepare_enable # good: [edb5c1f885207d1d74e8a1528e6937e02829ee6e] ASoC: renesas: msiof: start DMAC first # good: [e2ab5f600bb01d3625d667d97b3eb7538e388336] rust: regulator: use `to_result` for error handling # good: [5b4dcaf851df8c414bfc2ac3bf9c65fc942f3be4] ASoC: amd: acp: Remove (explicitly) unused header # good: [899fb38dd76dd3ede425bbaf8a96d390180a5d1c] regulator: core: Remove redundant ternary operators # good: [11f5c5f9e43e9020bae452232983fe98e7abfce0] ASoC: qcom: use int type to store negative error codes # good: [a12b74d2bd4724ee1883bc97ec93eac8fafc8d3c] ASoC: tlv320aic32x4: use dev_err_probe() for regulators # good: [f840737d1746398c2993be34bfdc80bdc19ecae2] ASoC: SOF: imx: Remove the use of dev_err_probe() # good: [d78e48ebe04e9566f8ecbf51471e80da3adbceeb] ASoC: dt-bindings: Minor whitespace cleanup in example # good: [96bcb34df55f7fee99795127c796315950c94fed] ASoC: test-component: Use kcalloc() instead of kzalloc() # good: [c232495d28ca092d0c39b10e35d3d613bd2414ab] ASoC: dt-bindings: omap-twl4030: convert to DT schema # good: [87a877de367d835b527d1086f75727123ef85fc4] KVM: x86: Rename handle_fastpath_set_msr_irqoff() to handle_fastpath_wrmsr() # good: [c26675447faff8c4ddc1dc5d2cd28326b8181aaf] KVM: x86: Zero XSTATE components on INIT by iterating over supported features # good: [ec0be3cdf40b5302248f3fb27a911cc630e8b855] regulator: consumer.rst: document bulk operations # good: [27848c082ba0b22850fd9fb7b185c015423dcdc7] spi: s3c64xx: Remove the use of dev_err_probe() # good: [c1dd310f1d76b4b13f1854618087af2513140897] spi: SPISG: Use devm_kcalloc() in aml_spisg_clk_init() # good: [da9881d00153cc6d3917f6b74144b1d41b58338c] ASoC: qcom: audioreach: add support for SMECNS module # good: [cf65182247761f7993737b710afe8c781699356b] ASoC: codecs: wsa883x: Handle shared reset GPIO for WSA883x speakers # good: [2a55135201d5e24b80b7624880ff42eafd8e320c] ASoC: Intel: avs: Streamline register-component function names # good: [550bc517e59347b3b1af7d290eac4fb1411a3d4e] regulator: bd718x7: Use kcalloc() instead of kzalloc() # good: [0056b410355713556d8a10306f82e55b28d33ba8] spi: offload trigger: adi-util-sigma-delta: clean up imports # good: [daf855f76a1210ceed9541f71ac5dd9be02018a6] ASoC: es8323: enable DAPM power widgets for playback DAC # good: [90179609efa421b1ccc7d8eafbc078bafb25777c] spi: spl022: use min_t() to improve code # good: [258384d8ce365dddd6c5c15204de8ccd53a7ab0a] ASoC: es8323: enable DAPM power widgets for playback DAC and output # good: [6d068f1ae2a2f713d7f21a9a602e65b3d6b6fc6d] regulator: rt5133: Fix spelling mistake "regualtor" -> "regulator" # good: [a46e95c81e3a28926ab1904d9f754fef8318074d] ASoC: wl1273: Remove # good: [48124569bbc6bfda1df3e9ee17b19d559f4b1aa3] spi: remove unneeded 'fast_io' parameter in regmap_config # good: [37533933bfe92cd5a99ef4743f31dac62ccc8de0] regulator: remove unneeded 'fast_io' parameter in regmap_config # good: [0e62438e476494a1891a8822b9785bc6e73e9c3f] ASoC: Intel: sst: Remove redundant semicolons # good: [5c36b86d2bf68fbcad16169983ef7ee8c537db59] regmap: Remove superfluous check for !config in __regmap_init() # good: [714165e1c4b0d5b8c6d095fe07f65e6e7047aaeb] regulator: rt5133: Add RT5133 PMIC regulator Support # good: [9c45f95222beecd6a284fd1284d54dd7a772cf59] spi: spi-qpic-snand: handle 'use_ecc' parameter of qcom_spi_config_cw_read() # good: [bab4ab484a6ca170847da9bffe86f1fa90df4bbe] ASoC: dt-bindings: Convert brcm,bcm2835-i2s to DT schema # good: [b832b19318534bb4f1673b24d78037fee339c679] spi: loopback-test: Don't use %pK through printk # good: [8c02c8353460f8630313aef6810f34e134a3c1ee] ASoC: dt-bindings: realtek,alc5623: convert to DT schema # good: [6b7e2aa50bdaf88cd4c2a5e2059a7bf32d85a8b1] spi: spi-qpic-snand: remove 'clr*status' members of struct 'qpic_ecc' # good: [2291a2186305faaf8525d57849d8ba12ad63f5e7] MAINTAINERS: Add entry for FourSemi audio amplifiers # good: [a54ef14188519a0994d0264f701f5771815fa11e] regulator: dt-bindings: Clean-up active-semi,act8945a duplication # good: [a1d0b0ae65ae3f32597edfbb547f16c75601cd87] spi: spi-qpic-snand: avoid double assignment in qcom_spi_probe() # good: [cf25eb8eae91bcae9b2065d84b0c0ba0f6d9dd34] ASoC: soc-component: unpack snd_soc_component_init_bias_level() # good: [595b7f155b926460a00776cc581e4dcd01220006] ASoC: Intel: avs: Conditional-path support # good: [3059067fd3378a5454e7928c08d20bf3ef186760] ASoC: cs48l32: Use PTR_ERR_OR_ZERO() to simplify code # good: [2d86d2585ab929a143d1e6f8963da1499e33bf13] ASoC: pxa: add GPIOLIB_LEGACY dependency # good: [9a200cbdb54349909a42b45379e792e4b39dd223] rust: regulator: implement Send and Sync for Regulator # good: [162e23657e5379f07c6404dbfbf4367cb438ea7d] regulator: pf0900: Add PMIC PF0900 support # good: [886f42ce96e7ce80545704e7168a9c6b60cd6c03] regmap: mmio: Add missing MODULE_DESCRIPTION() # good: [6684aba0780da9f505c202f27e68ee6d18c0aa66] XArray: Add extra debugging check to xas_lock and friends git bisect start 'be5d4872e528796df9d7425f2bd9b3893eb3a42c' '5fe42852269dc659c8d511864410bd5cf3393e91' '0ccc1eeda155c947d88ef053e0b54e434e218ee2' '7748328c2fd82efed24257b2bfd796eb1fa1d09b' 'dd7ae5b8b3c291c0206f127a564ae1e316705ca0' 'ce1a46b2d6a8465a86f7a6f71beb4c6de83bce5c' 'ce57b718006a069226b5e5d3afe7969acd59154e' '94b39cb3ad6db935b585988b36378884199cd5fc' '5cc49b5a36b32a2dba41441ea13b93fb5ea21cfd' '3279052eab235bfb7130b1fabc74029c2260ed8d' '8f57dcf39fd0864f5f3e6701fe885e55f45d0d3a' '9d35d068fb138160709e04e3ee97fe29a6f8615b' '8a9772ec08f87c9e45ab1ad2c8d2b8c1763836eb' '07752abfa5dbf7cb4d9ce69fa94dc3b12bc597d9' 'd57d27171c92e9049d5301785fb38de127b28fbf' 'f7c41911ad744177d8289820f01009dc93d8f91c' '3d439e1ec3368fae17db379354bd7a9e568ca0ab' '5c39bc498f5ff7ef016abf3f16698f3e8db79677' 'f522da9ab56c96db8703b2ea0f09be7cdc3bffeb' 'f4672dc6e9c07643c8c755856ba8e9eb9ca95d0c' 'b088b6189a4066b97cef459afd312fd168a76dea' 'c42e36a488c7e01f833fc9f4814f735b66b2d494' 'a37280daa4d583c7212681c49b285de9464a5200' 'ff9a7857b7848227788f113d6dc6a72e989084e0' 'edb5c1f885207d1d74e8a1528e6937e02829ee6e' 'e2ab5f600bb01d3625d667d97b3eb7538e388336' '5b4dcaf851df8c414bfc2ac3bf9c65fc942f3be4' '899fb38dd76dd3ede425bbaf8a96d390180a5d1c' '11f5c5f9e43e9020bae452232983fe98e7abfce0' 'a12b74d2bd4724ee1883bc97ec93eac8fafc8d3c' 'f840737d1746398c2993be34bfdc80bdc19ecae2' 'd78e48ebe04e9566f8ecbf51471e80da3adbceeb' '96bcb34df55f7fee99795127c796315950c94fed' 'c232495d28ca092d0c39b10e35d3d613bd2414ab' '87a877de367d835b527d1086f75727123ef85fc4' 'c26675447faff8c4ddc1dc5d2cd28326b8181aaf' 'ec0be3cdf40b5302248f3fb27a911cc630e8b855' '27848c082ba0b22850fd9fb7b185c015423dcdc7' 'c1dd310f1d76b4b13f1854618087af2513140897' 'da9881d00153cc6d3917f6b74144b1d41b58338c' 'cf65182247761f7993737b710afe8c781699356b' '2a55135201d5e24b80b7624880ff42eafd8e320c' '550bc517e59347b3b1af7d290eac4fb1411a3d4e' '0056b410355713556d8a10306f82e55b28d33ba8' 'daf855f76a1210ceed9541f71ac5dd9be02018a6' '90179609efa421b1ccc7d8eafbc078bafb25777c' '258384d8ce365dddd6c5c15204de8ccd53a7ab0a' '6d068f1ae2a2f713d7f21a9a602e65b3d6b6fc6d' 'a46e95c81e3a28926ab1904d9f754fef8318074d' '48124569bbc6bfda1df3e9ee17b19d559f4b1aa3' '37533933bfe92cd5a99ef4743f31dac62ccc8de0' '0e62438e476494a1891a8822b9785bc6e73e9c3f' '5c36b86d2bf68fbcad16169983ef7ee8c537db59' '714165e1c4b0d5b8c6d095fe07f65e6e7047aaeb' '9c45f95222beecd6a284fd1284d54dd7a772cf59' 'bab4ab484a6ca170847da9bffe86f1fa90df4bbe' 'b832b19318534bb4f1673b24d78037fee339c679' '8c02c8353460f8630313aef6810f34e134a3c1ee' '6b7e2aa50bdaf88cd4c2a5e2059a7bf32d85a8b1' '2291a2186305faaf8525d57849d8ba12ad63f5e7' 'a54ef14188519a0994d0264f701f5771815fa11e' 'a1d0b0ae65ae3f32597edfbb547f16c75601cd87' 'cf25eb8eae91bcae9b2065d84b0c0ba0f6d9dd34' '595b7f155b926460a00776cc581e4dcd01220006' '3059067fd3378a5454e7928c08d20bf3ef186760' '2d86d2585ab929a143d1e6f8963da1499e33bf13' '9a200cbdb54349909a42b45379e792e4b39dd223' '162e23657e5379f07c6404dbfbf4367cb438ea7d' '886f42ce96e7ce80545704e7168a9c6b60cd6c03' '6684aba0780da9f505c202f27e68ee6d18c0aa66' # test job: [0ccc1eeda155c947d88ef053e0b54e434e218ee2] https://lava.sirena.org.uk/scheduler/job/1773040 # test job: [7748328c2fd82efed24257b2bfd796eb1fa1d09b] https://lava.sirena.org.uk/scheduler/job/1773378 # test job: [dd7ae5b8b3c291c0206f127a564ae1e316705ca0] https://lava.sirena.org.uk/scheduler/job/1773233 # test job: [ce1a46b2d6a8465a86f7a6f71beb4c6de83bce5c] https://lava.sirena.org.uk/scheduler/job/1768983 # test job: [ce57b718006a069226b5e5d3afe7969acd59154e] https://lava.sirena.org.uk/scheduler/job/1768713 # test job: [94b39cb3ad6db935b585988b36378884199cd5fc] https://lava.sirena.org.uk/scheduler/job/1768603 # test job: [5cc49b5a36b32a2dba41441ea13b93fb5ea21cfd] https://lava.sirena.org.uk/scheduler/job/1769293 # test job: [3279052eab235bfb7130b1fabc74029c2260ed8d] https://lava.sirena.org.uk/scheduler/job/1762427 # test job: [8f57dcf39fd0864f5f3e6701fe885e55f45d0d3a] https://lava.sirena.org.uk/scheduler/job/1760074 # test job: [9d35d068fb138160709e04e3ee97fe29a6f8615b] https://lava.sirena.org.uk/scheduler/job/1758673 # test job: [8a9772ec08f87c9e45ab1ad2c8d2b8c1763836eb] https://lava.sirena.org.uk/scheduler/job/1758556 # test job: [07752abfa5dbf7cb4d9ce69fa94dc3b12bc597d9] https://lava.sirena.org.uk/scheduler/job/1752251 # test job: [d57d27171c92e9049d5301785fb38de127b28fbf] https://lava.sirena.org.uk/scheduler/job/1752624 # test job: [f7c41911ad744177d8289820f01009dc93d8f91c] https://lava.sirena.org.uk/scheduler/job/1752345 # test job: [3d439e1ec3368fae17db379354bd7a9e568ca0ab] https://lava.sirena.org.uk/scheduler/job/1753454 # test job: [5c39bc498f5ff7ef016abf3f16698f3e8db79677] https://lava.sirena.org.uk/scheduler/job/1751954 # test job: [f522da9ab56c96db8703b2ea0f09be7cdc3bffeb] https://lava.sirena.org.uk/scheduler/job/1751875 # test job: [f4672dc6e9c07643c8c755856ba8e9eb9ca95d0c] https://lava.sirena.org.uk/scheduler/job/1747876 # test job: [b088b6189a4066b97cef459afd312fd168a76dea] https://lava.sirena.org.uk/scheduler/job/1746202 # test job: [c42e36a488c7e01f833fc9f4814f735b66b2d494] https://lava.sirena.org.uk/scheduler/job/1746271 # test job: [a37280daa4d583c7212681c49b285de9464a5200] https://lava.sirena.org.uk/scheduler/job/1746918 # test job: [ff9a7857b7848227788f113d6dc6a72e989084e0] https://lava.sirena.org.uk/scheduler/job/1746336 # test job: [edb5c1f885207d1d74e8a1528e6937e02829ee6e] https://lava.sirena.org.uk/scheduler/job/1746134 # test job: [e2ab5f600bb01d3625d667d97b3eb7538e388336] https://lava.sirena.org.uk/scheduler/job/1746607 # test job: [5b4dcaf851df8c414bfc2ac3bf9c65fc942f3be4] https://lava.sirena.org.uk/scheduler/job/1747672 # test job: [899fb38dd76dd3ede425bbaf8a96d390180a5d1c] https://lava.sirena.org.uk/scheduler/job/1747375 # test job: [11f5c5f9e43e9020bae452232983fe98e7abfce0] https://lava.sirena.org.uk/scheduler/job/1747503 # test job: [a12b74d2bd4724ee1883bc97ec93eac8fafc8d3c] https://lava.sirena.org.uk/scheduler/job/1734077 # test job: [f840737d1746398c2993be34bfdc80bdc19ecae2] https://lava.sirena.org.uk/scheduler/job/1727318 # test job: [d78e48ebe04e9566f8ecbf51471e80da3adbceeb] https://lava.sirena.org.uk/scheduler/job/1706175 # test job: [96bcb34df55f7fee99795127c796315950c94fed] https://lava.sirena.org.uk/scheduler/job/1699577 # test job: [c232495d28ca092d0c39b10e35d3d613bd2414ab] https://lava.sirena.org.uk/scheduler/job/1699507 # test job: [87a877de367d835b527d1086f75727123ef85fc4] https://lava.sirena.org.uk/scheduler/job/1697972 # test job: [c26675447faff8c4ddc1dc5d2cd28326b8181aaf] https://lava.sirena.org.uk/scheduler/job/1698132 # test job: [ec0be3cdf40b5302248f3fb27a911cc630e8b855] https://lava.sirena.org.uk/scheduler/job/1694308 # test job: [27848c082ba0b22850fd9fb7b185c015423dcdc7] https://lava.sirena.org.uk/scheduler/job/1693100 # test job: [c1dd310f1d76b4b13f1854618087af2513140897] https://lava.sirena.org.uk/scheduler/job/1693035 # test job: [da9881d00153cc6d3917f6b74144b1d41b58338c] https://lava.sirena.org.uk/scheduler/job/1693416 # test job: [cf65182247761f7993737b710afe8c781699356b] https://lava.sirena.org.uk/scheduler/job/1687562 # test job: [2a55135201d5e24b80b7624880ff42eafd8e320c] https://lava.sirena.org.uk/scheduler/job/1685772 # test job: [550bc517e59347b3b1af7d290eac4fb1411a3d4e] https://lava.sirena.org.uk/scheduler/job/1685910 # test job: [0056b410355713556d8a10306f82e55b28d33ba8] https://lava.sirena.org.uk/scheduler/job/1685649 # test job: [daf855f76a1210ceed9541f71ac5dd9be02018a6] https://lava.sirena.org.uk/scheduler/job/1685441 # test job: [90179609efa421b1ccc7d8eafbc078bafb25777c] https://lava.sirena.org.uk/scheduler/job/1686081 # test job: [258384d8ce365dddd6c5c15204de8ccd53a7ab0a] https://lava.sirena.org.uk/scheduler/job/1673411 # test job: [6d068f1ae2a2f713d7f21a9a602e65b3d6b6fc6d] https://lava.sirena.org.uk/scheduler/job/1673133 # test job: [a46e95c81e3a28926ab1904d9f754fef8318074d] https://lava.sirena.org.uk/scheduler/job/1673748 # test job: [48124569bbc6bfda1df3e9ee17b19d559f4b1aa3] https://lava.sirena.org.uk/scheduler/job/1670184 # test job: [37533933bfe92cd5a99ef4743f31dac62ccc8de0] https://lava.sirena.org.uk/scheduler/job/1668977 # test job: [0e62438e476494a1891a8822b9785bc6e73e9c3f] https://lava.sirena.org.uk/scheduler/job/1669534 # test job: [5c36b86d2bf68fbcad16169983ef7ee8c537db59] https://lava.sirena.org.uk/scheduler/job/1667971 # test job: [714165e1c4b0d5b8c6d095fe07f65e6e7047aaeb] https://lava.sirena.org.uk/scheduler/job/1667699 # test job: [9c45f95222beecd6a284fd1284d54dd7a772cf59] https://lava.sirena.org.uk/scheduler/job/1667598 # test job: [bab4ab484a6ca170847da9bffe86f1fa90df4bbe] https://lava.sirena.org.uk/scheduler/job/1664664 # test job: [b832b19318534bb4f1673b24d78037fee339c679] https://lava.sirena.org.uk/scheduler/job/1659213 # test job: [8c02c8353460f8630313aef6810f34e134a3c1ee] https://lava.sirena.org.uk/scheduler/job/1659264 # test job: [6b7e2aa50bdaf88cd4c2a5e2059a7bf32d85a8b1] https://lava.sirena.org.uk/scheduler/job/1656585 # test job: [2291a2186305faaf8525d57849d8ba12ad63f5e7] https://lava.sirena.org.uk/scheduler/job/1655709 # test job: [a54ef14188519a0994d0264f701f5771815fa11e] https://lava.sirena.org.uk/scheduler/job/1656024 # test job: [a1d0b0ae65ae3f32597edfbb547f16c75601cd87] https://lava.sirena.org.uk/scheduler/job/1654201 # test job: [cf25eb8eae91bcae9b2065d84b0c0ba0f6d9dd34] https://lava.sirena.org.uk/scheduler/job/1654790 # test job: [595b7f155b926460a00776cc581e4dcd01220006] https://lava.sirena.org.uk/scheduler/job/1653119 # test job: [3059067fd3378a5454e7928c08d20bf3ef186760] https://lava.sirena.org.uk/scheduler/job/1655440 # test job: [2d86d2585ab929a143d1e6f8963da1499e33bf13] https://lava.sirena.org.uk/scheduler/job/1655917 # test job: [9a200cbdb54349909a42b45379e792e4b39dd223] https://lava.sirena.org.uk/scheduler/job/1654762 # test job: [162e23657e5379f07c6404dbfbf4367cb438ea7d] https://lava.sirena.org.uk/scheduler/job/1652978 # test job: [886f42ce96e7ce80545704e7168a9c6b60cd6c03] https://lava.sirena.org.uk/scheduler/job/1654270 # test job: [6684aba0780da9f505c202f27e68ee6d18c0aa66] https://lava.sirena.org.uk/scheduler/job/1738722 # test job: [be5d4872e528796df9d7425f2bd9b3893eb3a42c] https://lava.sirena.org.uk/scheduler/job/1778528 # bad: [be5d4872e528796df9d7425f2bd9b3893eb3a42c] Add linux-next specific files for 20250905 git bisect bad be5d4872e528796df9d7425f2bd9b3893eb3a42c # test job: [c3ce85ecd0268df1e0ca692e8126bb181fc89a08] https://lava.sirena.org.uk/scheduler/job/1779086 # bad: [c3ce85ecd0268df1e0ca692e8126bb181fc89a08] Merge branch 'main' of https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git git bisect bad c3ce85ecd0268df1e0ca692e8126bb181fc89a08 # test job: [973a887a5bb9a42878e276209592e0f75c287bb6] https://lava.sirena.org.uk/scheduler/job/1780104 # bad: [973a887a5bb9a42878e276209592e0f75c287bb6] Merge branch 'fs-next' of linux-next git bisect bad 973a887a5bb9a42878e276209592e0f75c287bb6 # test job: [fdabd8890022a9439b95d7395f7ae046544d96fd] https://lava.sirena.org.uk/scheduler/job/1780530 # bad: [fdabd8890022a9439b95d7395f7ae046544d96fd] Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git git bisect bad fdabd8890022a9439b95d7395f7ae046544d96fd # test job: [94bd0249a4a06131c4a1c2097b6134217a658976] https://lava.sirena.org.uk/scheduler/job/1780904 # bad: [94bd0249a4a06131c4a1c2097b6134217a658976] Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git git bisect bad 94bd0249a4a06131c4a1c2097b6134217a658976 # test job: [702b6c2f1008779e8fc8a4a4438410165309a4b4] https://lava.sirena.org.uk/scheduler/job/1781370 # bad: [702b6c2f1008779e8fc8a4a4438410165309a4b4] kasan-apply-write-only-mode-in-kasan-kunit-testcases-v7 git bisect bad 702b6c2f1008779e8fc8a4a4438410165309a4b4 # test job: [0ac48805721d5952a920356e454167bba8d27737] https://lava.sirena.org.uk/scheduler/job/1781448 # good: [0ac48805721d5952a920356e454167bba8d27737] mm: convert page_to_section() to memdesc_section() git bisect good 0ac48805721d5952a920356e454167bba8d27737 # test job: [dc731eba2e47fa81d50aa1cb167100889253cfe0] https://lava.sirena.org.uk/scheduler/job/1781608 # good: [dc731eba2e47fa81d50aa1cb167100889253cfe0] mm/damon/paddr: support addr_unit for MIGRATE_{HOT,COLD} git bisect good dc731eba2e47fa81d50aa1cb167100889253cfe0 # test job: [e24bb041cafabaa5fa3d76386c86af389cc324f5] https://lava.sirena.org.uk/scheduler/job/1781660 # good: [e24bb041cafabaa5fa3d76386c86af389cc324f5] mm/memremap: reject unreasonable folio/compound page sizes in memremap_pages() git bisect good e24bb041cafabaa5fa3d76386c86af389cc324f5 # test job: [62fd63f4688f40f01a6df23225523ece10d4b69a] https://lava.sirena.org.uk/scheduler/job/1781975 # bad: [62fd63f4688f40f01a6df23225523ece10d4b69a] dma-remap: drop nth_page() in dma_common_contiguous_remap() git bisect bad 62fd63f4688f40f01a6df23225523ece10d4b69a # test job: [cb42f7f6d9e4eff4e5259cddf82fd913306b8fe7] https://lava.sirena.org.uk/scheduler/job/1782145 # good: [cb42f7f6d9e4eff4e5259cddf82fd913306b8fe7] fs: hugetlbfs: remove nth_page() usage within folio in adjust_range_hwpoison() git bisect good cb42f7f6d9e4eff4e5259cddf82fd913306b8fe7 # test job: [db076b5db550aa34169dceee81d0974c7b2a2482] https://lava.sirena.org.uk/scheduler/job/1782813 # bad: [db076b5db550aa34169dceee81d0974c7b2a2482] mm/gup: remove record_subpages() git bisect bad db076b5db550aa34169dceee81d0974c7b2a2482 # test job: [891d0b3189945a5c37ce92c4e5337ec2c17b6378] https://lava.sirena.org.uk/scheduler/job/1782916 # good: [891d0b3189945a5c37ce92c4e5337ec2c17b6378] mm/pagewalk: drop nth_page() usage within folio in folio_walk_start() git bisect good 891d0b3189945a5c37ce92c4e5337ec2c17b6378 # test job: [21999f6315d786cbd21d5b2d0ad56f3f6125279f] https://lava.sirena.org.uk/scheduler/job/1783020 # good: [21999f6315d786cbd21d5b2d0ad56f3f6125279f] mm/gup: drop nth_page() usage within folio when recording subpages git bisect good 21999f6315d786cbd21d5b2d0ad56f3f6125279f # first bad commit: [db076b5db550aa34169dceee81d0974c7b2a2482] mm/gup: remove record_subpages() -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From david at redhat.com Mon Sep 8 15:22:24 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 8 Sep 2025 17:22:24 +0200 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> Message-ID: <83d3ef61-abc7-458d-b6ea-20094eeff6cd@redhat.com> On 08.09.25 17:16, Mark Brown wrote: > On Mon, Sep 01, 2025 at 05:03:40PM +0200, David Hildenbrand wrote: >> We can just cleanup the code by calculating the #refs earlier, >> so we can just inline what remains of record_subpages(). >> >> Calculate the number of references/pages ahead of times, and record them >> only once all our tests passed. > > I'm seeing failures in kselftest-mm in -next on at least Raspberry Pi 4 > and Orion O6 which bisect to this patch. I'm seeing a NULL pointer > dereference during the GUP test (which isn't actually doing anything as > I'm just using a standard defconfig rather than one with the mm > fragment): On which -next label are you on? next-20250908 should no longer have that commit. -- Cheers David / dhildenb From broonie at kernel.org Mon Sep 8 15:28:28 2025 From: broonie at kernel.org (Mark Brown) Date: Mon, 8 Sep 2025 16:28:28 +0100 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <83d3ef61-abc7-458d-b6ea-20094eeff6cd@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <83d3ef61-abc7-458d-b6ea-20094eeff6cd@redhat.com> Message-ID: On Mon, Sep 08, 2025 at 05:22:24PM +0200, David Hildenbrand wrote: > On 08.09.25 17:16, Mark Brown wrote: > > I'm seeing failures in kselftest-mm in -next on at least Raspberry Pi 4 > > and Orion O6 which bisect to this patch. I'm seeing a NULL pointer > On which -next label are you on? next-20250908 should no longer have that > commit. Ah, sorry - it was Friday's -next but I only saw the report this morning. Sorry for the noise. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From Jason at zx2c4.com Mon Sep 8 16:47:08 2025 From: Jason at zx2c4.com (Jason A. Donenfeld) Date: Mon, 8 Sep 2025 18:47:08 +0200 Subject: [PATCH RFC 05/35] wireguard: selftests: remove CONFIG_SPARSEMEM_VMEMMAP=y from qemu kernel config In-Reply-To: <20250821200701.1329277-6-david@redhat.com> References: <20250821200701.1329277-1-david@redhat.com> <20250821200701.1329277-6-david@redhat.com> Message-ID: Applied, thanks. From Jason at zx2c4.com Mon Sep 8 16:48:04 2025 From: Jason at zx2c4.com (Jason A. Donenfeld) Date: Mon, 8 Sep 2025 18:48:04 +0200 Subject: [PATCH v2 05/37] wireguard: selftests: remove CONFIG_SPARSEMEM_VMEMMAP=y from qemu kernel config In-Reply-To: <20250901150359.867252-6-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-6-david@redhat.com> Message-ID: Applied this one, actually. Thank you. From Jason at zx2c4.com Mon Sep 8 16:50:59 2025 From: Jason at zx2c4.com (Jason A. Donenfeld) Date: Mon, 8 Sep 2025 18:50:59 +0200 Subject: [PATCH v2 0/2] rework wg_cpumask_next_online() In-Reply-To: References: <20250719224444.411074-1-yury.norov@gmail.com> Message-ID: Applied this series, thanks. From akpm at linux-foundation.org Tue Sep 9 04:25:18 2025 From: akpm at linux-foundation.org (Andrew Morton) Date: Mon, 8 Sep 2025 21:25:18 -0700 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <64fe4c61-f9cc-4a5a-9c33-07bd0f089e94@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <5090355d-546a-4d06-99e1-064354d156b5@redhat.com> <20250905230006.GA1776@sol> <64fe4c61-f9cc-4a5a-9c33-07bd0f089e94@redhat.com> Message-ID: <20250908212518.77671b31aaad2832c17eab07@linux-foundation.org> On Sat, 6 Sep 2025 08:57:37 +0200 David Hildenbrand wrote: > >> @@ -3024,6 +3025,7 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > >> return 0; > >> } > >> + pages += *nr; > >> *nr += refs; > >> for (; refs; refs--) > >> *(pages++) = page++; > > > > Can this get folded in soon? This bug is causing crashes in AF_ALG too. > > Andrew immediately dropped the original patch, so it's gone from > mm-unstable and should be gone from next soon (today?). I restored it once you sent out the fix. It doesn't seem to be in present -next but it should be there in the next one. From david at redhat.com Tue Sep 9 09:55:51 2025 From: david at redhat.com (David Hildenbrand) Date: Tue, 9 Sep 2025 11:55:51 +0200 Subject: [PATCH v2 22/37] mm/cma: refuse handing out non-contiguous page ranges In-Reply-To: <20250901150359.867252-23-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-23-david@redhat.com> Message-ID: <6ec933b1-b3f7-41c0-95d8-e518bb87375e@redhat.com> On 01.09.25 17:03, David Hildenbrand wrote: > Let's disallow handing out PFN ranges with non-contiguous pages, so we > can remove the nth-page usage in __cma_alloc(), and so any callers don't > have to worry about that either when wanting to blindly iterate pages. > > This is really only a problem in configs with SPARSEMEM but without > SPARSEMEM_VMEMMAP, and only when we would cross memory sections in some > cases. > > Will this cause harm? Probably not, because it's mostly 32bit that does > not support SPARSEMEM_VMEMMAP. If this ever becomes a problem we could > look into allocating the memmap for the memory sections spanned by a > single CMA region in one go from memblock. > > Reviewed-by: Alexandru Elisei > Reviewed-by: Lorenzo Stoakes > Signed-off-by: David Hildenbrand > --- @Andrew, the following fixup on top. I'm still cross-compiling it, but at the time you read this mail my cross compiles should have been done. From cbfa2763e1820b917ce3430f45e5f3a55eb2970f Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 9 Sep 2025 05:50:13 -0400 Subject: [PATCH] fixup: mm/cma: refuse handing out non-contiguous page ranges Apparently we can have NUMMU configs with SPARSEMEM enabled. Signed-off-by: David Hildenbrand --- mm/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/util.c b/mm/util.c index 248f877f629b6..6c1d64ed02211 100644 --- a/mm/util.c +++ b/mm/util.c @@ -1306,6 +1306,7 @@ unsigned int folio_pte_batch(struct folio *folio, pte_t *ptep, pte_t pte, { return folio_pte_batch_flags(folio, NULL, ptep, &pte, max_nr, 0); } +#endif /* CONFIG_MMU */ #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP) /** @@ -1342,4 +1343,3 @@ bool page_range_contiguous(const struct page *page, unsigned long nr_pages) } EXPORT_SYMBOL(page_range_contiguous); #endif -#endif /* CONFIG_MMU */ -- 2.50.1 -- Cheers David / dhildenb From jacob.e.keller at intel.com Tue Sep 9 23:02:58 2025 From: jacob.e.keller at intel.com (Jacob Keller) Date: Tue, 9 Sep 2025 16:02:58 -0700 Subject: [PATCH net-next 02/11] tools: ynl-gen: generate nested array policies In-Reply-To: <6e31a9e0-5450-4b45-a557-2aa08d23c25a@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-2-ast@fiberby.net> <6e31a9e0-5450-4b45-a557-2aa08d23c25a@fiberby.net> Message-ID: <2b62f1bb-ad39-4b51-8730-f8304552c161@intel.com> On 9/6/2025 7:13 AM, Asbj?rn Sloth T?nnesen wrote: > CC: Johannes > > On 9/6/25 12:19 AM, Jacob Keller wrote: >> On 9/4/2025 3:01 PM, Asbj?rn Sloth T?nnesen wrote: >>> This patch adds support for NLA_POLICY_NESTED_ARRAY() policies. >>> >>> Example spec (from future wireguard.yaml): >>> - >>> name: wgpeer >>> attributes: >>> - >>> name: allowedips >>> type: indexed-array >>> sub-type: nest >>> nested-attributes: wgallowedip >>> >>> yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy). >>> >>> This doesn't change any currently generated code, as it isn't >>> used in any specs currently used for generating code. >>> >>> Signed-off-by: Asbj?rn Sloth T?nnesen >>> --- >> >> Is this keyed of off the sub-type? Does you mean that all the existing >> uses of 'sub-type: nest' don't generate code today? Or that this >> _attr_policy implementation is not called yet? > > Thanks for the reviews. Yeah, it is a careful wording, because we have > specs matching it, but there aren't any source files that triggers > ynl-gen to generate code based on those specs. > Ok. That's what I thought and just wanted to be certain, since I saw several uses in the code. Thanks for explaining! -------------- next part -------------- A non-text attachment was scrubbed... Name: OpenPGP_signature.asc Type: application/pgp-signature Size: 236 bytes Desc: OpenPGP digital signature URL: From jacob.e.keller at intel.com Wed Sep 10 16:58:37 2025 From: jacob.e.keller at intel.com (Jacob Keller) Date: Wed, 10 Sep 2025 09:58:37 -0700 Subject: [PATCH net-next 06/11] tools: ynl-gen: don't validate nested array attribute types In-Reply-To: References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-6-ast@fiberby.net> Message-ID: <7fff6b2f-f17e-4179-8507-397b76ea24bb@intel.com> On 9/6/2025 8:10 AM, Asbj?rn Sloth T?nnesen wrote: > CC: Johannes > > On 9/6/25 12:24 AM, Jacob Keller wrote: >> On 9/4/2025 3:01 PM, Asbj?rn Sloth T?nnesen wrote: >>> In nested arrays don't require that the intermediate >>> attribute type should be a valid attribute type, it >>> might just be an index or simple 0, it is often not >>> even used. >>> >>> See include/net/netlink.h about NLA_NESTED_ARRAY: >>>> The difference to NLA_NESTED is the structure: >>>> NLA_NESTED has the nested attributes directly inside >>>> while an array has the nested attributes at another >>>> level down and the attribute types directly in the >>>> nesting don't matter. >>> >> >> To me, it would seem like it makes more sense to define these (even if >> thats defined per family?) than to just say they aren't defined at all? >> >> Hm. > > I considered adding some of that metadata too, as I am actually removing > it for wireguard (in comment form, but still). > > In include/uapi/linux/wireguard.h in the comment block at the top, it is > very clear that wireguard only used type 0 for all the nested array > entries, however the truth is that it doesn't care. It therefore doesn't > matter if the generated -user.* keeps track of the index in .idx, or that > cli.py decodes a JSON array and sends it with indexes, it's not needed, > but it still works. > > In practice I don't think we will break any clients if we enforced it, and > validated that wireguard only accepts type 0 entries, in it's nested arrays. > > For the other families, I don't know how well defined it is, Johannes have > stated that nl80211 doesn't care which types are used, but I have no idea > how consistent clients have abused that statement to send random data, > or do they all just send zeros? > Changing it at this point could be a significant backwards compat break, as some clients might somehow send data that wasn't zero-initialized, and checking would break them. At this point I guess it makes sense to leave it as is... It would increase code cost and complexity for no gain. > This would make a lot more sense if 'array-nest' hadn't been renamed to > 'indexed-array' in ynl, because it feels wrong to add 'unindexed: true' now. > We could also call it 'all-zero-indexed: true'. > > In cli.py this gives some extra issues, as seen in [1], the nested arrays > are outputted as '[{0: {..}}, {0: {..}}, ..]', but on input has the format > '[{..},{..}, ..]' because it has to be JSON-compatible on input. > > If we had an attribute like 'all-zero-indexed' then cli.py, could also output > '[{..},{..}, ..]'. > This part would be cool. If we know the index is "uninteresting", eliding it so that the input and output formats match is good. > [1] https://lore.kernel.org/netdev/20250904220255.1006675-3-ast at fiberby.net/ -------------- next part -------------- A non-text attachment was scrubbed... Name: OpenPGP_signature.asc Type: application/pgp-signature Size: 236 bytes Desc: OpenPGP digital signature URL: From kuba at kernel.org Thu Sep 11 00:27:14 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Wed, 10 Sep 2025 17:27:14 -0700 Subject: [PATCH net-next 05/11] tools: ynl-gen: define nlattr *array in a block scope In-Reply-To: <3b52386e-6127-4bdc-b7db-e3c885b03f72@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-5-ast@fiberby.net> <20250905171809.694562c6@kernel.org> <4eda9c57-bde0-43c3-b8a0-3e45f2e672ac@fiberby.net> <20250906120754.7b90c718@kernel.org> <3b52386e-6127-4bdc-b7db-e3c885b03f72@fiberby.net> Message-ID: <20250910172714.25274ad0@kernel.org> On Thu, 11 Sep 2025 00:01:48 +0000 Asbj?rn Sloth T?nnesen wrote: > I left this for you to submit, there is a trivial conflict with patch 8 > in my v2 posting. Hah, no, please take this and submit as yours if you can. You can add me as Suggested-by. I already dropped it form my tree. Maintainers tend to throw random snippets of code at people, it's just quicker than explaining but we have enough commits in our name.. From kuba at kernel.org Thu Sep 11 01:29:55 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Wed, 10 Sep 2025 18:29:55 -0700 Subject: [PATCH net-next v2 00/12] tools: ynl: prepare for wireguard In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910182955.5d220149@kernel.org> On Wed, 10 Sep 2025 23:08:22 +0000 Asbj?rn Sloth T?nnesen wrote: > This series contains the last batch of YNL changes to support > the wireguard YNL conversion. please rebase From kuba at kernel.org Sat Sep 13 00:19:54 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 12 Sep 2025 17:19:54 -0700 Subject: [PATCH net-next v3 04/13] tools: ynl-gen: refactor local vars for .attr_put() callers In-Reply-To: <20250911200508.79341-5-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-5-ast@fiberby.net> Message-ID: <20250912171954.7c020c60@kernel.org> On Thu, 11 Sep 2025 20:04:57 +0000 Asbj?rn Sloth T?nnesen wrote: > + def attr_put_local_vars(self): > + local_vars = [] > + if self.presence_type() == 'count': > + local_vars.append('unsigned int i;') > + return local_vars > + > def attr_put(self, ri, var): > raise Exception(f"Put not implemented for class type {self.type}") > > @@ -840,6 +846,10 @@ class TypeArrayNest(Type): > '}'] > return get_lines, None, local_vars > > + def attr_put_local_vars(self): > + local_vars = ['struct nlattr *array;'] > + return local_vars + super().attr_put_local_vars() Doesn't feel right. The Type method is a helper which is compatible with the specific types by checking presence, then you override it, and on top of that combine the output with super(). I don't like. From kuba at kernel.org Sat Sep 13 00:21:24 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 12 Sep 2025 17:21:24 -0700 Subject: [PATCH net-next v3 05/13] tools: ynl-gen: add CodeWriter.p_lines() helper In-Reply-To: <20250911200508.79341-6-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-6-ast@fiberby.net> Message-ID: <20250912172124.57f96054@kernel.org> On Thu, 11 Sep 2025 20:04:58 +0000 Asbj?rn Sloth T?nnesen wrote: > Add a helper for writing an array of lines, and convert > all the existing loops doing that, to use the new helper. > > This is a trivial patch with no behavioural changes intended, > there are no changes to the generated code. I don't see the need for this. From kuba at kernel.org Sat Sep 13 00:24:18 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 12 Sep 2025 17:24:18 -0700 Subject: [PATCH net-next v3 06/13] tools: ynl-gen: deduplicate fixed_header handling In-Reply-To: <20250911200508.79341-7-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-7-ast@fiberby.net> Message-ID: <20250912172418.1271771d@kernel.org> On Thu, 11 Sep 2025 20:04:59 +0000 Asbj?rn Sloth T?nnesen wrote: > Fixed headers are handled nearly identical in print_dump(), > print_req() and put_req_nested(), generalize them and use a > common function to generate them. > > This only causes cosmetic changes to tc_netem_attrs_put() in > tc-user.c. > > Signed-off-by: Asbj?rn Sloth T?nnesen > --- > tools/net/ynl/pyynl/ynl_gen_c.py | 39 ++++++++++++++++---------------- > 1 file changed, 20 insertions(+), 19 deletions(-) This only makes the code longer and harder to follow. From kuba at kernel.org Sat Sep 13 00:27:42 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 12 Sep 2025 17:27:42 -0700 Subject: [PATCH net-next v3 08/13] tools: ynl-gen: only validate nested array payload In-Reply-To: <20250911200508.79341-9-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-9-ast@fiberby.net> Message-ID: <20250912172742.3a41b81e@kernel.org> On Thu, 11 Sep 2025 20:05:01 +0000 Asbj?rn Sloth T?nnesen wrote: > +int ynl_attr_validate_payload(struct ynl_parse_arg *yarg, > + const struct nlattr *attr, unsigned int type) > +{ > + return __ynl_attr_validate(yarg, attr, type); > +} Why not expose __ynl_attr_validate() to the callers? I don't think the _payload() suffix is crystal clear, we're still validating attr, _payload() makes it sound like we're validating what's inside attr? From kuba at kernel.org Sun Sep 14 18:08:04 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Sun, 14 Sep 2025 11:08:04 -0700 Subject: [PATCH net-next v4 04/11] tools: ynl-gen: refactor local vars for .attr_put() callers In-Reply-To: <20250913235847.358851-5-ast@fiberby.net> References: <20250913235847.358851-1-ast@fiberby.net> <20250913235847.358851-5-ast@fiberby.net> Message-ID: <20250914110804.3549eb9d@kernel.org> On Sat, 13 Sep 2025 23:58:25 +0000 Asbj?rn Sloth T?nnesen wrote: > Refactor the generation of local variables needed when building > requests, by moving the logic into the Type classes, and use the > same helper in all places where .attr_put() is called. > > If any attributes requests identical local_vars, then they will > be deduplicated, attributes are assumed to only use their local > variables transiently. Nope, this is not good enough. I prefer the obvious hack than a one-off member mixed into the object model. From kuba at kernel.org Tue Sep 16 01:42:12 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Mon, 15 Sep 2025 18:42:12 -0700 Subject: [PATCH net-next v5 04/11] tools: ynl-gen: refactor local vars for .attr_put() callers In-Reply-To: <20250915144301.725949-5-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> <20250915144301.725949-5-ast@fiberby.net> Message-ID: <20250915184212.1dc0abf2@kernel.org> On Mon, 15 Sep 2025 14:42:49 +0000 Asbj?rn Sloth T?nnesen wrote: > Refactor the generation of local variables needed when building > requests, by moving the logic from put_req_nested() into a new > helper put_local_vars(), and use the helper before .attr_put() is > called, thus generating the local variables assumed by .attr_put(). > > Previously only put_req_nested() generated the variables assumed > by .attr_put(), print_req() only generated the count iterator `i`, > and print_dump() neither generated `i` nor `array`. Reviewed-by: Jakub Kicinski From kuba at kernel.org Tue Sep 16 01:42:28 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Mon, 15 Sep 2025 18:42:28 -0700 Subject: [PATCH net-next v5 05/11] tools: ynl-gen: avoid repetitive variables definitions In-Reply-To: <20250915144301.725949-6-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> <20250915144301.725949-6-ast@fiberby.net> Message-ID: <20250915184228.49fe90ec@kernel.org> On Mon, 15 Sep 2025 14:42:50 +0000 Asbj?rn Sloth T?nnesen wrote: > In the generated attribute parsing code, avoid repetitively > defining the same variables over and over again, local to > the conditional block for each attribute. > > This patch consolidates the definitions of local variables > for attribute parsing, so that they are defined at the > function level, and re-used across attributes, thus making > the generated code read more natural. > > If attributes defines identical local_vars, then they will > be deduplicated, attributes are assumed to only use their > local variables transiently. Reviewed-by: Jakub Kicinski From kuba at kernel.org Tue Sep 16 01:42:58 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Mon, 15 Sep 2025 18:42:58 -0700 Subject: [PATCH net-next v5 06/11] tools: ynl-gen: validate nested arrays In-Reply-To: <20250915144301.725949-7-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> <20250915144301.725949-7-ast@fiberby.net> Message-ID: <20250915184258.14e04716@kernel.org> On Mon, 15 Sep 2025 14:42:51 +0000 Asbj?rn Sloth T?nnesen wrote: > This patch renames the old nl_attr_validate() to > __nl_attr_validate(), and creates a new inline function > nl_attr_validate() to mimic the old one. Reviewed-by: Jakub Kicinski From kuba at kernel.org Tue Sep 16 01:43:12 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Mon, 15 Sep 2025 18:43:12 -0700 Subject: [PATCH net-next v5 07/11] tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray In-Reply-To: <20250915144301.725949-8-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> <20250915144301.725949-8-ast@fiberby.net> Message-ID: <20250915184312.6a216d82@kernel.org> On Mon, 15 Sep 2025 14:42:52 +0000 Asbj?rn Sloth T?nnesen wrote: > Since TypeArrayNest can now be used with many other sub-types > than nest, then rename it to TypeIndexedArray, to reduce > confusion. > > This patch continues the rename, that was started in commit > aa6485d813ad ("ynl: rename array-nest to indexed-array"), > when the YNL type was renamed. > > In order to get rid of all references to the old naming, > within ynl, then renaming some variables in _multi_parse(). > > This is a trivial patch with no behavioural changes intended. Reviewed-by: Jakub Kicinski From patchwork-bot+netdevbpf at kernel.org Tue Sep 16 15:38:03 2025 From: patchwork-bot+netdevbpf at kernel.org (patchwork-bot+netdevbpf at kernel.org) Date: Tue, 16 Sep 2025 15:38:03 +0000 Subject: [PATCH net-next v5 00/11] tools: ynl: prepare for wireguard In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <175803708374.1166060.16728108514341236086.git-patchwork-notify@kernel.org> Hello: This series was applied to netdev/net-next.git (main) by Jakub Kicinski : On Mon, 15 Sep 2025 14:42:45 +0000 you wrote: > This series contains the last batch of YNL changes to support > the wireguard YNL conversion. > > The wireguard changes, to be applied on top of this series, > has been posted as an RFC series here: > https://lore.kernel.org/netdev/20250904-wg-ynl-rfc at fiberby.net/ > > [...] Here is the summary with links: - [net-next,v5,01/11] tools: ynl-gen: allow overriding name-prefix for constants https://git.kernel.org/netdev/net-next/c/3ff5258b9781 - [net-next,v5,02/11] tools: ynl-gen: generate nested array policies https://git.kernel.org/netdev/net-next/c/d0bdfe36d777 - [net-next,v5,03/11] tools: ynl-gen: add sub-type check https://git.kernel.org/netdev/net-next/c/8df78d97e498 - [net-next,v5,04/11] tools: ynl-gen: refactor local vars for .attr_put() callers https://git.kernel.org/netdev/net-next/c/db4ea3baa484 - [net-next,v5,05/11] tools: ynl-gen: avoid repetitive variables definitions https://git.kernel.org/netdev/net-next/c/099902fc66f8 - [net-next,v5,06/11] tools: ynl-gen: validate nested arrays https://git.kernel.org/netdev/net-next/c/1d99aa4ed707 - [net-next,v5,07/11] tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray https://git.kernel.org/netdev/net-next/c/a44a93ea6f06 - [net-next,v5,08/11] tools: ynl: move nest packing to a helper function https://git.kernel.org/netdev/net-next/c/328c13426240 - [net-next,v5,09/11] tools: ynl: encode indexed-arrays https://git.kernel.org/netdev/net-next/c/5c51ae2446c2 - [net-next,v5,10/11] tools: ynl: decode hex input https://git.kernel.org/netdev/net-next/c/52550d518d24 - [net-next,v5,11/11] tools: ynl: add ipv4-or-v6 display hint https://git.kernel.org/netdev/net-next/c/1b255e1beabf You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html From Jason at zx2c4.com Tue Sep 16 15:51:21 2025 From: Jason at zx2c4.com (Jason A. Donenfeld) Date: Tue, 16 Sep 2025 17:51:21 +0200 Subject: [RFC net-next 00/14] wireguard: netlink: ynl conversion In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: Hi Asbjorn, On Fri, Sep 5, 2025 at 12:03?AM Asbj?rn Sloth T?nnesen wrote: > > This series contains the wireguard changes needed to adopt > an YNL-based generated netlink code. > > This RFC series is posted for reference, as it is referenced > from the current v1 series of ynl preparations, which has to > go in before this series can be submitted for net-next. I'm not actually convinced this makes anything better. It seems like the code becomes more complicated and less obvious. What is the benefit here? As is, I really don't like this direction. Jason From Jason at zx2c4.com Tue Sep 16 15:53:00 2025 From: Jason at zx2c4.com (Jason A. Donenfeld) Date: Tue, 16 Sep 2025 17:53:00 +0200 Subject: [PATCH net-next v5 00/11] tools: ynl: prepare for wireguard In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: Hi Asbjorn, On Mon, Sep 15, 2025 at 4:47?PM Asbj?rn Sloth T?nnesen wrote: > > This series contains the last batch of YNL changes to support > the wireguard YNL conversion. "the wireguard YNL conversion" Did I miss some conversation about this? I figure I must have. I must say I'm not too keen on wireguard (and apparently only wireguard?) being a guinea pig for this. Jason From kuba at kernel.org Tue Sep 16 22:39:32 2025 From: kuba at kernel.org (Jakub Kicinski) Date: Tue, 16 Sep 2025 15:39:32 -0700 Subject: [PATCH net-next v5 00/11] tools: ynl: prepare for wireguard In-Reply-To: References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <20250916153932.200647ad@kernel.org> On Tue, 16 Sep 2025 17:53:00 +0200 Jason A. Donenfeld wrote: > On Mon, Sep 15, 2025 at 4:47?PM Asbj?rn Sloth T?nnesen wrote: > > > > This series contains the last batch of YNL changes to support > > the wireguard YNL conversion. > > "the wireguard YNL conversion" FWIW these patches stand on their own whether we accept the wireguard patches or not. Put more plainly - please do not read me applying this set as an endorsement of the larger plan.. > Did I miss some conversation about this? I figure I must have. I must > say I'm not too keen on wireguard (and apparently only wireguard?) > being a guinea pig for this. The specs themselves are gaining maturity. I think adding a YNL spec for wireguard would be quite nice. Whether we should be converting the kernel code and uAPI to take advantage of the auto-generation is a completely separate conversation. If you're not anticipating many new additions in the uAPI there's little to be gained. Intro: https://docs.kernel.org/next/userspace-api/netlink/specs.html Existing specs: https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/tree/Documentation/netlink/specs/ Libs: https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/tree/tools/net/ynl/pyynl/lib/ynl.py https://github.com/linux-netdev/ynl-c (this one is also in tree) https://github.com/linux-netdev/ynl-cpp From ast at fiberby.net Mon Sep 1 14:52:15 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 01 Sep 2025 14:52:15 -0000 Subject: [PATCH net 1/4] netlink: specs: fou: change local-v6/peer-v6 check In-Reply-To: <20250901145034.525518-1-ast@fiberby.net> References: <20250901145034.525518-1-ast@fiberby.net> Message-ID: <20250901145034.525518-2-ast@fiberby.net> While fixing the binary min-len implementaion, I noticed that the only user, should AFAICT be using exact-len instead. In net/ipv4/fou_core.c FOU_ATTR_LOCAL_V6 and FOU_ATTR_PEER_V6 are only used for singular IPv6 addresses, a exact-len policy, therefore seams like a better fit. AFAICT this was caused by lacking support for the exact-len check at the time of the blamed commit, which was later remedied by c63ad379526 ("tools: ynl-gen: add support for exact-len validation"). This patch therefore changes the local-v6/peer-v6 attributes to use an exact-len check, instead of a min-len check. Fixes: 4eb77b4ecd3c ("netlink: add a proto specification for FOU") Signed-off-by: Asbj?rn Sloth T?nnesen --- Documentation/netlink/specs/fou.yaml | 4 ++-- net/ipv4/fou_nl.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/netlink/specs/fou.yaml b/Documentation/netlink/specs/fou.yaml index 57735726262ec..8e7974ec453fc 100644 --- a/Documentation/netlink/specs/fou.yaml +++ b/Documentation/netlink/specs/fou.yaml @@ -52,7 +52,7 @@ attribute-sets: name: local-v6 type: binary checks: - min-len: 16 + exact-len: 16 - name: peer-v4 type: u32 @@ -60,7 +60,7 @@ attribute-sets: name: peer-v6 type: binary checks: - min-len: 16 + exact-len: 16 - name: peer-port type: u16 diff --git a/net/ipv4/fou_nl.c b/net/ipv4/fou_nl.c index 3d9614609b2d3..506260b4a4dc2 100644 --- a/net/ipv4/fou_nl.c +++ b/net/ipv4/fou_nl.c @@ -18,9 +18,9 @@ const struct nla_policy fou_nl_policy[FOU_ATTR_IFINDEX + 1] = { [FOU_ATTR_TYPE] = { .type = NLA_U8, }, [FOU_ATTR_REMCSUM_NOPARTIAL] = { .type = NLA_FLAG, }, [FOU_ATTR_LOCAL_V4] = { .type = NLA_U32, }, - [FOU_ATTR_LOCAL_V6] = { .len = 16, }, + [FOU_ATTR_LOCAL_V6] = NLA_POLICY_EXACT_LEN(16), [FOU_ATTR_PEER_V4] = { .type = NLA_U32, }, - [FOU_ATTR_PEER_V6] = { .len = 16, }, + [FOU_ATTR_PEER_V6] = NLA_POLICY_EXACT_LEN(16), [FOU_ATTR_PEER_PORT] = { .type = NLA_BE16, }, [FOU_ATTR_IFINDEX] = { .type = NLA_S32, }, }; -- 2.50.1 From ast at fiberby.net Mon Sep 1 14:52:16 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 01 Sep 2025 14:52:16 -0000 Subject: [PATCH net 3/4] tools: ynl-gen: fix nested array counting In-Reply-To: <20250901145034.525518-1-ast@fiberby.net> References: <20250901145034.525518-1-ast@fiberby.net> Message-ID: <20250901145034.525518-4-ast@fiberby.net> The blamed commit introduced the concept of split attribute counting, and later allocating an array to hold them, however TypeArrayNest wasn't updated to use the new counting variable. Abbreviated example from tools/net/ynl/generated/nl80211-user.c: nl80211_if_combination_attributes_parse(...): unsigned int n_limits = 0; [...] ynl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len) if (type == NL80211_IFACE_COMB_LIMITS) ynl_attr_for_each_nested(attr2, attr) dst->_count.limits++; if (n_limits) { dst->_count.limits = n_limits; /* allocate and parse attributes */ } In the above example n_limits is guaranteed to always be 0, hence the conditional is unsatisfiable and is optimized out. This patch changes the attribute counting to use n_limits++ in the attribute counting loop in the above example. Fixes: 58da455b31ba ("tools: ynl-gen: improve unwind on parsing errors") Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 52f955ed84a7f..fb7e03805a113 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -830,7 +830,7 @@ class TypeArrayNest(Type): 'ynl_attr_for_each_nested(attr2, attr) {', '\tif (ynl_attr_validate(yarg, attr2))', '\t\treturn YNL_PARSE_CB_ERROR;', - f'\t{var}->_count.{self.c_name}++;', + f'\tn_{self.c_name}++;', '}'] return get_lines, None, local_vars -- 2.50.1 From ast at fiberby.net Mon Sep 1 14:52:16 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 01 Sep 2025 14:52:16 -0000 Subject: [PATCH net 4/4] genetlink: fix typo in comment In-Reply-To: <20250901145034.525518-1-ast@fiberby.net> References: <20250901145034.525518-1-ast@fiberby.net> Message-ID: <20250901145034.525518-5-ast@fiberby.net> In this context "not that ..." should properly be "note that ...". Fixes: b8fd60c36a44 ("genetlink: allow families to use split ops directly") Signed-off-by: Asbj?rn Sloth T?nnesen --- include/net/genetlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/genetlink.h b/include/net/genetlink.h index a03d567658328..7b84f2cef8b1f 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -62,7 +62,7 @@ struct genl_info; * @small_ops: the small-struct operations supported by this family * @n_small_ops: number of small-struct operations supported by this family * @split_ops: the split do/dump form of operation definition - * @n_split_ops: number of entries in @split_ops, not that with split do/dump + * @n_split_ops: number of entries in @split_ops, note that with split do/dump * ops the number of entries is not the same as number of commands * @sock_priv_size: the size of per-socket private memory * @sock_priv_init: the per-socket private memory initializer -- 2.50.1 From ast at fiberby.net Mon Sep 1 14:52:16 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 01 Sep 2025 14:52:16 -0000 Subject: [PATCH net 2/4] tools: ynl-gen: use macro for binary min-len check In-Reply-To: <20250901145034.525518-1-ast@fiberby.net> References: <20250901145034.525518-1-ast@fiberby.net> Message-ID: <20250901145034.525518-3-ast@fiberby.net> This patch changes the generated min-len check for binary attributes to use the NLA_POLICY_MIN_LEN() macro, and thereby ensures that .validation_type is not left at NLA_VALIDATE_NONE. This doesn't change any currently generated code, as it isn't used in any specs currently used for generating code. Fixes: be5bea1cc0bf ("net: add basic C code generators for Netlink") Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index ef032e17fec44..52f955ed84a7f 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -556,7 +556,7 @@ class TypeBinary(Type): elif 'exact-len' in self.checks: mem = 'NLA_POLICY_EXACT_LEN(' + self.get_limit_str('exact-len') + ')' elif 'min-len' in self.checks: - mem = '{ .len = ' + self.get_limit_str('min-len') + ', }' + mem = 'NLA_POLICY_MIN_LEN(' + self.get_limit_str('min-len') + ')' elif 'max-len' in self.checks: mem = 'NLA_POLICY_MAX_LEN(' + self.get_limit_str('max-len') + ')' -- 2.50.1 From ast at fiberby.net Mon Sep 1 14:52:16 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 01 Sep 2025 14:52:16 -0000 Subject: [PATCH net 0/4] tools: ynl-gen: misc fixes + wireguard ynl plan Message-ID: <20250901145034.525518-1-ast@fiberby.net> Hi, This is the first batch of changes related to converting the netlink around wireguard, to be based on an YNL spec, with the focus on making it a 1-to-1 replacement. I will post these 28 patches in 3 batches. This 1st series with some misc fixes for net. Once this 1st series makes its way to net-next, then I plan to post the 2nd series with YNL improvements for net-next, and the 3rd series with the wireguard changes as RFC at the same time, as many of the patches in the 2nd series is using the 3rd series for justification, so they should be available for reviewers. Once the 2nd series is accepted into net-next, then I will post the 3rd series in v1 for net-next. Below are the diff stats for each series: 1st series (this) - misc fixes (4 patches): Documentation/netlink/specs/fou.yaml | 4 ++-- include/net/genetlink.h | 2 +- net/ipv4/fou_nl.c | 4 ++-- tools/net/ynl/pyynl/ynl_gen_c.py | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) 2nd series - ynl improvements (10 patches): Doc../netlink/genetlink-legacy.yaml | 2 +- tools/net/ynl/pyynl/lib/ynl.py | 36 ++++++++++++--- tools/net/ynl/pyynl/ynl_gen_c.py | 34 ++++++++------ 3 files changed, 52 insertions(+), 20 deletions(-) 3rd series - wireguard changes (14 patches): Doc../netlink/specs/wireguard.yaml | 321 ++++++++++++++ MAINTAINERS | 3 + drivers/net/wireguard/Makefile | 1 + drivers/net/wireguard/netlink.c | 73 +-- drivers/net/wireguard/netlink_gen.c | 72 +++ drivers/net/wireguard/netlink_gen.h | 30 ++ include/uapi/linux/wireguard.h | 202 ++------- include/uapi/linux/wireguard_params.h | 18 + tools/net/ynl/samples/.gitignore | 1 + tools/net/ynl/samples/wireguard.c | 104 +++++ 10 files changed, 605 insertions(+), 220 deletions(-) Asbj?rn Sloth T?nnesen (4): netlink: specs: fou: change local-v6/peer-v6 check tools: ynl-gen: use macro for binary min-len check tools: ynl-gen: fix nested array counting genetlink: fix typo in comment Documentation/netlink/specs/fou.yaml | 4 ++-- include/net/genetlink.h | 2 +- net/ipv4/fou_nl.c | 4 ++-- tools/net/ynl/pyynl/ynl_gen_c.py | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) -- 2.50.1 From david at redhat.com Mon Sep 1 15:04:47 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:04:47 -0000 Subject: [PATCH v2 00/37] mm: remove nth_page() Message-ID: <20250901150359.867252-1-david@redhat.com> This is based on mm-unstable. I will only CC non-MM folks on the cover letter and the respective patch to not flood too many inboxes (the lists receive all patches). -- As discussed recently with Linus, nth_page() is just nasty and we would like to remove it. To recap, the reason we currently need nth_page() within a folio is because on some kernel configs (SPARSEMEM without SPARSEMEM_VMEMMAP), the memmap is allocated per memory section. While buddy allocations cannot cross memory section boundaries, hugetlb and dax folios can. So crossing a memory section means that "page++" could do the wrong thing. Instead, nth_page() on these problematic configs always goes from page->pfn, to the go from (++pfn)->page, which is rather nasty. Likely, many people have no idea when nth_page() is required and when it might be dropped. We refer to such problematic PFN ranges and "non-contiguous pages". If we only deal with "contiguous pages", there is not need for nth_page(). Besides that "obvious" folio case, we might end up using nth_page() within CMA allocations (again, could span memory sections), and in one corner case (kfence) when processing memblock allocations (again, could span memory sections). So let's handle all that, add sanity checks, and remove nth_page(). Patch #1 -> #5 : stop making SPARSEMEM_VMEMMAP user-selectable + cleanups Patch #6 -> #13 : disallow folios to have non-contiguous pages Patch #14 -> #20 : remove nth_page() usage within folios Patch #22 : disallow CMA allocations of non-contiguous pages Patch #23 -> #33 : sanity+check + remove nth_page() usage within SG entry Patch #34 : sanity-check + remove nth_page() usage in unpin_user_page_range_dirty_lock() Patch #35 : remove nth_page() in kfence Patch #36 : adjust stale comment regarding nth_page Patch #37 : mm: remove nth_page() A lot of this is inspired from the discussion at [1] between Linus, Jason and me, so cudos to them. [1] https://lore.kernel.org/all/CAHk-=wiCYfNp4AJLBORU-c7ZyRBUp66W2-Et6cdQ4REx-GyQ_A at mail.gmail.com/T/#u v1 -> v2: * "fs: hugetlbfs: cleanup folio in adjust_range_hwpoison()" -> Add comment for loop and remove comment of function regarding copy_page_to_iter(). * Various smaller patch description tweaks I am not going to list for my sanity * "mips: mm: convert __flush_dcache_pages() to __flush_dcache_folio_pages()" -> Fix flush_dcache_page() -> Drop "extern" * "mm/gup: remove record_subpages()" -> Added * "mm/hugetlb: check for unreasonable folio sizes when registering hstate" -> Refine comment * "mm/cma: refuse handing out non-contiguous page ranges" -> Add comment above loop * "mm/page_alloc: reject unreasonable folio/compound page sizes in alloc_contig_range_noprof()" -> Added comment above check * "mm/gup: drop nth_page() usage in unpin_user_page_range_dirty_lock()" -> Refined comment RFC -> v1: * "wireguard: selftests: remove CONFIG_SPARSEMEM_VMEMMAP=y from qemu kernel config" -> Mention that it was never really relevant for the test * "mm/mm_init: make memmap_init_compound() look more like prep_compound_page()" -> Mention the setup of page links * "mm: limit folio/compound page sizes in problematic kernel configs" -> Improve comment for PUD handling, mentioning hugetlb and dax * "mm: simplify folio_page() and folio_page_idx()" -> Call variable "n" * "mm/hugetlb: cleanup hugetlb_folio_init_tail_vmemmap()" -> Keep __init_single_page() and refer to the usage of memblock_reserved_mark_noinit() * "fs: hugetlbfs: cleanup folio in adjust_range_hwpoison()" * "fs: hugetlbfs: remove nth_page() usage within folio in adjust_range_hwpoison()" -> Separate nth_page() removal from cleanups -> Further improve cleanups * "io_uring/zcrx: remove nth_page() usage within folio" -> Keep the io_copy_cache for now and limit to nth_page() removal * "mm/gup: drop nth_page() usage within folio when recording subpages" -> Cleanup record_subpages as bit * "mm/cma: refuse handing out non-contiguous page ranges" -> Replace another instance of "pfn_to_page(pfn)" where we already have the page * "scatterlist: disallow non-contigous page ranges in a single SG entry" -> We have to EXPORT the symbol. I thought about moving it to mm_inline.h, but I really don't want to include that in include/linux/scatterlist.h * "ata: libata-eh: drop nth_page() usage within SG entry" * "mspro_block: drop nth_page() usage within SG entry" * "memstick: drop nth_page() usage within SG entry" * "mmc: drop nth_page() usage within SG entry" -> Keep PAGE_SHIFT * "scsi: scsi_lib: drop nth_page() usage within SG entry" * "scsi: sg: drop nth_page() usage within SG entry" -> Split patches, Keep PAGE_SHIFT * "crypto: remove nth_page() usage within SG entry" -> Keep PAGE_SHIFT * "kfence: drop nth_page() usage" -> Keep modifying i and use "start_pfn" only instead Cc: Andrew Morton Cc: Linus Torvalds Cc: Jason Gunthorpe Cc: Lorenzo Stoakes Cc: "Liam R. Howlett" Cc: Vlastimil Babka Cc: Mike Rapoport Cc: Suren Baghdasaryan Cc: Michal Hocko Cc: Jens Axboe Cc: Marek Szyprowski Cc: Robin Murphy Cc: John Hubbard Cc: Peter Xu Cc: Alexander Potapenko Cc: Marco Elver Cc: Dmitry Vyukov Cc: Brendan Jackman Cc: Johannes Weiner Cc: Zi Yan Cc: Dennis Zhou Cc: Tejun Heo Cc: Christoph Lameter Cc: Muchun Song Cc: Oscar Salvador Cc: x86 at kernel.org Cc: linux-arm-kernel at lists.infradead.org Cc: linux-mips at vger.kernel.org Cc: linux-s390 at vger.kernel.org Cc: linux-crypto at vger.kernel.org Cc: linux-ide at vger.kernel.org Cc: intel-gfx at lists.freedesktop.org Cc: dri-devel at lists.freedesktop.org Cc: linux-mmc at vger.kernel.org Cc: linux-arm-kernel at axis.com Cc: linux-scsi at vger.kernel.org Cc: kvm at vger.kernel.org Cc: virtualization at lists.linux.dev Cc: linux-mm at kvack.org Cc: io-uring at vger.kernel.org Cc: iommu at lists.linux.dev Cc: kasan-dev at googlegroups.com Cc: wireguard at lists.zx2c4.com Cc: netdev at vger.kernel.org Cc: linux-kselftest at vger.kernel.org Cc: linux-riscv at lists.infradead.org David Hildenbrand (37): mm: stop making SPARSEMEM_VMEMMAP user-selectable arm64: Kconfig: drop superfluous "select SPARSEMEM_VMEMMAP" s390/Kconfig: drop superfluous "select SPARSEMEM_VMEMMAP" x86/Kconfig: drop superfluous "select SPARSEMEM_VMEMMAP" wireguard: selftests: remove CONFIG_SPARSEMEM_VMEMMAP=y from qemu kernel config mm/page_alloc: reject unreasonable folio/compound page sizes in alloc_contig_range_noprof() mm/memremap: reject unreasonable folio/compound page sizes in memremap_pages() mm/hugetlb: check for unreasonable folio sizes when registering hstate mm/mm_init: make memmap_init_compound() look more like prep_compound_page() mm: sanity-check maximum folio size in folio_set_order() mm: limit folio/compound page sizes in problematic kernel configs mm: simplify folio_page() and folio_page_idx() mm/hugetlb: cleanup hugetlb_folio_init_tail_vmemmap() mm/mm/percpu-km: drop nth_page() usage within single allocation fs: hugetlbfs: remove nth_page() usage within folio in adjust_range_hwpoison() fs: hugetlbfs: cleanup folio in adjust_range_hwpoison() mm/pagewalk: drop nth_page() usage within folio in folio_walk_start() mm/gup: drop nth_page() usage within folio when recording subpages mm/gup: remove record_subpages() io_uring/zcrx: remove nth_page() usage within folio mips: mm: convert __flush_dcache_pages() to __flush_dcache_folio_pages() mm/cma: refuse handing out non-contiguous page ranges dma-remap: drop nth_page() in dma_common_contiguous_remap() scatterlist: disallow non-contigous page ranges in a single SG entry ata: libata-sff: drop nth_page() usage within SG entry drm/i915/gem: drop nth_page() usage within SG entry mspro_block: drop nth_page() usage within SG entry memstick: drop nth_page() usage within SG entry mmc: drop nth_page() usage within SG entry scsi: scsi_lib: drop nth_page() usage within SG entry scsi: sg: drop nth_page() usage within SG entry vfio/pci: drop nth_page() usage within SG entry crypto: remove nth_page() usage within SG entry mm/gup: drop nth_page() usage in unpin_user_page_range_dirty_lock() kfence: drop nth_page() usage block: update comment of "struct bio_vec" regarding nth_page() mm: remove nth_page() arch/arm64/Kconfig | 1 - arch/mips/include/asm/cacheflush.h | 11 +++-- arch/mips/mm/cache.c | 8 ++-- arch/s390/Kconfig | 1 - arch/x86/Kconfig | 1 - crypto/ahash.c | 4 +- crypto/scompress.c | 8 ++-- drivers/ata/libata-sff.c | 6 +-- drivers/gpu/drm/i915/gem/i915_gem_pages.c | 2 +- drivers/memstick/core/mspro_block.c | 3 +- drivers/memstick/host/jmb38x_ms.c | 3 +- drivers/memstick/host/tifm_ms.c | 3 +- drivers/mmc/host/tifm_sd.c | 4 +- drivers/mmc/host/usdhi6rol0.c | 4 +- drivers/scsi/scsi_lib.c | 3 +- drivers/scsi/sg.c | 3 +- drivers/vfio/pci/pds/lm.c | 3 +- drivers/vfio/pci/virtio/migrate.c | 3 +- fs/hugetlbfs/inode.c | 36 +++++--------- include/crypto/scatterwalk.h | 4 +- include/linux/bvec.h | 7 +-- include/linux/mm.h | 48 +++++++++++++++---- include/linux/page-flags.h | 5 +- include/linux/scatterlist.h | 3 +- io_uring/zcrx.c | 4 +- kernel/dma/remap.c | 2 +- mm/Kconfig | 3 +- mm/cma.c | 39 +++++++++------ mm/gup.c | 36 +++++++------- mm/hugetlb.c | 22 +++++---- mm/internal.h | 1 + mm/kfence/core.c | 12 +++-- mm/memremap.c | 3 ++ mm/mm_init.c | 15 +++--- mm/page_alloc.c | 10 +++- mm/pagewalk.c | 2 +- mm/percpu-km.c | 2 +- mm/util.c | 36 ++++++++++++++ tools/testing/scatterlist/linux/mm.h | 1 - .../selftests/wireguard/qemu/kernel.config | 1 - 40 files changed, 217 insertions(+), 146 deletions(-) base-commit: b73c6f2b5712809f5f386780ac46d1d78c31b2e6 -- 2.50.1 From david at redhat.com Mon Sep 1 15:05:05 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:05:05 -0000 Subject: [PATCH v2 01/37] mm: stop making SPARSEMEM_VMEMMAP user-selectable In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-2-david@redhat.com> In an ideal world, we wouldn't have to deal with SPARSEMEM without SPARSEMEM_VMEMMAP, but in particular for 32bit SPARSEMEM_VMEMMAP is considered too costly and consequently not supported. However, if an architecture does support SPARSEMEM with SPARSEMEM_VMEMMAP, let's forbid the user to disable VMEMMAP: just like we already do for arm64, s390 and x86. So if SPARSEMEM_VMEMMAP is supported, don't allow to use SPARSEMEM without SPARSEMEM_VMEMMAP. This implies that the option to not use SPARSEMEM_VMEMMAP will now be gone for loongarch, powerpc, riscv and sparc. All architectures only enable SPARSEMEM_VMEMMAP with 64bit support, so there should not really be a big downside to using the VMEMMAP (quite the contrary). This is a preparation for not supporting (1) folio sizes that exceed a single memory section (2) CMA allocations of non-contiguous page ranges in SPARSEMEM without SPARSEMEM_VMEMMAP configs, whereby we want to limit possible impact as much as possible (e.g., gigantic hugetlb page allocations suddenly fails). Acked-by: Zi Yan Acked-by: Mike Rapoport (Microsoft) Acked-by: SeongJae Park Reviewed-by: Wei Yang Reviewed-by: Lorenzo Stoakes Reviewed-by: Liam R. Howlett Cc: Huacai Chen Cc: WANG Xuerui Cc: Madhavan Srinivasan Cc: Michael Ellerman Cc: Nicholas Piggin Cc: Christophe Leroy Cc: Paul Walmsley Cc: Palmer Dabbelt Cc: Albert Ou Cc: Alexandre Ghiti Cc: "David S. Miller" Cc: Andreas Larsson Signed-off-by: David Hildenbrand --- mm/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mm/Kconfig b/mm/Kconfig index 4108bcd967848..330d0e698ef96 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -439,9 +439,8 @@ config SPARSEMEM_VMEMMAP_ENABLE bool config SPARSEMEM_VMEMMAP - bool "Sparse Memory virtual memmap" + def_bool y depends on SPARSEMEM && SPARSEMEM_VMEMMAP_ENABLE - default y help SPARSEMEM_VMEMMAP uses a virtually mapped memmap to optimise pfn_to_page and page_to_pfn operations. This is the most -- 2.50.1 From david at redhat.com Mon Sep 1 15:05:23 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:05:23 -0000 Subject: [PATCH v2 02/37] arm64: Kconfig: drop superfluous "select SPARSEMEM_VMEMMAP" In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-3-david@redhat.com> Now handled by the core automatically once SPARSEMEM_VMEMMAP_ENABLE is selected. Reviewed-by: Mike Rapoport (Microsoft) Acked-by: Catalin Marinas Reviewed-by: Lorenzo Stoakes Reviewed-by: Liam R. Howlett Cc: Will Deacon Signed-off-by: David Hildenbrand --- arch/arm64/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index e9bbfacc35a64..b1d1f2ff2493b 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1570,7 +1570,6 @@ source "kernel/Kconfig.hz" config ARCH_SPARSEMEM_ENABLE def_bool y select SPARSEMEM_VMEMMAP_ENABLE - select SPARSEMEM_VMEMMAP config HW_PERF_EVENTS def_bool y -- 2.50.1 From david at redhat.com Mon Sep 1 15:05:41 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:05:41 -0000 Subject: [PATCH v2 03/37] s390/Kconfig: drop superfluous "select SPARSEMEM_VMEMMAP" In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-4-david@redhat.com> Now handled by the core automatically once SPARSEMEM_VMEMMAP_ENABLE is selected. Reviewed-by: Mike Rapoport (Microsoft) Reviewed-by: Lorenzo Stoakes Reviewed-by: Liam R. Howlett Cc: Heiko Carstens Cc: Vasily Gorbik Cc: Alexander Gordeev Cc: Christian Borntraeger Cc: Sven Schnelle Signed-off-by: David Hildenbrand --- arch/s390/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index bf680c26a33cf..145ca23c2fff6 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -710,7 +710,6 @@ menu "Memory setup" config ARCH_SPARSEMEM_ENABLE def_bool y select SPARSEMEM_VMEMMAP_ENABLE - select SPARSEMEM_VMEMMAP config ARCH_SPARSEMEM_DEFAULT def_bool y -- 2.50.1 From david at redhat.com Mon Sep 1 15:05:58 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:05:58 -0000 Subject: [PATCH v2 04/37] x86/Kconfig: drop superfluous "select SPARSEMEM_VMEMMAP" In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-5-david@redhat.com> Now handled by the core automatically once SPARSEMEM_VMEMMAP_ENABLE is selected. Reviewed-by: Mike Rapoport (Microsoft) Acked-by: Dave Hansen Reviewed-by: Lorenzo Stoakes Reviewed-by: Liam R. Howlett Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Borislav Petkov Signed-off-by: David Hildenbrand --- arch/x86/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 58d890fe2100e..e431d1c06fecd 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1552,7 +1552,6 @@ config ARCH_SPARSEMEM_ENABLE def_bool y select SPARSEMEM_STATIC if X86_32 select SPARSEMEM_VMEMMAP_ENABLE if X86_64 - select SPARSEMEM_VMEMMAP if X86_64 config ARCH_SPARSEMEM_DEFAULT def_bool X86_64 || (NUMA && X86_32) -- 2.50.1 From david at redhat.com Mon Sep 1 15:06:09 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:06:09 -0000 Subject: [PATCH v2 05/37] wireguard: selftests: remove CONFIG_SPARSEMEM_VMEMMAP=y from qemu kernel config In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-6-david@redhat.com> It's no longer user-selectable (and the default was already "y"), so let's just drop it. It was never really relevant to the wireguard selftests either way. Acked-by: Mike Rapoport (Microsoft) Reviewed-by: Lorenzo Stoakes Reviewed-by: Liam R. Howlett Cc: "Jason A. Donenfeld" Cc: Shuah Khan Signed-off-by: David Hildenbrand --- tools/testing/selftests/wireguard/qemu/kernel.config | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/testing/selftests/wireguard/qemu/kernel.config b/tools/testing/selftests/wireguard/qemu/kernel.config index 0a5381717e9f4..1149289f4b30f 100644 --- a/tools/testing/selftests/wireguard/qemu/kernel.config +++ b/tools/testing/selftests/wireguard/qemu/kernel.config @@ -48,7 +48,6 @@ CONFIG_JUMP_LABEL=y CONFIG_FUTEX=y CONFIG_SHMEM=y CONFIG_SLUB=y -CONFIG_SPARSEMEM_VMEMMAP=y CONFIG_SMP=y CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y -- 2.50.1 From david at redhat.com Mon Sep 1 15:06:28 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:06:28 -0000 Subject: [PATCH v2 06/37] mm/page_alloc: reject unreasonable folio/compound page sizes in alloc_contig_range_noprof() In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-7-david@redhat.com> Let's reject them early, which in turn makes folio_alloc_gigantic() reject them properly. To avoid converting from order to nr_pages, let's just add MAX_FOLIO_ORDER and calculate MAX_FOLIO_NR_PAGES based on that. While at it, let's just make the order a "const unsigned order". Reviewed-by: Zi Yan Acked-by: SeongJae Park Reviewed-by: Wei Yang Reviewed-by: Lorenzo Stoakes Reviewed-by: Liam R. Howlett Signed-off-by: David Hildenbrand --- include/linux/mm.h | 6 ++++-- mm/page_alloc.c | 10 +++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 00c8a54127d37..77737cbf2216a 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2055,11 +2055,13 @@ static inline long folio_nr_pages(const struct folio *folio) /* Only hugetlbfs can allocate folios larger than MAX_ORDER */ #ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE -#define MAX_FOLIO_NR_PAGES (1UL << PUD_ORDER) +#define MAX_FOLIO_ORDER PUD_ORDER #else -#define MAX_FOLIO_NR_PAGES MAX_ORDER_NR_PAGES +#define MAX_FOLIO_ORDER MAX_PAGE_ORDER #endif +#define MAX_FOLIO_NR_PAGES (1UL << MAX_FOLIO_ORDER) + /* * compound_nr() returns the number of pages in this potentially compound * page. compound_nr() can be called on a tail page, and is defined to diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 27ea4c7acd158..7e96c69a06ccb 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -6841,6 +6841,7 @@ static int __alloc_contig_verify_gfp_mask(gfp_t gfp_mask, gfp_t *gfp_cc_mask) int alloc_contig_range_noprof(unsigned long start, unsigned long end, acr_flags_t alloc_flags, gfp_t gfp_mask) { + const unsigned int order = ilog2(end - start); unsigned long outer_start, outer_end; int ret = 0; @@ -6858,6 +6859,14 @@ int alloc_contig_range_noprof(unsigned long start, unsigned long end, PB_ISOLATE_MODE_CMA_ALLOC : PB_ISOLATE_MODE_OTHER; + /* + * In contrast to the buddy, we allow for orders here that exceed + * MAX_PAGE_ORDER, so we must manually make sure that we are not + * exceeding the maximum folio order. + */ + if (WARN_ON_ONCE((gfp_mask & __GFP_COMP) && order > MAX_FOLIO_ORDER)) + return -EINVAL; + gfp_mask = current_gfp_context(gfp_mask); if (__alloc_contig_verify_gfp_mask(gfp_mask, (gfp_t *)&cc.gfp_mask)) return -EINVAL; @@ -6955,7 +6964,6 @@ int alloc_contig_range_noprof(unsigned long start, unsigned long end, free_contig_range(end, outer_end - end); } else if (start == outer_start && end == outer_end && is_power_of_2(end - start)) { struct page *head = pfn_to_page(start); - int order = ilog2(end - start); check_new_pages(head, order); prep_new_page(head, order, gfp_mask, 0); -- 2.50.1 From david at redhat.com Mon Sep 1 15:11:27 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:11:27 -0000 Subject: [PATCH v2 26/37] drm/i915/gem: drop nth_page() usage within SG entry In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-27-david@redhat.com> It's no longer required to use nth_page() when iterating pages within a single SG entry, so let's drop the nth_page() usage. Reviewed-by: Lorenzo Stoakes Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: David Airlie Cc: Simona Vetter Signed-off-by: David Hildenbrand --- drivers/gpu/drm/i915/gem/i915_gem_pages.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c index c16a57160b262..031d7acc16142 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c @@ -779,7 +779,7 @@ __i915_gem_object_get_page(struct drm_i915_gem_object *obj, pgoff_t n) GEM_BUG_ON(!i915_gem_object_has_struct_page(obj)); sg = i915_gem_object_get_sg(obj, n, &offset); - return nth_page(sg_page(sg), offset); + return sg_page(sg) + offset; } /* Like i915_gem_object_get_page(), but mark the returned page dirty */ -- 2.50.1 From david at redhat.com Mon Sep 1 15:12:06 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:12:06 -0000 Subject: [PATCH v2 28/37] memstick: drop nth_page() usage within SG entry In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-29-david@redhat.com> It's no longer required to use nth_page() when iterating pages within a single SG entry, so let's drop the nth_page() usage. Acked-by: Ulf Hansson Reviewed-by: Lorenzo Stoakes Cc: Maxim Levitsky Cc: Alex Dubov Signed-off-by: David Hildenbrand --- drivers/memstick/host/jmb38x_ms.c | 3 +-- drivers/memstick/host/tifm_ms.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index cddddb3a5a27f..79e66e30417c1 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -317,8 +317,7 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) unsigned int p_off; if (host->req->long_data) { - pg = nth_page(sg_page(&host->req->sg), - off >> PAGE_SHIFT); + pg = sg_page(&host->req->sg) + (off >> PAGE_SHIFT); p_off = offset_in_page(off); p_cnt = PAGE_SIZE - p_off; p_cnt = min(p_cnt, length); diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index db7f3a088fb09..0b6a90661eee5 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c @@ -201,8 +201,7 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms *host) unsigned int p_off; if (host->req->long_data) { - pg = nth_page(sg_page(&host->req->sg), - off >> PAGE_SHIFT); + pg = sg_page(&host->req->sg) + (off >> PAGE_SHIFT); p_off = offset_in_page(off); p_cnt = PAGE_SIZE - p_off; p_cnt = min(p_cnt, length); -- 2.50.1 From david at redhat.com Mon Sep 1 15:12:15 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:12:15 -0000 Subject: [PATCH v2 29/37] mmc: drop nth_page() usage within SG entry In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-30-david@redhat.com> It's no longer required to use nth_page() when iterating pages within a single SG entry, so let's drop the nth_page() usage. Acked-by: Ulf Hansson Reviewed-by: Lorenzo Stoakes Cc: Alex Dubov Cc: Jesper Nilsson Cc: Lars Persson Signed-off-by: David Hildenbrand --- drivers/mmc/host/tifm_sd.c | 4 ++-- drivers/mmc/host/usdhi6rol0.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index ac636efd911d3..2cd69c9e9571b 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -191,7 +191,7 @@ static void tifm_sd_transfer_data(struct tifm_sd *host) } off = sg[host->sg_pos].offset + host->block_pos; - pg = nth_page(sg_page(&sg[host->sg_pos]), off >> PAGE_SHIFT); + pg = sg_page(&sg[host->sg_pos]) + (off >> PAGE_SHIFT); p_off = offset_in_page(off); p_cnt = PAGE_SIZE - p_off; p_cnt = min(p_cnt, cnt); @@ -240,7 +240,7 @@ static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data) } off = sg[host->sg_pos].offset + host->block_pos; - pg = nth_page(sg_page(&sg[host->sg_pos]), off >> PAGE_SHIFT); + pg = sg_page(&sg[host->sg_pos]) + (off >> PAGE_SHIFT); p_off = offset_in_page(off); p_cnt = PAGE_SIZE - p_off; p_cnt = min(p_cnt, cnt); diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 85b49c07918b3..3bccf800339ba 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -323,7 +323,7 @@ static void usdhi6_blk_bounce(struct usdhi6_host *host, host->head_pg.page = host->pg.page; host->head_pg.mapped = host->pg.mapped; - host->pg.page = nth_page(host->pg.page, 1); + host->pg.page = host->pg.page + 1; host->pg.mapped = kmap(host->pg.page); host->blk_page = host->bounce_buf; @@ -503,7 +503,7 @@ static void usdhi6_sg_advance(struct usdhi6_host *host) /* We cannot get here after crossing a page border */ /* Next page in the same SG */ - host->pg.page = nth_page(sg_page(host->sg), host->page_idx); + host->pg.page = sg_page(host->sg) + host->page_idx; host->pg.mapped = kmap(host->pg.page); host->blk_page = host->pg.mapped; -- 2.50.1 From david at redhat.com Mon Sep 1 15:12:37 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:12:37 -0000 Subject: [PATCH v2 30/37] scsi: scsi_lib: drop nth_page() usage within SG entry In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-31-david@redhat.com> It's no longer required to use nth_page() when iterating pages within a single SG entry, so let's drop the nth_page() usage. Reviewed-by: Bart Van Assche Reviewed-by: Lorenzo Stoakes Reviewed-by: Martin K. Petersen Cc: "James E.J. Bottomley" Signed-off-by: David Hildenbrand --- drivers/scsi/scsi_lib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 0c65ecfedfbd6..d7e42293b8645 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -3148,8 +3148,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count, /* Offset starting from the beginning of first page in this sg-entry */ *offset = *offset - len_complete + sg->offset; - /* Assumption: contiguous pages can be accessed as "page + i" */ - page = nth_page(sg_page(sg), (*offset >> PAGE_SHIFT)); + page = sg_page(sg) + (*offset >> PAGE_SHIFT); *offset &= ~PAGE_MASK; /* Bytes in this sg-entry from *offset to the end of the page */ -- 2.50.1 From david at redhat.com Mon Sep 1 15:12:52 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:12:52 -0000 Subject: [PATCH v2 31/37] scsi: sg: drop nth_page() usage within SG entry In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-32-david@redhat.com> It's no longer required to use nth_page() when iterating pages within a single SG entry, so let's drop the nth_page() usage. Reviewed-by: Bart Van Assche Reviewed-by: Lorenzo Stoakes Reviewed-by: Martin K. Petersen Cc: Doug Gilbert Cc: "James E.J. Bottomley" Signed-off-by: David Hildenbrand --- drivers/scsi/sg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 3c02a5f7b5f39..4c62c597c7be9 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1235,8 +1235,7 @@ sg_vma_fault(struct vm_fault *vmf) len = vma->vm_end - sa; len = (len < length) ? len : length; if (offset < len) { - struct page *page = nth_page(rsv_schp->pages[k], - offset >> PAGE_SHIFT); + struct page *page = rsv_schp->pages[k] + (offset >> PAGE_SHIFT); get_page(page); /* increment page count */ vmf->page = page; return 0; /* success */ -- 2.50.1 From david at redhat.com Mon Sep 1 15:13:19 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:13:19 -0000 Subject: [PATCH v2 32/37] vfio/pci: drop nth_page() usage within SG entry In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-33-david@redhat.com> It's no longer required to use nth_page() when iterating pages within a single SG entry, so let's drop the nth_page() usage. Reviewed-by: Lorenzo Stoakes Reviewed-by: Alex Williamson Reviewed-by: Brett Creeley Cc: Jason Gunthorpe Cc: Yishai Hadas Cc: Shameer Kolothum Cc: Kevin Tian Signed-off-by: David Hildenbrand --- drivers/vfio/pci/pds/lm.c | 3 +-- drivers/vfio/pci/virtio/migrate.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/vfio/pci/pds/lm.c b/drivers/vfio/pci/pds/lm.c index f2673d395236a..4d70c833fa32e 100644 --- a/drivers/vfio/pci/pds/lm.c +++ b/drivers/vfio/pci/pds/lm.c @@ -151,8 +151,7 @@ static struct page *pds_vfio_get_file_page(struct pds_vfio_lm_file *lm_file, lm_file->last_offset_sg = sg; lm_file->sg_last_entry += i; lm_file->last_offset = cur_offset; - return nth_page(sg_page(sg), - (offset - cur_offset) / PAGE_SIZE); + return sg_page(sg) + (offset - cur_offset) / PAGE_SIZE; } cur_offset += sg->length; } diff --git a/drivers/vfio/pci/virtio/migrate.c b/drivers/vfio/pci/virtio/migrate.c index ba92bb4e9af94..7dd0ac866461d 100644 --- a/drivers/vfio/pci/virtio/migrate.c +++ b/drivers/vfio/pci/virtio/migrate.c @@ -53,8 +53,7 @@ virtiovf_get_migration_page(struct virtiovf_data_buffer *buf, buf->last_offset_sg = sg; buf->sg_last_entry += i; buf->last_offset = cur_offset; - return nth_page(sg_page(sg), - (offset - cur_offset) / PAGE_SIZE); + return sg_page(sg) + (offset - cur_offset) / PAGE_SIZE; } cur_offset += sg->length; } -- 2.50.1 From ast at fiberby.net Mon Sep 1 21:10:55 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Mon, 01 Sep 2025 21:10:55 -0000 Subject: [PATCH net 2/4] tools: ynl-gen: use macro for binary min-len check In-Reply-To: <20250901115208.0cc7e9a6@kernel.org> References: <20250901145034.525518-1-ast@fiberby.net> <20250901145034.525518-3-ast@fiberby.net> <20250901115208.0cc7e9a6@kernel.org> Message-ID: Thank you for the quick reviews. On 9/1/25 6:52 PM, Jakub Kicinski wrote: > On Mon, 1 Sep 2025 14:50:21 +0000 Asbj?rn Sloth T?nnesen wrote: >> This patch changes the generated min-len check for binary >> attributes to use the NLA_POLICY_MIN_LEN() macro, and thereby >> ensures that .validation_type is not left at NLA_VALIDATE_NONE. > > Please test this well and include the results in the commit message. > I'm pretty sure it's fine as is. You are right, because .type is unset, then .validation_type doesn't matter. Sorry, I didn't do enough testing for the fixes, I had looked at the NLA_BINARY case in validate_nla(), not NLA_UNSPEC. Will re-post for net-next without fixes, and a new commit message. From david at redhat.com Tue Sep 2 09:42:41 2025 From: david at redhat.com (David Hildenbrand) Date: Tue, 02 Sep 2025 09:42:41 -0000 Subject: [PATCH v2 26/37] drm/i915/gem: drop nth_page() usage within SG entry In-Reply-To: <4bbf5590-7591-4dfc-a23e-0bda6cb31a80@ursulin.net> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-27-david@redhat.com> <4bbf5590-7591-4dfc-a23e-0bda6cb31a80@ursulin.net> Message-ID: <22019944-2ef2-4463-9b3f-23c9e7c70b2f@redhat.com> On 02.09.25 11:22, Tvrtko Ursulin wrote: > > On 01/09/2025 16:03, David Hildenbrand wrote: >> It's no longer required to use nth_page() when iterating pages within a >> single SG entry, so let's drop the nth_page() usage. >> >> Reviewed-by: Lorenzo Stoakes >> Cc: Jani Nikula >> Cc: Joonas Lahtinen >> Cc: Rodrigo Vivi >> Cc: Tvrtko Ursulin >> Cc: David Airlie >> Cc: Simona Vetter >> Signed-off-by: David Hildenbrand >> --- >> drivers/gpu/drm/i915/gem/i915_gem_pages.c | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> >> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c >> index c16a57160b262..031d7acc16142 100644 >> --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c >> +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c >> @@ -779,7 +779,7 @@ __i915_gem_object_get_page(struct drm_i915_gem_object *obj, pgoff_t n) >> GEM_BUG_ON(!i915_gem_object_has_struct_page(obj)); >> >> sg = i915_gem_object_get_sg(obj, n, &offset); >> - return nth_page(sg_page(sg), offset); >> + return sg_page(sg) + offset; >> } >> >> /* Like i915_gem_object_get_page(), but mark the returned page dirty */ > > LGTM. If you want an ack to merge via a tree other than i915 you have > it. I suspect it might be easier to coordinate like that. Yeah, it would be best to route all of that through the MM tree. Thanks! -- Cheers David / dhildenb From ast at fiberby.net Thu Sep 4 22:03:19 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:19 -0000 Subject: [RFC net-next 08/14] uapi: wireguard: generate header with ynl-gen In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-8-ast@fiberby.net> Use ynl-gen to generate the UAPI header for wireguard. Changes in generated header: * As __*_F_ALL are not generated by ynl-gen: * All users have been replaced by their current value. * Once the policies are also generated, then the NLA_POLICY_MASK() policies will be kept in sync. * Convert the last bit-shifted flag value in enum wgdevice_flag. * Trivial include guard rename. * Trivial white space changes. No behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- drivers/net/wireguard/netlink.c | 6 +++--- include/uapi/linux/wireguard.h | 26 +++++++++++--------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c index 742d3f88d132..5dae2aa51346 100644 --- a/drivers/net/wireguard/netlink.c +++ b/drivers/net/wireguard/netlink.c @@ -24,7 +24,7 @@ static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = { [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, [WGDEVICE_A_PRIVATE_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), [WGDEVICE_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), - [WGDEVICE_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, __WGDEVICE_F_ALL), + [WGDEVICE_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 1), [WGDEVICE_A_LISTEN_PORT] = { .type = NLA_U16 }, [WGDEVICE_A_FWMARK] = { .type = NLA_U32 }, [WGDEVICE_A_PEERS] = NLA_POLICY_NESTED_ARRAY(peer_policy), @@ -33,7 +33,7 @@ static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = { static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = { [WGPEER_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), [WGPEER_A_PRESHARED_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), - [WGPEER_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, __WGPEER_F_ALL), + [WGPEER_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 7), [WGPEER_A_ENDPOINT] = NLA_POLICY_MIN_LEN(sizeof(struct sockaddr)), [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NLA_U16 }, [WGPEER_A_LAST_HANDSHAKE_TIME] = NLA_POLICY_EXACT_LEN(sizeof(struct __kernel_timespec)), @@ -47,7 +47,7 @@ static const struct nla_policy allowedip_policy[WGALLOWEDIP_A_MAX + 1] = { [WGALLOWEDIP_A_FAMILY] = { .type = NLA_U16 }, [WGALLOWEDIP_A_IPADDR] = NLA_POLICY_MIN_LEN(sizeof(struct in_addr)), [WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8 }, - [WGALLOWEDIP_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, __WGALLOWEDIP_F_ALL), + [WGALLOWEDIP_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 1), }; static struct wg_device *lookup_interface(struct nlattr **attrs, diff --git a/include/uapi/linux/wireguard.h b/include/uapi/linux/wireguard.h index 623ec9527e22..b83973aed9f8 100644 --- a/include/uapi/linux/wireguard.h +++ b/include/uapi/linux/wireguard.h @@ -1,32 +1,28 @@ -/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT */ -/* - * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. - */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/wireguard.yaml */ +/* YNL-GEN uapi header */ -#ifndef _WG_UAPI_WIREGUARD_H -#define _WG_UAPI_WIREGUARD_H +#ifndef _UAPI_LINUX_WIREGUARD_H +#define _UAPI_LINUX_WIREGUARD_H -#define WG_GENL_NAME "wireguard" -#define WG_GENL_VERSION 1 +#define WG_GENL_NAME "wireguard" +#define WG_GENL_VERSION 1 -#define WG_KEY_LEN 32 +#define WG_KEY_LEN 32 enum wgdevice_flag { - WGDEVICE_F_REPLACE_PEERS = 1U << 0, - __WGDEVICE_F_ALL = WGDEVICE_F_REPLACE_PEERS + WGDEVICE_F_REPLACE_PEERS = 1, }; enum wgpeer_flag { WGPEER_F_REMOVE_ME = 1, WGPEER_F_REPLACE_ALLOWEDIPS = 2, WGPEER_F_UPDATE_ONLY = 4, - __WGPEER_F_ALL = WGPEER_F_REMOVE_ME | WGPEER_F_REPLACE_ALLOWEDIPS | - WGPEER_F_UPDATE_ONLY }; enum wgallowedip_flag { WGALLOWEDIP_F_REMOVE_ME = 1, - __WGALLOWEDIP_F_ALL = WGALLOWEDIP_F_REMOVE_ME }; enum wgdevice_attribute { @@ -80,4 +76,4 @@ enum wg_cmd { }; #define WG_CMD_MAX (__WG_CMD_MAX - 1) -#endif /* _WG_UAPI_WIREGUARD_H */ +#endif /* _UAPI_LINUX_WIREGUARD_H */ -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:19 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:19 -0000 Subject: [PATCH net-next 10/11] tools: ynl: decode hex input In-Reply-To: <20250904-wg-ynl-prep@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> Message-ID: <20250904220156.1006541-10-ast@fiberby.net> This patch add support for decoding hex input, so that binary attributes can be read through --json. Example (using future wireguard.yaml): $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ --do set-device --json '{"ifindex":3, "private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}' Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/lib/ynl.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index a37294a751da..78c0245ca587 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -973,6 +973,8 @@ class YnlFamily(SpecFamily): raw = ip.packed else: raw = int(ip) + elif attr_spec.display_hint == 'hex': + raw = bytes.fromhex(string) else: raise Exception(f"Display hint '{attr_spec.display_hint}' not implemented" f" when parsing '{attr_spec['name']}'") -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:20 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:20 -0000 Subject: [PATCH net-next 01/11] tools: ynl-gen: allow overriding name-prefix for constants In-Reply-To: <20250904-wg-ynl-prep@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> Message-ID: <20250904220156.1006541-1-ast@fiberby.net> Allow using custom name-prefix with constants, just like it is for enum and flags declarations. This is needed for generating WG_KEY_LEN in include/uapi/linux/wireguard.h from a spec. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index fb7e03805a11..1543d4911bf5 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -3211,8 +3211,9 @@ def render_uapi(family, cw): cw.block_end(line=';') cw.nl() elif const['type'] == 'const': + name_pfx = const.get('name-prefix', f"{family.ident_name}-") defines.append([c_upper(family.get('c-define-name', - f"{family.ident_name}-{const['name']}")), + f"{name_pfx}{const['name']}")), const['value']]) if defines: -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:20 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:20 -0000 Subject: [RFC net-next 09/14] wireguard: netlink: convert to split ops In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-9-ast@fiberby.net> This patch converts wireguard from using legacy struct genl_ops to struct genl_split_ops, by applying the same transformation as genl_cmd_full_to_split() does. WGDEVICE_A_MAX is swapped for WGDEVICE_A_PEERS, which is currently equivalent and is what ynl-gen would generate. This is an incremental step towards adopting netlink policy code generated by ynl-gen. This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- drivers/net/wireguard/netlink.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c index 5dae2aa51346..1311f64d9fcf 100644 --- a/drivers/net/wireguard/netlink.c +++ b/drivers/net/wireguard/netlink.c @@ -614,29 +614,31 @@ static int wg_set_device(struct sk_buff *skb, struct genl_info *info) return ret; } -static const struct genl_ops genl_ops[] = { +static const struct genl_split_ops wireguard_nl_ops[] = { { .cmd = WG_CMD_GET_DEVICE, .start = wg_get_device_start, .dumpit = wg_get_device_dump, .done = wg_get_device_done, - .flags = GENL_UNS_ADMIN_PERM + .policy = device_policy, + .maxattr = WGDEVICE_A_PEERS, + .flags = GENL_UNS_ADMIN_PERM | GENL_CMD_CAP_DUMP, }, { .cmd = WG_CMD_SET_DEVICE, .doit = wg_set_device, - .flags = GENL_UNS_ADMIN_PERM + .policy = device_policy, + .maxattr = WGDEVICE_A_PEERS, + .flags = GENL_UNS_ADMIN_PERM | GENL_CMD_CAP_DO, } }; static struct genl_family genl_family __ro_after_init = { - .ops = genl_ops, - .n_ops = ARRAY_SIZE(genl_ops), + .split_ops = wireguard_nl_ops, + .n_split_ops = ARRAY_SIZE(wireguard_nl_ops), .resv_start_op = WG_CMD_SET_DEVICE + 1, .name = WG_GENL_NAME, .version = WG_GENL_VERSION, - .maxattr = WGDEVICE_A_MAX, .module = THIS_MODULE, - .policy = device_policy, .netnsok = true }; -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:21 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:21 -0000 Subject: [PATCH net-next 09/11] tools: ynl: encode indexed-array In-Reply-To: <20250904-wg-ynl-prep@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> Message-ID: <20250904220156.1006541-9-ast@fiberby.net> This patch adds support for encoding indexed-array attributes with sub-type nest in pyynl. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/lib/ynl.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 4928b41c636a..a37294a751da 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -564,6 +564,11 @@ class YnlFamily(SpecFamily): nl_type |= Netlink.NLA_F_NESTED sub_space = attr['nested-attributes'] attr_payload = self._add_nest_attrs(value, sub_space, search_attrs) + elif attr['type'] == 'indexed-array' and attr['sub-type'] == 'nest': + nl_type |= Netlink.NLA_F_NESTED + sub_space = attr['nested-attributes'] + attr_payload = self._encode_indexed_array(value, sub_space, + search_attrs) elif attr["type"] == 'flag': if not value: # If value is absent or false then skip attribute creation. @@ -617,6 +622,9 @@ class YnlFamily(SpecFamily): else: raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}') + return self._add_attr_raw(nl_type, attr_payload) + + def _add_attr_raw(self, nl_type, attr_payload): pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad @@ -628,6 +636,15 @@ class YnlFamily(SpecFamily): sub_attrs) return attr_payload + def _encode_indexed_array(self, vals, sub_space, search_attrs): + attr_payload = b'' + nested_flag = Netlink.NLA_F_NESTED + for i, val in enumerate(vals): + idx = i | Netlink.NLA_F_NESTED + val_payload = self._add_nest_attrs(val, sub_space, search_attrs) + attr_payload += self._add_attr_raw(idx, val_payload) + return attr_payload + def _get_enum_or_unknown(self, enum, raw): try: name = enum.entries_by_val[raw].name -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:21 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:21 -0000 Subject: [RFC net-next 14/14] tools: ynl: add sample for wireguard In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-14-ast@fiberby.net> Add a sample application using the generated C library. Example: [install uapi headers, then] $ make -C tools/net/ynl/lib $ make -C tools/net/ynl/generated $ make -C tools/net/ynl/samples wireguard $ ./tools/net/ynl/samples/wireguard usage: ./tools/net/ynl/samples/wireguard $ sudo ./tools/net/ynl/samples/wireguard wg-test Interface 3: wg-test Peer 6adfb183a4a2c94a2f92dab5ade762a4788[...]: Data: rx: 42 / tx: 42 bytes Allowed IPs: 0.0.0.0/0 ::/0 Signed-off-by: Asbj?rn Sloth T?nnesen --- MAINTAINERS | 1 + tools/net/ynl/samples/.gitignore | 1 + tools/net/ynl/samples/wireguard.c | 104 ++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 tools/net/ynl/samples/wireguard.c diff --git a/MAINTAINERS b/MAINTAINERS index e8360e4b55c6..dafc374b25d0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27171,6 +27171,7 @@ S: Maintained F: Documentation/netlink/specs/wireguard.yaml F: drivers/net/wireguard/ F: include/uapi/linux/wireguard_params.h +F: tools/net/ynl/samples/wireguard.c F: tools/testing/selftests/wireguard/ WISTRON LAPTOP BUTTON DRIVER diff --git a/tools/net/ynl/samples/.gitignore b/tools/net/ynl/samples/.gitignore index 7f5fca7682d7..09c61e4c18cd 100644 --- a/tools/net/ynl/samples/.gitignore +++ b/tools/net/ynl/samples/.gitignore @@ -7,3 +7,4 @@ rt-addr rt-link rt-route tc +wireguard diff --git a/tools/net/ynl/samples/wireguard.c b/tools/net/ynl/samples/wireguard.c new file mode 100644 index 000000000000..f1549e585949 --- /dev/null +++ b/tools/net/ynl/samples/wireguard.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include + +#include "wireguard-user.h" + +static void print_allowed_ip(const struct wireguard_wgallowedip *aip) +{ + char addr_out[INET6_ADDRSTRLEN]; + + if (!inet_ntop(aip->family, aip->ipaddr, addr_out, sizeof(addr_out))) { + addr_out[0] = '?'; + addr_out[1] = '\0'; + } + printf("\t\t\t%s/%u\n", addr_out, aip->cidr_mask); +} + +/* Only printing public key in this demo. For better key formatting, + * use constant-time implementation as found in wireguard-tools. + */ +static void print_peer_header(const struct wireguard_wgpeer *peer) +{ + unsigned int i; + uint8_t *key = peer->public_key; + unsigned int len = peer->_len.public_key; + + if (len != 32) + return; + printf("\tPeer "); + for (i = 0; i < len; i++) + printf("%02x", key[i]); + printf(":\n"); +} + +static void print_peer(const struct wireguard_wgpeer *peer) +{ + unsigned int i; + + print_peer_header(peer); + printf("\t\tData: rx: %llu / tx: %llu bytes\n", + peer->rx_bytes, peer->tx_bytes); + printf("\t\tAllowed IPs:\n"); + for (i = 0; i < peer->_count.allowedips; i++) + print_allowed_ip(&peer->allowedips[i]); +} + +static void build_request(struct wireguard_get_device_req *req, char *arg) +{ + char *endptr; + int ifindex; + + ifindex = strtol(arg, &endptr, 0); + if (endptr != arg + strlen(arg) || errno != 0) + ifindex = 0; + if (ifindex > 0) + wireguard_get_device_req_set_ifindex(req, ifindex); + else + wireguard_get_device_req_set_ifname(req, arg); +} + +int main(int argc, char **argv) +{ + struct wireguard_get_device_list *devs; + struct wireguard_get_device_req *req; + struct ynl_sock *ys; + + if (argc < 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + return 1; + } + + req = wireguard_get_device_req_alloc(); + build_request(req, argv[1]); + + ys = ynl_sock_create(&ynl_wireguard_family, NULL); + if (!ys) + return 2; + + devs = wireguard_get_device_dump(ys, req); + if (!devs) + goto err_close; + + ynl_dump_foreach(devs, d) { + unsigned int i; + + printf("Interface %d: %s\n", d->ifindex, d->ifname); + for (i = 0; i < d->_count.peers; i++) + print_peer(&d->peers[i]); + } + wireguard_get_device_list_free(devs); + wireguard_get_device_req_free(req); + ynl_sock_destroy(ys); + + return 0; + +err_close: + fprintf(stderr, "YNL (%d): %s\n", ys->err.code, ys->err.msg); + wireguard_get_device_req_free(req); + ynl_sock_destroy(ys); + return 3; +} -- 2.51.0 From david at redhat.com Mon Sep 1 15:13:28 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:13:28 -0000 Subject: [PATCH v2 33/37] crypto: remove nth_page() usage within SG entry In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-34-david@redhat.com> It's no longer required to use nth_page() when iterating pages within a single SG entry, so let's drop the nth_page() usage. Reviewed-by: Lorenzo Stoakes Acked-by: Herbert Xu Cc: "David S. Miller" Signed-off-by: David Hildenbrand --- crypto/ahash.c | 4 ++-- crypto/scompress.c | 8 ++++---- include/crypto/scatterwalk.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crypto/ahash.c b/crypto/ahash.c index a227793d2c5b5..dfb4f5476428f 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -88,7 +88,7 @@ static int hash_walk_new_entry(struct crypto_hash_walk *walk) sg = walk->sg; walk->offset = sg->offset; - walk->pg = nth_page(sg_page(walk->sg), (walk->offset >> PAGE_SHIFT)); + walk->pg = sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT); walk->offset = offset_in_page(walk->offset); walk->entrylen = sg->length; @@ -226,7 +226,7 @@ int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) if (!IS_ENABLED(CONFIG_HIGHMEM)) return crypto_shash_digest(desc, data, nbytes, req->result); - page = nth_page(page, offset >> PAGE_SHIFT); + page += offset >> PAGE_SHIFT; offset = offset_in_page(offset); if (nbytes > (unsigned int)PAGE_SIZE - offset) diff --git a/crypto/scompress.c b/crypto/scompress.c index c651e7f2197a9..1a7ed8ae65b07 100644 --- a/crypto/scompress.c +++ b/crypto/scompress.c @@ -198,7 +198,7 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) } else return -ENOSYS; - dpage = nth_page(dpage, doff / PAGE_SIZE); + dpage += doff / PAGE_SIZE; doff = offset_in_page(doff); n = (dlen - 1) / PAGE_SIZE; @@ -220,12 +220,12 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) } else break; - spage = nth_page(spage, soff / PAGE_SIZE); + spage = spage + soff / PAGE_SIZE; soff = offset_in_page(soff); n = (slen - 1) / PAGE_SIZE; n += (offset_in_page(slen - 1) + soff) / PAGE_SIZE; - if (PageHighMem(nth_page(spage, n)) && + if (PageHighMem(spage + n) && size_add(soff, slen) > PAGE_SIZE) break; src = kmap_local_page(spage) + soff; @@ -270,7 +270,7 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) if (dlen <= PAGE_SIZE) break; dlen -= PAGE_SIZE; - dpage = nth_page(dpage, 1); + dpage++; } } diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h index 15ab743f68c8f..83d14376ff2bc 100644 --- a/include/crypto/scatterwalk.h +++ b/include/crypto/scatterwalk.h @@ -159,7 +159,7 @@ static inline void scatterwalk_map(struct scatter_walk *walk) if (IS_ENABLED(CONFIG_HIGHMEM)) { struct page *page; - page = nth_page(base_page, offset >> PAGE_SHIFT); + page = base_page + (offset >> PAGE_SHIFT); offset = offset_in_page(offset); addr = kmap_local_page(page) + offset; } else { @@ -259,7 +259,7 @@ static inline void scatterwalk_done_dst(struct scatter_walk *walk, end += (offset_in_page(offset) + offset_in_page(nbytes) + PAGE_SIZE - 1) >> PAGE_SHIFT; for (i = start; i < end; i++) - flush_dcache_page(nth_page(base_page, i)); + flush_dcache_page(base_page + i); } scatterwalk_advance(walk, nbytes); } -- 2.50.1 From ast at fiberby.net Thu Sep 4 22:03:21 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:21 -0000 Subject: [RFC net-next 01/14] wireguard: netlink: use WG_KEY_LEN in policies In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-1-ast@fiberby.net> When converting the netlink policies to YNL, then the constants used in the policy has to be visible to user-space. As NOISE_*_KEY_LEN isn't visible for userspace, then change to use WG_KEY_LEN, as is also documented in the UAPI header: $ grep WG_KEY_LEN include/uapi/linux/wireguard.h * WGDEVICE_A_PRIVATE_KEY: NLA_EXACT_LEN, len WG_KEY_LEN * WGDEVICE_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN * WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN * WGPEER_A_PRESHARED_KEY: NLA_EXACT_LEN, len WG_KEY_LEN [...] Add a couple of BUILD_BUG_ON() to ensure that they stay in sync. No behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- drivers/net/wireguard/netlink.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c index 67f962eb8b46..086edd4bb33b 100644 --- a/drivers/net/wireguard/netlink.c +++ b/drivers/net/wireguard/netlink.c @@ -22,8 +22,8 @@ static struct genl_family genl_family; static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = { [WGDEVICE_A_IFINDEX] = { .type = NLA_U32 }, [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, - [WGDEVICE_A_PRIVATE_KEY] = NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN), - [WGDEVICE_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN), + [WGDEVICE_A_PRIVATE_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), + [WGDEVICE_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), [WGDEVICE_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, __WGDEVICE_F_ALL), [WGDEVICE_A_LISTEN_PORT] = { .type = NLA_U16 }, [WGDEVICE_A_FWMARK] = { .type = NLA_U32 }, @@ -31,8 +31,8 @@ static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = { }; static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = { - [WGPEER_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN), - [WGPEER_A_PRESHARED_KEY] = NLA_POLICY_EXACT_LEN(NOISE_SYMMETRIC_KEY_LEN), + [WGPEER_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), + [WGPEER_A_PRESHARED_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), [WGPEER_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, __WGPEER_F_ALL), [WGPEER_A_ENDPOINT] = NLA_POLICY_MIN_LEN(sizeof(struct sockaddr)), [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NLA_U16 }, @@ -642,6 +642,9 @@ static struct genl_family genl_family __ro_after_init = { int __init wg_genetlink_init(void) { + BUILD_BUG_ON(WG_KEY_LEN != NOISE_PUBLIC_KEY_LEN); + BUILD_BUG_ON(WG_KEY_LEN != NOISE_SYMMETRIC_KEY_LEN); + return genl_register_family(&genl_family); } -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:21 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:21 -0000 Subject: [PATCH net-next 02/11] tools: ynl-gen: generate nested array policies In-Reply-To: <20250904-wg-ynl-prep@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> Message-ID: <20250904220156.1006541-2-ast@fiberby.net> This patch adds support for NLA_POLICY_NESTED_ARRAY() policies. Example spec (from future wireguard.yaml): - name: wgpeer attributes: - name: allowedips type: indexed-array sub-type: nest nested-attributes: wgallowedip yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy). This doesn't change any currently generated code, as it isn't used in any specs currently used for generating code. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 1543d4911bf5..b7de7f6b1fc7 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -816,6 +816,11 @@ class TypeArrayNest(Type): f'unsigned int n_{self.c_name}'] return super().arg_member(ri) + def _attr_policy(self, policy): + if self.attr['sub-type'] == 'nest': + return f'NLA_POLICY_NESTED_ARRAY({self.nested_render_name}_nl_policy)' + return super()._attr_policy(policy) + def _attr_typol(self): if self.attr['sub-type'] in scalars: return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, ' -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:21 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:21 -0000 Subject: [RFC net-next 13/14] wireguard: netlink: enable strict genetlink validation In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-13-ast@fiberby.net> Wireguard is a modern enough genetlink family, that it doesn't need resv_start_op. It already had policies in place when it was first merged, it has also never used reserved fields, or other things toggled by resv_start_op. [TODO: before v1, also test with ancient wireguard-tools versions] Signed-off-by: Asbj?rn Sloth T?nnesen --- drivers/net/wireguard/netlink.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c index 0e34817126b9..67c448eef25d 100644 --- a/drivers/net/wireguard/netlink.c +++ b/drivers/net/wireguard/netlink.c @@ -592,7 +592,6 @@ int wireguard_nl_set_device_doit(struct sk_buff *skb, static struct genl_family genl_family __ro_after_init = { .split_ops = wireguard_nl_ops, .n_split_ops = ARRAY_SIZE(wireguard_nl_ops), - .resv_start_op = WG_CMD_SET_DEVICE + 1, .name = WG_GENL_NAME, .version = WG_GENL_VERSION, .module = THIS_MODULE, -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:22 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:22 -0000 Subject: [PATCH net-next 03/11] tools: ynl-gen: add sub-type check In-Reply-To: <20250904-wg-ynl-prep@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> Message-ID: <20250904220156.1006541-3-ast@fiberby.net> Add a check to verify that the sub-type is "nest", and throw an exception if no policy could be generated, as a guard to prevent against generating a bad policy. This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index b7de7f6b1fc7..04c26ed92ca3 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -826,8 +826,10 @@ class TypeArrayNest(Type): return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, ' elif self.attr['sub-type'] == 'binary' and 'exact-len' in self.checks: return f'.type = YNL_PT_BINARY, .len = {self.checks["exact-len"]}, ' - else: + elif self.attr['sub-type'] == 'nest': return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' + else: + raise Exception(f"Typol for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") def _attr_get(self, ri, var): local_vars = ['const struct nlattr *attr2;'] -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:22 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:22 -0000 Subject: [PATCH net-next 05/11] tools: ynl-gen: define nlattr *array in a block scope In-Reply-To: <20250904-wg-ynl-prep@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> Message-ID: <20250904220156.1006541-5-ast@fiberby.net> Instead of trying to define "struct nlattr *array;" in the all the right places, then simply define it in a block scope, as it's only used here. Before this patch it was generated for attribute set _put() functions, like wireguard_wgpeer_put(), but missing and caused a compile error for the command function wireguard_set_device(). $ make -C tools/net/ynl/generated wireguard-user.o -e CC wireguard-user.o wireguard-user.c: In function ?wireguard_set_device?: wireguard-user.c:548:9: error: ?array? undeclared (first use in ..) 548 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); | ^~~~~ Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index b0eeedfca2f2..e6a84e13ec0a 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -842,6 +842,9 @@ class TypeArrayNest(Type): return get_lines, None, local_vars def attr_put(self, ri, var): + ri.cw.block_start() + ri.cw.p('struct nlattr *array;') + ri.cw.nl() ri.cw.p(f'array = ynl_attr_nest_start(nlh, {self.enum_name});') if self.sub_type in scalars: put_type = self.sub_type @@ -857,6 +860,7 @@ class TypeArrayNest(Type): else: raise Exception(f"Put for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") ri.cw.p('ynl_attr_nest_end(nlh, array);') + ri.cw.block_end() def _setter_lines(self, ri, member, presence): return [f"{member} = {self.c_name};", @@ -2063,13 +2067,9 @@ def put_req_nested(ri, struct): init_lines.append(f"hdr = ynl_nlmsg_put_extra_header(nlh, {struct_sz});") init_lines.append(f"memcpy(hdr, &obj->_hdr, {struct_sz});") - has_anest = False has_count = False for _, arg in struct.member_list(): - has_anest |= arg.type == 'indexed-array' has_count |= arg.presence_type() == 'count' - if has_anest: - local_vars.append('struct nlattr *array;') if has_count: local_vars.append('unsigned int i;') -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:22 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:22 -0000 Subject: [PATCH net-next 06/11] tools: ynl-gen: don't validate nested array attribute types In-Reply-To: <20250904-wg-ynl-prep@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> Message-ID: <20250904220156.1006541-6-ast@fiberby.net> In nested arrays don't require that the intermediate attribute type should be a valid attribute type, it might just be an index or simple 0, it is often not even used. See include/net/netlink.h about NLA_NESTED_ARRAY: > The difference to NLA_NESTED is the structure: > NLA_NESTED has the nested attributes directly inside > while an array has the nested attributes at another > level down and the attribute types directly in the > nesting don't matter. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index e6a84e13ec0a..3c0b158c4da8 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -834,11 +834,12 @@ class TypeArrayNest(Type): def _attr_get(self, ri, var): local_vars = ['const struct nlattr *attr2;'] get_lines = [f'attr_{self.c_name} = attr;', - 'ynl_attr_for_each_nested(attr2, attr) {', - '\tif (ynl_attr_validate(yarg, attr2))', - '\t\treturn YNL_PARSE_CB_ERROR;', - f'\tn_{self.c_name}++;', - '}'] + 'ynl_attr_for_each_nested(attr2, attr) {'] + if self.attr['sub-type'] != 'nest': + get_lines.append('\tif (ynl_attr_validate(yarg, attr2))') + get_lines.append('\t\treturn YNL_PARSE_CB_ERROR;') + get_lines.append(f'\tn_{self.c_name}++;') + get_lines.append('}') return get_lines, None, local_vars def attr_put(self, ri, var): -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:22 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:22 -0000 Subject: [RFC net-next 06/14] uapi: wireguard: move enum wg_cmd In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-6-ast@fiberby.net> This patch moves enum wg_cmd to the end of the file, where ynl-gen would like to generate it. This is an incremental step towards adopting an UAPI header generated by ynl-gen. This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- include/uapi/linux/wireguard.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/wireguard.h b/include/uapi/linux/wireguard.h index c2bb2463211a..ee63aba7f98f 100644 --- a/include/uapi/linux/wireguard.h +++ b/include/uapi/linux/wireguard.h @@ -11,13 +11,6 @@ #define WG_KEY_LEN 32 -enum wg_cmd { - WG_CMD_GET_DEVICE, - WG_CMD_SET_DEVICE, - __WG_CMD_MAX -}; -#define WG_CMD_MAX (__WG_CMD_MAX - 1) - enum wgdevice_flag { WGDEVICE_F_REPLACE_PEERS = 1U << 0, __WGDEVICE_F_ALL = WGDEVICE_F_REPLACE_PEERS @@ -76,4 +69,12 @@ enum wgallowedip_attribute { }; #define WGALLOWEDIP_A_MAX (__WGALLOWEDIP_A_MAX - 1) +enum wg_cmd { + WG_CMD_GET_DEVICE, + WG_CMD_SET_DEVICE, + + __WG_CMD_MAX +}; +#define WG_CMD_MAX (__WG_CMD_MAX - 1) + #endif /* _WG_UAPI_WIREGUARD_H */ -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:23 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:23 -0000 Subject: [RFC net-next 00/14] wireguard: netlink: ynl conversion Message-ID: <20250904-wg-ynl-rfc@fiberby.net> This series contains the wireguard changes needed to adopt an YNL-based generated netlink code. This RFC series is posted for reference, as it is referenced from the current v1 series of ynl preparations, which has to go in before this series can be submitted for net-next. This series applies on top of this series: https://lore.kernel.org/netdev/20250904-wg-ynl-prep at fiberby.net/ Asbj?rn Sloth T?nnesen (14): wireguard: netlink: use WG_KEY_LEN in policies wireguard: netlink: validate nested arrays in policy netlink: specs: add specification for wireguard netlink: specs: wireguard: add remaining checks uapi: wireguard: use __*_A_MAX in enums uapi: wireguard: move enum wg_cmd uapi: wireguard: move flag enums uapi: wireguard: generate header with ynl-gen wireguard: netlink: convert to split ops wireguard: netlink: rename netlink handlers wireguard: netlink: generate netlink code netlink: specs: wireguard: alternative to wireguard_params.h wireguard: netlink: enable strict genetlink validation tools: ynl: add sample for wireguard Documentation/netlink/specs/wireguard.yaml | 289 +++++++++++++++++++++ MAINTAINERS | 3 + drivers/net/wireguard/Makefile | 1 + drivers/net/wireguard/netlink.c | 73 ++---- drivers/net/wireguard/netlink_gen.c | 77 ++++++ drivers/net/wireguard/netlink_gen.h | 29 +++ include/uapi/linux/wireguard.h | 202 +++----------- tools/net/ynl/samples/.gitignore | 1 + tools/net/ynl/samples/wireguard.c | 104 ++++++++ 9 files changed, 559 insertions(+), 220 deletions(-) create mode 100644 Documentation/netlink/specs/wireguard.yaml create mode 100644 drivers/net/wireguard/netlink_gen.c create mode 100644 drivers/net/wireguard/netlink_gen.h create mode 100644 tools/net/ynl/samples/wireguard.c -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:23 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:23 -0000 Subject: [RFC net-next 02/14] wireguard: netlink: validate nested arrays in policy In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-2-ast@fiberby.net> Use NLA_POLICY_NESTED_ARRAY() to add nested array validation. No behavioural changes intended, as the nested policy is already enforced through nla_parse_nested(). This patch is an incremental step towards adopting a policy generated by ynl-gen. Signed-off-by: Asbj?rn Sloth T?nnesen --- drivers/net/wireguard/netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c index 086edd4bb33b..742d3f88d132 100644 --- a/drivers/net/wireguard/netlink.c +++ b/drivers/net/wireguard/netlink.c @@ -27,7 +27,7 @@ static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = { [WGDEVICE_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, __WGDEVICE_F_ALL), [WGDEVICE_A_LISTEN_PORT] = { .type = NLA_U16 }, [WGDEVICE_A_FWMARK] = { .type = NLA_U32 }, - [WGDEVICE_A_PEERS] = { .type = NLA_NESTED } + [WGDEVICE_A_PEERS] = NLA_POLICY_NESTED_ARRAY(peer_policy), }; static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = { @@ -39,7 +39,7 @@ static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = { [WGPEER_A_LAST_HANDSHAKE_TIME] = NLA_POLICY_EXACT_LEN(sizeof(struct __kernel_timespec)), [WGPEER_A_RX_BYTES] = { .type = NLA_U64 }, [WGPEER_A_TX_BYTES] = { .type = NLA_U64 }, - [WGPEER_A_ALLOWEDIPS] = { .type = NLA_NESTED }, + [WGPEER_A_ALLOWEDIPS] = NLA_POLICY_NESTED_ARRAY(allowedip_policy), [WGPEER_A_PROTOCOL_VERSION] = { .type = NLA_U32 } }; -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:23 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:23 -0000 Subject: [PATCH net-next 07/11] tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray In-Reply-To: <20250904-wg-ynl-prep@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> Message-ID: <20250904220156.1006541-7-ast@fiberby.net> As TypeArrayNest can now be used with many other sub-types than nest, then rename it to TypeIndexedArray, to reduce confusion. This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 3c0b158c4da8..c4a6895ab5bb 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -792,7 +792,7 @@ class TypeMultiAttr(Type): f"{presence} = n_{self.c_name};"] -class TypeArrayNest(Type): +class TypeIndexedArray(Type): def is_multi_val(self): return True @@ -829,7 +829,7 @@ class TypeArrayNest(Type): elif self.attr['sub-type'] == 'nest': return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' else: - raise Exception(f"Typol for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") + raise Exception(f"Typol for IndexedArray sub-type {self.attr['sub-type']} not supported, yet") def _attr_get(self, ri, var): local_vars = ['const struct nlattr *attr2;'] @@ -859,7 +859,7 @@ class TypeArrayNest(Type): ri.cw.p(f'for (i = 0; i < {var}->_count.{self.c_name}; i++)') ri.cw.p(f"{self.nested_render_name}_put(nlh, i, &{var}->{self.c_name}[i]);") else: - raise Exception(f"Put for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") + raise Exception(f"Put for IndexedArray sub-type {self.attr['sub-type']} not supported, yet") ri.cw.p('ynl_attr_nest_end(nlh, array);') ri.cw.block_end() @@ -1137,7 +1137,7 @@ class AttrSet(SpecAttrSet): t = TypeNest(self.family, self, elem, value) elif elem['type'] == 'indexed-array' and 'sub-type' in elem: if elem["sub-type"] in ['binary', 'nest', 'u32']: - t = TypeArrayNest(self.family, self, elem, value) + t = TypeIndexedArray(self.family, self, elem, value) else: raise Exception(f'new_attr: unsupported sub-type {elem["sub-type"]}') elif elem['type'] == 'nest-type-value': -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:23 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:23 -0000 Subject: [RFC net-next 07/14] uapi: wireguard: move flag enums In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-7-ast@fiberby.net> Move the wg*_flag enums, so that they are defined above the attribute set enums, as ynl-gen would place them. While touching these lines, also pre-compute bitshifted flag values, like ynl-gen would generate them. This is an incremental step towards adopting an UAPI header generated by ynl-gen. This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- include/uapi/linux/wireguard.h | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/include/uapi/linux/wireguard.h b/include/uapi/linux/wireguard.h index ee63aba7f98f..623ec9527e22 100644 --- a/include/uapi/linux/wireguard.h +++ b/include/uapi/linux/wireguard.h @@ -15,6 +15,20 @@ enum wgdevice_flag { WGDEVICE_F_REPLACE_PEERS = 1U << 0, __WGDEVICE_F_ALL = WGDEVICE_F_REPLACE_PEERS }; + +enum wgpeer_flag { + WGPEER_F_REMOVE_ME = 1, + WGPEER_F_REPLACE_ALLOWEDIPS = 2, + WGPEER_F_UPDATE_ONLY = 4, + __WGPEER_F_ALL = WGPEER_F_REMOVE_ME | WGPEER_F_REPLACE_ALLOWEDIPS | + WGPEER_F_UPDATE_ONLY +}; + +enum wgallowedip_flag { + WGALLOWEDIP_F_REMOVE_ME = 1, + __WGALLOWEDIP_F_ALL = WGALLOWEDIP_F_REMOVE_ME +}; + enum wgdevice_attribute { WGDEVICE_A_UNSPEC, WGDEVICE_A_IFINDEX, @@ -30,13 +44,6 @@ enum wgdevice_attribute { }; #define WGDEVICE_A_MAX (__WGDEVICE_A_MAX - 1) -enum wgpeer_flag { - WGPEER_F_REMOVE_ME = 1U << 0, - WGPEER_F_REPLACE_ALLOWEDIPS = 1U << 1, - WGPEER_F_UPDATE_ONLY = 1U << 2, - __WGPEER_F_ALL = WGPEER_F_REMOVE_ME | WGPEER_F_REPLACE_ALLOWEDIPS | - WGPEER_F_UPDATE_ONLY -}; enum wgpeer_attribute { WGPEER_A_UNSPEC, WGPEER_A_PUBLIC_KEY, @@ -54,10 +61,6 @@ enum wgpeer_attribute { }; #define WGPEER_A_MAX (__WGPEER_A_MAX - 1) -enum wgallowedip_flag { - WGALLOWEDIP_F_REMOVE_ME = 1U << 0, - __WGALLOWEDIP_F_ALL = WGALLOWEDIP_F_REMOVE_ME -}; enum wgallowedip_attribute { WGALLOWEDIP_A_UNSPEC, WGALLOWEDIP_A_FAMILY, -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:23 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:23 -0000 Subject: [PATCH net-next 11/11] tools: ynl: add ipv4-or-v6 display hint In-Reply-To: <20250904-wg-ynl-prep@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> Message-ID: <20250904220156.1006541-11-ast@fiberby.net> The attribute WGALLOWEDIP_A_IPADDR can contain either an IPv4 or an IPv6 address depending on WGALLOWEDIP_A_FAMILY, however in practice it is enough to look at the attribute length. This patch implements an ipv4-or-v6 display hint, that can deal with this kind of attribute. It only implements this display hint for genetlink-legacy, it can be added to other protocol variants if needed, but we don't want to encourage it's use. Signed-off-by: Asbj?rn Sloth T?nnesen --- Documentation/netlink/genetlink-legacy.yaml | 2 +- tools/net/ynl/pyynl/lib/ynl.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index b29d62eefa16..66fb8653a344 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -154,7 +154,7 @@ properties: Optional format indicator that is intended only for choosing the right formatting mechanism when displaying values of this type. - enum: [ hex, mac, fddi, ipv4, ipv6, uuid ] + enum: [ hex, mac, fddi, ipv4, ipv6, ipv4-or-v6, uuid ] struct: description: Name of the nested struct type. type: string diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 78c0245ca587..6d2f12d43a08 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -958,7 +958,7 @@ class YnlFamily(SpecFamily): formatted = hex(raw) else: formatted = bytes.hex(raw, ' ') - elif display_hint in [ 'ipv4', 'ipv6' ]: + elif display_hint in [ 'ipv4', 'ipv6', 'ipv4-or-v6' ]: formatted = format(ipaddress.ip_address(raw)) elif display_hint == 'uuid': formatted = str(uuid.UUID(bytes=raw)) @@ -967,7 +967,7 @@ class YnlFamily(SpecFamily): return formatted def _from_string(self, string, attr_spec): - if attr_spec.display_hint in ['ipv4', 'ipv6']: + if attr_spec.display_hint in ['ipv4', 'ipv6', 'ipv4-or-v6']: ip = ipaddress.ip_address(string) if attr_spec['type'] == 'binary': raw = ip.packed -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:24 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:24 -0000 Subject: [PATCH net-next 08/11] tools: ynl: move nest packing to a helper function In-Reply-To: <20250904-wg-ynl-prep@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> Message-ID: <20250904220156.1006541-8-ast@fiberby.net> This patch moves nest packing into a helper function, that can also be used for packing indexed arrays. No behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/lib/ynl.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 8244a5f440b2..4928b41c636a 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -562,11 +562,8 @@ class YnlFamily(SpecFamily): if attr["type"] == 'nest': nl_type |= Netlink.NLA_F_NESTED - attr_payload = b'' sub_space = attr['nested-attributes'] - sub_attrs = SpaceAttrs(self.attr_sets[sub_space], value, search_attrs) - for subname, subvalue in value.items(): - attr_payload += self._add_attr(sub_space, subname, subvalue, sub_attrs) + attr_payload = self._add_nest_attrs(value, sub_space, search_attrs) elif attr["type"] == 'flag': if not value: # If value is absent or false then skip attribute creation. @@ -623,6 +620,14 @@ class YnlFamily(SpecFamily): pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad + def _add_nest_attrs(self, value, sub_space, search_attrs): + sub_attrs = SpaceAttrs(self.attr_sets[sub_space], value, search_attrs) + attr_payload = b'' + for subname, subvalue in value.items(): + attr_payload += self._add_attr(sub_space, subname, subvalue, + sub_attrs) + return attr_payload + def _get_enum_or_unknown(self, enum, raw): try: name = enum.entries_by_val[raw].name -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:24 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:24 -0000 Subject: [RFC net-next 03/14] netlink: specs: add specification for wireguard In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-3-ast@fiberby.net> This patch adds an almost complete specification for wireguard, only missing a few checks which will be added in the next patch. This makes the documentation in the UAPI header redundant, and is therefore removed. Once the header is generated from YNL, then it will include a pointer towards the spec as well. Generate wireguard.rst from this spec: $ make -C tools/net/ynl/generated/ wireguard.rst Query wireguard interface through pyynl: $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ --dump get-device \ --json '{"ifindex":3}' [{'fwmark': 0, 'ifindex': 3, 'ifname': 'wg-test', 'listen-port': 54318, 'peers': [{0: {'allowedips': [{0: {'cidr-mask': 0, 'family': 2, 'ipaddr': '0.0.0.0'}}, {0: {'cidr-mask': 0, 'family': 10, 'ipaddr': '::'}}], 'endpoint': b'[...]', 'last-handshake-time': {'nsec': 42, 'sec': 42}, 'persistent-keepalive-interval': 42, 'preshared-key': '[...]', 'protocol-version': 1, 'public-key': '[...]', 'rx-bytes': 42, 'tx-bytes': 42}}], 'private-key': '[...]', 'public-key': '[...]'}] Add another allowed IP prefix: $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ --do set-device --json '{"ifindex":3,"peers":[ {"public-key":"6a df b1 83 a4 ..","allowedips":[ {"cidr-mask":0,"family":10,"ipaddr":"::"}]}]}' Signed-off-by: Asbj?rn Sloth T?nnesen --- Documentation/netlink/specs/wireguard.yaml | 281 +++++++++++++++++++++ MAINTAINERS | 1 + include/uapi/linux/wireguard.h | 129 ---------- 3 files changed, 282 insertions(+), 129 deletions(-) create mode 100644 Documentation/netlink/specs/wireguard.yaml diff --git a/Documentation/netlink/specs/wireguard.yaml b/Documentation/netlink/specs/wireguard.yaml new file mode 100644 index 000000000000..c6db3bbf0985 --- /dev/null +++ b/Documentation/netlink/specs/wireguard.yaml @@ -0,0 +1,281 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +--- +name: wireguard +protocol: genetlink-legacy + +doc: | + Netlink protocol to control WireGuard network devices. + + The below enums and macros are for interfacing with WireGuard, using generic + netlink, with family WG_GENL_NAME and version WG_GENL_VERSION. It defines two + commands: get and set. Note that while they share many common attributes, + these two commands actually accept a slightly different set of inputs and + outputs. These differences are noted under the individual attributes. +c-family-name: wg-genl-name +c-version-name: wg-genl-version +max-by-define: true + +definitions: + - + name-prefix: wg- + name: key-len + type: const + value: 32 + - + name: --kernel-timespec + type: struct + header: linux/time_types.h + members: + - + name: sec + type: u64 + doc: Number of seconds, since UNIX epoch. + - + name: nsec + type: u64 + doc: Number of nanoseconds, after the second began. + - + name: wgdevice-flags + name-prefix: wgdevice-f- + enum-name: wgdevice-flag + type: flags + entries: + - replace-peers + - + name: wgpeer-flags + name-prefix: wgpeer-f- + enum-name: wgpeer-flag + type: flags + entries: + - remove-me + - replace-allowedips + - update-only + - + name: wgallowedip-flags + name-prefix: wgallowedip-f- + enum-name: wgallowedip-flag + type: flags + entries: + - remove-me + +attribute-sets: + - + name: wgdevice + enum-name: wgdevice-attribute + name-prefix: wgdevice-a- + attributes: + - + name: unspec + type: unused + value: 0 + - + name: ifindex + type: u32 + - + name: ifname + type: string + - + name: private-key + type: binary + doc: Set to all zeros to remove. + display-hint: hex + checks: + exact-len: wg-key-len + - + name: public-key + type: binary + display-hint: hex + checks: + exact-len: wg-key-len + - + name: flags + doc: | + 0 or WGDEVICE_F_REPLACE_PEERS if all current peers + should be removed prior to adding the list below. + type: u32 + enum: wgdevice-flags + checks: + flags-mask: wgdevice-flags + - + name: listen-port + type: u16 + doc: Set as 0 to choose randomly. + - + name: fwmark + type: u32 + doc: Set as 0 to disable. + - + name: peers + type: indexed-array + sub-type: nest + nested-attributes: wgpeer + - + name: wgpeer + enum-name: wgpeer-attribute + name-prefix: wgpeer-a- + attributes: + - + name: unspec + type: unused + value: 0 + - + name: public-key + type: binary + display-hint: hex + checks: + exact-len: wg-key-len + - + name: preshared-key + type: binary + doc: Set as all zeros to remove. + display-hint: hex + checks: + exact-len: wg-key-len + - + name: flags + doc: | + 0 and/or WGPEER_F_REMOVE_ME if the specified peer should not + exist at the end of the operation, rather than added/updated + and/or WGPEER_F_REPLACE_ALLOWEDIPS if all current allowed IPs + of this peer should be removed prior to adding the list below + and/or WGPEER_F_UPDATE_ONLY if the peer should only be set if + it already exists. + type: u32 + enum: wgpeer-flags + checks: + flags-mask: wgpeer-flags + - + name: endpoint + doc: struct sockaddr_in or struct sockaddr_in6 + type: binary + - + name: persistent-keepalive-interval + type: u16 + doc: Set as 0 to disable. + - + name: last-handshake-time + type: binary + struct: --kernel-timespec + - + name: rx-bytes + type: u64 + - + name: tx-bytes + type: u64 + - + name: allowedips + type: indexed-array + sub-type: nest + nested-attributes: wgallowedip + - + name: protocol-version + type: u32 + doc: | + should not be set or used at all by most users of this API, + as the most recent protocol will be used when this is unset. + Otherwise, must be set to 1. + - + name: wgallowedip + enum-name: wgallowedip-attribute + name-prefix: wgallowedip-a- + attributes: + - + name: unspec + type: unused + value: 0 + - + name: family + type: u16 + - + name: ipaddr + type: binary + doc: struct in_addr or struct in6_add + display-hint: ipv4-or-v6 + - + name: cidr-mask + type: u8 + - + name: flags + type: u32 + doc: | + WGALLOWEDIP_F_REMOVE_ME if the specified IP should be removed; + otherwise, this IP will be added if it is not already present. + enum: wgallowedip-flags + checks: + flags-mask: wgallowedip-flags + +operations: + enum-name: wg-cmd + name-prefix: wg-cmd- + list: + - + name: get-device + value: 0 + doc: | + Retrieve WireGuard device. + + The command should be called with one but not both of: + * WGDEVICE_A_IFINDEX + * WGDEVICE_A_IFNAME + + The kernel will then return several messages (NLM_F_MULTI). + It is possible that all of the allowed IPs of a single peer will not + fit within a single netlink message. In that case, the same peer will + be written in the following message, except it will only contain + WGPEER_A_PUBLIC_KEY and WGPEER_A_ALLOWEDIPS. This may occur several + times in a row for the same peer. It is then up to the receiver to + coalesce adjacent peers. Likewise, it is possible that all peers will + not fit within a single message. So, subsequent peers will be sent + in following messages, except those will only contain + WGDEVICE_A_IFNAME and WGDEVICE_A_PEERS. It is then up to the receiver + to coalesce these messages to form the complete list of peers. + + Since this is an NLA_F_DUMP command, the final message will always be + NLMSG_DONE, even if an error occurs. However, this NLMSG_DONE message + contains an integer error code. It is either zero or a negative error + code corresponding to the errno. + attribute-set: wgdevice + flags: [uns-admin-perm] + + dump: + pre: wireguard-nl-get-device-start + post: wireguard-nl-get-device-done + # request only accepts ifindex | ifname, but keep .maxattr as is + request: &all-attrs + attributes: + - ifindex + - ifname + - private-key + - public-key + - flags + - listen-port + - fwmark + - peers + reply: *all-attrs + - + name: set-device + value: 1 + doc: | + Set WireGuard device. + + This command should be called with a wgdevice set, containing one but + not both of WGDEVICE_A_IFINDEX and WGDEVICE_A_IFNAME. + + It is possible that the amount of configuration data exceeds that of + the maximum message length accepted by the kernel. In that case, + several messages should be sent one after another, with each + successive one filling in information not contained in the prior. + Note that if WGDEVICE_F_REPLACE_PEERS is specified in the first + message, it probably should not be specified in fragments that come + after, so that the list of peers is only cleared the first time but + appended after. + Likewise for peers, if WGPEER_F_REPLACE_ALLOWEDIPS is specified in + the first message of a peer, it likely should not be specified in + subsequent fragments. + + If an error occurs, NLMSG_ERROR will reply containing an errno. + attribute-set: wgdevice + flags: [uns-admin-perm] + + do: + request: *all-attrs diff --git a/MAINTAINERS b/MAINTAINERS index b81595e9ea95..1540aa22d152 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27168,6 +27168,7 @@ M: Jason A. Donenfeld L: wireguard at lists.zx2c4.com L: netdev at vger.kernel.org S: Maintained +F: Documentation/netlink/specs/wireguard.yaml F: drivers/net/wireguard/ F: tools/testing/selftests/wireguard/ diff --git a/include/uapi/linux/wireguard.h b/include/uapi/linux/wireguard.h index 8c26391196d5..dee4401e0b5d 100644 --- a/include/uapi/linux/wireguard.h +++ b/include/uapi/linux/wireguard.h @@ -1,135 +1,6 @@ /* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT */ /* * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. - * - * Documentation - * ============= - * - * The below enums and macros are for interfacing with WireGuard, using generic - * netlink, with family WG_GENL_NAME and version WG_GENL_VERSION. It defines two - * methods: get and set. Note that while they share many common attributes, - * these two functions actually accept a slightly different set of inputs and - * outputs. - * - * WG_CMD_GET_DEVICE - * ----------------- - * - * May only be called via NLM_F_REQUEST | NLM_F_DUMP. The command should contain - * one but not both of: - * - * WGDEVICE_A_IFINDEX: NLA_U32 - * WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMSIZ - 1 - * - * The kernel will then return several messages (NLM_F_MULTI) containing the - * following tree of nested items: - * - * WGDEVICE_A_IFINDEX: NLA_U32 - * WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMSIZ - 1 - * WGDEVICE_A_PRIVATE_KEY: NLA_EXACT_LEN, len WG_KEY_LEN - * WGDEVICE_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN - * WGDEVICE_A_LISTEN_PORT: NLA_U16 - * WGDEVICE_A_FWMARK: NLA_U32 - * WGDEVICE_A_PEERS: NLA_NESTED - * 0: NLA_NESTED - * WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN - * WGPEER_A_PRESHARED_KEY: NLA_EXACT_LEN, len WG_KEY_LEN - * WGPEER_A_ENDPOINT: NLA_MIN_LEN(struct sockaddr), struct sockaddr_in or struct sockaddr_in6 - * WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL: NLA_U16 - * WGPEER_A_LAST_HANDSHAKE_TIME: NLA_EXACT_LEN, struct __kernel_timespec - * WGPEER_A_RX_BYTES: NLA_U64 - * WGPEER_A_TX_BYTES: NLA_U64 - * WGPEER_A_ALLOWEDIPS: NLA_NESTED - * 0: NLA_NESTED - * WGALLOWEDIP_A_FAMILY: NLA_U16 - * WGALLOWEDIP_A_IPADDR: NLA_MIN_LEN(struct in_addr), struct in_addr or struct in6_addr - * WGALLOWEDIP_A_CIDR_MASK: NLA_U8 - * 0: NLA_NESTED - * ... - * 0: NLA_NESTED - * ... - * ... - * WGPEER_A_PROTOCOL_VERSION: NLA_U32 - * 0: NLA_NESTED - * ... - * ... - * - * It is possible that all of the allowed IPs of a single peer will not - * fit within a single netlink message. In that case, the same peer will - * be written in the following message, except it will only contain - * WGPEER_A_PUBLIC_KEY and WGPEER_A_ALLOWEDIPS. This may occur several - * times in a row for the same peer. It is then up to the receiver to - * coalesce adjacent peers. Likewise, it is possible that all peers will - * not fit within a single message. So, subsequent peers will be sent - * in following messages, except those will only contain WGDEVICE_A_IFNAME - * and WGDEVICE_A_PEERS. It is then up to the receiver to coalesce these - * messages to form the complete list of peers. - * - * Since this is an NLA_F_DUMP command, the final message will always be - * NLMSG_DONE, even if an error occurs. However, this NLMSG_DONE message - * contains an integer error code. It is either zero or a negative error - * code corresponding to the errno. - * - * WG_CMD_SET_DEVICE - * ----------------- - * - * May only be called via NLM_F_REQUEST. The command should contain the - * following tree of nested items, containing one but not both of - * WGDEVICE_A_IFINDEX and WGDEVICE_A_IFNAME: - * - * WGDEVICE_A_IFINDEX: NLA_U32 - * WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMSIZ - 1 - * WGDEVICE_A_FLAGS: NLA_U32, 0 or WGDEVICE_F_REPLACE_PEERS if all current - * peers should be removed prior to adding the list below. - * WGDEVICE_A_PRIVATE_KEY: len WG_KEY_LEN, all zeros to remove - * WGDEVICE_A_LISTEN_PORT: NLA_U16, 0 to choose randomly - * WGDEVICE_A_FWMARK: NLA_U32, 0 to disable - * WGDEVICE_A_PEERS: NLA_NESTED - * 0: NLA_NESTED - * WGPEER_A_PUBLIC_KEY: len WG_KEY_LEN - * WGPEER_A_FLAGS: NLA_U32, 0 and/or WGPEER_F_REMOVE_ME if the - * specified peer should not exist at the end of the - * operation, rather than added/updated and/or - * WGPEER_F_REPLACE_ALLOWEDIPS if all current allowed - * IPs of this peer should be removed prior to adding - * the list below and/or WGPEER_F_UPDATE_ONLY if the - * peer should only be set if it already exists. - * WGPEER_A_PRESHARED_KEY: len WG_KEY_LEN, all zeros to remove - * WGPEER_A_ENDPOINT: struct sockaddr_in or struct sockaddr_in6 - * WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL: NLA_U16, 0 to disable - * WGPEER_A_ALLOWEDIPS: NLA_NESTED - * 0: NLA_NESTED - * WGALLOWEDIP_A_FAMILY: NLA_U16 - * WGALLOWEDIP_A_IPADDR: struct in_addr or struct in6_addr - * WGALLOWEDIP_A_CIDR_MASK: NLA_U8 - * WGALLOWEDIP_A_FLAGS: NLA_U32, WGALLOWEDIP_F_REMOVE_ME if - * the specified IP should be removed; - * otherwise, this IP will be added if - * it is not already present. - * 0: NLA_NESTED - * ... - * 0: NLA_NESTED - * ... - * ... - * WGPEER_A_PROTOCOL_VERSION: NLA_U32, should not be set or used at - * all by most users of this API, as the - * most recent protocol will be used when - * this is unset. Otherwise, must be set - * to 1. - * 0: NLA_NESTED - * ... - * ... - * - * It is possible that the amount of configuration data exceeds that of - * the maximum message length accepted by the kernel. In that case, several - * messages should be sent one after another, with each successive one - * filling in information not contained in the prior. Note that if - * WGDEVICE_F_REPLACE_PEERS is specified in the first message, it probably - * should not be specified in fragments that come after, so that the list - * of peers is only cleared the first time but appended after. Likewise for - * peers, if WGPEER_F_REPLACE_ALLOWEDIPS is specified in the first message - * of a peer, it likely should not be specified in subsequent fragments. - * - * If an error occurs, NLMSG_ERROR will reply containing an errno. */ #ifndef _WG_UAPI_WIREGUARD_H -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:24 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:24 -0000 Subject: [RFC net-next 05/14] uapi: wireguard: use __*_A_MAX in enums In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-5-ast@fiberby.net> This patch renames enum members from __*_A_LAST to __*_A_MAX. This is an incremental step towards adopting an UAPI header generated by YNL. This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- include/uapi/linux/wireguard.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/include/uapi/linux/wireguard.h b/include/uapi/linux/wireguard.h index dee4401e0b5d..c2bb2463211a 100644 --- a/include/uapi/linux/wireguard.h +++ b/include/uapi/linux/wireguard.h @@ -32,9 +32,10 @@ enum wgdevice_attribute { WGDEVICE_A_LISTEN_PORT, WGDEVICE_A_FWMARK, WGDEVICE_A_PEERS, - __WGDEVICE_A_LAST + + __WGDEVICE_A_MAX }; -#define WGDEVICE_A_MAX (__WGDEVICE_A_LAST - 1) +#define WGDEVICE_A_MAX (__WGDEVICE_A_MAX - 1) enum wgpeer_flag { WGPEER_F_REMOVE_ME = 1U << 0, @@ -55,9 +56,10 @@ enum wgpeer_attribute { WGPEER_A_TX_BYTES, WGPEER_A_ALLOWEDIPS, WGPEER_A_PROTOCOL_VERSION, - __WGPEER_A_LAST + + __WGPEER_A_MAX }; -#define WGPEER_A_MAX (__WGPEER_A_LAST - 1) +#define WGPEER_A_MAX (__WGPEER_A_MAX - 1) enum wgallowedip_flag { WGALLOWEDIP_F_REMOVE_ME = 1U << 0, @@ -69,8 +71,9 @@ enum wgallowedip_attribute { WGALLOWEDIP_A_IPADDR, WGALLOWEDIP_A_CIDR_MASK, WGALLOWEDIP_A_FLAGS, - __WGALLOWEDIP_A_LAST + + __WGALLOWEDIP_A_MAX }; -#define WGALLOWEDIP_A_MAX (__WGALLOWEDIP_A_LAST - 1) +#define WGALLOWEDIP_A_MAX (__WGALLOWEDIP_A_MAX - 1) #endif /* _WG_UAPI_WIREGUARD_H */ -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:24 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:24 -0000 Subject: [RFC net-next 04/14] netlink: specs: wireguard: add remaining checks In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-4-ast@fiberby.net> This patch adds the remaining checks from the existing policy code, and thereby completes the wireguard spec. These are added separately in this RFC mainly to showcase two difference approaches to convert them. They require a sizeof() operations or arithmetics, both of which can't be expressed in YNL currently. In order to keep the C code 1:1, then in this patch they are added as an additional UAPI header wireguard_params.h, defining them so that ynl-gen can reference them as constants. This approach could also allow a selftest to validate that the value of the constant in the YNL spec, is the same as the value in the header file. In patch 12 in this series, this patch is reverted, and replaced with magic numbers in the YNL checks, as an alternative. Signed-off-by: Asbj?rn Sloth T?nnesen --- Documentation/netlink/specs/wireguard.yaml | 36 ++++++++++++++++++++++ MAINTAINERS | 1 + include/uapi/linux/wireguard_params.h | 18 +++++++++++ 3 files changed, 55 insertions(+) create mode 100644 include/uapi/linux/wireguard_params.h diff --git a/Documentation/netlink/specs/wireguard.yaml b/Documentation/netlink/specs/wireguard.yaml index c6db3bbf0985..37011c3f158b 100644 --- a/Documentation/netlink/specs/wireguard.yaml +++ b/Documentation/netlink/specs/wireguard.yaml @@ -21,6 +21,34 @@ definitions: name: key-len type: const value: 32 + - + name-prefix: --wg- + name: inaddr-sz + type: const + doc: Equivalent of ``sizeof(struct in_addr)``. + header: linux/wireguard_params.h + value: 4 + - + name-prefix: --wg- + name: sockaddr-sz + type: const + doc: Equivalent of ``sizeof(struct sockaddr)``. + header: linux/wireguard_params.h + value: 16 + - + name-prefix: --wg- + name: timespec-sz + type: const + doc: Equivalent of ``sizeof(struct __kernel_timespec)``. + header: linux/wireguard_params.h + value: 16 + - + name-prefix: --wg- + name: ifnamlen + type: const + doc: Equivalent of ``IFNAMSIZ - 1``. + header: linux/wireguard_params.h + value: 15 - name: --kernel-timespec type: struct @@ -74,6 +102,8 @@ attribute-sets: - name: ifname type: string + checks: + max-len: --wg-ifnamlen - name: private-key type: binary @@ -148,6 +178,8 @@ attribute-sets: name: endpoint doc: struct sockaddr_in or struct sockaddr_in6 type: binary + checks: + min-len: --wg-sockaddr-sz - name: persistent-keepalive-interval type: u16 @@ -156,6 +188,8 @@ attribute-sets: name: last-handshake-time type: binary struct: --kernel-timespec + checks: + exact-len: --wg-timespec-sz - name: rx-bytes type: u64 @@ -191,6 +225,8 @@ attribute-sets: type: binary doc: struct in_addr or struct in6_add display-hint: ipv4-or-v6 + checks: + min-len: --wg-inaddr-sz - name: cidr-mask type: u8 diff --git a/MAINTAINERS b/MAINTAINERS index 1540aa22d152..e8360e4b55c6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27170,6 +27170,7 @@ L: netdev at vger.kernel.org S: Maintained F: Documentation/netlink/specs/wireguard.yaml F: drivers/net/wireguard/ +F: include/uapi/linux/wireguard_params.h F: tools/testing/selftests/wireguard/ WISTRON LAPTOP BUTTON DRIVER diff --git a/include/uapi/linux/wireguard_params.h b/include/uapi/linux/wireguard_params.h new file mode 100644 index 000000000000..c218e4b8042f --- /dev/null +++ b/include/uapi/linux/wireguard_params.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ + +#ifndef _UAPI_LINUX_WIREGUARD_PARAMS_H +#define _UAPI_LINUX_WIREGUARD_PARAMS_H + +#include +#include +#include + +/* These definitions are currently needed for definitions which can't + * be expressed directly in Documentation/netlink/specs/wireguard.yaml + */ +#define __WG_INADDR_SZ (sizeof(struct in_addr)) +#define __WG_SOCKADDR_SZ (sizeof(struct sockaddr)) +#define __WG_TIMESPEC_SZ (sizeof(struct __kernel_timespec)) +#define __WG_IFNAMLEN (IFNAMSIZ - 1) + +#endif /* _UAPI_LINUX_WIREGUARD_PARAMS_H */ -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:24 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:24 -0000 Subject: [PATCH net-next 04/11] tools: ynl-gen: define count iterator in print_dump() In-Reply-To: <20250904-wg-ynl-prep@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> Message-ID: <20250904220156.1006541-4-ast@fiberby.net> In wireguard_get_device_dump(), as generated by print_dump(), it didn't generate a declaration of `unsigned int i`: $ make -C tools/net/ynl/generated wireguard-user.o -e CC wireguard-user.o wireguard-user.c: In function ?wireguard_get_device_dump?: wireguard-user.c:502:22: error: ?i? undeclared (first use in this fn) 502 | for (i = 0; i < req->_count.peers; i++) | ^ Copy the logic from print_req() as it correctly generated the iterator in wireguard_set_device(). Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 04c26ed92ca3..b0eeedfca2f2 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -2425,6 +2425,11 @@ def print_dump(ri): local_vars += ['size_t hdr_len;', 'void *hdr;'] + for _, attr in ri.struct['request'].member_list(): + if attr.presence_type() == 'count': + local_vars += ['unsigned int i;'] + break + ri.cw.write_func_lvar(local_vars) ri.cw.p('yds.yarg.ys = ys;') -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:25 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:25 -0000 Subject: [RFC net-next 11/14] wireguard: netlink: generate netlink code In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-11-ast@fiberby.net> This patch adopts netlink policy and command definitions as generated by ynl-gen. No behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- drivers/net/wireguard/Makefile | 1 + drivers/net/wireguard/netlink.c | 69 +++++-------------------- drivers/net/wireguard/netlink_gen.c | 78 +++++++++++++++++++++++++++++ drivers/net/wireguard/netlink_gen.h | 30 +++++++++++ 4 files changed, 121 insertions(+), 57 deletions(-) create mode 100644 drivers/net/wireguard/netlink_gen.c create mode 100644 drivers/net/wireguard/netlink_gen.h diff --git a/drivers/net/wireguard/Makefile b/drivers/net/wireguard/Makefile index dbe1f8514efc..ae4b479cddbd 100644 --- a/drivers/net/wireguard/Makefile +++ b/drivers/net/wireguard/Makefile @@ -14,4 +14,5 @@ wireguard-y += allowedips.o wireguard-y += ratelimiter.o wireguard-y += cookie.o wireguard-y += netlink.o +wireguard-y += netlink_gen.o obj-$(CONFIG_WIREGUARD) := wireguard.o diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c index a61e1c5c7850..0e34817126b9 100644 --- a/drivers/net/wireguard/netlink.c +++ b/drivers/net/wireguard/netlink.c @@ -9,6 +9,7 @@ #include "socket.h" #include "queueing.h" #include "messages.h" +#include "netlink_gen.h" #include @@ -19,37 +20,6 @@ static struct genl_family genl_family; -static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = { - [WGDEVICE_A_IFINDEX] = { .type = NLA_U32 }, - [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, - [WGDEVICE_A_PRIVATE_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), - [WGDEVICE_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), - [WGDEVICE_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 1), - [WGDEVICE_A_LISTEN_PORT] = { .type = NLA_U16 }, - [WGDEVICE_A_FWMARK] = { .type = NLA_U32 }, - [WGDEVICE_A_PEERS] = NLA_POLICY_NESTED_ARRAY(peer_policy), -}; - -static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = { - [WGPEER_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), - [WGPEER_A_PRESHARED_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), - [WGPEER_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 7), - [WGPEER_A_ENDPOINT] = NLA_POLICY_MIN_LEN(sizeof(struct sockaddr)), - [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NLA_U16 }, - [WGPEER_A_LAST_HANDSHAKE_TIME] = NLA_POLICY_EXACT_LEN(sizeof(struct __kernel_timespec)), - [WGPEER_A_RX_BYTES] = { .type = NLA_U64 }, - [WGPEER_A_TX_BYTES] = { .type = NLA_U64 }, - [WGPEER_A_ALLOWEDIPS] = NLA_POLICY_NESTED_ARRAY(allowedip_policy), - [WGPEER_A_PROTOCOL_VERSION] = { .type = NLA_U32 } -}; - -static const struct nla_policy allowedip_policy[WGALLOWEDIP_A_MAX + 1] = { - [WGALLOWEDIP_A_FAMILY] = { .type = NLA_U16 }, - [WGALLOWEDIP_A_IPADDR] = NLA_POLICY_MIN_LEN(sizeof(struct in_addr)), - [WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8 }, - [WGALLOWEDIP_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 1), -}; - static struct wg_device *lookup_interface(struct nlattr **attrs, struct sk_buff *skb) { @@ -197,7 +167,7 @@ get_peer(struct wg_peer *peer, struct sk_buff *skb, struct dump_ctx *ctx) return -EMSGSIZE; } -static int wireguard_nl_get_device_start(struct netlink_callback *cb) +int wireguard_nl_get_device_start(struct netlink_callback *cb) { struct wg_device *wg; @@ -208,8 +178,8 @@ static int wireguard_nl_get_device_start(struct netlink_callback *cb) return 0; } -static int wireguard_nl_get_device_dumpit(struct sk_buff *skb, - struct netlink_callback *cb) +int wireguard_nl_get_device_dumpit(struct sk_buff *skb, + struct netlink_callback *cb) { struct wg_peer *peer, *next_peer_cursor; struct dump_ctx *ctx = DUMP_CTX(cb); @@ -303,7 +273,7 @@ static int wireguard_nl_get_device_dumpit(struct sk_buff *skb, */ } -static int wireguard_nl_get_device_done(struct netlink_callback *cb) +int wireguard_nl_get_device_done(struct netlink_callback *cb) { struct dump_ctx *ctx = DUMP_CTX(cb); @@ -468,7 +438,9 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs) nla_for_each_nested(attr, attrs[WGPEER_A_ALLOWEDIPS], rem) { ret = nla_parse_nested(allowedip, WGALLOWEDIP_A_MAX, - attr, allowedip_policy, NULL); + attr, + wireguard_wgallowedip_nl_policy, + NULL); if (ret < 0) goto out; ret = set_allowedip(peer, allowedip); @@ -501,8 +473,8 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs) return ret; } -static int wireguard_nl_set_device_doit(struct sk_buff *skb, - struct genl_info *info) +int wireguard_nl_set_device_doit(struct sk_buff *skb, + struct genl_info *info) { struct wg_device *wg = lookup_interface(info->attrs, skb); u32 flags = 0; @@ -595,7 +567,8 @@ static int wireguard_nl_set_device_doit(struct sk_buff *skb, nla_for_each_nested(attr, info->attrs[WGDEVICE_A_PEERS], rem) { ret = nla_parse_nested(peer, WGPEER_A_MAX, attr, - peer_policy, NULL); + wireguard_wgpeer_nl_policy, + NULL); if (ret < 0) goto out; ret = set_peer(wg, peer); @@ -616,24 +589,6 @@ static int wireguard_nl_set_device_doit(struct sk_buff *skb, return ret; } -static const struct genl_split_ops wireguard_nl_ops[] = { - { - .cmd = WG_CMD_GET_DEVICE, - .start = wireguard_nl_get_device_start, - .dumpit = wireguard_nl_get_device_dumpit, - .done = wireguard_nl_get_device_done, - .policy = device_policy, - .maxattr = WGDEVICE_A_PEERS, - .flags = GENL_UNS_ADMIN_PERM | GENL_CMD_CAP_DUMP, - }, { - .cmd = WG_CMD_SET_DEVICE, - .doit = wireguard_nl_set_device_doit, - .policy = device_policy, - .maxattr = WGDEVICE_A_PEERS, - .flags = GENL_UNS_ADMIN_PERM | GENL_CMD_CAP_DO, - } -}; - static struct genl_family genl_family __ro_after_init = { .split_ops = wireguard_nl_ops, .n_split_ops = ARRAY_SIZE(wireguard_nl_ops), diff --git a/drivers/net/wireguard/netlink_gen.c b/drivers/net/wireguard/netlink_gen.c new file mode 100644 index 000000000000..75f5b4b297a9 --- /dev/null +++ b/drivers/net/wireguard/netlink_gen.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/wireguard.yaml */ +/* YNL-GEN kernel source */ + +#include +#include + +#include "netlink_gen.h" + +#include +#include +#include + +/* Common nested types */ +const struct nla_policy wireguard_wgallowedip_nl_policy[WGALLOWEDIP_A_FLAGS + 1] = { + [WGALLOWEDIP_A_FAMILY] = { .type = NLA_U16, }, + [WGALLOWEDIP_A_IPADDR] = NLA_POLICY_MIN_LEN(__WG_INADDR_SZ), + [WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8, }, + [WGALLOWEDIP_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 0x1), +}; + +const struct nla_policy wireguard_wgpeer_nl_policy[WGPEER_A_PROTOCOL_VERSION + 1] = { + [WGPEER_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), + [WGPEER_A_PRESHARED_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), + [WGPEER_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 0x7), + [WGPEER_A_ENDPOINT] = NLA_POLICY_MIN_LEN(__WG_SOCKADDR_SZ), + [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NLA_U16, }, + [WGPEER_A_LAST_HANDSHAKE_TIME] = NLA_POLICY_EXACT_LEN(__WG_TIMESPEC_SZ), + [WGPEER_A_RX_BYTES] = { .type = NLA_U64, }, + [WGPEER_A_TX_BYTES] = { .type = NLA_U64, }, + [WGPEER_A_ALLOWEDIPS] = NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy), + [WGPEER_A_PROTOCOL_VERSION] = { .type = NLA_U32, }, +}; + +/* WG_CMD_GET_DEVICE - dump */ +static const struct nla_policy wireguard_get_device_nl_policy[WGDEVICE_A_PEERS + 1] = { + [WGDEVICE_A_IFINDEX] = { .type = NLA_U32, }, + [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .len = __WG_IFNAMLEN, }, + [WGDEVICE_A_PRIVATE_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), + [WGDEVICE_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), + [WGDEVICE_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 0x1), + [WGDEVICE_A_LISTEN_PORT] = { .type = NLA_U16, }, + [WGDEVICE_A_FWMARK] = { .type = NLA_U32, }, + [WGDEVICE_A_PEERS] = NLA_POLICY_NESTED_ARRAY(wireguard_wgpeer_nl_policy), +}; + +/* WG_CMD_SET_DEVICE - do */ +static const struct nla_policy wireguard_set_device_nl_policy[WGDEVICE_A_PEERS + 1] = { + [WGDEVICE_A_IFINDEX] = { .type = NLA_U32, }, + [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .len = __WG_IFNAMLEN, }, + [WGDEVICE_A_PRIVATE_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), + [WGDEVICE_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), + [WGDEVICE_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 0x1), + [WGDEVICE_A_LISTEN_PORT] = { .type = NLA_U16, }, + [WGDEVICE_A_FWMARK] = { .type = NLA_U32, }, + [WGDEVICE_A_PEERS] = NLA_POLICY_NESTED_ARRAY(wireguard_wgpeer_nl_policy), +}; + +/* Ops table for wireguard */ +const struct genl_split_ops wireguard_nl_ops[2] = { + { + .cmd = WG_CMD_GET_DEVICE, + .start = wireguard_nl_get_device_start, + .dumpit = wireguard_nl_get_device_dumpit, + .done = wireguard_nl_get_device_done, + .policy = wireguard_get_device_nl_policy, + .maxattr = WGDEVICE_A_PEERS, + .flags = GENL_UNS_ADMIN_PERM | GENL_CMD_CAP_DUMP, + }, + { + .cmd = WG_CMD_SET_DEVICE, + .doit = wireguard_nl_set_device_doit, + .policy = wireguard_set_device_nl_policy, + .maxattr = WGDEVICE_A_PEERS, + .flags = GENL_UNS_ADMIN_PERM | GENL_CMD_CAP_DO, + }, +}; diff --git a/drivers/net/wireguard/netlink_gen.h b/drivers/net/wireguard/netlink_gen.h new file mode 100644 index 000000000000..a067ab0d61b6 --- /dev/null +++ b/drivers/net/wireguard/netlink_gen.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/wireguard.yaml */ +/* YNL-GEN kernel header */ + +#ifndef _LINUX_WIREGUARD_GEN_H +#define _LINUX_WIREGUARD_GEN_H + +#include +#include + +#include +#include +#include + +/* Common nested types */ +extern const struct nla_policy wireguard_wgallowedip_nl_policy[WGALLOWEDIP_A_FLAGS + 1]; +extern const struct nla_policy wireguard_wgpeer_nl_policy[WGPEER_A_PROTOCOL_VERSION + 1]; + +/* Ops table for wireguard */ +extern const struct genl_split_ops wireguard_nl_ops[2]; + +int wireguard_nl_get_device_start(struct netlink_callback *cb); +int wireguard_nl_get_device_done(struct netlink_callback *cb); + +int wireguard_nl_get_device_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); +int wireguard_nl_set_device_doit(struct sk_buff *skb, struct genl_info *info); + +#endif /* _LINUX_WIREGUARD_GEN_H */ -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:25 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:25 -0000 Subject: [PATCH net-next 00/11] tools: ynl: prepare for wireguard Message-ID: <20250904-wg-ynl-prep@fiberby.net> This series contains the last batch of YNL changes to support the wireguard YNL conversion. The next batch has been posted as an RFC series here: https://lore.kernel.org/netdev/20250904-wg-ynl-rfc at fiberby.net/ Asbj?rn Sloth T?nnesen (11): tools: ynl-gen: allow overriding name-prefix for constants tools: ynl-gen: generate nested array policies tools: ynl-gen: add sub-type check tools: ynl-gen: define count iterator in print_dump() tools: ynl-gen: define nlattr *array in a block scope tools: ynl-gen: don't validate nested array attribute types tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray tools: ynl: move nest packing to a helper function tools: ynl: encode indexed-array tools: ynl: decode hex input tools: ynl: add ipv4-or-v6 display hint Documentation/netlink/genetlink-legacy.yaml | 2 +- tools/net/ynl/pyynl/lib/ynl.py | 36 +++++++++++++++--- tools/net/ynl/pyynl/ynl_gen_c.py | 42 ++++++++++++++------- 3 files changed, 59 insertions(+), 21 deletions(-) -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:25 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:25 -0000 Subject: [RFC net-next 12/14] netlink: specs: wireguard: alternative to wireguard_params.h In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-12-ast@fiberby.net> This is an alternative to the approach taken in patch 04, Use magic constants in C as well, and thereby obfuscate their origin. If this is preferred then I will split and squash this patch into the previous commits, so that it's done like this in the original specification patch. Signed-off-by: Asbj?rn Sloth T?nnesen --- Documentation/netlink/specs/wireguard.yaml | 36 +++------------------- drivers/net/wireguard/netlink_gen.c | 11 +++---- drivers/net/wireguard/netlink_gen.h | 1 - include/uapi/linux/wireguard_params.h | 18 ----------- 4 files changed, 9 insertions(+), 57 deletions(-) delete mode 100644 include/uapi/linux/wireguard_params.h diff --git a/Documentation/netlink/specs/wireguard.yaml b/Documentation/netlink/specs/wireguard.yaml index 37011c3f158b..bb44171d9ac5 100644 --- a/Documentation/netlink/specs/wireguard.yaml +++ b/Documentation/netlink/specs/wireguard.yaml @@ -21,34 +21,6 @@ definitions: name: key-len type: const value: 32 - - - name-prefix: --wg- - name: inaddr-sz - type: const - doc: Equivalent of ``sizeof(struct in_addr)``. - header: linux/wireguard_params.h - value: 4 - - - name-prefix: --wg- - name: sockaddr-sz - type: const - doc: Equivalent of ``sizeof(struct sockaddr)``. - header: linux/wireguard_params.h - value: 16 - - - name-prefix: --wg- - name: timespec-sz - type: const - doc: Equivalent of ``sizeof(struct __kernel_timespec)``. - header: linux/wireguard_params.h - value: 16 - - - name-prefix: --wg- - name: ifnamlen - type: const - doc: Equivalent of ``IFNAMSIZ - 1``. - header: linux/wireguard_params.h - value: 15 - name: --kernel-timespec type: struct @@ -103,7 +75,7 @@ attribute-sets: name: ifname type: string checks: - max-len: --wg-ifnamlen + max-len: 15 - name: private-key type: binary @@ -179,7 +151,7 @@ attribute-sets: doc: struct sockaddr_in or struct sockaddr_in6 type: binary checks: - min-len: --wg-sockaddr-sz + min-len: 16 - name: persistent-keepalive-interval type: u16 @@ -189,7 +161,7 @@ attribute-sets: type: binary struct: --kernel-timespec checks: - exact-len: --wg-timespec-sz + exact-len: 16 - name: rx-bytes type: u64 @@ -226,7 +198,7 @@ attribute-sets: doc: struct in_addr or struct in6_add display-hint: ipv4-or-v6 checks: - min-len: --wg-inaddr-sz + min-len: 4 - name: cidr-mask type: u8 diff --git a/drivers/net/wireguard/netlink_gen.c b/drivers/net/wireguard/netlink_gen.c index 75f5b4b297a9..f95fa133778f 100644 --- a/drivers/net/wireguard/netlink_gen.c +++ b/drivers/net/wireguard/netlink_gen.c @@ -9,13 +9,12 @@ #include "netlink_gen.h" #include -#include #include /* Common nested types */ const struct nla_policy wireguard_wgallowedip_nl_policy[WGALLOWEDIP_A_FLAGS + 1] = { [WGALLOWEDIP_A_FAMILY] = { .type = NLA_U16, }, - [WGALLOWEDIP_A_IPADDR] = NLA_POLICY_MIN_LEN(__WG_INADDR_SZ), + [WGALLOWEDIP_A_IPADDR] = NLA_POLICY_MIN_LEN(4), [WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8, }, [WGALLOWEDIP_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 0x1), }; @@ -24,9 +23,9 @@ const struct nla_policy wireguard_wgpeer_nl_policy[WGPEER_A_PROTOCOL_VERSION + 1 [WGPEER_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), [WGPEER_A_PRESHARED_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), [WGPEER_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 0x7), - [WGPEER_A_ENDPOINT] = NLA_POLICY_MIN_LEN(__WG_SOCKADDR_SZ), + [WGPEER_A_ENDPOINT] = NLA_POLICY_MIN_LEN(16), [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NLA_U16, }, - [WGPEER_A_LAST_HANDSHAKE_TIME] = NLA_POLICY_EXACT_LEN(__WG_TIMESPEC_SZ), + [WGPEER_A_LAST_HANDSHAKE_TIME] = NLA_POLICY_EXACT_LEN(16), [WGPEER_A_RX_BYTES] = { .type = NLA_U64, }, [WGPEER_A_TX_BYTES] = { .type = NLA_U64, }, [WGPEER_A_ALLOWEDIPS] = NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy), @@ -36,7 +35,7 @@ const struct nla_policy wireguard_wgpeer_nl_policy[WGPEER_A_PROTOCOL_VERSION + 1 /* WG_CMD_GET_DEVICE - dump */ static const struct nla_policy wireguard_get_device_nl_policy[WGDEVICE_A_PEERS + 1] = { [WGDEVICE_A_IFINDEX] = { .type = NLA_U32, }, - [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .len = __WG_IFNAMLEN, }, + [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .len = 15, }, [WGDEVICE_A_PRIVATE_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), [WGDEVICE_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), [WGDEVICE_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 0x1), @@ -48,7 +47,7 @@ static const struct nla_policy wireguard_get_device_nl_policy[WGDEVICE_A_PEERS + /* WG_CMD_SET_DEVICE - do */ static const struct nla_policy wireguard_set_device_nl_policy[WGDEVICE_A_PEERS + 1] = { [WGDEVICE_A_IFINDEX] = { .type = NLA_U32, }, - [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .len = __WG_IFNAMLEN, }, + [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .len = 15, }, [WGDEVICE_A_PRIVATE_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), [WGDEVICE_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(WG_KEY_LEN), [WGDEVICE_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, 0x1), diff --git a/drivers/net/wireguard/netlink_gen.h b/drivers/net/wireguard/netlink_gen.h index a067ab0d61b6..e635b1f5f0df 100644 --- a/drivers/net/wireguard/netlink_gen.h +++ b/drivers/net/wireguard/netlink_gen.h @@ -10,7 +10,6 @@ #include #include -#include #include /* Common nested types */ diff --git a/include/uapi/linux/wireguard_params.h b/include/uapi/linux/wireguard_params.h deleted file mode 100644 index c218e4b8042f..000000000000 --- a/include/uapi/linux/wireguard_params.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ - -#ifndef _UAPI_LINUX_WIREGUARD_PARAMS_H -#define _UAPI_LINUX_WIREGUARD_PARAMS_H - -#include -#include -#include - -/* These definitions are currently needed for definitions which can't - * be expressed directly in Documentation/netlink/specs/wireguard.yaml - */ -#define __WG_INADDR_SZ (sizeof(struct in_addr)) -#define __WG_SOCKADDR_SZ (sizeof(struct sockaddr)) -#define __WG_TIMESPEC_SZ (sizeof(struct __kernel_timespec)) -#define __WG_IFNAMLEN (IFNAMSIZ - 1) - -#endif /* _UAPI_LINUX_WIREGUARD_PARAMS_H */ -- 2.51.0 From ast at fiberby.net Fri Sep 5 15:34:39 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Fri, 05 Sep 2025 15:34:39 -0000 Subject: [PATCH net-next 09/11] tools: ynl: encode indexed-array In-Reply-To: References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-9-ast@fiberby.net> Message-ID: Hi Donald, Thanks for the reviews. On 9/5/25 10:49 AM, Donald Hunter wrote: > Asbj?rn Sloth T?nnesen writes: > >> This patch adds support for encoding indexed-array >> attributes with sub-type nest in pyynl. >> >> Signed-off-by: Asbj?rn Sloth T?nnesen >> --- >> tools/net/ynl/pyynl/lib/ynl.py | 17 +++++++++++++++++ >> 1 file changed, 17 insertions(+) >> >> diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py >> index 4928b41c636a..a37294a751da 100644 >> --- a/tools/net/ynl/pyynl/lib/ynl.py >> +++ b/tools/net/ynl/pyynl/lib/ynl.py >> @@ -564,6 +564,11 @@ class YnlFamily(SpecFamily): >> nl_type |= Netlink.NLA_F_NESTED >> sub_space = attr['nested-attributes'] >> attr_payload = self._add_nest_attrs(value, sub_space, search_attrs) >> + elif attr['type'] == 'indexed-array' and attr['sub-type'] == 'nest': >> + nl_type |= Netlink.NLA_F_NESTED >> + sub_space = attr['nested-attributes'] >> + attr_payload = self._encode_indexed_array(value, sub_space, >> + search_attrs) >> elif attr["type"] == 'flag': >> if not value: >> # If value is absent or false then skip attribute creation. >> @@ -617,6 +622,9 @@ class YnlFamily(SpecFamily): >> else: >> raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}') >> >> + return self._add_attr_raw(nl_type, attr_payload) >> + >> + def _add_attr_raw(self, nl_type, attr_payload): >> pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) >> return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad >> >> @@ -628,6 +636,15 @@ class YnlFamily(SpecFamily): >> sub_attrs) >> return attr_payload >> >> + def _encode_indexed_array(self, vals, sub_space, search_attrs): >> + attr_payload = b'' >> + nested_flag = Netlink.NLA_F_NESTED > > This line is not doing anything, right? Right, that line shouldn't be there, it is a remain of an early version, where I didn't add the indexes, as NLA_NESTED_ARRAY is actually an unindexed-array. The wireguard kernel code only sends zero types, and it doesn't care that user- space sends an indexed array back, eg. when setting multiple allowed ips. >> + for i, val in enumerate(vals): >> + idx = i | Netlink.NLA_F_NESTED >> + val_payload = self._add_nest_attrs(val, sub_space, search_attrs) >> + attr_payload += self._add_attr_raw(idx, val_payload) >> + return attr_payload >> + >> def _get_enum_or_unknown(self, enum, raw): >> try: >> name = enum.entries_by_val[raw].name -- pw-bot: cr From ast at fiberby.net Sat Sep 6 13:13:39 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Sat, 06 Sep 2025 13:13:39 -0000 Subject: [PATCH net-next 05/11] tools: ynl-gen: define nlattr *array in a block scope In-Reply-To: <20250905171809.694562c6@kernel.org> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-5-ast@fiberby.net> <20250905171809.694562c6@kernel.org> Message-ID: <4eda9c57-bde0-43c3-b8a0-3e45f2e672ac@fiberby.net> On 9/6/25 12:18 AM, Jakub Kicinski wrote: > On Thu, 4 Sep 2025 22:01:28 +0000 Asbj?rn Sloth T?nnesen wrote: >> Instead of trying to define "struct nlattr *array;" in the all >> the right places, then simply define it in a block scope, >> as it's only used here. >> >> Before this patch it was generated for attribute set _put() >> functions, like wireguard_wgpeer_put(), but missing and caused a >> compile error for the command function wireguard_set_device(). >> >> $ make -C tools/net/ynl/generated wireguard-user.o >> -e CC wireguard-user.o >> wireguard-user.c: In function ?wireguard_set_device?: >> wireguard-user.c:548:9: error: ?array? undeclared (first use in ..) >> 548 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); >> | ^~~~~ > > Dunno about this one. In patch 4 you basically add another instance of > the "let's declare local vars at function level" approach. And here > you're going the other way. This patch will certainly work, but I felt > like I wouldn't have written it this way if I was typing in the parsers > by hand. Thanks for the reviews. In patch 4, it is about a variable used by multiple Type classes having presence_type() = 'count', which is currently 3 classes: - TypeBinaryScalarArray - TypeMultiAttr - TypeArrayNest (later renamed to TypeIndexedArray) In patch 5, I move code for a special variable used by one Type class, to be contained within that class. It makes it easier to ensure that the variable is only defined, when used, and vice versa. This comes at the cost of the generated code looking generated. If we should make the generated code look like it was written by humans, then I would move the definition of these local variables into a class method, so `i` can be generated by the generic implementation, and `array` can be implemented in it's class. I will take a stab at this, but it might be too much refactoring for this series, eg. `len` is also defined local to conditional blocks multiple branches in a row. tools/net/ynl/generated/nl80211-user.c: nl80211_iftype_data_attrs_parse(..) { [..] ynl_attr_for_each_nested(attr, nested) { unsigned int type = ynl_attr_type(attr); if (type == NL80211_BAND_IFTYPE_ATTR_IFTYPES) { unsigned int len; [..] } else if (type == NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC) { unsigned int len; [..] [same pattern 8 times, so 11 times in total] } else if (type == NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE) { unsigned int len; [..] } } return 0; } (I didn't have to search for this, I saw the pattern in wireguard-user.c, looked for it in nl80211-user.c and this was the first `len` usage there.) That looks very generated, I would have `len` defined together with `type`, and a switch statement would also look a lot more natural, but maybe leave the if->switch conversion for the compiler to detect. From ast at fiberby.net Sat Sep 6 13:22:13 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Sat, 06 Sep 2025 13:22:13 -0000 Subject: [PATCH net-next 06/11] tools: ynl-gen: don't validate nested array attribute types In-Reply-To: <20250905172334.0411e05e@kernel.org> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-6-ast@fiberby.net> <20250905172334.0411e05e@kernel.org> Message-ID: <0a9a7c41-7deb-4078-8cc9-aee8f8784443@fiberby.net> On 9/6/25 12:23 AM, Jakub Kicinski wrote: > On Thu, 4 Sep 2025 22:01:29 +0000 Asbj?rn Sloth T?nnesen wrote: >> In nested arrays don't require that the intermediate >> attribute type should be a valid attribute type, it >> might just be an index or simple 0, it is often not >> even used. >> >> See include/net/netlink.h about NLA_NESTED_ARRAY: >>> The difference to NLA_NESTED is the structure: >>> NLA_NESTED has the nested attributes directly inside >>> while an array has the nested attributes at another >>> level down and the attribute types directly in the >>> nesting don't matter. > > I don't understand, please provide more details. > This is an ArrayNest, right? > > [ARRAY-ATTR] > [ENTRY] > [MEMBER1] > [MEMBER2] > [ENTRY] > [MEMBER1] > [MEMBER2] > > Which level are you saying doesn't matter? > If entry is a nest it must be a valid nest. > What the comment you're quoting is saying is that the nla_type of ENTRY > doesn't matter. I will expand this in v2, but the gist of it is that this is part of the "split attribute counting, and later allocating an array to hold them" code. The check that I remove for nested arrays, is an early exit during the counting phase. Later in the allocation and parse phase it validates the nested payload. In include/uapi/linux/wireguard.h: > WGDEVICE_A_PEERS: NLA_NESTED > 0: NLA_NESTED > WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN > [..] > 0: NLA_NESTED > ... > ... The current check requires that the nested type is valid in the nested attribute set, which in this case resolves to WGDEVICE_A_UNSPEC, which is YNL_PT_REJECT, and it takes the early exit and returns YNL_PARSE_CB_ERROR. From ast at fiberby.net Sat Sep 6 14:13:15 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Sat, 06 Sep 2025 14:13:15 -0000 Subject: [PATCH net-next 02/11] tools: ynl-gen: generate nested array policies In-Reply-To: References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-2-ast@fiberby.net> Message-ID: <6e31a9e0-5450-4b45-a557-2aa08d23c25a@fiberby.net> CC: Johannes On 9/6/25 12:19 AM, Jacob Keller wrote: > On 9/4/2025 3:01 PM, Asbj?rn Sloth T?nnesen wrote: >> This patch adds support for NLA_POLICY_NESTED_ARRAY() policies. >> >> Example spec (from future wireguard.yaml): >> - >> name: wgpeer >> attributes: >> - >> name: allowedips >> type: indexed-array >> sub-type: nest >> nested-attributes: wgallowedip >> >> yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy). >> >> This doesn't change any currently generated code, as it isn't >> used in any specs currently used for generating code. >> >> Signed-off-by: Asbj?rn Sloth T?nnesen >> --- > > Is this keyed of off the sub-type? Does you mean that all the existing > uses of 'sub-type: nest' don't generate code today? Or that this > _attr_policy implementation is not called yet? Thanks for the reviews. Yeah, it is a careful wording, because we have specs matching it, but there aren't any source files that triggers ynl-gen to generate code based on those specs. Therefore this patch, doesn't result in any code changes when running: $ ./tools/net/ynl/ynl-regen.sh -f Actually ynl-gen generates a fictive "{ .type = NLA_INDEXED_ARRAY, }" policy, without this patch, leading to a build failure. > I checked and we have quite a number of uses: > >> $ rg 'sub-type: nest' >> Documentation/netlink/specs/nlctrl.yaml >> [..] >> Documentation/netlink/specs/tc.yaml >> [..] >> Documentation/netlink/specs/rt-link.yaml >> [..] >> Documentation/netlink/specs/nl80211.yaml >> [..] None of those currently have a generated netlink policy. These are the netlink policies currently generated by ynl-gen: $ git grep -h -B1 'YNL-GEN kernel source' | grep '^/\*[^ ]' /* Documentation/netlink/specs/dpll.yaml */ /* Documentation/netlink/specs/ovpn.yaml */ /* Documentation/netlink/specs/team.yaml */ /* Documentation/netlink/specs/lockd.yaml */ /* Documentation/netlink/specs/nfsd.yaml */ /* Documentation/netlink/specs/netdev.yaml */ /* Documentation/netlink/specs/devlink.yaml */ /* Documentation/netlink/specs/handshake.yaml */ /* Documentation/netlink/specs/fou.yaml */ /* Documentation/netlink/specs/mptcp_pm.yaml */ /* Documentation/netlink/specs/net_shaper.yaml */ Johannes introduced NLA_NESTED_ARRAY and the NLA_POLICY_NESTED_ARRAY() macro in commit 1501d13596b9 for use in nl80211, and it's therefore used in net/wireless/nl80211.c, but outside of that the macro is only sparsely adopted (only by mac80211_hwsim.c and nf_tables_api.c). Wireguard adopts the macro in this RFC patch: https://lore.kernel.org/netdev/20250904220255.1006675-2-ast at fiberby.net/ From ast at fiberby.net Sat Sep 6 14:31:50 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Sat, 06 Sep 2025 14:31:50 -0000 Subject: [PATCH net-next 10/11] tools: ynl: decode hex input In-Reply-To: <410d69e5-d1f8-40e0-84b1-b5d56e0d9366@intel.com> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-10-ast@fiberby.net> <410d69e5-d1f8-40e0-84b1-b5d56e0d9366@intel.com> Message-ID: On 9/6/25 12:27 AM, Jacob Keller wrote: > On 9/5/2025 3:51 AM, Donald Hunter wrote: >> Asbj?rn Sloth T?nnesen writes: >> >>> This patch add support for decoding hex input, so >>> that binary attributes can be read through --json. >>> >>> Example (using future wireguard.yaml): >>> $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ >>> --do set-device --json '{"ifindex":3, >>> "private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}' >>> >>> Signed-off-by: Asbj?rn Sloth T?nnesen >> >> Reviewed-by: Donald Hunter >> >> FWIW, the hex can include spaces or not when using bytes.fromhex(). When >> formatting hex for output, I chose to include spaces, but I don't really >> know if that was a good choice or not. > > I also prefer the spaces for readability. I formatted it with spaces for clarity, even without spaces it was a bit long for one line. Spaces also has the advantage that you don't have to think about endianness. Should we define the display hints a bit more in a .rst, or is it OK that they end up being implementation specific for each language library? Do we want them to behave the same in a Rust YNL library, as they do in Python? BTW: The rest of the key used in the example can be found with this key-gen: $ printf "hello world" | sha1sum [redacted key material] From ast at fiberby.net Sat Sep 6 15:10:44 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Sat, 06 Sep 2025 15:10:44 -0000 Subject: [PATCH net-next 06/11] tools: ynl-gen: don't validate nested array attribute types In-Reply-To: References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-6-ast@fiberby.net> Message-ID: CC: Johannes On 9/6/25 12:24 AM, Jacob Keller wrote: > On 9/4/2025 3:01 PM, Asbj?rn Sloth T?nnesen wrote: >> In nested arrays don't require that the intermediate >> attribute type should be a valid attribute type, it >> might just be an index or simple 0, it is often not >> even used. >> >> See include/net/netlink.h about NLA_NESTED_ARRAY: >>> The difference to NLA_NESTED is the structure: >>> NLA_NESTED has the nested attributes directly inside >>> while an array has the nested attributes at another >>> level down and the attribute types directly in the >>> nesting don't matter. >> > > To me, it would seem like it makes more sense to define these (even if > thats defined per family?) than to just say they aren't defined at all? > > Hm. I considered adding some of that metadata too, as I am actually removing it for wireguard (in comment form, but still). In include/uapi/linux/wireguard.h in the comment block at the top, it is very clear that wireguard only used type 0 for all the nested array entries, however the truth is that it doesn't care. It therefore doesn't matter if the generated -user.* keeps track of the index in .idx, or that cli.py decodes a JSON array and sends it with indexes, it's not needed, but it still works. In practice I don't think we will break any clients if we enforced it, and validated that wireguard only accepts type 0 entries, in it's nested arrays. For the other families, I don't know how well defined it is, Johannes have stated that nl80211 doesn't care which types are used, but I have no idea how consistent clients have abused that statement to send random data, or do they all just send zeros? This would make a lot more sense if 'array-nest' hadn't been renamed to 'indexed-array' in ynl, because it feels wrong to add 'unindexed: true' now. We could also call it 'all-zero-indexed: true'. In cli.py this gives some extra issues, as seen in [1], the nested arrays are outputted as '[{0: {..}}, {0: {..}}, ..]', but on input has the format '[{..},{..}, ..]' because it has to be JSON-compatible on input. If we had an attribute like 'all-zero-indexed' then cli.py, could also output '[{..},{..}, ..]'. [1] https://lore.kernel.org/netdev/20250904220255.1006675-3-ast at fiberby.net/ From ast at fiberby.net Sat Sep 6 15:59:12 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Sat, 06 Sep 2025 15:59:12 -0000 Subject: [PATCH net-next 11/11] tools: ynl: add ipv4-or-v6 display hint In-Reply-To: References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-11-ast@fiberby.net> Message-ID: <228eae2b-5a52-48c0-a3a2-afbd3e45adf2@fiberby.net> On 9/5/25 10:53 AM, Donald Hunter wrote: > Asbj?rn Sloth T?nnesen writes: >> The attribute WGALLOWEDIP_A_IPADDR can contain either an IPv4 >> or an IPv6 address depending on WGALLOWEDIP_A_FAMILY, however >> in practice it is enough to look at the attribute length. >> >> This patch implements an ipv4-or-v6 display hint, that can >> deal with this kind of attribute. >> >> It only implements this display hint for genetlink-legacy, it >> can be added to other protocol variants if needed, but we don't >> want to encourage it's use. >> >> Signed-off-by: Asbj?rn Sloth T?nnesen > > Reviewed-by: Donald Hunter > > I suspect there are occurrences of ipv4 or ipv6 in the existing specs > that really should be ipv4-or-ipv6 but the python code doesn't care. I haven't been able to find any, containing 'ip' or 'addr'. Speaking of display hints, then WGPEER_A_ENDPOINT is another interesting case, it is struct sockaddr_in or struct sockaddr_in6, I have left that as a plain binary for now, but maybe that could be a struct map, based on struct length. attribute-sets: - name: wgpeer [..] attributes: [..] - name: endpoint type: binary struct-map: - sockaddr_in - sockaddr_in6 With the requirement being, that all structs must have a unique length. From ast at fiberby.net Mon Sep 8 09:08:23 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Mon, 08 Sep 2025 09:08:23 -0000 Subject: [PATCH net-next 02/11] tools: ynl-gen: generate nested array policies In-Reply-To: References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-2-ast@fiberby.net> <6e31a9e0-5450-4b45-a557-2aa08d23c25a@fiberby.net> Message-ID: On 9/8/25 7:54 AM, Johannes Berg wrote: > On Sat, 2025-09-06 at 14:13 +0000, Asbj?rn Sloth T?nnesen wrote: >> Johannes introduced NLA_NESTED_ARRAY and the NLA_POLICY_NESTED_ARRAY() >> macro in commit 1501d13596b9 for use in nl80211, and it's therefore >> used in net/wireless/nl80211.c, but outside of that the macro is >> only sparsely adopted (only by mac80211_hwsim.c and nf_tables_api.c). >> >> Wireguard adopts the macro in this RFC patch: >> https://lore.kernel.org/netdev/20250904220255.1006675-2-ast at fiberby.net/ > > I think the general consensus now is that preference should be towards > arrays being expressed by giving the attribute holding the array > multiple times, i.e. each occurrence of an attribute holds a single > entry of the array: > > [header][type1:a1][type2:b][type1:a2][type1:a3] > > resulting in an array > > [a1, a2, a3] and a separate value "b", > > rather than a nested array: > > [header][type1:[1:a1][2:a2][3:a3]][type2:b] > > > Of course if each entry has multiple values, then you'd still need > nesting: > > [header][type1:[subtype1:x1][subtype2:x2]][type1:[subtype1:y1][subtype2:y2]] > > would be an array > > [[x1, x2], [y1, y2]]. Thank you for the consensus write up. Should we prohibit indexed-array with sub-type nest for families with a genetlink protocol? It is currently only used in families with a netlink-raw or genetlink-legacy protocol. > I can't get rid of the nested array types in nl80211 though, of course. Wireguard is already in the same boat. It is not using the term, nor the policy, but it is doing the validation in the handler through, so it can adopt a NLA_POLICY_NESTED_ARRAY() policy, instead of a plain '{ .type = NLA_NESTED }'. Comments on the protocol in include/uapi/linux/wireguard.h: > WGDEVICE_A_PEERS: NLA_NESTED > 0: NLA_NESTED > WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN > [..] > 0: NLA_NESTED > ... > ... Given that, as Jacob pointed out, there are more families with nested arrays in their YNL spec, than those using NLA_NESTED_ARRAY, then it appears that there are more families already in the boat. From ast at fiberby.net Tue Sep 9 20:19:00 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Tue, 09 Sep 2025 20:19:00 -0000 Subject: [PATCH net-next 10/11] tools: ynl: decode hex input In-Reply-To: References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-10-ast@fiberby.net> Message-ID: <412f5811-bc54-45d4-92cd-7eea02a7ecc0@fiberby.net> On 9/9/25 6:10 PM, Sabrina Dubroca wrote: > 2025-09-04, 22:01:33 +0000, Asbj?rn Sloth T?nnesen wrote: >> This patch add support for decoding hex input, so >> that binary attributes can be read through --json. >> >> Example (using future wireguard.yaml): >> $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ >> --do set-device --json '{"ifindex":3, >> "private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}' >> >> Signed-off-by: Asbj?rn Sloth T?nnesen >> --- >> tools/net/ynl/pyynl/lib/ynl.py | 2 ++ >> 1 file changed, 2 insertions(+) >> >> diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py >> index a37294a751da..78c0245ca587 100644 >> --- a/tools/net/ynl/pyynl/lib/ynl.py >> +++ b/tools/net/ynl/pyynl/lib/ynl.py >> @@ -973,6 +973,8 @@ class YnlFamily(SpecFamily): >> raw = ip.packed >> else: >> raw = int(ip) >> + elif attr_spec.display_hint == 'hex': >> + raw = bytes.fromhex(string) > > I'm working on a spec for macsec and ended up with a similar change, > but doing instead: > > + elif attr_spec.display_hint == 'hex': > + raw = int(string, 16) > > since the destination attribute is u32/u64 and not binary for macsec. > > So maybe this should be: > > + if attr_spec['type'] == 'binary': > + raw = bytes.fromhex(string) > + else: > + raw = int(string, 16) > > to cover both cases? > > I think it matches better what's already in _formatted_string. > > (I don't mind having the current patch go in and making this change > together with the macsec spec when it's ready) Cool, I will include it in v2, which I hope to get out tomorrow. From ast at fiberby.net Wed Sep 10 23:08:51 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:51 -0000 Subject: [PATCH net-next v2 02/12] tools: ynl-gen: generate nested array policies In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910230841.384545-3-ast@fiberby.net> This patch adds support for NLA_POLICY_NESTED_ARRAY() policies. Example spec (from future wireguard.yaml): - name: wgpeer attributes: - name: allowedips type: indexed-array sub-type: nest nested-attributes: wgallowedip yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy). This doesn't change any currently generated code, as it isn't used in any specs currently used for generating code. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski --- tools/net/ynl/pyynl/ynl_gen_c.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 1543d4911bf5..b7de7f6b1fc7 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -816,6 +816,11 @@ class TypeArrayNest(Type): f'unsigned int n_{self.c_name}'] return super().arg_member(ri) + def _attr_policy(self, policy): + if self.attr['sub-type'] == 'nest': + return f'NLA_POLICY_NESTED_ARRAY({self.nested_render_name}_nl_policy)' + return super()._attr_policy(policy) + def _attr_typol(self): if self.attr['sub-type'] in scalars: return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, ' -- 2.51.0 From ast at fiberby.net Wed Sep 10 23:08:51 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:51 -0000 Subject: [PATCH net-next v2 00/12] tools: ynl: prepare for wireguard Message-ID: <20250910230841.384545-1-ast@fiberby.net> This series contains the last batch of YNL changes to support the wireguard YNL conversion. The wireguard changes, to be applied on top of this series, has been posted as an RFC series here: https://lore.kernel.org/netdev/20250904-wg-ynl-rfc at fiberby.net/ --- v2: - Added Reviewed-By's to unchanged patches. Thanks to all reviewers. - Patch 4, refactors local variables for .attr_put() callers, and replaces the old patch 4 and 5. - Patch 5 and 6 are new, and reduces the differences between the 3 .attr_put() callers, so it might be easier to keep them in sync. - Patch 7, now validates the nested payload (thanks Jakub). - Patch 8, now renames more variables (thanks Jakub), - Patch 10, got a dead line remove (thanks Donald). - Patch 11, revised hex input to support macsec (suggested by Sabrina). v1: https://lore.kernel.org/netdev/20250904-wg-ynl-prep at fiberby.net/ Asbj?rn Sloth T?nnesen (12): tools: ynl-gen: allow overriding name-prefix for constants tools: ynl-gen: generate nested array policies tools: ynl-gen: add sub-type check tools: ynl-gen: refactor local vars for .attr_put() callers tools: ynl-gen: add CodeWriter.p_lines() helper tools: ynl-gen: deduplicate fixed_header handling tools: ynl-gen: only validate nested array payload tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray tools: ynl: move nest packing to a helper function tools: ynl: encode indexed-arrays tools: ynl: decode hex input tools: ynl: add ipv4-or-v6 display hint Documentation/netlink/genetlink-legacy.yaml | 2 +- tools/net/ynl/lib/ynl-priv.h | 2 + tools/net/ynl/lib/ynl.c | 17 ++- tools/net/ynl/pyynl/lib/ynl.py | 38 ++++- tools/net/ynl/pyynl/ynl_gen_c.py | 152 +++++++++++--------- 5 files changed, 133 insertions(+), 78 deletions(-) -- 2.51.0 From ast at fiberby.net Wed Sep 10 23:08:52 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:52 -0000 Subject: [PATCH net-next v2 05/12] tools: ynl-gen: add CodeWriter.p_lines() helper In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910230841.384545-6-ast@fiberby.net> Add a helper for writing an array of lines, and convert all the existing loops doing that, to use the new helper. This is a trivial patch with no behavioural changes intended, there are no changes to the generated code. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 6441d5a31391..18c6ed0044b9 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -181,8 +181,7 @@ class Type(SpecAttr): def free(self, ri, var, ref): lines = self._free_lines(ri, var, ref) - for line in lines: - ri.cw.p(line) + ri.cw.p_lines(lines) def arg_member(self, ri): member = self._complex_member_type(ri) @@ -268,13 +267,9 @@ class Type(SpecAttr): if self.presence_type() == 'present': ri.cw.p(f"{var}->_present.{self.c_name} = 1;") - if init_lines: - ri.cw.nl() - for line in init_lines: - ri.cw.p(line) + ri.cw.p_lines(init_lines, nl_before=True) - for line in lines: - ri.cw.p(line) + ri.cw.p_lines(lines) ri.cw.block_end() return True @@ -1789,8 +1784,7 @@ class CodeWriter: self.block_start() self.write_func_lvar(local_vars=local_vars) - for line in body: - self.p(line) + self.p_lines(body) self.block_end() def writes_defines(self, defines): @@ -1831,6 +1825,12 @@ class CodeWriter: self.p('#ifdef ' + config_option) self._ifdef_block = config_option + def p_lines(self, lines, nl_before=False): + if lines and nl_before: + self.nl() + for line in lines or []: + self.p(line) + scalars = {'u8', 'u16', 'u32', 'u64', 's8', 's16', 's32', 's64', 'uint', 'sint'} @@ -2088,8 +2088,7 @@ def put_req_nested(ri, struct): ri.cw.block_start() ri.cw.write_func_lvar(local_vars) - for line in init_lines: - ri.cw.p(line) + ri.cw.p_lines(init_lines) for _, arg in struct.member_list(): arg.attr_put(ri, "obj") @@ -2150,8 +2149,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.block_start() ri.cw.write_func_lvar(local_vars) - for line in init_lines: - ri.cw.p(line) + ri.cw.p_lines(init_lines) ri.cw.nl() for arg in struct.inherited: @@ -2280,10 +2278,8 @@ def parse_rsp_submsg(ri, struct): ri.cw.block_start(line=f'{kw} (!strcmp(sel, "{name}"))') get_lines, init_lines, _ = arg._attr_get(ri, var) - for line in init_lines or []: - ri.cw.p(line) - for line in get_lines: - ri.cw.p(line) + ri.cw.p_lines(init_lines) + ri.cw.p_lines(get_lines) if arg.presence_type() == 'present': ri.cw.p(f"{var}->_present.{arg.c_name} = 1;") ri.cw.block_end() -- 2.51.0 From ast at fiberby.net Wed Sep 10 23:08:52 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:52 -0000 Subject: [PATCH net-next v2 12/12] tools: ynl: add ipv4-or-v6 display hint In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910230841.384545-13-ast@fiberby.net> The attribute WGALLOWEDIP_A_IPADDR can contain either an IPv4 or an IPv6 address depending on WGALLOWEDIP_A_FAMILY, however in practice it is enough to look at the attribute length. This patch implements an ipv4-or-v6 display hint, that can deal with this kind of attribute. It only implements this display hint for genetlink-legacy, it can be added to other protocol variants if needed, but we don't want to encourage it's use. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- Documentation/netlink/genetlink-legacy.yaml | 2 +- tools/net/ynl/pyynl/lib/ynl.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index b29d62eefa16..66fb8653a344 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -154,7 +154,7 @@ properties: Optional format indicator that is intended only for choosing the right formatting mechanism when displaying values of this type. - enum: [ hex, mac, fddi, ipv4, ipv6, uuid ] + enum: [ hex, mac, fddi, ipv4, ipv6, ipv4-or-v6, uuid ] struct: description: Name of the nested struct type. type: string diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 50f4889e721b..4f2c8126d6e9 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -957,7 +957,7 @@ class YnlFamily(SpecFamily): formatted = hex(raw) else: formatted = bytes.hex(raw, ' ') - elif display_hint in [ 'ipv4', 'ipv6' ]: + elif display_hint in [ 'ipv4', 'ipv6', 'ipv4-or-v6' ]: formatted = format(ipaddress.ip_address(raw)) elif display_hint == 'uuid': formatted = str(uuid.UUID(bytes=raw)) @@ -966,7 +966,7 @@ class YnlFamily(SpecFamily): return formatted def _from_string(self, string, attr_spec): - if attr_spec.display_hint in ['ipv4', 'ipv6']: + if attr_spec.display_hint in ['ipv4', 'ipv6', 'ipv4-or-v6']: ip = ipaddress.ip_address(string) if attr_spec['type'] == 'binary': raw = ip.packed -- 2.51.0 From ast at fiberby.net Wed Sep 10 23:08:53 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:53 -0000 Subject: [PATCH net-next v2 09/12] tools: ynl: move nest packing to a helper function In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910230841.384545-10-ast@fiberby.net> This patch moves nest packing into a helper function, that can also be used for packing indexed arrays. No behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/lib/ynl.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 8244a5f440b2..4928b41c636a 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -562,11 +562,8 @@ class YnlFamily(SpecFamily): if attr["type"] == 'nest': nl_type |= Netlink.NLA_F_NESTED - attr_payload = b'' sub_space = attr['nested-attributes'] - sub_attrs = SpaceAttrs(self.attr_sets[sub_space], value, search_attrs) - for subname, subvalue in value.items(): - attr_payload += self._add_attr(sub_space, subname, subvalue, sub_attrs) + attr_payload = self._add_nest_attrs(value, sub_space, search_attrs) elif attr["type"] == 'flag': if not value: # If value is absent or false then skip attribute creation. @@ -623,6 +620,14 @@ class YnlFamily(SpecFamily): pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad + def _add_nest_attrs(self, value, sub_space, search_attrs): + sub_attrs = SpaceAttrs(self.attr_sets[sub_space], value, search_attrs) + attr_payload = b'' + for subname, subvalue in value.items(): + attr_payload += self._add_attr(sub_space, subname, subvalue, + sub_attrs) + return attr_payload + def _get_enum_or_unknown(self, enum, raw): try: name = enum.entries_by_val[raw].name -- 2.51.0 From ast at fiberby.net Wed Sep 10 23:08:53 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:53 -0000 Subject: [PATCH net-next v2 10/12] tools: ynl: encode indexed-arrays In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910230841.384545-11-ast@fiberby.net> This patch adds support for encoding indexed-array attributes with sub-type nest in pyynl. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/lib/ynl.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 4928b41c636a..7ddf689a2a6e 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -564,6 +564,11 @@ class YnlFamily(SpecFamily): nl_type |= Netlink.NLA_F_NESTED sub_space = attr['nested-attributes'] attr_payload = self._add_nest_attrs(value, sub_space, search_attrs) + elif attr['type'] == 'indexed-array' and attr['sub-type'] == 'nest': + nl_type |= Netlink.NLA_F_NESTED + sub_space = attr['nested-attributes'] + attr_payload = self._encode_indexed_array(value, sub_space, + search_attrs) elif attr["type"] == 'flag': if not value: # If value is absent or false then skip attribute creation. @@ -617,6 +622,9 @@ class YnlFamily(SpecFamily): else: raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}') + return self._add_attr_raw(nl_type, attr_payload) + + def _add_attr_raw(self, nl_type, attr_payload): pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad @@ -628,6 +636,14 @@ class YnlFamily(SpecFamily): sub_attrs) return attr_payload + def _encode_indexed_array(self, vals, sub_space, search_attrs): + attr_payload = b'' + for i, val in enumerate(vals): + idx = i | Netlink.NLA_F_NESTED + val_payload = self._add_nest_attrs(val, sub_space, search_attrs) + attr_payload += self._add_attr_raw(idx, val_payload) + return attr_payload + def _get_enum_or_unknown(self, enum, raw): try: name = enum.entries_by_val[raw].name -- 2.51.0 From ast at fiberby.net Wed Sep 10 23:08:53 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:53 -0000 Subject: [PATCH net-next v2 01/12] tools: ynl-gen: allow overriding name-prefix for constants In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910230841.384545-2-ast@fiberby.net> Allow using custom name-prefix with constants, just like it is for enum and flags declarations. This is needed for generating WG_KEY_LEN in include/uapi/linux/wireguard.h from a spec. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski Reviewed-by: Jacob Keller --- tools/net/ynl/pyynl/ynl_gen_c.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index fb7e03805a11..1543d4911bf5 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -3211,8 +3211,9 @@ def render_uapi(family, cw): cw.block_end(line=';') cw.nl() elif const['type'] == 'const': + name_pfx = const.get('name-prefix', f"{family.ident_name}-") defines.append([c_upper(family.get('c-define-name', - f"{family.ident_name}-{const['name']}")), + f"{name_pfx}{const['name']}")), const['value']]) if defines: -- 2.51.0 From ast at fiberby.net Wed Sep 10 23:08:53 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:53 -0000 Subject: [PATCH net-next v2 11/12] tools: ynl: decode hex input In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910230841.384545-12-ast@fiberby.net> This patch adds support for decoding hex input, so that binary attributes can be read through --json. Example (using future wireguard.yaml): $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ --do set-device --json '{"ifindex":3, "private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}' In order to somewhat mirror what is done in _formatted_string(), then for non-binary attributes attempt to convert it to an int. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/lib/ynl.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 7ddf689a2a6e..50f4889e721b 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -972,6 +972,11 @@ class YnlFamily(SpecFamily): raw = ip.packed else: raw = int(ip) + elif attr_spec.display_hint == 'hex': + if attr_spec['type'] == 'binary': + raw = bytes.fromhex(string) + else: + raw = int(string, 16) else: raise Exception(f"Display hint '{attr_spec.display_hint}' not implemented" f" when parsing '{attr_spec['name']}'") -- 2.51.0 From ast at fiberby.net Wed Sep 10 23:08:53 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:53 -0000 Subject: [PATCH net-next v2 08/12] tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910230841.384545-9-ast@fiberby.net> Since TypeArrayNest can now be used with many other sub-types than nest, then rename it to TypeIndexedArray, to reduce confusion. This patch continues the rename, that was started in commit aa6485d813ad ("ynl: rename array-nest to indexed-array"), when the YNL type was renamed. In order to get rid of all references to the old naming, within ynl, then renaming some variables in _multi_parse(). This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index e93f5d724b42..574faa89b1f7 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -793,7 +793,7 @@ class TypeMultiAttr(Type): f"{presence} = n_{self.c_name};"] -class TypeArrayNest(Type): +class TypeIndexedArray(Type): def is_multi_val(self): return True @@ -830,7 +830,7 @@ class TypeArrayNest(Type): elif self.attr['sub-type'] == 'nest': return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' else: - raise Exception(f"Typol for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") + raise Exception(f"Typol for IndexedArray sub-type {self.attr['sub-type']} not supported, yet") def _attr_get(self, ri, var): local_vars = ['const struct nlattr *attr2;'] @@ -860,7 +860,7 @@ class TypeArrayNest(Type): ri.cw.p(f'for (i = 0; i < {var}->_count.{self.c_name}; i++)') ri.cw.p(f"{self.nested_render_name}_put(nlh, i, &{var}->{self.c_name}[i]);") else: - raise Exception(f"Put for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") + raise Exception(f"Put for IndexedArray sub-type {self.attr['sub-type']} not supported, yet") ri.cw.p('ynl_attr_nest_end(nlh, array);') def _setter_lines(self, ri, member, presence): @@ -1137,7 +1137,7 @@ class AttrSet(SpecAttrSet): t = TypeNest(self.family, self, elem, value) elif elem['type'] == 'indexed-array' and 'sub-type' in elem: if elem["sub-type"] in ['binary', 'nest', 'u32']: - t = TypeArrayNest(self.family, self, elem, value) + t = TypeIndexedArray(self.family, self, elem, value) else: raise Exception(f'new_attr: unsupported sub-type {elem["sub-type"]}') elif elem['type'] == 'nest-type-value': @@ -2127,33 +2127,33 @@ def _multi_parse(ri, struct, init_lines, local_vars): else: raise Exception(f"Per-op fixed header not supported, yet") - array_nests = set() + indexed_arrays = set() multi_attrs = set() needs_parg = False for arg, aspec in struct.member_list(): if aspec['type'] == 'indexed-array' and 'sub-type' in aspec: if aspec["sub-type"] in {'binary', 'nest'}: local_vars.append(f'const struct nlattr *attr_{aspec.c_name};') - array_nests.add(arg) + indexed_arrays.add(arg) elif aspec['sub-type'] in scalars: local_vars.append(f'const struct nlattr *attr_{aspec.c_name};') - array_nests.add(arg) + indexed_arrays.add(arg) else: raise Exception(f'Not supported sub-type {aspec["sub-type"]}') if 'multi-attr' in aspec: multi_attrs.add(arg) needs_parg |= 'nested-attributes' in aspec needs_parg |= 'sub-message' in aspec - if array_nests or multi_attrs: + if indexed_arrays or multi_attrs: local_vars.append('int i;') if needs_parg: local_vars.append('struct ynl_parse_arg parg;') init_lines.append('parg.ys = yarg->ys;') - all_multi = array_nests | multi_attrs + all_multi = indexed_arrays | multi_attrs - for anest in sorted(all_multi): - local_vars.append(f"unsigned int n_{struct[anest].c_name} = 0;") + for arg in sorted(all_multi): + local_vars.append(f"unsigned int n_{struct[arg].c_name} = 0;") ri.cw.block_start() ri.cw.write_func_lvar(local_vars) @@ -2172,8 +2172,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): else: ri.cw.p('hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr));') ri.cw.p(f"memcpy(&dst->_hdr, hdr, sizeof({struct.fixed_header}));") - for anest in sorted(all_multi): - aspec = struct[anest] + for arg in sorted(all_multi): + aspec = struct[arg] ri.cw.p(f"if (dst->{aspec.c_name})") ri.cw.p(f'return ynl_error_parse(yarg, "attribute already present ({struct.attr_set.name}.{aspec.name})");') @@ -2191,8 +2191,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.block_end() ri.cw.nl() - for anest in sorted(array_nests): - aspec = struct[anest] + for arg in sorted(indexed_arrays): + aspec = struct[arg] ri.cw.block_start(line=f"if (n_{aspec.c_name})") ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") @@ -2217,8 +2217,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.block_end() ri.cw.nl() - for anest in sorted(multi_attrs): - aspec = struct[anest] + for arg in sorted(multi_attrs): + aspec = struct[arg] ri.cw.block_start(line=f"if (n_{aspec.c_name})") ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") ri.cw.p(f"dst->_count.{aspec.c_name} = n_{aspec.c_name};") -- 2.51.0 From ast at fiberby.net Wed Sep 10 23:08:53 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:53 -0000 Subject: [PATCH net-next v2 04/12] tools: ynl-gen: refactor local vars for .attr_put() callers In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910230841.384545-5-ast@fiberby.net> Refactor the generation of local variables needed when building requests, by moving the logic into the Type classes, and use the same helper in all places where .attr_put() is called. If any attributes requests identical local_vars, then they will be deduplicated, attributes are assumed to only use their local variables transiently. This patch fixes the build errors below: $ make -C tools/net/ynl/generated/ [...] -e GEN wireguard-user.c -e GEN wireguard-user.h -e CC wireguard-user.o wireguard-user.c: In function ?wireguard_get_device_dump?: wireguard-user.c:480:9: error: ?array? undeclared (first use in func) 480 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); | ^~~~~ wireguard-user.c:480:9: note: each undeclared identifier is reported only once for each function it appears in wireguard-user.c:481:14: error: ?i? undeclared (first use in func) 481 | for (i = 0; i < req->_count.peers; i++) | ^ wireguard-user.c: In function ?wireguard_set_device?: wireguard-user.c:533:9: error: ?array? undeclared (first use in func) 533 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); | ^~~~~ make: *** [Makefile:52: wireguard-user.o] Error 1 make: Leaving directory '/usr/src/linux/tools/net/ynl/generated' Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 37 +++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 04c26ed92ca3..6441d5a31391 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -236,6 +236,12 @@ class Type(SpecAttr): line = f"ynl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name})" self._attr_put_line(ri, var, line) + def attr_put_local_vars(self): + local_vars = [] + if self.presence_type() == 'count': + local_vars.append('unsigned int i;') + return local_vars + def attr_put(self, ri, var): raise Exception(f"Put not implemented for class type {self.type}") @@ -841,6 +847,10 @@ class TypeArrayNest(Type): '}'] return get_lines, None, local_vars + def attr_put_local_vars(self): + local_vars = ['struct nlattr *array;'] + return local_vars + super().attr_put_local_vars() + def attr_put(self, ri, var): ri.cw.p(f'array = ynl_attr_nest_start(nlh, {self.enum_name});') if self.sub_type in scalars: @@ -2041,6 +2051,15 @@ def put_enum_to_str(family, cw, enum): _put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum) +def put_local_vars(struct): + local_vars = [] + for _, attr in struct.member_list(): + for local_var in attr.attr_put_local_vars(): + if local_var not in local_vars: + local_vars.append(local_var) + return local_vars + + def put_req_nested_prototype(ri, struct, suffix=';'): func_args = ['struct nlmsghdr *nlh', 'unsigned int attr_type', @@ -2063,15 +2082,7 @@ def put_req_nested(ri, struct): init_lines.append(f"hdr = ynl_nlmsg_put_extra_header(nlh, {struct_sz});") init_lines.append(f"memcpy(hdr, &obj->_hdr, {struct_sz});") - has_anest = False - has_count = False - for _, arg in struct.member_list(): - has_anest |= arg.type == 'indexed-array' - has_count |= arg.presence_type() == 'count' - if has_anest: - local_vars.append('struct nlattr *array;') - if has_count: - local_vars.append('unsigned int i;') + local_vars += put_local_vars(struct) put_req_nested_prototype(ri, struct, suffix='') ri.cw.block_start() @@ -2355,10 +2366,7 @@ def print_req(ri): local_vars += ['size_t hdr_len;', 'void *hdr;'] - for _, attr in ri.struct["request"].member_list(): - if attr.presence_type() == 'count': - local_vars += ['unsigned int i;'] - break + local_vars += put_local_vars(ri.struct["request"]) print_prototype(ri, direction, terminate=False) ri.cw.block_start() @@ -2425,6 +2433,9 @@ def print_dump(ri): local_vars += ['size_t hdr_len;', 'void *hdr;'] + if "request" in ri.op[ri.op_mode]: + local_vars += put_local_vars(ri.struct["request"]) + ri.cw.write_func_lvar(local_vars) ri.cw.p('yds.yarg.ys = ys;') -- 2.51.0 From ast at fiberby.net Thu Sep 4 22:03:22 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 04 Sep 2025 22:03:22 -0000 Subject: [RFC net-next 10/14] wireguard: netlink: rename netlink handlers In-Reply-To: <20250904-wg-ynl-rfc@fiberby.net> References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: <20250904220255.1006675-10-ast@fiberby.net> Rename netlink handlers to use the naming expected by ynl-gen. This is an incremental step towards adopting netlink command definitions generated by ynl-gen. This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- drivers/net/wireguard/netlink.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c index 1311f64d9fcf..a61e1c5c7850 100644 --- a/drivers/net/wireguard/netlink.c +++ b/drivers/net/wireguard/netlink.c @@ -197,7 +197,7 @@ get_peer(struct wg_peer *peer, struct sk_buff *skb, struct dump_ctx *ctx) return -EMSGSIZE; } -static int wg_get_device_start(struct netlink_callback *cb) +static int wireguard_nl_get_device_start(struct netlink_callback *cb) { struct wg_device *wg; @@ -208,7 +208,8 @@ static int wg_get_device_start(struct netlink_callback *cb) return 0; } -static int wg_get_device_dump(struct sk_buff *skb, struct netlink_callback *cb) +static int wireguard_nl_get_device_dumpit(struct sk_buff *skb, + struct netlink_callback *cb) { struct wg_peer *peer, *next_peer_cursor; struct dump_ctx *ctx = DUMP_CTX(cb); @@ -302,7 +303,7 @@ static int wg_get_device_dump(struct sk_buff *skb, struct netlink_callback *cb) */ } -static int wg_get_device_done(struct netlink_callback *cb) +static int wireguard_nl_get_device_done(struct netlink_callback *cb) { struct dump_ctx *ctx = DUMP_CTX(cb); @@ -500,7 +501,8 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs) return ret; } -static int wg_set_device(struct sk_buff *skb, struct genl_info *info) +static int wireguard_nl_set_device_doit(struct sk_buff *skb, + struct genl_info *info) { struct wg_device *wg = lookup_interface(info->attrs, skb); u32 flags = 0; @@ -617,15 +619,15 @@ static int wg_set_device(struct sk_buff *skb, struct genl_info *info) static const struct genl_split_ops wireguard_nl_ops[] = { { .cmd = WG_CMD_GET_DEVICE, - .start = wg_get_device_start, - .dumpit = wg_get_device_dump, - .done = wg_get_device_done, + .start = wireguard_nl_get_device_start, + .dumpit = wireguard_nl_get_device_dumpit, + .done = wireguard_nl_get_device_done, .policy = device_policy, .maxattr = WGDEVICE_A_PEERS, .flags = GENL_UNS_ADMIN_PERM | GENL_CMD_CAP_DUMP, }, { .cmd = WG_CMD_SET_DEVICE, - .doit = wg_set_device, + .doit = wireguard_nl_set_device_doit, .policy = device_policy, .maxattr = WGDEVICE_A_PEERS, .flags = GENL_UNS_ADMIN_PERM | GENL_CMD_CAP_DO, -- 2.51.0 From ast at fiberby.net Wed Sep 10 23:08:54 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:54 -0000 Subject: [PATCH net-next v2 03/12] tools: ynl-gen: add sub-type check In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910230841.384545-4-ast@fiberby.net> Add a check to verify that the sub-type is "nest", and throw an exception if no policy could be generated, as a guard to prevent against generating a bad policy. This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski Reviewed-by: Jacob Keller --- tools/net/ynl/pyynl/ynl_gen_c.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index b7de7f6b1fc7..04c26ed92ca3 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -826,8 +826,10 @@ class TypeArrayNest(Type): return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, ' elif self.attr['sub-type'] == 'binary' and 'exact-len' in self.checks: return f'.type = YNL_PT_BINARY, .len = {self.checks["exact-len"]}, ' - else: + elif self.attr['sub-type'] == 'nest': return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' + else: + raise Exception(f"Typol for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") def _attr_get(self, ri, var): local_vars = ['const struct nlattr *attr2;'] -- 2.51.0 From ast at fiberby.net Wed Sep 10 23:08:54 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:54 -0000 Subject: [PATCH net-next v2 06/12] tools: ynl-gen: deduplicate fixed_header handling In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910230841.384545-7-ast@fiberby.net> Fixed headers are handled nearly identical in print_dump(), print_req() and put_req_nested(), generalize them and use a common function to generate them. This only causes cosmetic changes to tc_netem_attrs_put() in tc-user.c. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 39 ++++++++++++++++---------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 18c6ed0044b9..f149c68ae84e 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -1829,7 +1829,10 @@ class CodeWriter: if lines and nl_before: self.nl() for line in lines or []: - self.p(line) + if line == '': + self.nl() + else: + self.p(line) scalars = {'u8', 'u16', 'u32', 'u64', 's8', 's16', 's32', 's64', 'uint', 'sint'} @@ -1922,6 +1925,15 @@ def type_name(ri, direction, deref=False): return f"struct {op_prefix(ri, direction, deref=deref)}" +def prepare_fixed_header(var, local_vars, init_lines): + local_vars += ['size_t hdr_len;', + 'void *hdr;'] + init_lines += [f'hdr_len = sizeof({var}->_hdr);', + 'hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);', + f'memcpy(hdr, &{var}->_hdr, hdr_len);', + ''] + + def print_prototype(ri, direction, terminate=True, doc=None): suffix = ';' if terminate else '' @@ -2077,10 +2089,7 @@ def put_req_nested(ri, struct): local_vars.append('struct nlattr *nest;') init_lines.append("nest = ynl_attr_nest_start(nlh, attr_type);") if struct.fixed_header: - local_vars.append('void *hdr;') - struct_sz = f'sizeof({struct.fixed_header})' - init_lines.append(f"hdr = ynl_nlmsg_put_extra_header(nlh, {struct_sz});") - init_lines.append(f"memcpy(hdr, &obj->_hdr, {struct_sz});") + prepare_fixed_header('obj', local_vars, init_lines) local_vars += put_local_vars(struct) @@ -2349,6 +2358,7 @@ def print_req(ri): ret_ok = '0' ret_err = '-1' direction = "request" + init_lines = [] local_vars = ['struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };', 'struct nlmsghdr *nlh;', 'int err;'] @@ -2359,8 +2369,7 @@ def print_req(ri): local_vars += [f'{type_name(ri, rdir(direction))} *rsp;'] if ri.struct["request"].fixed_header: - local_vars += ['size_t hdr_len;', - 'void *hdr;'] + prepare_fixed_header('req', local_vars, init_lines) local_vars += put_local_vars(ri.struct["request"]) @@ -2379,11 +2388,7 @@ def print_req(ri): ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;") ri.cw.nl() - if ri.struct['request'].fixed_header: - ri.cw.p("hdr_len = sizeof(req->_hdr);") - ri.cw.p("hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);") - ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);") - ri.cw.nl() + ri.cw.p_lines(init_lines) for _, attr in ri.struct["request"].member_list(): attr.attr_put(ri, "req") @@ -2421,13 +2426,13 @@ def print_dump(ri): direction = "request" print_prototype(ri, direction, terminate=False) ri.cw.block_start() + init_lines = [] local_vars = ['struct ynl_dump_state yds = {};', 'struct nlmsghdr *nlh;', 'int err;'] if ri.struct['request'].fixed_header: - local_vars += ['size_t hdr_len;', - 'void *hdr;'] + prepare_fixed_header('req', local_vars, init_lines) if "request" in ri.op[ri.op_mode]: local_vars += put_local_vars(ri.struct["request"]) @@ -2449,11 +2454,7 @@ def print_dump(ri): else: ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") - if ri.struct['request'].fixed_header: - ri.cw.p("hdr_len = sizeof(req->_hdr);") - ri.cw.p("hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);") - ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);") - ri.cw.nl() + ri.cw.p_lines(init_lines) if "request" in ri.op[ri.op_mode]: ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;") -- 2.51.0 From ast at fiberby.net Wed Sep 10 23:08:54 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Wed, 10 Sep 2025 23:08:54 -0000 Subject: [PATCH net-next v2 07/12] tools: ynl-gen: only validate nested array payload In-Reply-To: <20250910230841.384545-1-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> Message-ID: <20250910230841.384545-8-ast@fiberby.net> In nested arrays don't require that the intermediate attribute type should be a valid attribute type, it might just be zero or an incrementing index, it is often not even used. See include/net/netlink.h about NLA_NESTED_ARRAY: > The difference to NLA_NESTED is the structure: > NLA_NESTED has the nested attributes directly inside > while an array has the nested attributes at another > level down and the attribute types directly in the > nesting don't matter. Example based on include/uapi/linux/wireguard.h: > WGDEVICE_A_PEERS: NLA_NESTED > 0: NLA_NESTED > WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN > [..] > 0: NLA_NESTED > ... > ... Previous the check required that the nested type was valid in the parent attribute set, which in this case resolves to WGDEVICE_A_UNSPEC, which is YNL_PT_REJECT, and it took the early exit and returned YNL_PARSE_CB_ERROR. This patch adds a new helper, ynl_attr_validate_payload(), which we can use to validate the payload of the nested attribute, in the context of the parents attribute type, and it's policy, which in the above case is generated as: [WGDEVICE_A_PEERS] = { .name = "peers", .type = YNL_PT_NEST, .nest = &wireguard_wgpeer_nest, }, Some other examples are NL80211_BAND_ATTR_FREQS (nest) and NL80211_ATTR_SUPPORTED_COMMANDS (u32). Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/lib/ynl-priv.h | 2 ++ tools/net/ynl/lib/ynl.c | 17 ++++++++++++++--- tools/net/ynl/pyynl/ynl_gen_c.py | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index 824777d7e05e..70ea14c0a0e9 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -107,6 +107,8 @@ struct nlmsghdr * ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); +int ynl_attr_validate_payload(struct ynl_parse_arg *yarg, + const struct nlattr *attr, unsigned int type); int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, const char *sel_name); diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 2a169c3c0797..d52aa188401f 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -360,15 +360,15 @@ static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) /* Attribute validation */ -int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) +int __ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr, + unsigned int type) { const struct ynl_policy_attr *policy; - unsigned int type, len; unsigned char *data; + unsigned int len; data = ynl_attr_data(attr); len = ynl_attr_data_len(attr); - type = ynl_attr_type(attr); if (type > yarg->rsp_policy->max_attr) { yerr(yarg->ys, YNL_ERROR_INTERNAL, "Internal error, validating unknown attribute"); @@ -450,6 +450,17 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) return 0; } +int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) +{ + return __ynl_attr_validate(yarg, attr, ynl_attr_type(attr)); +} + +int ynl_attr_validate_payload(struct ynl_parse_arg *yarg, + const struct nlattr *attr, unsigned int type) +{ + return __ynl_attr_validate(yarg, attr, type); +} + int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, const char *sel_name) { diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index f149c68ae84e..e93f5d724b42 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -836,7 +836,7 @@ class TypeArrayNest(Type): local_vars = ['const struct nlattr *attr2;'] get_lines = [f'attr_{self.c_name} = attr;', 'ynl_attr_for_each_nested(attr2, attr) {', - '\tif (ynl_attr_validate(yarg, attr2))', + '\tif (ynl_attr_validate_payload(yarg, attr2, type))', '\t\treturn YNL_PARSE_CB_ERROR;', f'\tn_{self.c_name}++;', '}'] -- 2.51.0 From ast at fiberby.net Thu Sep 11 00:01:55 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 00:01:55 -0000 Subject: [PATCH net-next 05/11] tools: ynl-gen: define nlattr *array in a block scope In-Reply-To: <20250906120754.7b90c718@kernel.org> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-5-ast@fiberby.net> <20250905171809.694562c6@kernel.org> <4eda9c57-bde0-43c3-b8a0-3e45f2e672ac@fiberby.net> <20250906120754.7b90c718@kernel.org> Message-ID: <3b52386e-6127-4bdc-b7db-e3c885b03f72@fiberby.net> On 9/6/25 7:07 PM, Jakub Kicinski wrote: > On Sat, 6 Sep 2025 13:13:29 +0000 Asbj?rn Sloth T?nnesen wrote: >> In patch 4, it is about a variable used by multiple Type classes having >> presence_type() = 'count', which is currently 3 classes: >> - TypeBinaryScalarArray >> - TypeMultiAttr >> - TypeArrayNest (later renamed to TypeIndexedArray) >> >> In patch 5, I move code for a special variable used by one Type class, >> to be contained within that class. It makes it easier to ensure that the >> variable is only defined, when used, and vice versa. This comes at the >> cost of the generated code looking generated. > > So you're agreeing? > >> If we should make the generated code look like it was written by humans, >> then I would move the definition of these local variables into a class >> method, so `i` can be generated by the generic implementation, and `array` >> can be implemented in it's class. I will take a stab at this, but it might >> be too much refactoring for this series, eg. `len` is also defined local >> to conditional blocks multiple branches in a row. >> >> tools/net/ynl/generated/nl80211-user.c: >> nl80211_iftype_data_attrs_parse(..) { >> [..] >> ynl_attr_for_each_nested(attr, nested) { >> unsigned int type = ynl_attr_type(attr); >> >> if (type == NL80211_BAND_IFTYPE_ATTR_IFTYPES) { >> unsigned int len; >> [..] >> } else if (type == NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC) { >> unsigned int len; >> [..] >> [same pattern 8 times, so 11 times in total] >> } else if (type == NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE) { >> unsigned int len; >> [..] >> } >> } >> return 0; >> } > > It's pretty easily doable, I already gave up on not calling _attr_get() > for sub-messages. > >> That looks very generated, I would have `len` defined together with `type`, >> and a switch statement would also look a lot more natural, but maybe leave >> the if->switch conversion for the compiler to detect. > > diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py > index fb7e03805a11..8a1f8a477566 100755 > --- a/tools/net/ynl/pyynl/ynl_gen_c.py > +++ b/tools/net/ynl/pyynl/ynl_gen_c.py > @@ -243,7 +243,7 @@ from lib import SpecSubMessage, SpecSubMessageFormat > raise Exception(f"Attr get not implemented for class type {self.type}") > > def attr_get(self, ri, var, first): > - lines, init_lines, local_vars = self._attr_get(ri, var) > + lines, init_lines, _ = self._attr_get(ri, var) > if type(lines) is str: > lines = [lines] > if type(init_lines) is str: > @@ -251,10 +251,6 @@ from lib import SpecSubMessage, SpecSubMessageFormat > > kw = 'if' if first else 'else if' > ri.cw.block_start(line=f"{kw} (type == {self.enum_name})") > - if local_vars: > - for local in local_vars: > - ri.cw.p(local) > - ri.cw.nl() > > if not self.is_multi_val(): > ri.cw.p("if (ynl_attr_validate(yarg, attr))") > @@ -2101,6 +2097,7 @@ _C_KW = { > else: > raise Exception(f"Per-op fixed header not supported, yet") > > + var_set = set() > array_nests = set() > multi_attrs = set() > needs_parg = False > @@ -2118,6 +2115,13 @@ _C_KW = { > multi_attrs.add(arg) > needs_parg |= 'nested-attributes' in aspec > needs_parg |= 'sub-message' in aspec > + > + try: > + _, _, l_vars = aspec._attr_get(ri, '') > + var_set |= set(l_vars) if l_vars else set() > + except: > + pass # _attr_get() not implemented by simple types, ignore > + local_vars += list(var_set) > if array_nests or multi_attrs: > local_vars.append('int i;') > if needs_parg: I left this for you to submit, there is a trivial conflict with patch 8 in my v2 posting. It gives a pretty nice diffstat when comparing the generated code: devlink-user.c | 187 +++---------------- dpll-user.c | 10 - ethtool-user.c | 49 +---- fou-user.c | 5 handshake-user.c | 3 mptcp_pm-user.c | 3 nfsd-user.c | 16 - nl80211-user.c | 159 +--------------- nlctrl-user.c | 21 -- ovpn-user.c | 7 ovs_datapath-user.c | 9 ovs_flow-user.c | 89 --------- ovs_vport-user.c | 7 rt-addr-user.c | 14 - rt-link-user.c | 183 ++---------------- rt-neigh-user.c | 14 - rt-route-user.c | 26 -- rt-rule-user.c | 11 - tc-user.c | 380 +++++---------------------------------- tcp_metrics-user.c | 7 team-user.c | 5 21 files changed, 175 insertions(+), 1030 deletions(-) From ast at fiberby.net Thu Sep 11 20:05:28 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:28 -0000 Subject: [PATCH net-next v3 11/13] tools: ynl: encode indexed-arrays In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-12-ast@fiberby.net> This patch adds support for encoding indexed-array attributes with sub-type nest in pyynl. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/lib/ynl.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 92ff26f34f4d..9fd83f8b091f 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -563,6 +563,11 @@ class YnlFamily(SpecFamily): nl_type |= Netlink.NLA_F_NESTED sub_space = attr['nested-attributes'] attr_payload = self._add_nest_attrs(value, sub_space, search_attrs) + elif attr['type'] == 'indexed-array' and attr['sub-type'] == 'nest': + nl_type |= Netlink.NLA_F_NESTED + sub_space = attr['nested-attributes'] + attr_payload = self._encode_indexed_array(value, sub_space, + search_attrs) elif attr["type"] == 'flag': if not value: # If value is absent or false then skip attribute creation. @@ -616,6 +621,9 @@ class YnlFamily(SpecFamily): else: raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}') + return self._add_attr_raw(nl_type, attr_payload) + + def _add_attr_raw(self, nl_type, attr_payload): pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad @@ -627,6 +635,14 @@ class YnlFamily(SpecFamily): sub_attrs) return attr_payload + def _encode_indexed_array(self, vals, sub_space, search_attrs): + attr_payload = b'' + for i, val in enumerate(vals): + idx = i | Netlink.NLA_F_NESTED + val_payload = self._add_nest_attrs(val, sub_space, search_attrs) + attr_payload += self._add_attr_raw(idx, val_payload) + return attr_payload + def _get_enum_or_unknown(self, enum, raw): try: name = enum.entries_by_val[raw].name -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:28 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:28 -0000 Subject: [PATCH net-next v3 04/13] tools: ynl-gen: refactor local vars for .attr_put() callers In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-5-ast@fiberby.net> Refactor the generation of local variables needed when building requests, by moving the logic into the Type classes, and use the same helper in all places where .attr_put() is called. If any attributes requests identical local_vars, then they will be deduplicated, attributes are assumed to only use their local variables transiently. This patch fixes the build errors below: $ make -C tools/net/ynl/generated/ [...] -e GEN wireguard-user.c -e GEN wireguard-user.h -e CC wireguard-user.o wireguard-user.c: In function ?wireguard_get_device_dump?: wireguard-user.c:480:9: error: ?array? undeclared (first use in func) 480 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); | ^~~~~ wireguard-user.c:480:9: note: each undeclared identifier is reported only once for each function it appears in wireguard-user.c:481:14: error: ?i? undeclared (first use in func) 481 | for (i = 0; i < req->_count.peers; i++) | ^ wireguard-user.c: In function ?wireguard_set_device?: wireguard-user.c:533:9: error: ?array? undeclared (first use in func) 533 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); | ^~~~~ make: *** [Makefile:52: wireguard-user.o] Error 1 make: Leaving directory '/usr/src/linux/tools/net/ynl/generated' Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 35 ++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 3266af19edcd..e4cb8c95632c 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -235,6 +235,12 @@ class Type(SpecAttr): line = f"ynl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name})" self._attr_put_line(ri, var, line) + def attr_put_local_vars(self): + local_vars = [] + if self.presence_type() == 'count': + local_vars.append('unsigned int i;') + return local_vars + def attr_put(self, ri, var): raise Exception(f"Put not implemented for class type {self.type}") @@ -840,6 +846,10 @@ class TypeArrayNest(Type): '}'] return get_lines, None, local_vars + def attr_put_local_vars(self): + local_vars = ['struct nlattr *array;'] + return local_vars + super().attr_put_local_vars() + def attr_put(self, ri, var): ri.cw.p(f'array = ynl_attr_nest_start(nlh, {self.enum_name});') if self.sub_type in scalars: @@ -2040,6 +2050,13 @@ def put_enum_to_str(family, cw, enum): _put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum) +def put_local_vars(struct): + local_vars = set() + for _, attr in struct.member_list(): + local_vars |= set(attr.attr_put_local_vars()) + return list(local_vars) + + def put_req_nested_prototype(ri, struct, suffix=';'): func_args = ['struct nlmsghdr *nlh', 'unsigned int attr_type', @@ -2062,15 +2079,7 @@ def put_req_nested(ri, struct): init_lines.append(f"hdr = ynl_nlmsg_put_extra_header(nlh, {struct_sz});") init_lines.append(f"memcpy(hdr, &obj->_hdr, {struct_sz});") - has_anest = False - has_count = False - for _, arg in struct.member_list(): - has_anest |= arg.type == 'indexed-array' - has_count |= arg.presence_type() == 'count' - if has_anest: - local_vars.append('struct nlattr *array;') - if has_count: - local_vars.append('unsigned int i;') + local_vars += put_local_vars(struct) put_req_nested_prototype(ri, struct, suffix='') ri.cw.block_start() @@ -2354,10 +2363,7 @@ def print_req(ri): local_vars += ['size_t hdr_len;', 'void *hdr;'] - for _, attr in ri.struct["request"].member_list(): - if attr.presence_type() == 'count': - local_vars += ['unsigned int i;'] - break + local_vars += put_local_vars(ri.struct["request"]) print_prototype(ri, direction, terminate=False) ri.cw.block_start() @@ -2424,6 +2430,9 @@ def print_dump(ri): local_vars += ['size_t hdr_len;', 'void *hdr;'] + if "request" in ri.op[ri.op_mode]: + local_vars += put_local_vars(ri.struct["request"]) + ri.cw.write_func_lvar(local_vars) ri.cw.p('yds.yarg.ys = ys;') -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:28 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:28 -0000 Subject: [PATCH net-next v3 01/13] tools: ynl-gen: allow overriding name-prefix for constants In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-2-ast@fiberby.net> Allow using custom name-prefix with constants, just like it is for enum and flags declarations. This is needed for generating WG_KEY_LEN in include/uapi/linux/wireguard.h from a spec. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski Reviewed-by: Jacob Keller --- tools/net/ynl/pyynl/ynl_gen_c.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 101d8ba9626f..c8b15569ecc1 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -3208,8 +3208,9 @@ def render_uapi(family, cw): cw.block_end(line=';') cw.nl() elif const['type'] == 'const': + name_pfx = const.get('name-prefix', f"{family.ident_name}-") defines.append([c_upper(family.get('c-define-name', - f"{family.ident_name}-{const['name']}")), + f"{name_pfx}{const['name']}")), const['value']]) if defines: -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:28 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:28 -0000 Subject: [PATCH net-next v3 00/13] tools: ynl: prepare for wireguard Message-ID: <20250911200508.79341-1-ast@fiberby.net> This series contains the last batch of YNL changes to support the wireguard YNL conversion. The wireguard changes, to be applied on top of this series, has been posted as an RFC series here: https://lore.kernel.org/netdev/20250904-wg-ynl-rfc at fiberby.net/ --- v3: - Rebased on top of new net-next, after Matthieu's cleanup. - Added a Reviewed-by (thanks Donald). - Added the parsing local vars cleanup as patch 7 - In patch 4, change to use set() for deduplication. - In patch 8, declare __ynl_attr_validate() as static. v2: https://lore.kernel.org/netdev/20250910230841.384545-1-ast at fiberby.net/ - Added Reviewed-by's to unchanged patches. Thanks to all reviewers. - Patch 4, refactors local variables for .attr_put() callers, and replaces the old patch 4 and 5. - Patch 5 and 6 are new, and reduces the differences between the 3 .attr_put() callers, so it might be easier to keep them in sync. - Patch 7, now validates the nested payload (thanks Jakub). - Patch 8, now renames more variables (thanks Jakub), - Patch 10, got a dead line removed (thanks Donald). - Patch 11, revised hex input to support macsec (suggested by Sabrina). v1: https://lore.kernel.org/netdev/20250904-wg-ynl-prep at fiberby.net/ Asbj?rn Sloth T?nnesen (13): tools: ynl-gen: allow overriding name-prefix for constants tools: ynl-gen: generate nested array policies tools: ynl-gen: add sub-type check tools: ynl-gen: refactor local vars for .attr_put() callers tools: ynl-gen: add CodeWriter.p_lines() helper tools: ynl-gen: deduplicate fixed_header handling tools: ynl-gen: avoid repetitive variables definitions tools: ynl-gen: only validate nested array payload tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray tools: ynl: move nest packing to a helper function tools: ynl: encode indexed-arrays tools: ynl: decode hex input tools: ynl: add ipv4-or-v6 display hint Documentation/netlink/genetlink-legacy.yaml | 2 +- tools/net/ynl/lib/ynl-priv.h | 2 + tools/net/ynl/lib/ynl.c | 17 +- tools/net/ynl/pyynl/lib/ynl.py | 38 ++++- tools/net/ynl/pyynl/ynl_gen_c.py | 164 +++++++++++--------- 5 files changed, 140 insertions(+), 83 deletions(-) -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:29 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:29 -0000 Subject: [PATCH net-next v3 12/13] tools: ynl: decode hex input In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-13-ast@fiberby.net> This patch adds support for decoding hex input, so that binary attributes can be read through --json. Example (using future wireguard.yaml): $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ --do set-device --json '{"ifindex":3, "private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}' In order to somewhat mirror what is done in _formatted_string(), then for non-binary attributes attempt to convert it to an int. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/lib/ynl.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 9fd83f8b091f..707753e371e2 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -971,6 +971,11 @@ class YnlFamily(SpecFamily): raw = ip.packed else: raw = int(ip) + elif attr_spec.display_hint == 'hex': + if attr_spec['type'] == 'binary': + raw = bytes.fromhex(string) + else: + raw = int(string, 16) else: raise Exception(f"Display hint '{attr_spec.display_hint}' not implemented" f" when parsing '{attr_spec['name']}'") -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:30 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:30 -0000 Subject: [PATCH net-next v3 05/13] tools: ynl-gen: add CodeWriter.p_lines() helper In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-6-ast@fiberby.net> Add a helper for writing an array of lines, and convert all the existing loops doing that, to use the new helper. This is a trivial patch with no behavioural changes intended, there are no changes to the generated code. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/ynl_gen_c.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index e4cb8c95632c..7a2e49a84735 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -180,8 +180,7 @@ class Type(SpecAttr): def free(self, ri, var, ref): lines = self._free_lines(ri, var, ref) - for line in lines: - ri.cw.p(line) + ri.cw.p_lines(lines) def arg_member(self, ri): member = self._complex_member_type(ri) @@ -267,13 +266,9 @@ class Type(SpecAttr): if self.presence_type() == 'present': ri.cw.p(f"{var}->_present.{self.c_name} = 1;") - if init_lines: - ri.cw.nl() - for line in init_lines: - ri.cw.p(line) + ri.cw.p_lines(init_lines, nl_before=True) - for line in lines: - ri.cw.p(line) + ri.cw.p_lines(lines) ri.cw.block_end() return True @@ -1788,8 +1783,7 @@ class CodeWriter: self.block_start() self.write_func_lvar(local_vars=local_vars) - for line in body: - self.p(line) + self.p_lines(body) self.block_end() def writes_defines(self, defines): @@ -1830,6 +1824,12 @@ class CodeWriter: self.p('#ifdef ' + config_option) self._ifdef_block = config_option + def p_lines(self, lines, nl_before=False): + if lines and nl_before: + self.nl() + for line in lines or []: + self.p(line) + scalars = {'u8', 'u16', 'u32', 'u64', 's8', 's16', 's32', 's64', 'uint', 'sint'} @@ -2085,8 +2085,7 @@ def put_req_nested(ri, struct): ri.cw.block_start() ri.cw.write_func_lvar(local_vars) - for line in init_lines: - ri.cw.p(line) + ri.cw.p_lines(init_lines) for _, arg in struct.member_list(): arg.attr_put(ri, "obj") @@ -2147,8 +2146,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.block_start() ri.cw.write_func_lvar(local_vars) - for line in init_lines: - ri.cw.p(line) + ri.cw.p_lines(init_lines) ri.cw.nl() for arg in struct.inherited: @@ -2277,10 +2275,8 @@ def parse_rsp_submsg(ri, struct): ri.cw.block_start(line=f'{kw} (!strcmp(sel, "{name}"))') get_lines, init_lines, _ = arg._attr_get(ri, var) - for line in init_lines or []: - ri.cw.p(line) - for line in get_lines: - ri.cw.p(line) + ri.cw.p_lines(init_lines) + ri.cw.p_lines(get_lines) if arg.presence_type() == 'present': ri.cw.p(f"{var}->_present.{arg.c_name} = 1;") ri.cw.block_end() -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:30 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:30 -0000 Subject: [PATCH net-next v3 07/13] tools: ynl-gen: avoid repetitive variables definitions In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-8-ast@fiberby.net> In the generated attribute parsing code, avoid repetitively defining the same variables over and over again, local to the conditional block for each attribute. This patch consolidates the definitions of local variables for attribute parsing, so that they are defined at the function level, and re-used across attributes, thus making the generated code read more natural. If attributes defines identical local_vars, then they will be deduplicated, attributes are assumed to only use their local variables transiently. The example below shows how `len` was defined repeatedly in tools/net/ynl/generated/nl80211-user.c: nl80211_iftype_data_attrs_parse(..) { [..] ynl_attr_for_each_nested(attr, nested) { unsigned int type = ynl_attr_type(attr); if (type == NL80211_BAND_IFTYPE_ATTR_IFTYPES) { unsigned int len; [..] } else if (type == NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC) { unsigned int len; [..] [same pattern 8 times, so 11 times in total] } else if (type == NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE) { unsigned int len; [..] } } return 0; } This patch results in this diffstat for the generated code: $ diff -Naur pre/ post/ | diffstat devlink-user.c | 187 +++---------------- dpll-user.c | 10 - ethtool-user.c | 49 +---- fou-user.c | 5 handshake-user.c | 3 mptcp_pm-user.c | 3 nfsd-user.c | 16 - nl80211-user.c | 159 +--------------- nlctrl-user.c | 21 -- ovpn-user.c | 7 ovs_datapath-user.c | 9 ovs_flow-user.c | 89 --------- ovs_vport-user.c | 7 rt-addr-user.c | 14 - rt-link-user.c | 183 ++---------------- rt-neigh-user.c | 14 - rt-route-user.c | 26 -- rt-rule-user.c | 11 - tc-user.c | 380 +++++---------------------------------- tcp_metrics-user.c | 7 team-user.c | 5 21 files changed, 175 insertions(+), 1030 deletions(-) The changed lines are mostly `unsigned int len;` definitions: $ diff -Naur pre/ post/ | grep ^[-+] | grep -v '^[-+]\{3\}' | grep -v '^.$' | sed -e 's/\t\+/ /g' | sort | uniq -c | sort -nr 488 - unsigned int len; 153 + unsigned int len; 24 - const struct nlattr *attr2; 18 + const struct nlattr *attr2; 1 - __u32 policy_id, attr_id; 1 + __u32 policy_id, attr_id; 1 - __u32 op_id; 1 + __u32 op_id; 1 - const struct nlattr *attr_policy_id, *attr_attr_id; 1 + const struct nlattr *attr_policy_id, *attr_attr_id; 1 - const struct nlattr *attr_op_id; 1 + const struct nlattr *attr_op_id; Suggested-by: Jakub Kicinski Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index b3ce0901a19b..d63b63ac0b8e 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -247,7 +247,7 @@ class Type(SpecAttr): raise Exception(f"Attr get not implemented for class type {self.type}") def attr_get(self, ri, var, first): - lines, init_lines, local_vars = self._attr_get(ri, var) + lines, init_lines, _ = self._attr_get(ri, var) if type(lines) is str: lines = [lines] if type(init_lines) is str: @@ -255,10 +255,6 @@ class Type(SpecAttr): kw = 'if' if first else 'else if' ri.cw.block_start(line=f"{kw} (type == {self.enum_name})") - if local_vars: - for local in local_vars: - ri.cw.p(local) - ri.cw.nl() if not self.is_multi_val(): ri.cw.p("if (ynl_attr_validate(yarg, attr))") @@ -2124,6 +2120,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): else: raise Exception("Per-op fixed header not supported, yet") + var_set = set() array_nests = set() multi_attrs = set() needs_parg = False @@ -2141,6 +2138,13 @@ def _multi_parse(ri, struct, init_lines, local_vars): multi_attrs.add(arg) needs_parg |= 'nested-attributes' in aspec needs_parg |= 'sub-message' in aspec + + try: + _, _, l_vars = aspec._attr_get(ri, '') + var_set |= set(l_vars) if l_vars else set() + except Exception: + pass # _attr_get() not implemented by simple types, ignore + local_vars += list(var_set) if array_nests or multi_attrs: local_vars.append('int i;') if needs_parg: -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:30 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:30 -0000 Subject: [PATCH net-next v3 03/13] tools: ynl-gen: add sub-type check In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-4-ast@fiberby.net> Add a check to verify that the sub-type is "nest", and throw an exception if no policy could be generated, as a guard to prevent against generating a bad policy. This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski Reviewed-by: Jacob Keller --- tools/net/ynl/pyynl/ynl_gen_c.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 95a60fdaf14e..3266af19edcd 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -825,8 +825,10 @@ class TypeArrayNest(Type): return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, ' elif self.attr['sub-type'] == 'binary' and 'exact-len' in self.checks: return f'.type = YNL_PT_BINARY, .len = {self.checks["exact-len"]}, ' - else: + elif self.attr['sub-type'] == 'nest': return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' + else: + raise Exception(f"Typol for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") def _attr_get(self, ri, var): local_vars = ['const struct nlattr *attr2;'] -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:30 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:30 -0000 Subject: [PATCH net-next v3 08/13] tools: ynl-gen: only validate nested array payload In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-9-ast@fiberby.net> In nested arrays don't require that the intermediate attribute type should be a valid attribute type, it might just be zero or an incrementing index, it is often not even used. See include/net/netlink.h about NLA_NESTED_ARRAY: > The difference to NLA_NESTED is the structure: > NLA_NESTED has the nested attributes directly inside > while an array has the nested attributes at another > level down and the attribute types directly in the > nesting don't matter. Example based on include/uapi/linux/wireguard.h: > WGDEVICE_A_PEERS: NLA_NESTED > 0: NLA_NESTED > WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN > [..] > 0: NLA_NESTED > ... > ... Previous the check required that the nested type was valid in the parent attribute set, which in this case resolves to WGDEVICE_A_UNSPEC, which is YNL_PT_REJECT, and it took the early exit and returned YNL_PARSE_CB_ERROR. This patch adds a new helper, ynl_attr_validate_payload(), which we can use to validate the payload of the nested attribute, in the context of the parents attribute type, and it's policy, which in the above case is generated as: [WGDEVICE_A_PEERS] = { .name = "peers", .type = YNL_PT_NEST, .nest = &wireguard_wgpeer_nest, }, Some other examples are NL80211_BAND_ATTR_FREQS (nest) and NL80211_ATTR_SUPPORTED_COMMANDS (u32). Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/lib/ynl-priv.h | 2 ++ tools/net/ynl/lib/ynl.c | 17 ++++++++++++++--- tools/net/ynl/pyynl/ynl_gen_c.py | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index 824777d7e05e..70ea14c0a0e9 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -107,6 +107,8 @@ struct nlmsghdr * ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); +int ynl_attr_validate_payload(struct ynl_parse_arg *yarg, + const struct nlattr *attr, unsigned int type); int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, const char *sel_name); diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 2a169c3c0797..0daf39229587 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -360,15 +360,15 @@ static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) /* Attribute validation */ -int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) +static int __ynl_attr_validate(struct ynl_parse_arg *yarg, + const struct nlattr *attr, unsigned int type) { const struct ynl_policy_attr *policy; - unsigned int type, len; unsigned char *data; + unsigned int len; data = ynl_attr_data(attr); len = ynl_attr_data_len(attr); - type = ynl_attr_type(attr); if (type > yarg->rsp_policy->max_attr) { yerr(yarg->ys, YNL_ERROR_INTERNAL, "Internal error, validating unknown attribute"); @@ -450,6 +450,17 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) return 0; } +int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) +{ + return __ynl_attr_validate(yarg, attr, ynl_attr_type(attr)); +} + +int ynl_attr_validate_payload(struct ynl_parse_arg *yarg, + const struct nlattr *attr, unsigned int type) +{ + return __ynl_attr_validate(yarg, attr, type); +} + int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, const char *sel_name) { diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index d63b63ac0b8e..ab5b8d98cbda 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -831,7 +831,7 @@ class TypeArrayNest(Type): local_vars = ['const struct nlattr *attr2;'] get_lines = [f'attr_{self.c_name} = attr;', 'ynl_attr_for_each_nested(attr2, attr) {', - '\tif (ynl_attr_validate(yarg, attr2))', + '\tif (ynl_attr_validate_payload(yarg, attr2, type))', '\t\treturn YNL_PARSE_CB_ERROR;', f'\tn_{self.c_name}++;', '}'] -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:30 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:30 -0000 Subject: [PATCH net-next v3 06/13] tools: ynl-gen: deduplicate fixed_header handling In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-7-ast@fiberby.net> Fixed headers are handled nearly identical in print_dump(), print_req() and put_req_nested(), generalize them and use a common function to generate them. This only causes cosmetic changes to tc_netem_attrs_put() in tc-user.c. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 39 ++++++++++++++++---------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 7a2e49a84735..b3ce0901a19b 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -1828,7 +1828,10 @@ class CodeWriter: if lines and nl_before: self.nl() for line in lines or []: - self.p(line) + if line == '': + self.nl() + else: + self.p(line) scalars = {'u8', 'u16', 'u32', 'u64', 's8', 's16', 's32', 's64', 'uint', 'sint'} @@ -1921,6 +1924,15 @@ def type_name(ri, direction, deref=False): return f"struct {op_prefix(ri, direction, deref=deref)}" +def prepare_fixed_header(var, local_vars, init_lines): + local_vars += ['size_t hdr_len;', + 'void *hdr;'] + init_lines += [f'hdr_len = sizeof({var}->_hdr);', + 'hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);', + f'memcpy(hdr, &{var}->_hdr, hdr_len);', + ''] + + def print_prototype(ri, direction, terminate=True, doc=None): suffix = ';' if terminate else '' @@ -2074,10 +2086,7 @@ def put_req_nested(ri, struct): local_vars.append('struct nlattr *nest;') init_lines.append("nest = ynl_attr_nest_start(nlh, attr_type);") if struct.fixed_header: - local_vars.append('void *hdr;') - struct_sz = f'sizeof({struct.fixed_header})' - init_lines.append(f"hdr = ynl_nlmsg_put_extra_header(nlh, {struct_sz});") - init_lines.append(f"memcpy(hdr, &obj->_hdr, {struct_sz});") + prepare_fixed_header('obj', local_vars, init_lines) local_vars += put_local_vars(struct) @@ -2346,6 +2355,7 @@ def print_req(ri): ret_ok = '0' ret_err = '-1' direction = "request" + init_lines = [] local_vars = ['struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };', 'struct nlmsghdr *nlh;', 'int err;'] @@ -2356,8 +2366,7 @@ def print_req(ri): local_vars += [f'{type_name(ri, rdir(direction))} *rsp;'] if ri.struct["request"].fixed_header: - local_vars += ['size_t hdr_len;', - 'void *hdr;'] + prepare_fixed_header('req', local_vars, init_lines) local_vars += put_local_vars(ri.struct["request"]) @@ -2376,11 +2385,7 @@ def print_req(ri): ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;") ri.cw.nl() - if ri.struct['request'].fixed_header: - ri.cw.p("hdr_len = sizeof(req->_hdr);") - ri.cw.p("hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);") - ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);") - ri.cw.nl() + ri.cw.p_lines(init_lines) for _, attr in ri.struct["request"].member_list(): attr.attr_put(ri, "req") @@ -2418,13 +2423,13 @@ def print_dump(ri): direction = "request" print_prototype(ri, direction, terminate=False) ri.cw.block_start() + init_lines = [] local_vars = ['struct ynl_dump_state yds = {};', 'struct nlmsghdr *nlh;', 'int err;'] if ri.struct['request'].fixed_header: - local_vars += ['size_t hdr_len;', - 'void *hdr;'] + prepare_fixed_header('req', local_vars, init_lines) if "request" in ri.op[ri.op_mode]: local_vars += put_local_vars(ri.struct["request"]) @@ -2446,11 +2451,7 @@ def print_dump(ri): else: ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") - if ri.struct['request'].fixed_header: - ri.cw.p("hdr_len = sizeof(req->_hdr);") - ri.cw.p("hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);") - ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);") - ri.cw.nl() + ri.cw.p_lines(init_lines) if "request" in ri.op[ri.op_mode]: ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;") -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:31 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:31 -0000 Subject: [PATCH net-next v3 09/13] tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-10-ast@fiberby.net> Since TypeArrayNest can now be used with many other sub-types than nest, then rename it to TypeIndexedArray, to reduce confusion. This patch continues the rename, that was started in commit aa6485d813ad ("ynl: rename array-nest to indexed-array"), when the YNL type was renamed. In order to get rid of all references to the old naming, within ynl, then renaming some variables in _multi_parse(). This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index ab5b8d98cbda..2c5787b518f0 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -788,7 +788,7 @@ class TypeMultiAttr(Type): f"{presence} = n_{self.c_name};"] -class TypeArrayNest(Type): +class TypeIndexedArray(Type): def is_multi_val(self): return True @@ -825,7 +825,7 @@ class TypeArrayNest(Type): elif self.attr['sub-type'] == 'nest': return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' else: - raise Exception(f"Typol for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") + raise Exception(f"Typol for IndexedArray sub-type {self.attr['sub-type']} not supported, yet") def _attr_get(self, ri, var): local_vars = ['const struct nlattr *attr2;'] @@ -855,7 +855,7 @@ class TypeArrayNest(Type): ri.cw.p(f'for (i = 0; i < {var}->_count.{self.c_name}; i++)') ri.cw.p(f"{self.nested_render_name}_put(nlh, i, &{var}->{self.c_name}[i]);") else: - raise Exception(f"Put for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") + raise Exception(f"Put for IndexedArray sub-type {self.attr['sub-type']} not supported, yet") ri.cw.p('ynl_attr_nest_end(nlh, array);') def _setter_lines(self, ri, member, presence): @@ -1132,7 +1132,7 @@ class AttrSet(SpecAttrSet): t = TypeNest(self.family, self, elem, value) elif elem['type'] == 'indexed-array' and 'sub-type' in elem: if elem["sub-type"] in ['binary', 'nest', 'u32']: - t = TypeArrayNest(self.family, self, elem, value) + t = TypeIndexedArray(self.family, self, elem, value) else: raise Exception(f'new_attr: unsupported sub-type {elem["sub-type"]}') elif elem['type'] == 'nest-type-value': @@ -2120,18 +2120,18 @@ def _multi_parse(ri, struct, init_lines, local_vars): else: raise Exception("Per-op fixed header not supported, yet") - var_set = set() - array_nests = set() + indexed_arrays = set() multi_attrs = set() needs_parg = False + var_set = set() for arg, aspec in struct.member_list(): if aspec['type'] == 'indexed-array' and 'sub-type' in aspec: if aspec["sub-type"] in {'binary', 'nest'}: local_vars.append(f'const struct nlattr *attr_{aspec.c_name};') - array_nests.add(arg) + indexed_arrays.add(arg) elif aspec['sub-type'] in scalars: local_vars.append(f'const struct nlattr *attr_{aspec.c_name};') - array_nests.add(arg) + indexed_arrays.add(arg) else: raise Exception(f'Not supported sub-type {aspec["sub-type"]}') if 'multi-attr' in aspec: @@ -2145,16 +2145,16 @@ def _multi_parse(ri, struct, init_lines, local_vars): except Exception: pass # _attr_get() not implemented by simple types, ignore local_vars += list(var_set) - if array_nests or multi_attrs: + if indexed_arrays or multi_attrs: local_vars.append('int i;') if needs_parg: local_vars.append('struct ynl_parse_arg parg;') init_lines.append('parg.ys = yarg->ys;') - all_multi = array_nests | multi_attrs + all_multi = indexed_arrays | multi_attrs - for anest in sorted(all_multi): - local_vars.append(f"unsigned int n_{struct[anest].c_name} = 0;") + for arg in sorted(all_multi): + local_vars.append(f"unsigned int n_{struct[arg].c_name} = 0;") ri.cw.block_start() ri.cw.write_func_lvar(local_vars) @@ -2173,8 +2173,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): else: ri.cw.p('hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr));') ri.cw.p(f"memcpy(&dst->_hdr, hdr, sizeof({struct.fixed_header}));") - for anest in sorted(all_multi): - aspec = struct[anest] + for arg in sorted(all_multi): + aspec = struct[arg] ri.cw.p(f"if (dst->{aspec.c_name})") ri.cw.p(f'return ynl_error_parse(yarg, "attribute already present ({struct.attr_set.name}.{aspec.name})");') @@ -2192,8 +2192,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.block_end() ri.cw.nl() - for anest in sorted(array_nests): - aspec = struct[anest] + for arg in sorted(indexed_arrays): + aspec = struct[arg] ri.cw.block_start(line=f"if (n_{aspec.c_name})") ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") @@ -2218,8 +2218,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.block_end() ri.cw.nl() - for anest in sorted(multi_attrs): - aspec = struct[anest] + for arg in sorted(multi_attrs): + aspec = struct[arg] ri.cw.block_start(line=f"if (n_{aspec.c_name})") ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") ri.cw.p(f"dst->_count.{aspec.c_name} = n_{aspec.c_name};") -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:31 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:31 -0000 Subject: [PATCH net-next v3 02/13] tools: ynl-gen: generate nested array policies In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-3-ast@fiberby.net> This patch adds support for NLA_POLICY_NESTED_ARRAY() policies. Example spec (from future wireguard.yaml): - name: wgpeer attributes: - name: allowedips type: indexed-array sub-type: nest nested-attributes: wgallowedip yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy). This doesn't change any currently generated code, as it isn't used in any specs currently used for generating code. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski --- tools/net/ynl/pyynl/ynl_gen_c.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index c8b15569ecc1..95a60fdaf14e 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -815,6 +815,11 @@ class TypeArrayNest(Type): f'unsigned int n_{self.c_name}'] return super().arg_member(ri) + def _attr_policy(self, policy): + if self.attr['sub-type'] == 'nest': + return f'NLA_POLICY_NESTED_ARRAY({self.nested_render_name}_nl_policy)' + return super()._attr_policy(policy) + def _attr_typol(self): if self.attr['sub-type'] in scalars: return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, ' -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:31 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:31 -0000 Subject: [PATCH net-next v3 10/13] tools: ynl: move nest packing to a helper function In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-11-ast@fiberby.net> This patch moves nest packing into a helper function, that can also be used for packing indexed arrays. No behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/lib/ynl.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 50805e05020a..92ff26f34f4d 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -561,11 +561,8 @@ class YnlFamily(SpecFamily): if attr["type"] == 'nest': nl_type |= Netlink.NLA_F_NESTED - attr_payload = b'' sub_space = attr['nested-attributes'] - sub_attrs = SpaceAttrs(self.attr_sets[sub_space], value, search_attrs) - for subname, subvalue in value.items(): - attr_payload += self._add_attr(sub_space, subname, subvalue, sub_attrs) + attr_payload = self._add_nest_attrs(value, sub_space, search_attrs) elif attr["type"] == 'flag': if not value: # If value is absent or false then skip attribute creation. @@ -622,6 +619,14 @@ class YnlFamily(SpecFamily): pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad + def _add_nest_attrs(self, value, sub_space, search_attrs): + sub_attrs = SpaceAttrs(self.attr_sets[sub_space], value, search_attrs) + attr_payload = b'' + for subname, subvalue in value.items(): + attr_payload += self._add_attr(sub_space, subname, subvalue, + sub_attrs) + return attr_payload + def _get_enum_or_unknown(self, enum, raw): try: name = enum.entries_by_val[raw].name -- 2.51.0 From ast at fiberby.net Thu Sep 11 20:05:31 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Thu, 11 Sep 2025 20:05:31 -0000 Subject: [PATCH net-next v3 13/13] tools: ynl: add ipv4-or-v6 display hint In-Reply-To: <20250911200508.79341-1-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> Message-ID: <20250911200508.79341-14-ast@fiberby.net> The attribute WGALLOWEDIP_A_IPADDR can contain either an IPv4 or an IPv6 address depending on WGALLOWEDIP_A_FAMILY, however in practice it is enough to look at the attribute length. This patch implements an ipv4-or-v6 display hint, that can deal with this kind of attribute. It only implements this display hint for genetlink-legacy, it can be added to other protocol variants if needed, but we don't want to encourage it's use. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- Documentation/netlink/genetlink-legacy.yaml | 2 +- tools/net/ynl/pyynl/lib/ynl.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index b29d62eefa16..66fb8653a344 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -154,7 +154,7 @@ properties: Optional format indicator that is intended only for choosing the right formatting mechanism when displaying values of this type. - enum: [ hex, mac, fddi, ipv4, ipv6, uuid ] + enum: [ hex, mac, fddi, ipv4, ipv6, ipv4-or-v6, uuid ] struct: description: Name of the nested struct type. type: string diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 707753e371e2..62383c70ebb9 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -956,7 +956,7 @@ class YnlFamily(SpecFamily): formatted = hex(raw) else: formatted = bytes.hex(raw, ' ') - elif display_hint in [ 'ipv4', 'ipv6' ]: + elif display_hint in [ 'ipv4', 'ipv6', 'ipv4-or-v6' ]: formatted = format(ipaddress.ip_address(raw)) elif display_hint == 'uuid': formatted = str(uuid.UUID(bytes=raw)) @@ -965,7 +965,7 @@ class YnlFamily(SpecFamily): return formatted def _from_string(self, string, attr_spec): - if attr_spec.display_hint in ['ipv4', 'ipv6']: + if attr_spec.display_hint in ['ipv4', 'ipv6', 'ipv4-or-v6']: ip = ipaddress.ip_address(string) if attr_spec['type'] == 'binary': raw = ip.packed -- 2.51.0 From ast at fiberby.net Sat Sep 13 23:14:50 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:14:50 -0000 Subject: [PATCH net-next v3 06/13] tools: ynl-gen: deduplicate fixed_header handling In-Reply-To: <20250912172418.1271771d@kernel.org> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-7-ast@fiberby.net> <20250912172418.1271771d@kernel.org> Message-ID: On 9/13/25 12:24 AM, Jakub Kicinski wrote: > On Thu, 11 Sep 2025 20:04:59 +0000 Asbj?rn Sloth T?nnesen wrote: >> Fixed headers are handled nearly identical in print_dump(), >> print_req() and put_req_nested(), generalize them and use a >> common function to generate them. >> >> This only causes cosmetic changes to tc_netem_attrs_put() in >> tc-user.c. >> >> Signed-off-by: Asbj?rn Sloth T?nnesen >> --- >> tools/net/ynl/pyynl/ynl_gen_c.py | 39 ++++++++++++++++---------------- >> 1 file changed, 20 insertions(+), 19 deletions(-) > > This only makes the code longer and harder to follow. We have 3 functions using put_attr(): * put_req_nested() * print_req() * print_dump() I was just trying to align them a bit more so that they don't do the same thing in three different ways. I would prefer to make these functions more aligned, as it will hopefully make it easier avoid issue like the missing local variables for .attr_put(). I agree these clean up patches would also fit better in a dedicated cleanup series, the only reason that I added this to this series, was because you pushed back, then I said that the `len` dedup, and other "make code look natural" cleanups might not be for this series. I have dropped this patch in v4, it's not important for this series. From ast at fiberby.net Sat Sep 13 23:14:50 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:14:50 -0000 Subject: [PATCH net-next v3 08/13] tools: ynl-gen: only validate nested array payload In-Reply-To: <20250912172742.3a41b81e@kernel.org> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-9-ast@fiberby.net> <20250912172742.3a41b81e@kernel.org> Message-ID: <9211971b-a392-4568-b147-d7e97c69ca54@fiberby.net> On 9/13/25 12:27 AM, Jakub Kicinski wrote: > On Thu, 11 Sep 2025 20:05:01 +0000 Asbj?rn Sloth T?nnesen wrote: >> +int ynl_attr_validate_payload(struct ynl_parse_arg *yarg, >> + const struct nlattr *attr, unsigned int type) >> +{ >> + return __ynl_attr_validate(yarg, attr, type); >> +} > > Why not expose __ynl_attr_validate() to the callers? > I don't think the _payload() suffix is crystal clear, we're still > validating attr, _payload() makes it sound like we're validating > what's inside attr? I didn't wanna call __ynl_attr_validate() directly, as the only __ynl_* function in ynl-priv.h is __ynl_attr_put_overflow(), and that is only used in other static functions within that file. I agree, that _payload() might not be the best given that we currently don't look deeper than validating that the length a bit, so maybe _length() would have been better. In v4, I have changed it to just expose __ynl_attr_validate() in ynl-priv.h, and changed ynl_attr_validate() to an inline function. From ast at fiberby.net Sat Sep 13 23:14:51 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:14:51 -0000 Subject: [PATCH net-next v3 04/13] tools: ynl-gen: refactor local vars for .attr_put() callers In-Reply-To: <20250912171954.7c020c60@kernel.org> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-5-ast@fiberby.net> <20250912171954.7c020c60@kernel.org> Message-ID: <254c0f1c-da49-4ba4-a36b-a79753316662@fiberby.net> On 9/13/25 12:19 AM, Jakub Kicinski wrote: > On Thu, 11 Sep 2025 20:04:57 +0000 Asbj?rn Sloth T?nnesen wrote: >> + def attr_put_local_vars(self): >> + local_vars = [] >> + if self.presence_type() == 'count': >> + local_vars.append('unsigned int i;') >> + return local_vars >> + >> def attr_put(self, ri, var): >> raise Exception(f"Put not implemented for class type {self.type}") >> >> @@ -840,6 +846,10 @@ class TypeArrayNest(Type): >> '}'] >> return get_lines, None, local_vars >> >> + def attr_put_local_vars(self): >> + local_vars = ['struct nlattr *array;'] >> + return local_vars + super().attr_put_local_vars() > > Doesn't feel right. The Type method is a helper which is compatible > with the specific types by checking presence, then you override it, > and on top of that combine the output with super(). I don't like. I prefer to keep the array variable as a detail isolated to TypeArrayNest, so I have given it another spin in v4. From ast at fiberby.net Sat Sep 13 23:14:51 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:14:51 -0000 Subject: [PATCH net-next v3 05/13] tools: ynl-gen: add CodeWriter.p_lines() helper In-Reply-To: <20250912172124.57f96054@kernel.org> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-6-ast@fiberby.net> <20250912172124.57f96054@kernel.org> Message-ID: <32fde530-f462-4ccf-99bf-7ee1e192b76a@fiberby.net> On 9/13/25 12:21 AM, Jakub Kicinski wrote: > On Thu, 11 Sep 2025 20:04:58 +0000 Asbj?rn Sloth T?nnesen wrote: >> Add a helper for writing an array of lines, and convert >> all the existing loops doing that, to use the new helper. >> >> This is a trivial patch with no behavioural changes intended, >> there are no changes to the generated code. > > I don't see the need for this. Ok, loop macros are only for C, not Python. :) I have dropped this patch in v4, as it's not important for this series. From ast at fiberby.net Sat Sep 13 23:59:13 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:59:13 -0000 Subject: [PATCH net-next v4 10/11] tools: ynl: decode hex input In-Reply-To: <20250913235847.358851-1-ast@fiberby.net> References: <20250913235847.358851-1-ast@fiberby.net> Message-ID: <20250913235847.358851-11-ast@fiberby.net> This patch adds support for decoding hex input, so that binary attributes can be read through --json. Example (using future wireguard.yaml): $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ --do set-device --json '{"ifindex":3, "private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}' In order to somewhat mirror what is done in _formatted_string(), then for non-binary attributes attempt to convert it to an int. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/lib/ynl.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 9fd83f8b091f..707753e371e2 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -971,6 +971,11 @@ class YnlFamily(SpecFamily): raw = ip.packed else: raw = int(ip) + elif attr_spec.display_hint == 'hex': + if attr_spec['type'] == 'binary': + raw = bytes.fromhex(string) + else: + raw = int(string, 16) else: raise Exception(f"Display hint '{attr_spec.display_hint}' not implemented" f" when parsing '{attr_spec['name']}'") -- 2.51.0 From ast at fiberby.net Sat Sep 13 23:59:13 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:59:13 -0000 Subject: [PATCH net-next v4 03/11] tools: ynl-gen: add sub-type check In-Reply-To: <20250913235847.358851-1-ast@fiberby.net> References: <20250913235847.358851-1-ast@fiberby.net> Message-ID: <20250913235847.358851-4-ast@fiberby.net> Add a check to verify that the sub-type is "nest", and throw an exception if no policy could be generated, as a guard to prevent against generating a bad policy. This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski Reviewed-by: Jacob Keller --- tools/net/ynl/pyynl/ynl_gen_c.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 95a60fdaf14e..3266af19edcd 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -825,8 +825,10 @@ class TypeArrayNest(Type): return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, ' elif self.attr['sub-type'] == 'binary' and 'exact-len' in self.checks: return f'.type = YNL_PT_BINARY, .len = {self.checks["exact-len"]}, ' - else: + elif self.attr['sub-type'] == 'nest': return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' + else: + raise Exception(f"Typol for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") def _attr_get(self, ri, var): local_vars = ['const struct nlattr *attr2;'] -- 2.51.0 From ast at fiberby.net Sat Sep 13 23:59:14 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:59:14 -0000 Subject: [PATCH net-next v4 08/11] tools: ynl: move nest packing to a helper function In-Reply-To: <20250913235847.358851-1-ast@fiberby.net> References: <20250913235847.358851-1-ast@fiberby.net> Message-ID: <20250913235847.358851-9-ast@fiberby.net> This patch moves nest packing into a helper function, that can also be used for packing indexed arrays. No behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/lib/ynl.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 50805e05020a..92ff26f34f4d 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -561,11 +561,8 @@ class YnlFamily(SpecFamily): if attr["type"] == 'nest': nl_type |= Netlink.NLA_F_NESTED - attr_payload = b'' sub_space = attr['nested-attributes'] - sub_attrs = SpaceAttrs(self.attr_sets[sub_space], value, search_attrs) - for subname, subvalue in value.items(): - attr_payload += self._add_attr(sub_space, subname, subvalue, sub_attrs) + attr_payload = self._add_nest_attrs(value, sub_space, search_attrs) elif attr["type"] == 'flag': if not value: # If value is absent or false then skip attribute creation. @@ -622,6 +619,14 @@ class YnlFamily(SpecFamily): pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad + def _add_nest_attrs(self, value, sub_space, search_attrs): + sub_attrs = SpaceAttrs(self.attr_sets[sub_space], value, search_attrs) + attr_payload = b'' + for subname, subvalue in value.items(): + attr_payload += self._add_attr(sub_space, subname, subvalue, + sub_attrs) + return attr_payload + def _get_enum_or_unknown(self, enum, raw): try: name = enum.entries_by_val[raw].name -- 2.51.0 From ast at fiberby.net Sat Sep 13 23:59:14 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:59:14 -0000 Subject: [PATCH net-next v4 04/11] tools: ynl-gen: refactor local vars for .attr_put() callers In-Reply-To: <20250913235847.358851-1-ast@fiberby.net> References: <20250913235847.358851-1-ast@fiberby.net> Message-ID: <20250913235847.358851-5-ast@fiberby.net> Refactor the generation of local variables needed when building requests, by moving the logic into the Type classes, and use the same helper in all places where .attr_put() is called. If any attributes requests identical local_vars, then they will be deduplicated, attributes are assumed to only use their local variables transiently. This patch fixes the build errors below: $ make -C tools/net/ynl/generated/ [...] -e GEN wireguard-user.c -e GEN wireguard-user.h -e CC wireguard-user.o wireguard-user.c: In function ?wireguard_get_device_dump?: wireguard-user.c:480:9: error: ?array? undeclared (first use in func) 480 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); | ^~~~~ wireguard-user.c:480:9: note: each undeclared identifier is reported only once for each function it appears in wireguard-user.c:481:14: error: ?i? undeclared (first use in func) 481 | for (i = 0; i < req->_count.peers; i++) | ^ wireguard-user.c: In function ?wireguard_set_device?: wireguard-user.c:533:9: error: ?array? undeclared (first use in func) 533 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); | ^~~~~ make: *** [Makefile:52: wireguard-user.o] Error 1 make: Leaving directory '/usr/src/linux/tools/net/ynl/generated' Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 33 +++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 3266af19edcd..85b1de6a7fef 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -840,6 +840,9 @@ class TypeArrayNest(Type): '}'] return get_lines, None, local_vars + def attr_put_local_vars(self): + return ['struct nlattr *array;'] + def attr_put(self, ri, var): ri.cw.p(f'array = ynl_attr_nest_start(nlh, {self.enum_name});') if self.sub_type in scalars: @@ -2040,6 +2043,18 @@ def put_enum_to_str(family, cw, enum): _put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum) +def put_local_vars(struct): + local_vars = set() + for _, attr in struct.member_list(): + if attr.presence_type() == 'count': + local_vars.add('unsigned int i;') + try: + local_vars |= set(attr.attr_put_local_vars()) + except AttributeError: + pass + return list(local_vars) + + def put_req_nested_prototype(ri, struct, suffix=';'): func_args = ['struct nlmsghdr *nlh', 'unsigned int attr_type', @@ -2062,15 +2077,7 @@ def put_req_nested(ri, struct): init_lines.append(f"hdr = ynl_nlmsg_put_extra_header(nlh, {struct_sz});") init_lines.append(f"memcpy(hdr, &obj->_hdr, {struct_sz});") - has_anest = False - has_count = False - for _, arg in struct.member_list(): - has_anest |= arg.type == 'indexed-array' - has_count |= arg.presence_type() == 'count' - if has_anest: - local_vars.append('struct nlattr *array;') - if has_count: - local_vars.append('unsigned int i;') + local_vars += put_local_vars(struct) put_req_nested_prototype(ri, struct, suffix='') ri.cw.block_start() @@ -2354,10 +2361,7 @@ def print_req(ri): local_vars += ['size_t hdr_len;', 'void *hdr;'] - for _, attr in ri.struct["request"].member_list(): - if attr.presence_type() == 'count': - local_vars += ['unsigned int i;'] - break + local_vars += put_local_vars(ri.struct['request']) print_prototype(ri, direction, terminate=False) ri.cw.block_start() @@ -2424,6 +2428,9 @@ def print_dump(ri): local_vars += ['size_t hdr_len;', 'void *hdr;'] + if 'request' in ri.op[ri.op_mode]: + local_vars += put_local_vars(ri.struct['request']) + ri.cw.write_func_lvar(local_vars) ri.cw.p('yds.yarg.ys = ys;') -- 2.51.0 From ast at fiberby.net Sat Sep 13 23:59:15 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:59:15 -0000 Subject: [PATCH net-next v4 11/11] tools: ynl: add ipv4-or-v6 display hint In-Reply-To: <20250913235847.358851-1-ast@fiberby.net> References: <20250913235847.358851-1-ast@fiberby.net> Message-ID: <20250913235847.358851-12-ast@fiberby.net> The attribute WGALLOWEDIP_A_IPADDR can contain either an IPv4 or an IPv6 address depending on WGALLOWEDIP_A_FAMILY, however in practice it is enough to look at the attribute length. This patch implements an ipv4-or-v6 display hint, that can deal with this kind of attribute. It only implements this display hint for genetlink-legacy, it can be added to other protocol variants if needed, but we don't want to encourage it's use. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- Documentation/netlink/genetlink-legacy.yaml | 2 +- tools/net/ynl/pyynl/lib/ynl.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index b29d62eefa16..66fb8653a344 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -154,7 +154,7 @@ properties: Optional format indicator that is intended only for choosing the right formatting mechanism when displaying values of this type. - enum: [ hex, mac, fddi, ipv4, ipv6, uuid ] + enum: [ hex, mac, fddi, ipv4, ipv6, ipv4-or-v6, uuid ] struct: description: Name of the nested struct type. type: string diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 707753e371e2..62383c70ebb9 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -956,7 +956,7 @@ class YnlFamily(SpecFamily): formatted = hex(raw) else: formatted = bytes.hex(raw, ' ') - elif display_hint in [ 'ipv4', 'ipv6' ]: + elif display_hint in [ 'ipv4', 'ipv6', 'ipv4-or-v6' ]: formatted = format(ipaddress.ip_address(raw)) elif display_hint == 'uuid': formatted = str(uuid.UUID(bytes=raw)) @@ -965,7 +965,7 @@ class YnlFamily(SpecFamily): return formatted def _from_string(self, string, attr_spec): - if attr_spec.display_hint in ['ipv4', 'ipv6']: + if attr_spec.display_hint in ['ipv4', 'ipv6', 'ipv4-or-v6']: ip = ipaddress.ip_address(string) if attr_spec['type'] == 'binary': raw = ip.packed -- 2.51.0 From ast at fiberby.net Sat Sep 13 23:59:15 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:59:15 -0000 Subject: [PATCH net-next v4 09/11] tools: ynl: encode indexed-arrays In-Reply-To: <20250913235847.358851-1-ast@fiberby.net> References: <20250913235847.358851-1-ast@fiberby.net> Message-ID: <20250913235847.358851-10-ast@fiberby.net> This patch adds support for encoding indexed-array attributes with sub-type nest in pyynl. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/lib/ynl.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 92ff26f34f4d..9fd83f8b091f 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -563,6 +563,11 @@ class YnlFamily(SpecFamily): nl_type |= Netlink.NLA_F_NESTED sub_space = attr['nested-attributes'] attr_payload = self._add_nest_attrs(value, sub_space, search_attrs) + elif attr['type'] == 'indexed-array' and attr['sub-type'] == 'nest': + nl_type |= Netlink.NLA_F_NESTED + sub_space = attr['nested-attributes'] + attr_payload = self._encode_indexed_array(value, sub_space, + search_attrs) elif attr["type"] == 'flag': if not value: # If value is absent or false then skip attribute creation. @@ -616,6 +621,9 @@ class YnlFamily(SpecFamily): else: raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}') + return self._add_attr_raw(nl_type, attr_payload) + + def _add_attr_raw(self, nl_type, attr_payload): pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad @@ -627,6 +635,14 @@ class YnlFamily(SpecFamily): sub_attrs) return attr_payload + def _encode_indexed_array(self, vals, sub_space, search_attrs): + attr_payload = b'' + for i, val in enumerate(vals): + idx = i | Netlink.NLA_F_NESTED + val_payload = self._add_nest_attrs(val, sub_space, search_attrs) + attr_payload += self._add_attr_raw(idx, val_payload) + return attr_payload + def _get_enum_or_unknown(self, enum, raw): try: name = enum.entries_by_val[raw].name -- 2.51.0 From ast at fiberby.net Sat Sep 13 23:59:15 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:59:15 -0000 Subject: [PATCH net-next v4 01/11] tools: ynl-gen: allow overriding name-prefix for constants In-Reply-To: <20250913235847.358851-1-ast@fiberby.net> References: <20250913235847.358851-1-ast@fiberby.net> Message-ID: <20250913235847.358851-2-ast@fiberby.net> Allow using custom name-prefix with constants, just like it is for enum and flags declarations. This is needed for generating WG_KEY_LEN in include/uapi/linux/wireguard.h from a spec. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski Reviewed-by: Jacob Keller --- tools/net/ynl/pyynl/ynl_gen_c.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 101d8ba9626f..c8b15569ecc1 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -3208,8 +3208,9 @@ def render_uapi(family, cw): cw.block_end(line=';') cw.nl() elif const['type'] == 'const': + name_pfx = const.get('name-prefix', f"{family.ident_name}-") defines.append([c_upper(family.get('c-define-name', - f"{family.ident_name}-{const['name']}")), + f"{name_pfx}{const['name']}")), const['value']]) if defines: -- 2.51.0 From ast at fiberby.net Sat Sep 13 23:59:15 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:59:15 -0000 Subject: [PATCH net-next v4 06/11] tools: ynl-gen: validate nested arrays In-Reply-To: <20250913235847.358851-1-ast@fiberby.net> References: <20250913235847.358851-1-ast@fiberby.net> Message-ID: <20250913235847.358851-7-ast@fiberby.net> In nested arrays don't require that the intermediate attribute type should be a valid attribute type, it might just be zero or an incrementing index, it is often not even used. See include/net/netlink.h about NLA_NESTED_ARRAY: > The difference to NLA_NESTED is the structure: > NLA_NESTED has the nested attributes directly inside > while an array has the nested attributes at another > level down and the attribute types directly in the > nesting don't matter. Example based on include/uapi/linux/wireguard.h: > WGDEVICE_A_PEERS: NLA_NESTED > 0: NLA_NESTED > WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN > [..] > 0: NLA_NESTED > ... > ... Previous the check required that the nested type was valid in the parent attribute set, which in this case resolves to WGDEVICE_A_UNSPEC, which is YNL_PT_REJECT, and it took the early exit and returned YNL_PARSE_CB_ERROR. This patch renames the old nl_attr_validate() to __nl_attr_validate(), and creates a new inline function nl_attr_validate() to mimic the old one. The new __nl_attr_validate() takes the attribute type as an argument, so we can use it to validate attributes of a nested attribute, in the context of the parents attribute type, which in the above case is generated as: [WGDEVICE_A_PEERS] = { .name = "peers", .type = YNL_PT_NEST, .nest = &wireguard_wgpeer_nest, }, __nl_attr_validate() only checks if the attribute length is plausible for a given attribute type, so the .nest in the above example is not used. As the new inline function needs to be defined after ynl_attr_type(), then the definitions are moved down, so we avoid a forward declaration of ynl_attr_type(). Some other examples are NL80211_BAND_ATTR_FREQS (nest) and NL80211_ATTR_SUPPORTED_COMMANDS (u32) both in nl80211-user.c $ make -C tools/net/ynl/generated nl80211-user.c Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/lib/ynl-priv.h | 10 +++++++++- tools/net/ynl/lib/ynl.c | 6 +++--- tools/net/ynl/pyynl/ynl_gen_c.py | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index 824777d7e05e..29481989ea76 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -106,7 +106,6 @@ ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); struct nlmsghdr * ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); -int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, const char *sel_name); @@ -467,4 +466,13 @@ ynl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data) else ynl_attr_put_s64(nlh, type, data); } + +int __ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr, + unsigned int type); + +static inline int ynl_attr_validate(struct ynl_parse_arg *yarg, + const struct nlattr *attr) +{ + return __ynl_attr_validate(yarg, attr, ynl_attr_type(attr)); +} #endif diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 2a169c3c0797..2bcd781111d7 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -360,15 +360,15 @@ static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) /* Attribute validation */ -int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) +int __ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr, + unsigned int type) { const struct ynl_policy_attr *policy; - unsigned int type, len; unsigned char *data; + unsigned int len; data = ynl_attr_data(attr); len = ynl_attr_data_len(attr); - type = ynl_attr_type(attr); if (type > yarg->rsp_policy->max_attr) { yerr(yarg->ys, YNL_ERROR_INTERNAL, "Internal error, validating unknown attribute"); diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 9555c9a2fea5..8f8d33593326 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -830,7 +830,7 @@ class TypeArrayNest(Type): local_vars = ['const struct nlattr *attr2;'] get_lines = [f'attr_{self.c_name} = attr;', 'ynl_attr_for_each_nested(attr2, attr) {', - '\tif (ynl_attr_validate(yarg, attr2))', + '\tif (__ynl_attr_validate(yarg, attr2, type))', '\t\treturn YNL_PARSE_CB_ERROR;', f'\tn_{self.c_name}++;', '}'] -- 2.51.0 From ast at fiberby.net Sat Sep 13 23:59:15 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:59:15 -0000 Subject: [PATCH net-next v4 00/11] tools: ynl: prepare for wireguard Message-ID: <20250913235847.358851-1-ast@fiberby.net> This series contains the last batch of YNL changes to support the wireguard YNL conversion. The wireguard changes, to be applied on top of this series, has been posted as an RFC series here: https://lore.kernel.org/netdev/20250904-wg-ynl-rfc at fiberby.net/ --- v4: - Added a few Reviewed-by (thanks Donald). - In patch 4, changed the implementation a bit, to avoid overloading. - In patch 6, expose __ynl_attr_validate(), and move ynl_attr_validate() to ynl-priv.h, as an inline function. - Dropped v3 patch 5 and 6 from this series. v3: https://lore.kernel.org/netdev/20250911200508.79341-1-ast at fiberby.net/ - Rebased on top of new net-next, after Matthieu's cleanup. - Added a Reviewed-by (thanks Donald). - Added the parsing local vars cleanup as patch 7 - In patch 4, change to use set() for deduplication. - In patch 8, declare __ynl_attr_validate() as static. v2: https://lore.kernel.org/netdev/20250910230841.384545-1-ast at fiberby.net/ - Added Reviewed-by's to unchanged patches. Thanks to all reviewers. - Patch 4, refactors local variables for .attr_put() callers, and replaces the old patch 4 and 5. - Patch 5 and 6 are new, and reduces the differences between the 3 .attr_put() callers, so it might be easier to keep them in sync. - Patch 7, now validates the nested payload (thanks Jakub). - Patch 8, now renames more variables (thanks Jakub), - Patch 10, got a dead line remove (thanks Donald). - Patch 11, revised hex input to support macsec (suggested by Sabrina). v1: https://lore.kernel.org/netdev/20250904-wg-ynl-prep at fiberby.net/ Asbj?rn Sloth T?nnesen (11): tools: ynl-gen: allow overriding name-prefix for constants tools: ynl-gen: generate nested array policies tools: ynl-gen: add sub-type check tools: ynl-gen: refactor local vars for .attr_put() callers tools: ynl-gen: avoid repetitive variables definitions tools: ynl-gen: validate nested arrays tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray tools: ynl: move nest packing to a helper function tools: ynl: encode indexed-arrays tools: ynl: decode hex input tools: ynl: add ipv4-or-v6 display hint Documentation/netlink/genetlink-legacy.yaml | 2 +- tools/net/ynl/lib/ynl-priv.h | 10 ++- tools/net/ynl/lib/ynl.c | 6 +- tools/net/ynl/pyynl/lib/ynl.py | 38 +++++++-- tools/net/ynl/pyynl/ynl_gen_c.py | 93 +++++++++++++-------- 5 files changed, 101 insertions(+), 48 deletions(-) -- 2.51.0 From ast at fiberby.net Sat Sep 13 23:59:16 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:59:16 -0000 Subject: [PATCH net-next v4 02/11] tools: ynl-gen: generate nested array policies In-Reply-To: <20250913235847.358851-1-ast@fiberby.net> References: <20250913235847.358851-1-ast@fiberby.net> Message-ID: <20250913235847.358851-3-ast@fiberby.net> This patch adds support for NLA_POLICY_NESTED_ARRAY() policies. Example spec (from future wireguard.yaml): - name: wgpeer attributes: - name: allowedips type: indexed-array sub-type: nest nested-attributes: wgallowedip yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy). This doesn't change any currently generated code, as it isn't used in any specs currently used for generating code. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski --- tools/net/ynl/pyynl/ynl_gen_c.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index c8b15569ecc1..95a60fdaf14e 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -815,6 +815,11 @@ class TypeArrayNest(Type): f'unsigned int n_{self.c_name}'] return super().arg_member(ri) + def _attr_policy(self, policy): + if self.attr['sub-type'] == 'nest': + return f'NLA_POLICY_NESTED_ARRAY({self.nested_render_name}_nl_policy)' + return super()._attr_policy(policy) + def _attr_typol(self): if self.attr['sub-type'] in scalars: return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, ' -- 2.51.0 From ast at fiberby.net Sat Sep 13 23:59:16 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:59:16 -0000 Subject: [PATCH net-next v4 05/11] tools: ynl-gen: avoid repetitive variables definitions In-Reply-To: <20250913235847.358851-1-ast@fiberby.net> References: <20250913235847.358851-1-ast@fiberby.net> Message-ID: <20250913235847.358851-6-ast@fiberby.net> In the generated attribute parsing code, avoid repetitively defining the same variables over and over again, local to the conditional block for each attribute. This patch consolidates the definitions of local variables for attribute parsing, so that they are defined at the function level, and re-used across attributes, thus making the generated code read more natural. If attributes defines identical local_vars, then they will be deduplicated, attributes are assumed to only use their local variables transiently. The example below shows how `len` was defined repeatedly in tools/net/ynl/generated/nl80211-user.c: nl80211_iftype_data_attrs_parse(..) { [..] ynl_attr_for_each_nested(attr, nested) { unsigned int type = ynl_attr_type(attr); if (type == NL80211_BAND_IFTYPE_ATTR_IFTYPES) { unsigned int len; [..] } else if (type == NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC) { unsigned int len; [..] [same pattern 8 times, so 11 times in total] } else if (type == NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE) { unsigned int len; [..] } } return 0; } This patch results in this diffstat for the generated code: $ diff -Naur pre/ post/ | diffstat devlink-user.c | 187 +++---------------- dpll-user.c | 10 - ethtool-user.c | 49 +---- fou-user.c | 5 handshake-user.c | 3 mptcp_pm-user.c | 3 nfsd-user.c | 16 - nl80211-user.c | 159 +--------------- nlctrl-user.c | 21 -- ovpn-user.c | 7 ovs_datapath-user.c | 9 ovs_flow-user.c | 89 --------- ovs_vport-user.c | 7 rt-addr-user.c | 14 - rt-link-user.c | 183 ++---------------- rt-neigh-user.c | 14 - rt-route-user.c | 26 -- rt-rule-user.c | 11 - tc-user.c | 380 +++++---------------------------------- tcp_metrics-user.c | 7 team-user.c | 5 21 files changed, 175 insertions(+), 1030 deletions(-) The changed lines are mostly `unsigned int len;` definitions: $ diff -Naur pre/ post/ | grep ^[-+] | grep -v '^[-+]\{3\}' | grep -v '^.$' | sed -e 's/\t\+/ /g' | sort | uniq -c | sort -nr 488 - unsigned int len; 153 + unsigned int len; 24 - const struct nlattr *attr2; 18 + const struct nlattr *attr2; 1 - __u32 policy_id, attr_id; 1 + __u32 policy_id, attr_id; 1 - __u32 op_id; 1 + __u32 op_id; 1 - const struct nlattr *attr_policy_id, *attr_attr_id; 1 + const struct nlattr *attr_policy_id, *attr_attr_id; 1 - const struct nlattr *attr_op_id; 1 + const struct nlattr *attr_op_id; Suggested-by: Jakub Kicinski Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 85b1de6a7fef..9555c9a2fea5 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -242,7 +242,7 @@ class Type(SpecAttr): raise Exception(f"Attr get not implemented for class type {self.type}") def attr_get(self, ri, var, first): - lines, init_lines, local_vars = self._attr_get(ri, var) + lines, init_lines, _ = self._attr_get(ri, var) if type(lines) is str: lines = [lines] if type(init_lines) is str: @@ -250,10 +250,6 @@ class Type(SpecAttr): kw = 'if' if first else 'else if' ri.cw.block_start(line=f"{kw} (type == {self.enum_name})") - if local_vars: - for local in local_vars: - ri.cw.p(local) - ri.cw.nl() if not self.is_multi_val(): ri.cw.p("if (ynl_attr_validate(yarg, attr))") @@ -2114,6 +2110,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): else: raise Exception("Per-op fixed header not supported, yet") + var_set = set() array_nests = set() multi_attrs = set() needs_parg = False @@ -2131,6 +2128,13 @@ def _multi_parse(ri, struct, init_lines, local_vars): multi_attrs.add(arg) needs_parg |= 'nested-attributes' in aspec needs_parg |= 'sub-message' in aspec + + try: + _, _, l_vars = aspec._attr_get(ri, '') + var_set |= set(l_vars) if l_vars else set() + except Exception: + pass # _attr_get() not implemented by simple types, ignore + local_vars += list(var_set) if array_nests or multi_attrs: local_vars.append('int i;') if needs_parg: -- 2.51.0 From ast at fiberby.net Sat Sep 13 23:59:16 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Sat, 13 Sep 2025 23:59:16 -0000 Subject: [PATCH net-next v4 07/11] tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray In-Reply-To: <20250913235847.358851-1-ast@fiberby.net> References: <20250913235847.358851-1-ast@fiberby.net> Message-ID: <20250913235847.358851-8-ast@fiberby.net> Since TypeArrayNest can now be used with many other sub-types than nest, then rename it to TypeIndexedArray, to reduce confusion. This patch continues the rename, that was started in commit aa6485d813ad ("ynl: rename array-nest to indexed-array"), when the YNL type was renamed. In order to get rid of all references to the old naming, within ynl, then renaming some variables in _multi_parse(). This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/ynl_gen_c.py | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 8f8d33593326..55b52fc9cf43 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -787,7 +787,7 @@ class TypeMultiAttr(Type): f"{presence} = n_{self.c_name};"] -class TypeArrayNest(Type): +class TypeIndexedArray(Type): def is_multi_val(self): return True @@ -824,7 +824,7 @@ class TypeArrayNest(Type): elif self.attr['sub-type'] == 'nest': return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' else: - raise Exception(f"Typol for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") + raise Exception(f"Typol for IndexedArray sub-type {self.attr['sub-type']} not supported, yet") def _attr_get(self, ri, var): local_vars = ['const struct nlattr *attr2;'] @@ -853,7 +853,7 @@ class TypeArrayNest(Type): ri.cw.p(f'for (i = 0; i < {var}->_count.{self.c_name}; i++)') ri.cw.p(f"{self.nested_render_name}_put(nlh, i, &{var}->{self.c_name}[i]);") else: - raise Exception(f"Put for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") + raise Exception(f"Put for IndexedArray sub-type {self.attr['sub-type']} not supported, yet") ri.cw.p('ynl_attr_nest_end(nlh, array);') def _setter_lines(self, ri, member, presence): @@ -1130,7 +1130,7 @@ class AttrSet(SpecAttrSet): t = TypeNest(self.family, self, elem, value) elif elem['type'] == 'indexed-array' and 'sub-type' in elem: if elem["sub-type"] in ['binary', 'nest', 'u32']: - t = TypeArrayNest(self.family, self, elem, value) + t = TypeIndexedArray(self.family, self, elem, value) else: raise Exception(f'new_attr: unsupported sub-type {elem["sub-type"]}') elif elem['type'] == 'nest-type-value': @@ -2110,18 +2110,18 @@ def _multi_parse(ri, struct, init_lines, local_vars): else: raise Exception("Per-op fixed header not supported, yet") - var_set = set() - array_nests = set() + indexed_arrays = set() multi_attrs = set() needs_parg = False + var_set = set() for arg, aspec in struct.member_list(): if aspec['type'] == 'indexed-array' and 'sub-type' in aspec: if aspec["sub-type"] in {'binary', 'nest'}: local_vars.append(f'const struct nlattr *attr_{aspec.c_name};') - array_nests.add(arg) + indexed_arrays.add(arg) elif aspec['sub-type'] in scalars: local_vars.append(f'const struct nlattr *attr_{aspec.c_name};') - array_nests.add(arg) + indexed_arrays.add(arg) else: raise Exception(f'Not supported sub-type {aspec["sub-type"]}') if 'multi-attr' in aspec: @@ -2135,16 +2135,16 @@ def _multi_parse(ri, struct, init_lines, local_vars): except Exception: pass # _attr_get() not implemented by simple types, ignore local_vars += list(var_set) - if array_nests or multi_attrs: + if indexed_arrays or multi_attrs: local_vars.append('int i;') if needs_parg: local_vars.append('struct ynl_parse_arg parg;') init_lines.append('parg.ys = yarg->ys;') - all_multi = array_nests | multi_attrs + all_multi = indexed_arrays | multi_attrs - for anest in sorted(all_multi): - local_vars.append(f"unsigned int n_{struct[anest].c_name} = 0;") + for arg in sorted(all_multi): + local_vars.append(f"unsigned int n_{struct[arg].c_name} = 0;") ri.cw.block_start() ri.cw.write_func_lvar(local_vars) @@ -2164,8 +2164,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): else: ri.cw.p('hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr));') ri.cw.p(f"memcpy(&dst->_hdr, hdr, sizeof({struct.fixed_header}));") - for anest in sorted(all_multi): - aspec = struct[anest] + for arg in sorted(all_multi): + aspec = struct[arg] ri.cw.p(f"if (dst->{aspec.c_name})") ri.cw.p(f'return ynl_error_parse(yarg, "attribute already present ({struct.attr_set.name}.{aspec.name})");') @@ -2183,8 +2183,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.block_end() ri.cw.nl() - for anest in sorted(array_nests): - aspec = struct[anest] + for arg in sorted(indexed_arrays): + aspec = struct[arg] ri.cw.block_start(line=f"if (n_{aspec.c_name})") ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") @@ -2209,8 +2209,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.block_end() ri.cw.nl() - for anest in sorted(multi_attrs): - aspec = struct[anest] + for arg in sorted(multi_attrs): + aspec = struct[arg] ri.cw.block_start(line=f"if (n_{aspec.c_name})") ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") ri.cw.p(f"dst->_count.{aspec.c_name} = n_{aspec.c_name};") -- 2.51.0 From ast at fiberby.net Mon Sep 15 14:47:41 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 15 Sep 2025 14:47:41 -0000 Subject: [PATCH net-next v5 01/11] tools: ynl-gen: allow overriding name-prefix for constants In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <20250915144301.725949-2-ast@fiberby.net> Allow using custom name-prefix with constants, just like it is for enum and flags declarations. This is needed for generating WG_KEY_LEN in include/uapi/linux/wireguard.h from a spec. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski Reviewed-by: Jacob Keller --- tools/net/ynl/pyynl/ynl_gen_c.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 101d8ba9626f..c8b15569ecc1 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -3208,8 +3208,9 @@ def render_uapi(family, cw): cw.block_end(line=';') cw.nl() elif const['type'] == 'const': + name_pfx = const.get('name-prefix', f"{family.ident_name}-") defines.append([c_upper(family.get('c-define-name', - f"{family.ident_name}-{const['name']}")), + f"{name_pfx}{const['name']}")), const['value']]) if defines: -- 2.51.0 From ast at fiberby.net Mon Sep 15 14:47:41 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 15 Sep 2025 14:47:41 -0000 Subject: [PATCH net-next v5 11/11] tools: ynl: add ipv4-or-v6 display hint In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <20250915144301.725949-12-ast@fiberby.net> The attribute WGALLOWEDIP_A_IPADDR can contain either an IPv4 or an IPv6 address depending on WGALLOWEDIP_A_FAMILY, however in practice it is enough to look at the attribute length. This patch implements an ipv4-or-v6 display hint, that can deal with this kind of attribute. It only implements this display hint for genetlink-legacy, it can be added to other protocol variants if needed, but we don't want to encourage it's use. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- Documentation/netlink/genetlink-legacy.yaml | 2 +- tools/net/ynl/pyynl/lib/ynl.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index b29d62eefa16..66fb8653a344 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -154,7 +154,7 @@ properties: Optional format indicator that is intended only for choosing the right formatting mechanism when displaying values of this type. - enum: [ hex, mac, fddi, ipv4, ipv6, uuid ] + enum: [ hex, mac, fddi, ipv4, ipv6, ipv4-or-v6, uuid ] struct: description: Name of the nested struct type. type: string diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 707753e371e2..62383c70ebb9 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -956,7 +956,7 @@ class YnlFamily(SpecFamily): formatted = hex(raw) else: formatted = bytes.hex(raw, ' ') - elif display_hint in [ 'ipv4', 'ipv6' ]: + elif display_hint in [ 'ipv4', 'ipv6', 'ipv4-or-v6' ]: formatted = format(ipaddress.ip_address(raw)) elif display_hint == 'uuid': formatted = str(uuid.UUID(bytes=raw)) @@ -965,7 +965,7 @@ class YnlFamily(SpecFamily): return formatted def _from_string(self, string, attr_spec): - if attr_spec.display_hint in ['ipv4', 'ipv6']: + if attr_spec.display_hint in ['ipv4', 'ipv6', 'ipv4-or-v6']: ip = ipaddress.ip_address(string) if attr_spec['type'] == 'binary': raw = ip.packed -- 2.51.0 From ast at fiberby.net Mon Sep 15 14:47:42 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 15 Sep 2025 14:47:42 -0000 Subject: [PATCH net-next v5 07/11] tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <20250915144301.725949-8-ast@fiberby.net> Since TypeArrayNest can now be used with many other sub-types than nest, then rename it to TypeIndexedArray, to reduce confusion. This patch continues the rename, that was started in commit aa6485d813ad ("ynl: rename array-nest to indexed-array"), when the YNL type was renamed. In order to get rid of all references to the old naming, within ynl, then renaming some variables in _multi_parse(). This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/ynl_gen_c.py | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 9b42e75d24e9..c064e6df41bd 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -787,7 +787,7 @@ class TypeMultiAttr(Type): f"{presence} = n_{self.c_name};"] -class TypeArrayNest(Type): +class TypeIndexedArray(Type): def is_multi_val(self): return True @@ -824,7 +824,7 @@ class TypeArrayNest(Type): elif self.attr['sub-type'] == 'nest': return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' else: - raise Exception(f"Typol for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") + raise Exception(f"Typol for IndexedArray sub-type {self.attr['sub-type']} not supported, yet") def _attr_get(self, ri, var): local_vars = ['const struct nlattr *attr2;'] @@ -850,7 +850,7 @@ class TypeArrayNest(Type): ri.cw.p(f'for (i = 0; i < {var}->_count.{self.c_name}; i++)') ri.cw.p(f"{self.nested_render_name}_put(nlh, i, &{var}->{self.c_name}[i]);") else: - raise Exception(f"Put for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") + raise Exception(f"Put for IndexedArray sub-type {self.attr['sub-type']} not supported, yet") ri.cw.p('ynl_attr_nest_end(nlh, array);') def _setter_lines(self, ri, member, presence): @@ -1127,7 +1127,7 @@ class AttrSet(SpecAttrSet): t = TypeNest(self.family, self, elem, value) elif elem['type'] == 'indexed-array' and 'sub-type' in elem: if elem["sub-type"] in ['binary', 'nest', 'u32']: - t = TypeArrayNest(self.family, self, elem, value) + t = TypeIndexedArray(self.family, self, elem, value) else: raise Exception(f'new_attr: unsupported sub-type {elem["sub-type"]}') elif elem['type'] == 'nest-type-value': @@ -2109,18 +2109,18 @@ def _multi_parse(ri, struct, init_lines, local_vars): else: raise Exception("Per-op fixed header not supported, yet") - var_set = set() - array_nests = set() + indexed_arrays = set() multi_attrs = set() needs_parg = False + var_set = set() for arg, aspec in struct.member_list(): if aspec['type'] == 'indexed-array' and 'sub-type' in aspec: if aspec["sub-type"] in {'binary', 'nest'}: local_vars.append(f'const struct nlattr *attr_{aspec.c_name};') - array_nests.add(arg) + indexed_arrays.add(arg) elif aspec['sub-type'] in scalars: local_vars.append(f'const struct nlattr *attr_{aspec.c_name};') - array_nests.add(arg) + indexed_arrays.add(arg) else: raise Exception(f'Not supported sub-type {aspec["sub-type"]}') if 'multi-attr' in aspec: @@ -2134,16 +2134,16 @@ def _multi_parse(ri, struct, init_lines, local_vars): except Exception: pass # _attr_get() not implemented by simple types, ignore local_vars += list(var_set) - if array_nests or multi_attrs: + if indexed_arrays or multi_attrs: local_vars.append('int i;') if needs_parg: local_vars.append('struct ynl_parse_arg parg;') init_lines.append('parg.ys = yarg->ys;') - all_multi = array_nests | multi_attrs + all_multi = indexed_arrays | multi_attrs - for anest in sorted(all_multi): - local_vars.append(f"unsigned int n_{struct[anest].c_name} = 0;") + for arg in sorted(all_multi): + local_vars.append(f"unsigned int n_{struct[arg].c_name} = 0;") ri.cw.block_start() ri.cw.write_func_lvar(local_vars) @@ -2163,8 +2163,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): else: ri.cw.p('hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr));') ri.cw.p(f"memcpy(&dst->_hdr, hdr, sizeof({struct.fixed_header}));") - for anest in sorted(all_multi): - aspec = struct[anest] + for arg in sorted(all_multi): + aspec = struct[arg] ri.cw.p(f"if (dst->{aspec.c_name})") ri.cw.p(f'return ynl_error_parse(yarg, "attribute already present ({struct.attr_set.name}.{aspec.name})");') @@ -2182,8 +2182,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.block_end() ri.cw.nl() - for anest in sorted(array_nests): - aspec = struct[anest] + for arg in sorted(indexed_arrays): + aspec = struct[arg] ri.cw.block_start(line=f"if (n_{aspec.c_name})") ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") @@ -2208,8 +2208,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.block_end() ri.cw.nl() - for anest in sorted(multi_attrs): - aspec = struct[anest] + for arg in sorted(multi_attrs): + aspec = struct[arg] ri.cw.block_start(line=f"if (n_{aspec.c_name})") ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") ri.cw.p(f"dst->_count.{aspec.c_name} = n_{aspec.c_name};") -- 2.51.0 From ast at fiberby.net Mon Sep 15 14:47:43 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 15 Sep 2025 14:47:43 -0000 Subject: [PATCH net-next v5 00/11] tools: ynl: prepare for wireguard Message-ID: <20250915144301.725949-1-ast@fiberby.net> This series contains the last batch of YNL changes to support the wireguard YNL conversion. The wireguard changes, to be applied on top of this series, has been posted as an RFC series here: https://lore.kernel.org/netdev/20250904-wg-ynl-rfc at fiberby.net/ --- v5: - In patch 4, just copy the old local_vars logic into the new helper. v4: - Added a few Reviewed-by (thanks Donald). - In patch 4, changed the implementation a bit, to avoid overloading. - In patch 6, expose __ynl_attr_validate(), and move ynl_attr_validate() to ynl-priv.h, as an inline function. - Dropped v3 patch 5 and 6 from this series. v3: https://lore.kernel.org/netdev/20250911200508.79341-1-ast at fiberby.net/ - Rebased on top of new net-next, after Matthieu's cleanup. - Added a Reviewed-by (thanks Donald). - Added the parsing local vars cleanup as patch 7 - In patch 4, change to use set() for deduplication. - In patch 8, declare __ynl_attr_validate() as static. v2: https://lore.kernel.org/netdev/20250910230841.384545-1-ast at fiberby.net/ - Added Reviewed-by's to unchanged patches. Thanks to all reviewers. - Patch 4, refactors local variables for .attr_put() callers, and replaces the old patch 4 and 5. - Patch 5 and 6 are new, and reduces the differences between the 3 .attr_put() callers, so it might be easier to keep them in sync. - Patch 7, now validates the nested payload (thanks Jakub). - Patch 8, now renames more variables (thanks Jakub), - Patch 10, got a dead line remove (thanks Donald). - Patch 11, revised hex input to support macsec (suggested by Sabrina). v1: https://lore.kernel.org/netdev/20250904-wg-ynl-prep at fiberby.net/ Asbj?rn Sloth T?nnesen (11): tools: ynl-gen: allow overriding name-prefix for constants tools: ynl-gen: generate nested array policies tools: ynl-gen: add sub-type check tools: ynl-gen: refactor local vars for .attr_put() callers tools: ynl-gen: avoid repetitive variables definitions tools: ynl-gen: validate nested arrays tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray tools: ynl: move nest packing to a helper function tools: ynl: encode indexed-arrays tools: ynl: decode hex input tools: ynl: add ipv4-or-v6 display hint Documentation/netlink/genetlink-legacy.yaml | 2 +- tools/net/ynl/lib/ynl-priv.h | 10 ++- tools/net/ynl/lib/ynl.c | 6 +- tools/net/ynl/pyynl/lib/ynl.py | 38 +++++++-- tools/net/ynl/pyynl/ynl_gen_c.py | 92 ++++++++++++--------- 5 files changed, 100 insertions(+), 48 deletions(-) -- 2.51.0 From ast at fiberby.net Mon Sep 15 14:47:44 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 15 Sep 2025 14:47:44 -0000 Subject: [PATCH net-next v5 03/11] tools: ynl-gen: add sub-type check In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <20250915144301.725949-4-ast@fiberby.net> Add a check to verify that the sub-type is "nest", and throw an exception if no policy could be generated, as a guard to prevent against generating a bad policy. This is a trivial patch with no behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski Reviewed-by: Jacob Keller --- tools/net/ynl/pyynl/ynl_gen_c.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 95a60fdaf14e..3266af19edcd 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -825,8 +825,10 @@ class TypeArrayNest(Type): return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, ' elif self.attr['sub-type'] == 'binary' and 'exact-len' in self.checks: return f'.type = YNL_PT_BINARY, .len = {self.checks["exact-len"]}, ' - else: + elif self.attr['sub-type'] == 'nest': return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' + else: + raise Exception(f"Typol for ArrayNest sub-type {self.attr['sub-type']} not supported, yet") def _attr_get(self, ri, var): local_vars = ['const struct nlattr *attr2;'] -- 2.51.0 From ast at fiberby.net Mon Sep 15 14:47:44 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 15 Sep 2025 14:47:44 -0000 Subject: [PATCH net-next v5 06/11] tools: ynl-gen: validate nested arrays In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <20250915144301.725949-7-ast@fiberby.net> In nested arrays don't require that the intermediate attribute type should be a valid attribute type, it might just be zero or an incrementing index, it is often not even used. See include/net/netlink.h about NLA_NESTED_ARRAY: > The difference to NLA_NESTED is the structure: > NLA_NESTED has the nested attributes directly inside > while an array has the nested attributes at another > level down and the attribute types directly in the > nesting don't matter. Example based on include/uapi/linux/wireguard.h: > WGDEVICE_A_PEERS: NLA_NESTED > 0: NLA_NESTED > WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN > [..] > 0: NLA_NESTED > ... > ... Previous the check required that the nested type was valid in the parent attribute set, which in this case resolves to WGDEVICE_A_UNSPEC, which is YNL_PT_REJECT, and it took the early exit and returned YNL_PARSE_CB_ERROR. This patch renames the old nl_attr_validate() to __nl_attr_validate(), and creates a new inline function nl_attr_validate() to mimic the old one. The new __nl_attr_validate() takes the attribute type as an argument, so we can use it to validate attributes of a nested attribute, in the context of the parents attribute type, which in the above case is generated as: [WGDEVICE_A_PEERS] = { .name = "peers", .type = YNL_PT_NEST, .nest = &wireguard_wgpeer_nest, }, __nl_attr_validate() only checks if the attribute length is plausible for a given attribute type, so the .nest in the above example is not used. As the new inline function needs to be defined after ynl_attr_type(), then the definitions are moved down, so we avoid a forward declaration of ynl_attr_type(). Some other examples are NL80211_BAND_ATTR_FREQS (nest) and NL80211_ATTR_SUPPORTED_COMMANDS (u32) both in nl80211-user.c $ make -C tools/net/ynl/generated nl80211-user.c Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/lib/ynl-priv.h | 10 +++++++++- tools/net/ynl/lib/ynl.c | 6 +++--- tools/net/ynl/pyynl/ynl_gen_c.py | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index 824777d7e05e..29481989ea76 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -106,7 +106,6 @@ ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); struct nlmsghdr * ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); -int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, const char *sel_name); @@ -467,4 +466,13 @@ ynl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data) else ynl_attr_put_s64(nlh, type, data); } + +int __ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr, + unsigned int type); + +static inline int ynl_attr_validate(struct ynl_parse_arg *yarg, + const struct nlattr *attr) +{ + return __ynl_attr_validate(yarg, attr, ynl_attr_type(attr)); +} #endif diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 2a169c3c0797..2bcd781111d7 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -360,15 +360,15 @@ static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) /* Attribute validation */ -int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) +int __ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr, + unsigned int type) { const struct ynl_policy_attr *policy; - unsigned int type, len; unsigned char *data; + unsigned int len; data = ynl_attr_data(attr); len = ynl_attr_data_len(attr); - type = ynl_attr_type(attr); if (type > yarg->rsp_policy->max_attr) { yerr(yarg->ys, YNL_ERROR_INTERNAL, "Internal error, validating unknown attribute"); diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index a7c65edc863d..9b42e75d24e9 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -830,7 +830,7 @@ class TypeArrayNest(Type): local_vars = ['const struct nlattr *attr2;'] get_lines = [f'attr_{self.c_name} = attr;', 'ynl_attr_for_each_nested(attr2, attr) {', - '\tif (ynl_attr_validate(yarg, attr2))', + '\tif (__ynl_attr_validate(yarg, attr2, type))', '\t\treturn YNL_PARSE_CB_ERROR;', f'\tn_{self.c_name}++;', '}'] -- 2.51.0 From ast at fiberby.net Mon Sep 15 14:47:44 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 15 Sep 2025 14:47:44 -0000 Subject: [PATCH net-next v5 02/11] tools: ynl-gen: generate nested array policies In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <20250915144301.725949-3-ast@fiberby.net> This patch adds support for NLA_POLICY_NESTED_ARRAY() policies. Example spec (from future wireguard.yaml): - name: wgpeer attributes: - name: allowedips type: indexed-array sub-type: nest nested-attributes: wgallowedip yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy). This doesn't change any currently generated code, as it isn't used in any specs currently used for generating code. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter Reviewed-by: Jakub Kicinski --- tools/net/ynl/pyynl/ynl_gen_c.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index c8b15569ecc1..95a60fdaf14e 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -815,6 +815,11 @@ class TypeArrayNest(Type): f'unsigned int n_{self.c_name}'] return super().arg_member(ri) + def _attr_policy(self, policy): + if self.attr['sub-type'] == 'nest': + return f'NLA_POLICY_NESTED_ARRAY({self.nested_render_name}_nl_policy)' + return super()._attr_policy(policy) + def _attr_typol(self): if self.attr['sub-type'] in scalars: return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, ' -- 2.51.0 From ast at fiberby.net Mon Sep 15 14:47:45 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 15 Sep 2025 14:47:45 -0000 Subject: [PATCH net-next v5 05/11] tools: ynl-gen: avoid repetitive variables definitions In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <20250915144301.725949-6-ast@fiberby.net> In the generated attribute parsing code, avoid repetitively defining the same variables over and over again, local to the conditional block for each attribute. This patch consolidates the definitions of local variables for attribute parsing, so that they are defined at the function level, and re-used across attributes, thus making the generated code read more natural. If attributes defines identical local_vars, then they will be deduplicated, attributes are assumed to only use their local variables transiently. The example below shows how `len` was defined repeatedly in tools/net/ynl/generated/nl80211-user.c: nl80211_iftype_data_attrs_parse(..) { [..] ynl_attr_for_each_nested(attr, nested) { unsigned int type = ynl_attr_type(attr); if (type == NL80211_BAND_IFTYPE_ATTR_IFTYPES) { unsigned int len; [..] } else if (type == NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC) { unsigned int len; [..] [same pattern 8 times, so 11 times in total] } else if (type == NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE) { unsigned int len; [..] } } return 0; } This patch results in this diffstat for the generated code: $ diff -Naur pre/ post/ | diffstat devlink-user.c | 187 +++---------------- dpll-user.c | 10 - ethtool-user.c | 49 +---- fou-user.c | 5 handshake-user.c | 3 mptcp_pm-user.c | 3 nfsd-user.c | 16 - nl80211-user.c | 159 +--------------- nlctrl-user.c | 21 -- ovpn-user.c | 7 ovs_datapath-user.c | 9 ovs_flow-user.c | 89 --------- ovs_vport-user.c | 7 rt-addr-user.c | 14 - rt-link-user.c | 183 ++---------------- rt-neigh-user.c | 14 - rt-route-user.c | 26 -- rt-rule-user.c | 11 - tc-user.c | 380 +++++---------------------------------- tcp_metrics-user.c | 7 team-user.c | 5 21 files changed, 175 insertions(+), 1030 deletions(-) The changed lines are mostly `unsigned int len;` definitions: $ diff -Naur pre/ post/ | grep ^[-+] | grep -v '^[-+]\{3\}' | grep -v '^.$' | sed -e 's/\t\+/ /g' | sort | uniq -c | sort -nr 488 - unsigned int len; 153 + unsigned int len; 24 - const struct nlattr *attr2; 18 + const struct nlattr *attr2; 1 - __u32 policy_id, attr_id; 1 + __u32 policy_id, attr_id; 1 - __u32 op_id; 1 + __u32 op_id; 1 - const struct nlattr *attr_policy_id, *attr_attr_id; 1 + const struct nlattr *attr_policy_id, *attr_attr_id; 1 - const struct nlattr *attr_op_id; 1 + const struct nlattr *attr_op_id; Suggested-by: Jakub Kicinski Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index a0c571456236..a7c65edc863d 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -242,7 +242,7 @@ class Type(SpecAttr): raise Exception(f"Attr get not implemented for class type {self.type}") def attr_get(self, ri, var, first): - lines, init_lines, local_vars = self._attr_get(ri, var) + lines, init_lines, _ = self._attr_get(ri, var) if type(lines) is str: lines = [lines] if type(init_lines) is str: @@ -250,10 +250,6 @@ class Type(SpecAttr): kw = 'if' if first else 'else if' ri.cw.block_start(line=f"{kw} (type == {self.enum_name})") - if local_vars: - for local in local_vars: - ri.cw.p(local) - ri.cw.nl() if not self.is_multi_val(): ri.cw.p("if (ynl_attr_validate(yarg, attr))") @@ -2113,6 +2109,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): else: raise Exception("Per-op fixed header not supported, yet") + var_set = set() array_nests = set() multi_attrs = set() needs_parg = False @@ -2130,6 +2127,13 @@ def _multi_parse(ri, struct, init_lines, local_vars): multi_attrs.add(arg) needs_parg |= 'nested-attributes' in aspec needs_parg |= 'sub-message' in aspec + + try: + _, _, l_vars = aspec._attr_get(ri, '') + var_set |= set(l_vars) if l_vars else set() + except Exception: + pass # _attr_get() not implemented by simple types, ignore + local_vars += list(var_set) if array_nests or multi_attrs: local_vars.append('int i;') if needs_parg: -- 2.51.0 From ast at fiberby.net Mon Sep 15 14:47:45 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 15 Sep 2025 14:47:45 -0000 Subject: [PATCH net-next v5 04/11] tools: ynl-gen: refactor local vars for .attr_put() callers In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <20250915144301.725949-5-ast@fiberby.net> Refactor the generation of local variables needed when building requests, by moving the logic from put_req_nested() into a new helper put_local_vars(), and use the helper before .attr_put() is called, thus generating the local variables assumed by .attr_put(). Previously only put_req_nested() generated the variables assumed by .attr_put(), print_req() only generated the count iterator `i`, and print_dump() neither generated `i` nor `array`. This patch fixes the build errors below: $ make -C tools/net/ynl/generated/ [...] -e GEN wireguard-user.c -e GEN wireguard-user.h -e CC wireguard-user.o wireguard-user.c: In function ?wireguard_get_device_dump?: wireguard-user.c:480:9: error: ?array? undeclared (first use in func) 480 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); | ^~~~~ wireguard-user.c:480:9: note: each undeclared identifier is reported only once for each function it appears in wireguard-user.c:481:14: error: ?i? undeclared (first use in func) 481 | for (i = 0; i < req->_count.peers; i++) | ^ wireguard-user.c: In function ?wireguard_set_device?: wireguard-user.c:533:9: error: ?array? undeclared (first use in func) 533 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); | ^~~~~ make: *** [Makefile:52: wireguard-user.o] Error 1 make: Leaving directory '/usr/src/linux/tools/net/ynl/generated' Signed-off-by: Asbj?rn Sloth T?nnesen --- tools/net/ynl/pyynl/ynl_gen_c.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 3266af19edcd..a0c571456236 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -2040,6 +2040,20 @@ def put_enum_to_str(family, cw, enum): _put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum) +def put_local_vars(struct): + local_vars = [] + has_array = False + has_count = False + for _, arg in struct.member_list(): + has_array |= arg.type == 'indexed-array' + has_count |= arg.presence_type() == 'count' + if has_array: + local_vars.append('struct nlattr *array;') + if has_count: + local_vars.append('unsigned int i;') + return local_vars + + def put_req_nested_prototype(ri, struct, suffix=';'): func_args = ['struct nlmsghdr *nlh', 'unsigned int attr_type', @@ -2062,15 +2076,7 @@ def put_req_nested(ri, struct): init_lines.append(f"hdr = ynl_nlmsg_put_extra_header(nlh, {struct_sz});") init_lines.append(f"memcpy(hdr, &obj->_hdr, {struct_sz});") - has_anest = False - has_count = False - for _, arg in struct.member_list(): - has_anest |= arg.type == 'indexed-array' - has_count |= arg.presence_type() == 'count' - if has_anest: - local_vars.append('struct nlattr *array;') - if has_count: - local_vars.append('unsigned int i;') + local_vars += put_local_vars(struct) put_req_nested_prototype(ri, struct, suffix='') ri.cw.block_start() @@ -2354,10 +2360,7 @@ def print_req(ri): local_vars += ['size_t hdr_len;', 'void *hdr;'] - for _, attr in ri.struct["request"].member_list(): - if attr.presence_type() == 'count': - local_vars += ['unsigned int i;'] - break + local_vars += put_local_vars(ri.struct['request']) print_prototype(ri, direction, terminate=False) ri.cw.block_start() @@ -2424,6 +2427,9 @@ def print_dump(ri): local_vars += ['size_t hdr_len;', 'void *hdr;'] + if 'request' in ri.op[ri.op_mode]: + local_vars += put_local_vars(ri.struct['request']) + ri.cw.write_func_lvar(local_vars) ri.cw.p('yds.yarg.ys = ys;') -- 2.51.0 From ast at fiberby.net Mon Sep 15 14:47:45 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 15 Sep 2025 14:47:45 -0000 Subject: [PATCH net-next v5 09/11] tools: ynl: encode indexed-arrays In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <20250915144301.725949-10-ast@fiberby.net> This patch adds support for encoding indexed-array attributes with sub-type nest in pyynl. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/lib/ynl.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 92ff26f34f4d..9fd83f8b091f 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -563,6 +563,11 @@ class YnlFamily(SpecFamily): nl_type |= Netlink.NLA_F_NESTED sub_space = attr['nested-attributes'] attr_payload = self._add_nest_attrs(value, sub_space, search_attrs) + elif attr['type'] == 'indexed-array' and attr['sub-type'] == 'nest': + nl_type |= Netlink.NLA_F_NESTED + sub_space = attr['nested-attributes'] + attr_payload = self._encode_indexed_array(value, sub_space, + search_attrs) elif attr["type"] == 'flag': if not value: # If value is absent or false then skip attribute creation. @@ -616,6 +621,9 @@ class YnlFamily(SpecFamily): else: raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}') + return self._add_attr_raw(nl_type, attr_payload) + + def _add_attr_raw(self, nl_type, attr_payload): pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad @@ -627,6 +635,14 @@ class YnlFamily(SpecFamily): sub_attrs) return attr_payload + def _encode_indexed_array(self, vals, sub_space, search_attrs): + attr_payload = b'' + for i, val in enumerate(vals): + idx = i | Netlink.NLA_F_NESTED + val_payload = self._add_nest_attrs(val, sub_space, search_attrs) + attr_payload += self._add_attr_raw(idx, val_payload) + return attr_payload + def _get_enum_or_unknown(self, enum, raw): try: name = enum.entries_by_val[raw].name -- 2.51.0 From ast at fiberby.net Mon Sep 15 14:47:45 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 15 Sep 2025 14:47:45 -0000 Subject: [PATCH net-next v5 08/11] tools: ynl: move nest packing to a helper function In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <20250915144301.725949-9-ast@fiberby.net> This patch moves nest packing into a helper function, that can also be used for packing indexed arrays. No behavioural changes intended. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/lib/ynl.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 50805e05020a..92ff26f34f4d 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -561,11 +561,8 @@ class YnlFamily(SpecFamily): if attr["type"] == 'nest': nl_type |= Netlink.NLA_F_NESTED - attr_payload = b'' sub_space = attr['nested-attributes'] - sub_attrs = SpaceAttrs(self.attr_sets[sub_space], value, search_attrs) - for subname, subvalue in value.items(): - attr_payload += self._add_attr(sub_space, subname, subvalue, sub_attrs) + attr_payload = self._add_nest_attrs(value, sub_space, search_attrs) elif attr["type"] == 'flag': if not value: # If value is absent or false then skip attribute creation. @@ -622,6 +619,14 @@ class YnlFamily(SpecFamily): pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad + def _add_nest_attrs(self, value, sub_space, search_attrs): + sub_attrs = SpaceAttrs(self.attr_sets[sub_space], value, search_attrs) + attr_payload = b'' + for subname, subvalue in value.items(): + attr_payload += self._add_attr(sub_space, subname, subvalue, + sub_attrs) + return attr_payload + def _get_enum_or_unknown(self, enum, raw): try: name = enum.entries_by_val[raw].name -- 2.51.0 From ast at fiberby.net Mon Sep 15 14:47:45 2025 From: ast at fiberby.net (=?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?=) Date: Mon, 15 Sep 2025 14:47:45 -0000 Subject: [PATCH net-next v5 10/11] tools: ynl: decode hex input In-Reply-To: <20250915144301.725949-1-ast@fiberby.net> References: <20250915144301.725949-1-ast@fiberby.net> Message-ID: <20250915144301.725949-11-ast@fiberby.net> This patch adds support for decoding hex input, so that binary attributes can be read through --json. Example (using future wireguard.yaml): $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ --do set-device --json '{"ifindex":3, "private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}' In order to somewhat mirror what is done in _formatted_string(), then for non-binary attributes attempt to convert it to an int. Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/lib/ynl.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py index 9fd83f8b091f..707753e371e2 100644 --- a/tools/net/ynl/pyynl/lib/ynl.py +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -971,6 +971,11 @@ class YnlFamily(SpecFamily): raw = ip.packed else: raw = int(ip) + elif attr_spec.display_hint == 'hex': + if attr_spec['type'] == 'binary': + raw = bytes.fromhex(string) + else: + raw = int(string, 16) else: raise Exception(f"Display hint '{attr_spec.display_hint}' not implemented" f" when parsing '{attr_spec['name']}'") -- 2.51.0 From david at redhat.com Mon Sep 1 15:11:13 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:11:13 -0000 Subject: [PATCH v2 25/37] ata: libata-sff: drop nth_page() usage within SG entry In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-26-david@redhat.com> It's no longer required to use nth_page() when iterating pages within a single SG entry, so let's drop the nth_page() usage. Acked-by: Damien Le Moal Reviewed-by: Lorenzo Stoakes Cc: Niklas Cassel Signed-off-by: David Hildenbrand --- drivers/ata/libata-sff.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 7fc407255eb46..1e2a2c33cdc80 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -614,7 +614,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) offset = qc->cursg->offset + qc->cursg_ofs; /* get the current page and offset */ - page = nth_page(page, (offset >> PAGE_SHIFT)); + page += offset >> PAGE_SHIFT; offset %= PAGE_SIZE; /* don't overrun current sg */ @@ -631,7 +631,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) unsigned int split_len = PAGE_SIZE - offset; ata_pio_xfer(qc, page, offset, split_len); - ata_pio_xfer(qc, nth_page(page, 1), 0, count - split_len); + ata_pio_xfer(qc, page + 1, 0, count - split_len); } else { ata_pio_xfer(qc, page, offset, count); } @@ -751,7 +751,7 @@ static int __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) offset = sg->offset + qc->cursg_ofs; /* get the current page and offset */ - page = nth_page(page, (offset >> PAGE_SHIFT)); + page += offset >> PAGE_SHIFT; offset %= PAGE_SIZE; /* don't overrun current sg */ -- 2.50.1 From david at redhat.com Mon Sep 1 15:11:44 2025 From: david at redhat.com (David Hildenbrand) Date: Mon, 01 Sep 2025 15:11:44 -0000 Subject: [PATCH v2 27/37] mspro_block: drop nth_page() usage within SG entry In-Reply-To: <20250901150359.867252-1-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> Message-ID: <20250901150359.867252-28-david@redhat.com> It's no longer required to use nth_page() when iterating pages within a single SG entry, so let's drop the nth_page() usage. Acked-by: Ulf Hansson Reviewed-by: Lorenzo Stoakes Cc: Maxim Levitsky Cc: Alex Dubov Signed-off-by: David Hildenbrand --- drivers/memstick/core/mspro_block.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index c9853d887d282..d3f160dc0da4c 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -560,8 +560,7 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card, t_offset += msb->current_page * msb->page_size; sg_set_page(&t_sg, - nth_page(sg_page(&(msb->req_sg[msb->current_seg])), - t_offset >> PAGE_SHIFT), + sg_page(&(msb->req_sg[msb->current_seg])) + (t_offset >> PAGE_SHIFT), msb->page_size, offset_in_page(t_offset)); memstick_init_req_sg(*mrq, msb->data_dir == READ -- 2.50.1 From tursulin at ursulin.net Tue Sep 2 09:22:12 2025 From: tursulin at ursulin.net (Tvrtko Ursulin) Date: Tue, 02 Sep 2025 09:22:12 -0000 Subject: [PATCH v2 26/37] drm/i915/gem: drop nth_page() usage within SG entry In-Reply-To: <20250901150359.867252-27-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-27-david@redhat.com> Message-ID: <4bbf5590-7591-4dfc-a23e-0bda6cb31a80@ursulin.net> On 01/09/2025 16:03, David Hildenbrand wrote: > It's no longer required to use nth_page() when iterating pages within a > single SG entry, so let's drop the nth_page() usage. > > Reviewed-by: Lorenzo Stoakes > Cc: Jani Nikula > Cc: Joonas Lahtinen > Cc: Rodrigo Vivi > Cc: Tvrtko Ursulin > Cc: David Airlie > Cc: Simona Vetter > Signed-off-by: David Hildenbrand > --- > drivers/gpu/drm/i915/gem/i915_gem_pages.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c > index c16a57160b262..031d7acc16142 100644 > --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c > +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c > @@ -779,7 +779,7 @@ __i915_gem_object_get_page(struct drm_i915_gem_object *obj, pgoff_t n) > GEM_BUG_ON(!i915_gem_object_has_struct_page(obj)); > > sg = i915_gem_object_get_sg(obj, n, &offset); > - return nth_page(sg_page(sg), offset); > + return sg_page(sg) + offset; > } > > /* Like i915_gem_object_get_page(), but mark the returned page dirty */ LGTM. If you want an ack to merge via a tree other than i915 you have it. I suspect it might be easier to coordinate like that. Regards, Tvrtko From donald.hunter at gmail.com Fri Sep 5 10:53:56 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 05 Sep 2025 10:53:56 -0000 Subject: [PATCH net-next 01/11] tools: ynl-gen: allow overriding name-prefix for constants In-Reply-To: <20250904220156.1006541-1-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-1-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > Allow using custom name-prefix with constants, > just like it is for enum and flags declarations. > > This is needed for generating WG_KEY_LEN in > include/uapi/linux/wireguard.h from a spec. > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From donald.hunter at gmail.com Fri Sep 5 10:53:58 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 05 Sep 2025 10:53:58 -0000 Subject: [PATCH net-next 02/11] tools: ynl-gen: generate nested array policies In-Reply-To: <20250904220156.1006541-2-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-2-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > This patch adds support for NLA_POLICY_NESTED_ARRAY() policies. > > Example spec (from future wireguard.yaml): > - > name: wgpeer > attributes: > - > name: allowedips > type: indexed-array > sub-type: nest > nested-attributes: wgallowedip > > yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy). > > This doesn't change any currently generated code, as it isn't > used in any specs currently used for generating code. > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From donald.hunter at gmail.com Fri Sep 5 10:53:59 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 05 Sep 2025 10:53:59 -0000 Subject: [PATCH net-next 03/11] tools: ynl-gen: add sub-type check In-Reply-To: <20250904220156.1006541-3-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-3-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > Add a check to verify that the sub-type is "nest", and throw an > exception if no policy could be generated, as a guard to prevent > against generating a bad policy. > > This is a trivial patch with no behavioural changes intended. > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From donald.hunter at gmail.com Fri Sep 5 10:54:01 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 05 Sep 2025 10:54:01 -0000 Subject: [PATCH net-next 04/11] tools: ynl-gen: define count iterator in print_dump() In-Reply-To: <20250904220156.1006541-4-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-4-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > In wireguard_get_device_dump(), as generated by print_dump(), > it didn't generate a declaration of `unsigned int i`: > > $ make -C tools/net/ynl/generated wireguard-user.o > -e CC wireguard-user.o > wireguard-user.c: In function ?wireguard_get_device_dump?: > wireguard-user.c:502:22: error: ?i? undeclared (first use in this fn) > 502 | for (i = 0; i < req->_count.peers; i++) > | ^ > > Copy the logic from print_req() as it correctly generated the > iterator in wireguard_set_device(). > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From donald.hunter at gmail.com Fri Sep 5 10:54:02 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 05 Sep 2025 10:54:02 -0000 Subject: [PATCH net-next 05/11] tools: ynl-gen: define nlattr *array in a block scope In-Reply-To: <20250904220156.1006541-5-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-5-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > Instead of trying to define "struct nlattr *array;" in the all > the right places, then simply define it in a block scope, > as it's only used here. > > Before this patch it was generated for attribute set _put() > functions, like wireguard_wgpeer_put(), but missing and caused a > compile error for the command function wireguard_set_device(). > > $ make -C tools/net/ynl/generated wireguard-user.o > -e CC wireguard-user.o > wireguard-user.c: In function ?wireguard_set_device?: > wireguard-user.c:548:9: error: ?array? undeclared (first use in ..) > 548 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); > | ^~~~~ > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From donald.hunter at gmail.com Fri Sep 5 10:54:04 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 05 Sep 2025 10:54:04 -0000 Subject: [PATCH net-next 07/11] tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray In-Reply-To: <20250904220156.1006541-7-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-7-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > As TypeArrayNest can now be used with many other sub-types > than nest, then rename it to TypeIndexedArray, to reduce > confusion. > > This is a trivial patch with no behavioural changes intended. > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From donald.hunter at gmail.com Fri Sep 5 10:54:05 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 05 Sep 2025 10:54:05 -0000 Subject: [PATCH net-next 08/11] tools: ynl: move nest packing to a helper function In-Reply-To: <20250904220156.1006541-8-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-8-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > This patch moves nest packing into a helper function, > that can also be used for packing indexed arrays. > > No behavioural changes intended. > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From donald.hunter at gmail.com Fri Sep 5 10:54:07 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 05 Sep 2025 10:54:07 -0000 Subject: [PATCH net-next 09/11] tools: ynl: encode indexed-array In-Reply-To: <20250904220156.1006541-9-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-9-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > This patch adds support for encoding indexed-array > attributes with sub-type nest in pyynl. > > Signed-off-by: Asbj?rn Sloth T?nnesen > --- > tools/net/ynl/pyynl/lib/ynl.py | 17 +++++++++++++++++ > 1 file changed, 17 insertions(+) > > diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py > index 4928b41c636a..a37294a751da 100644 > --- a/tools/net/ynl/pyynl/lib/ynl.py > +++ b/tools/net/ynl/pyynl/lib/ynl.py > @@ -564,6 +564,11 @@ class YnlFamily(SpecFamily): > nl_type |= Netlink.NLA_F_NESTED > sub_space = attr['nested-attributes'] > attr_payload = self._add_nest_attrs(value, sub_space, search_attrs) > + elif attr['type'] == 'indexed-array' and attr['sub-type'] == 'nest': > + nl_type |= Netlink.NLA_F_NESTED > + sub_space = attr['nested-attributes'] > + attr_payload = self._encode_indexed_array(value, sub_space, > + search_attrs) > elif attr["type"] == 'flag': > if not value: > # If value is absent or false then skip attribute creation. > @@ -617,6 +622,9 @@ class YnlFamily(SpecFamily): > else: > raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}') > > + return self._add_attr_raw(nl_type, attr_payload) > + > + def _add_attr_raw(self, nl_type, attr_payload): > pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) > return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad > > @@ -628,6 +636,15 @@ class YnlFamily(SpecFamily): > sub_attrs) > return attr_payload > > + def _encode_indexed_array(self, vals, sub_space, search_attrs): > + attr_payload = b'' > + nested_flag = Netlink.NLA_F_NESTED This line is not doing anything, right? > + for i, val in enumerate(vals): > + idx = i | Netlink.NLA_F_NESTED > + val_payload = self._add_nest_attrs(val, sub_space, search_attrs) > + attr_payload += self._add_attr_raw(idx, val_payload) > + return attr_payload > + > def _get_enum_or_unknown(self, enum, raw): > try: > name = enum.entries_by_val[raw].name From donald.hunter at gmail.com Fri Sep 5 10:54:08 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 05 Sep 2025 10:54:08 -0000 Subject: [PATCH net-next 10/11] tools: ynl: decode hex input In-Reply-To: <20250904220156.1006541-10-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-10-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > This patch add support for decoding hex input, so > that binary attributes can be read through --json. > > Example (using future wireguard.yaml): > $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ > --do set-device --json '{"ifindex":3, > "private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}' > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter FWIW, the hex can include spaces or not when using bytes.fromhex(). When formatting hex for output, I chose to include spaces, but I don't really know if that was a good choice or not. From donald.hunter at gmail.com Fri Sep 5 10:54:10 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 05 Sep 2025 10:54:10 -0000 Subject: [PATCH net-next 11/11] tools: ynl: add ipv4-or-v6 display hint In-Reply-To: <20250904220156.1006541-11-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-11-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > The attribute WGALLOWEDIP_A_IPADDR can contain either an IPv4 > or an IPv6 address depending on WGALLOWEDIP_A_FAMILY, however > in practice it is enough to look at the attribute length. > > This patch implements an ipv4-or-v6 display hint, that can > deal with this kind of attribute. > > It only implements this display hint for genetlink-legacy, it > can be added to other protocol variants if needed, but we don't > want to encourage it's use. > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter I suspect there are occurrences of ipv4 or ipv6 in the existing specs that really should be ipv4-or-ipv6 but the python code doesn't care. From jhubbard at nvidia.com Sat Sep 6 01:05:31 2025 From: jhubbard at nvidia.com (John Hubbard) Date: Sat, 06 Sep 2025 01:05:31 -0000 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <20250901150359.867252-20-david@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> Message-ID: <016307ba-427d-4646-8e4d-1ffefd2c1968@nvidia.com> On 9/1/25 8:03 AM, David Hildenbrand wrote: > We can just cleanup the code by calculating the #refs earlier, > so we can just inline what remains of record_subpages(). > > Calculate the number of references/pages ahead of times, and record them > only once all our tests passed. > > Signed-off-by: David Hildenbrand > --- > mm/gup.c | 25 ++++++++----------------- > 1 file changed, 8 insertions(+), 17 deletions(-) > > diff --git a/mm/gup.c b/mm/gup.c > index c10cd969c1a3b..f0f4d1a68e094 100644 > --- a/mm/gup.c > +++ b/mm/gup.c > @@ -484,19 +484,6 @@ static inline void mm_set_has_pinned_flag(struct mm_struct *mm) > #ifdef CONFIG_MMU > > #ifdef CONFIG_HAVE_GUP_FAST > -static int record_subpages(struct page *page, unsigned long sz, > - unsigned long addr, unsigned long end, > - struct page **pages) > -{ > - int nr; > - > - page += (addr & (sz - 1)) >> PAGE_SHIFT; > - for (nr = 0; addr != end; nr++, addr += PAGE_SIZE) > - pages[nr] = page++; > - > - return nr; > -} > - > /** > * try_grab_folio_fast() - Attempt to get or pin a folio in fast path. > * @page: pointer to page to be grabbed > @@ -2967,8 +2954,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > if (pmd_special(orig)) > return 0; > > - page = pmd_page(orig); > - refs = record_subpages(page, PMD_SIZE, addr, end, pages + *nr); > + refs = (end - addr) >> PAGE_SHIFT; > + page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); > > folio = try_grab_folio_fast(page, refs, flags); > if (!folio) > @@ -2989,6 +2976,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > } > > *nr += refs; > + for (; refs; refs--) > + *(pages++) = page++; > folio_set_referenced(folio); > return 1; > } > @@ -3007,8 +2996,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > if (pud_special(orig)) > return 0; > > - page = pud_page(orig); > - refs = record_subpages(page, PUD_SIZE, addr, end, pages + *nr); > + refs = (end - addr) >> PAGE_SHIFT; > + page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT); > > folio = try_grab_folio_fast(page, refs, flags); > if (!folio) > @@ -3030,6 +3019,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > } > > *nr += refs; > + for (; refs; refs--) > + *(pages++) = page++; Hi David, Probably a similar sentiment as Lorenzo here...the above diffs make the code *worse* to read. In fact, I recall adding record_subpages() here long ago, specifically to help clarify what was going on. Now it's been returned to it's original, cryptic form. Just my take on it, for whatever that's worth. :) thanks, -- John Hubbard > folio_set_referenced(folio); > return 1; > } From jhubbard at nvidia.com Sun Sep 7 05:14:33 2025 From: jhubbard at nvidia.com (John Hubbard) Date: Sun, 07 Sep 2025 05:14:33 -0000 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <85e760cf-b994-40db-8d13-221feee55c60@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <016307ba-427d-4646-8e4d-1ffefd2c1968@nvidia.com> <85e760cf-b994-40db-8d13-221feee55c60@redhat.com> Message-ID: <0a28adde-acaf-4d55-96ba-c32d6113285f@nvidia.com> On 9/5/25 11:56 PM, David Hildenbrand wrote: > On 06.09.25 03:05, John Hubbard wrote: >> On 9/1/25 8:03 AM, David Hildenbrand wrote: ...> Well, there is a lot I dislike about record_subpages() to go back there. > Starting with "as Willy keeps explaining, the concept of subpages do > not exist and ending with "why do we fill out the array even on failure". > > :) I am also very glad to see the entire concept of subpages disappear. >> >> Now it's been returned to it's original, cryptic form. >> > > The code in the caller was so uncryptic that both me and Lorenzo missed > that magical addition. :P > >> Just my take on it, for whatever that's worth. :) > > As always, appreciated. > > I could of course keep the simple loop in some "record_folio_pages" > function and clean up what I dislike about record_subpages(). > > But I much rather want the call chain to be cleaned up instead, if > possible. > Right! The primary way that record_subpages() helped was in showing what was going on: a function call helps a lot to self-document, sometimes. > > Roughly, what I am thinking (limiting it to pte+pmd case) about is the > following: The code below looks much cleaner, that's great! thanks, -- John Hubbard > > > From d6d6d21dbf435d8030782a627175e36e6c7b2dfb Mon Sep 17 00:00:00 2001 > From: David Hildenbrand > Date: Sat, 6 Sep 2025 08:33:42 +0200 > Subject: [PATCH] tmp > > Signed-off-by: David Hildenbrand > --- > ?mm/gup.c | 79 ++++++++++++++++++++++++++------------------------------ > ?1 file changed, 36 insertions(+), 43 deletions(-) > > diff --git a/mm/gup.c b/mm/gup.c > index 22420f2069ee1..98907ead749c0 100644 > --- a/mm/gup.c > +++ b/mm/gup.c > @@ -2845,12 +2845,11 @@ static void __maybe_unused > gup_fast_undo_dev_pagemap(int *nr, int nr_start, > ? * also check pmd here to make sure pmd doesn't change (corresponds to > ? * pmdp_collapse_flush() in the THP collapse code path). > ? */ > -static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, > -??????? unsigned long end, unsigned int flags, struct page **pages, > -??????? int *nr) > +static unsigned long gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, > unsigned long addr, > +??????? unsigned long end, unsigned int flags, struct page **pages) > ?{ > ???? struct dev_pagemap *pgmap = NULL; > -??? int ret = 0; > +??? unsigned long nr_pages = 0; > ???? pte_t *ptep, *ptem; > > ???? ptem = ptep = pte_offset_map(&pmd, addr); > @@ -2908,24 +2907,20 @@ static int gup_fast_pte_range(pmd_t pmd, pmd_t > *pmdp, unsigned long addr, > ????????? * details. > ????????? */ > ???????? if (flags & FOLL_PIN) { > -??????????? ret = arch_make_folio_accessible(folio); > -??????????? if (ret) { > +??????????? if (arch_make_folio_accessible(folio)) { > ???????????????? gup_put_folio(folio, 1, flags); > ???????????????? goto pte_unmap; > ???????????? } > ???????? } > ???????? folio_set_referenced(folio); > -??????? pages[*nr] = page; > -??????? (*nr)++; > +??????? pages[nr_pages++] = page; > ???? } while (ptep++, addr += PAGE_SIZE, addr != end); > > -??? ret = 1; > - > ?pte_unmap: > ???? if (pgmap) > ???????? put_dev_pagemap(pgmap); > ???? pte_unmap(ptem); > -??? return ret; > +??? return nr_pages; > ?} > ?#else > > @@ -2938,21 +2933,24 @@ static int gup_fast_pte_range(pmd_t pmd, pmd_t > *pmdp, unsigned long addr, > ? * get_user_pages_fast_only implementation that can pin pages. Thus > it's still > ? * useful to have gup_fast_pmd_leaf even if we can't operate on ptes. > ? */ > -static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, > -??????? unsigned long end, unsigned int flags, struct page **pages, > -??????? int *nr) > +static unsigned long gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, > unsigned long addr, > +??????? unsigned long end, unsigned int flags, struct page **pages) > ?{ > ???? return 0; > ?} > ?#endif /* CONFIG_ARCH_HAS_PTE_SPECIAL */ > > -static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > -??????? unsigned long end, unsigned int flags, struct page **pages, > -??????? int *nr) > +static unsigned long gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, > unsigned long addr, > +??????? unsigned long end, unsigned int flags, struct page **pages) > ?{ > +??? const unsigned long nr_pages = (end - addr) >> PAGE_SHIFT; > ???? struct page *page; > ???? struct folio *folio; > -??? int refs; > +??? unsigned long i; > + > +??? /* See gup_fast_pte_range() */ > +??? if (pmd_protnone(orig)) > +??????? return 0; > > ???? if (!pmd_access_permitted(orig, flags & FOLL_WRITE)) > ???????? return 0; > @@ -2960,33 +2958,30 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t > *pmdp, unsigned long addr, > ???? if (pmd_special(orig)) > ???????? return 0; > > -??? refs = (end - addr) >> PAGE_SHIFT; > ???? page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); > > -??? folio = try_grab_folio_fast(page, refs, flags); > +??? folio = try_grab_folio_fast(page, nr_pages, flags); > ???? if (!folio) > ???????? return 0; > > ???? if (unlikely(pmd_val(orig) != pmd_val(*pmdp))) { > -??????? gup_put_folio(folio, refs, flags); > +??????? gup_put_folio(folio, nr_pages, flags); > ???????? return 0; > ???? } > > ???? if (!gup_fast_folio_allowed(folio, flags)) { > -??????? gup_put_folio(folio, refs, flags); > +??????? gup_put_folio(folio, nr_pages, flags); > ???????? return 0; > ???? } > ???? if (!pmd_write(orig) && gup_must_unshare(NULL, flags, &folio- > >page)) { > -??????? gup_put_folio(folio, refs, flags); > +??????? gup_put_folio(folio, nr_pages, flags); > ???????? return 0; > ???? } > > -??? pages += *nr; > -??? *nr += refs; > -??? for (; refs; refs--) > +??? for (i = 0; i < nr_pages; i++) > ???????? *(pages++) = page++; > ???? folio_set_referenced(folio); > -??? return 1; > +??? return nr_pages; > ?} > > ?static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > @@ -3033,11 +3028,11 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t > *pudp, unsigned long addr, > ???? return 1; > ?} > > -static int gup_fast_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr, > -??????? unsigned long end, unsigned int flags, struct page **pages, > -??????? int *nr) > +static unsigned long gup_fast_pmd_range(pud_t *pudp, pud_t pud, > unsigned long addr, > +??????? unsigned long end, unsigned int flags, struct page **pages) > ?{ > -??? unsigned long next; > +??? unsigned long cur_nr_pages, next; > +??? unsigned long nr_pages = 0; > ???? pmd_t *pmdp; > > ???? pmdp = pmd_offset_lockless(pudp, pud, addr); > @@ -3046,23 +3041,21 @@ static int gup_fast_pmd_range(pud_t *pudp, pud_t > pud, unsigned long addr, > > ???????? next = pmd_addr_end(addr, end); > ???????? if (!pmd_present(pmd)) > -??????????? return 0; > +??????????? break; > > -??????? if (unlikely(pmd_leaf(pmd))) { > -??????????? /* See gup_fast_pte_range() */ > -??????????? if (pmd_protnone(pmd)) > -??????????????? return 0; > +??????? if (unlikely(pmd_leaf(pmd))) > +??????????? cur_nr_pages = gup_fast_pmd_leaf(pmd, pmdp, addr, next, > flags, pages); > +??????? else > +??????????? cur_nr_pages = gup_fast_pte_range(pmd, pmdp, addr, next, > flags, pages); > > -??????????? if (!gup_fast_pmd_leaf(pmd, pmdp, addr, next, flags, > -??????????????? pages, nr)) > -??????????????? return 0; > +??????? nr_pages += cur_nr_pages; > +??????? pages += cur_nr_pages; > > -??????? } else if (!gup_fast_pte_range(pmd, pmdp, addr, next, flags, > -?????????????????????????? pages, nr)) > -??????????? return 0; > +??????? if (nr_pages != (next - addr) >> PAGE_SIZE) > +??????????? break; > ???? } while (pmdp++, addr = next, addr != end); > > -??? return 1; > +??? return nr_pages; > ?} > > ?static int gup_fast_pud_range(p4d_t *p4dp, p4d_t p4d, unsigned long addr, From donald.hunter at gmail.com Mon Sep 8 10:35:04 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Mon, 08 Sep 2025 10:35:04 -0000 Subject: [PATCH net-next 10/11] tools: ynl: decode hex input In-Reply-To: References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-10-ast@fiberby.net> <410d69e5-d1f8-40e0-84b1-b5d56e0d9366@intel.com> Message-ID: Asbj?rn Sloth T?nnesen writes: > On 9/6/25 12:27 AM, Jacob Keller wrote: >> On 9/5/2025 3:51 AM, Donald Hunter wrote: >>> Asbj?rn Sloth T?nnesen writes: >>> >>>> This patch add support for decoding hex input, so >>>> that binary attributes can be read through --json. >>>> >>>> Example (using future wireguard.yaml): >>>> $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ >>>> --do set-device --json '{"ifindex":3, >>>> "private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}' >>>> >>>> Signed-off-by: Asbj?rn Sloth T?nnesen >>> >>> Reviewed-by: Donald Hunter >>> >>> FWIW, the hex can include spaces or not when using bytes.fromhex(). When >>> formatting hex for output, I chose to include spaces, but I don't really >>> know if that was a good choice or not. >> I also prefer the spaces for readability. > I formatted it with spaces for clarity, even without spaces it was a bit > long for one line. Spaces also has the advantage that you don't have to > think about endianness. > > Should we define the display hints a bit more in a .rst, or is it OK that > they end up being implementation specific for each language library? Do we > want them to behave the same in a Rust YNL library, as they do in Python? Yes we should probably extend the existing doc to at least describe some of the defacto behaviour. https://docs.kernel.org/userspace-api/netlink/specs.html#display-hint > BTW: The rest of the key used in the example can be found with this key-gen: > $ printf "hello world" | sha1sum > [redacted key material] From lorenzo.stoakes at oracle.com Mon Sep 8 12:26:10 2025 From: lorenzo.stoakes at oracle.com (Lorenzo Stoakes) Date: Mon, 08 Sep 2025 12:26:10 -0000 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <85e760cf-b994-40db-8d13-221feee55c60@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <016307ba-427d-4646-8e4d-1ffefd2c1968@nvidia.com> <85e760cf-b994-40db-8d13-221feee55c60@redhat.com> Message-ID: <727cabec-5ee8-4793-926b-8d78febcd623@lucifer.local> On Sat, Sep 06, 2025 at 08:56:48AM +0200, David Hildenbrand wrote: > On 06.09.25 03:05, John Hubbard wrote: > > > > Probably a similar sentiment as Lorenzo here...the above diffs make the code > > *worse* to read. In fact, I recall adding record_subpages() here long ago, > > specifically to help clarify what was going on. > > Well, there is a lot I dislike about record_subpages() to go back there. > Starting with "as Willy keeps explaining, the concept of subpages do > not exist and ending with "why do we fill out the array even on failure". Yes > > :) > > > > > Now it's been returned to it's original, cryptic form. > > > > The code in the caller was so uncryptic that both me and Lorenzo missed > that magical addition. :P :'( > > > Just my take on it, for whatever that's worth. :) > > As always, appreciated. > > I could of course keep the simple loop in some "record_folio_pages" > function and clean up what I dislike about record_subpages(). > > But I much rather want the call chain to be cleaned up instead, if possible. > > > Roughly, what I am thinking (limiting it to pte+pmd case) about is the following: I cannot get the below to apply even with the original patch here applied + fix. It looks like (in mm-new :) commit e73f43a66d5f ("mm/gup: remove dead pgmap refcounting code") by Alastair has conflicted here, but even then I can't make it apply, with/without your fix...! > > > From d6d6d21dbf435d8030782a627175e36e6c7b2dfb Mon Sep 17 00:00:00 2001 > From: David Hildenbrand > Date: Sat, 6 Sep 2025 08:33:42 +0200 > Subject: [PATCH] tmp > > Signed-off-by: David Hildenbrand > --- > mm/gup.c | 79 ++++++++++++++++++++++++++------------------------------ > 1 file changed, 36 insertions(+), 43 deletions(-) > > diff --git a/mm/gup.c b/mm/gup.c > index 22420f2069ee1..98907ead749c0 100644 > --- a/mm/gup.c > +++ b/mm/gup.c > @@ -2845,12 +2845,11 @@ static void __maybe_unused gup_fast_undo_dev_pagemap(int *nr, int nr_start, > * also check pmd here to make sure pmd doesn't change (corresponds to > * pmdp_collapse_flush() in the THP collapse code path). > */ > -static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, > - unsigned long end, unsigned int flags, struct page **pages, > - int *nr) > +static unsigned long gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, > + unsigned long end, unsigned int flags, struct page **pages) > { > struct dev_pagemap *pgmap = NULL; > - int ret = 0; > + unsigned long nr_pages = 0; > pte_t *ptep, *ptem; > ptem = ptep = pte_offset_map(&pmd, addr); > @@ -2908,24 +2907,20 @@ static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, > * details. > */ > if (flags & FOLL_PIN) { > - ret = arch_make_folio_accessible(folio); > - if (ret) { > + if (arch_make_folio_accessible(folio)) { > gup_put_folio(folio, 1, flags); > goto pte_unmap; > } > } > folio_set_referenced(folio); > - pages[*nr] = page; > - (*nr)++; > + pages[nr_pages++] = page; > } while (ptep++, addr += PAGE_SIZE, addr != end); > - ret = 1; > - > pte_unmap: > if (pgmap) > put_dev_pagemap(pgmap); > pte_unmap(ptem); > - return ret; > + return nr_pages; > } > #else > @@ -2938,21 +2933,24 @@ static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, > * get_user_pages_fast_only implementation that can pin pages. Thus it's still > * useful to have gup_fast_pmd_leaf even if we can't operate on ptes. > */ > -static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, > - unsigned long end, unsigned int flags, struct page **pages, > - int *nr) > +static unsigned long gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, > + unsigned long end, unsigned int flags, struct page **pages) > { > return 0; > } > #endif /* CONFIG_ARCH_HAS_PTE_SPECIAL */ > -static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > - unsigned long end, unsigned int flags, struct page **pages, > - int *nr) > +static unsigned long gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > + unsigned long end, unsigned int flags, struct page **pages) > { > + const unsigned long nr_pages = (end - addr) >> PAGE_SHIFT; > struct page *page; > struct folio *folio; > - int refs; > + unsigned long i; > + > + /* See gup_fast_pte_range() */ > + if (pmd_protnone(orig)) > + return 0; > if (!pmd_access_permitted(orig, flags & FOLL_WRITE)) > return 0; > @@ -2960,33 +2958,30 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > if (pmd_special(orig)) > return 0; > - refs = (end - addr) >> PAGE_SHIFT; > page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); > - folio = try_grab_folio_fast(page, refs, flags); > + folio = try_grab_folio_fast(page, nr_pages, flags); > if (!folio) > return 0; > if (unlikely(pmd_val(orig) != pmd_val(*pmdp))) { > - gup_put_folio(folio, refs, flags); > + gup_put_folio(folio, nr_pages, flags); > return 0; > } > if (!gup_fast_folio_allowed(folio, flags)) { > - gup_put_folio(folio, refs, flags); > + gup_put_folio(folio, nr_pages, flags); > return 0; > } > if (!pmd_write(orig) && gup_must_unshare(NULL, flags, &folio->page)) { > - gup_put_folio(folio, refs, flags); > + gup_put_folio(folio, nr_pages, flags); > return 0; > } > - pages += *nr; > - *nr += refs; > - for (; refs; refs--) > + for (i = 0; i < nr_pages; i++) > *(pages++) = page++; > folio_set_referenced(folio); > - return 1; > + return nr_pages; > } > static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > @@ -3033,11 +3028,11 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > return 1; > } > -static int gup_fast_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr, > - unsigned long end, unsigned int flags, struct page **pages, > - int *nr) > +static unsigned long gup_fast_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr, > + unsigned long end, unsigned int flags, struct page **pages) > { > - unsigned long next; > + unsigned long cur_nr_pages, next; > + unsigned long nr_pages = 0; > pmd_t *pmdp; > pmdp = pmd_offset_lockless(pudp, pud, addr); > @@ -3046,23 +3041,21 @@ static int gup_fast_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr, > next = pmd_addr_end(addr, end); > if (!pmd_present(pmd)) > - return 0; > + break; > - if (unlikely(pmd_leaf(pmd))) { > - /* See gup_fast_pte_range() */ > - if (pmd_protnone(pmd)) > - return 0; > + if (unlikely(pmd_leaf(pmd))) > + cur_nr_pages = gup_fast_pmd_leaf(pmd, pmdp, addr, next, flags, pages); > + else > + cur_nr_pages = gup_fast_pte_range(pmd, pmdp, addr, next, flags, pages); > - if (!gup_fast_pmd_leaf(pmd, pmdp, addr, next, flags, > - pages, nr)) > - return 0; > + nr_pages += cur_nr_pages; > + pages += cur_nr_pages; > - } else if (!gup_fast_pte_range(pmd, pmdp, addr, next, flags, > - pages, nr)) > - return 0; > + if (nr_pages != (next - addr) >> PAGE_SIZE) > + break; > } while (pmdp++, addr = next, addr != end); > - return 1; > + return nr_pages; > } > static int gup_fast_pud_range(p4d_t *p4dp, p4d_t p4d, unsigned long addr, OK I guess you intentionally left the rest as a TODO :) So I'll wait for you to post it before reviewing in-depth. This generally LGTM as an approach, getting rid of *nr is important that's really horrible. > -- > 2.50.1 > > > > Oh, I might even have found a bug moving away from that questionable > "ret==1 means success" handling in gup_fast_pte_range()? Will > have to double-check, but likely the following is the right thing to do. > > > > From 8f48b25ef93e7ef98611fd58ec89384ad5171782 Mon Sep 17 00:00:00 2001 > From: David Hildenbrand > Date: Sat, 6 Sep 2025 08:46:45 +0200 > Subject: [PATCH] mm/gup: fix handling of errors from > arch_make_folio_accessible() in follow_page_pte() > > In case we call arch_make_folio_accessible() and it fails, we would > incorrectly return a value that is "!= 0" to the caller, indicating that > we pinned all requested pages and that the caller can keep going. > > follow_page_pte() is not supposed to return error values, but instead > 0 on failure and 1 on success. > > That is of course wrong, because the caller will just keep going pinning > more pages. If we happen to pin a page afterwards, we're in trouble, > because we essentially skipped some pages. > > Fixes: f28d43636d6f ("mm/gup/writeback: add callbacks for inaccessible pages") > Signed-off-by: David Hildenbrand > --- > mm/gup.c | 3 +-- > 1 file changed, 1 insertion(+), 2 deletions(-) > > diff --git a/mm/gup.c b/mm/gup.c > index 22420f2069ee1..cff226ec0ee7d 100644 > --- a/mm/gup.c > +++ b/mm/gup.c > @@ -2908,8 +2908,7 @@ static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, > * details. > */ > if (flags & FOLL_PIN) { > - ret = arch_make_folio_accessible(folio); > - if (ret) { > + if (arch_make_folio_accessible(folio)) { Oh Lord above. Lol. Yikes. Yeah I think your fix is valid... > gup_put_folio(folio, 1, flags); > goto pte_unmap; > } > -- > 2.50.1 > > > -- > Cheers > > David / dhildenb > From jhubbard at nvidia.com Mon Sep 8 17:12:10 2025 From: jhubbard at nvidia.com (John Hubbard) Date: Mon, 08 Sep 2025 17:12:10 -0000 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <7ee0b58a-8fe4-46fe-bfef-f04f900f3040@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <016307ba-427d-4646-8e4d-1ffefd2c1968@nvidia.com> <85e760cf-b994-40db-8d13-221feee55c60@redhat.com> <727cabec-5ee8-4793-926b-8d78febcd623@lucifer.local> <7ee0b58a-8fe4-46fe-bfef-f04f900f3040@redhat.com> Message-ID: On 9/8/25 5:53 AM, David Hildenbrand wrote: > On 08.09.25 14:25, Lorenzo Stoakes wrote: >> On Sat, Sep 06, 2025 at 08:56:48AM +0200, David Hildenbrand wrote: >>> On 06.09.25 03:05, John Hubbard wrote: ... >>> Roughly, what I am thinking (limiting it to pte+pmd case) about is >>> the following: >> >> I cannot get the below to apply even with the original patch here >> applied + fix. >> >> It looks like (in mm-new :) commit e73f43a66d5f ("mm/gup: remove dead >> pgmap >> refcounting code") by Alastair has conflicted here, but even then I >> can't make >> it apply, with/without your fix...! I eventually resorted to telling the local AI to read the diffs and apply them on top of the nth_page series locally. :) Attaching the resulting patch, which worked well enough to at least see the proposal clearly. > > To be clear: it was never intended to be applied, because it wouldn't > even compile in the current form. > > It was based on this nth_page submission + fix. > > thanks, -- John Hubbard -------------- next part -------------- A non-text attachment was scrubbed... Name: 0001-David-Hildenbrand-s-fix-for-record_subpages.patch Type: text/x-patch Size: 5603 bytes Desc: not available URL: From sd at queasysnail.net Tue Sep 9 18:10:07 2025 From: sd at queasysnail.net (Sabrina Dubroca) Date: Tue, 09 Sep 2025 18:10:07 -0000 Subject: [PATCH net-next 10/11] tools: ynl: decode hex input In-Reply-To: <20250904220156.1006541-10-ast@fiberby.net> References: <20250904-wg-ynl-prep@fiberby.net> <20250904220156.1006541-10-ast@fiberby.net> Message-ID: 2025-09-04, 22:01:33 +0000, Asbj?rn Sloth T?nnesen wrote: > This patch add support for decoding hex input, so > that binary attributes can be read through --json. > > Example (using future wireguard.yaml): > $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ > --do set-device --json '{"ifindex":3, > "private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}' > > Signed-off-by: Asbj?rn Sloth T?nnesen > --- > tools/net/ynl/pyynl/lib/ynl.py | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py > index a37294a751da..78c0245ca587 100644 > --- a/tools/net/ynl/pyynl/lib/ynl.py > +++ b/tools/net/ynl/pyynl/lib/ynl.py > @@ -973,6 +973,8 @@ class YnlFamily(SpecFamily): > raw = ip.packed > else: > raw = int(ip) > + elif attr_spec.display_hint == 'hex': > + raw = bytes.fromhex(string) I'm working on a spec for macsec and ended up with a similar change, but doing instead: + elif attr_spec.display_hint == 'hex': + raw = int(string, 16) since the destination attribute is u32/u64 and not binary for macsec. So maybe this should be: + if attr_spec['type'] == 'binary': + raw = bytes.fromhex(string) + else: + raw = int(string, 16) to cover both cases? I think it matches better what's already in _formatted_string. (I don't mind having the current patch go in and making this change together with the macsec spec when it's ready) > else: > raise Exception(f"Display hint '{attr_spec.display_hint}' not implemented" > f" when parsing '{attr_spec['name']}'") > -- > 2.51.0 > > -- Sabrina From donald.hunter at gmail.com Thu Sep 11 11:20:54 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Thu, 11 Sep 2025 11:20:54 -0000 Subject: [PATCH net-next v2 05/12] tools: ynl-gen: add CodeWriter.p_lines() helper In-Reply-To: <20250910230841.384545-6-ast@fiberby.net> References: <20250910230841.384545-1-ast@fiberby.net> <20250910230841.384545-6-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > Add a helper for writing an array of lines, and convert > all the existing loops doing that, to use the new helper. > > This is a trivial patch with no behavioural changes intended, > there are no changes to the generated code. > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From donald.hunter at gmail.com Fri Sep 12 12:08:50 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 12 Sep 2025 12:08:50 -0000 Subject: [PATCH net-next v3 04/13] tools: ynl-gen: refactor local vars for .attr_put() callers In-Reply-To: <20250911200508.79341-5-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-5-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > Refactor the generation of local variables needed when building > requests, by moving the logic into the Type classes, and use the > same helper in all places where .attr_put() is called. > > If any attributes requests identical local_vars, then they will > be deduplicated, attributes are assumed to only use their local > variables transiently. > > This patch fixes the build errors below: > $ make -C tools/net/ynl/generated/ > [...] > -e GEN wireguard-user.c > -e GEN wireguard-user.h > -e CC wireguard-user.o > wireguard-user.c: In function ?wireguard_get_device_dump?: > wireguard-user.c:480:9: error: ?array? undeclared (first use in func) > 480 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); > | ^~~~~ > wireguard-user.c:480:9: note: each undeclared identifier is reported > only once for each function it appears in > wireguard-user.c:481:14: error: ?i? undeclared (first use in func) > 481 | for (i = 0; i < req->_count.peers; i++) > | ^ > wireguard-user.c: In function ?wireguard_set_device?: > wireguard-user.c:533:9: error: ?array? undeclared (first use in func) > 533 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS); > | ^~~~~ > make: *** [Makefile:52: wireguard-user.o] Error 1 > make: Leaving directory '/usr/src/linux/tools/net/ynl/generated' > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From donald.hunter at gmail.com Fri Sep 12 12:08:51 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 12 Sep 2025 12:08:51 -0000 Subject: [PATCH net-next v3 06/13] tools: ynl-gen: deduplicate fixed_header handling In-Reply-To: <20250911200508.79341-7-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-7-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > Fixed headers are handled nearly identical in print_dump(), > print_req() and put_req_nested(), generalize them and use a > common function to generate them. > > This only causes cosmetic changes to tc_netem_attrs_put() in > tc-user.c. > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From donald.hunter at gmail.com Fri Sep 12 12:08:53 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 12 Sep 2025 12:08:53 -0000 Subject: [PATCH net-next v3 07/13] tools: ynl-gen: avoid repetitive variables definitions In-Reply-To: <20250911200508.79341-8-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-8-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > In the generated attribute parsing code, avoid repetitively > defining the same variables over and over again, local to > the conditional block for each attribute. > > This patch consolidates the definitions of local variables > for attribute parsing, so that they are defined at the > function level, and re-used across attributes, thus making > the generated code read more natural. > > If attributes defines identical local_vars, then they will > be deduplicated, attributes are assumed to only use their > local variables transiently. > > ... > > Suggested-by: Jakub Kicinski > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From donald.hunter at gmail.com Fri Sep 12 12:08:57 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 12 Sep 2025 12:08:57 -0000 Subject: [PATCH net-next v3 12/13] tools: ynl: decode hex input In-Reply-To: <20250911200508.79341-13-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-13-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > This patch adds support for decoding hex input, so > that binary attributes can be read through --json. > > Example (using future wireguard.yaml): > $ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \ > --do set-device --json '{"ifindex":3, > "private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}' > > In order to somewhat mirror what is done in _formatted_string(), > then for non-binary attributes attempt to convert it to an int. > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From torin at tcarey.uk Mon Sep 15 11:58:39 2025 From: torin at tcarey.uk (Torin Carey) Date: Mon, 15 Sep 2025 11:58:39 -0000 Subject: [PATCH] wireguard: do not use sin6_scope_id if not needed Message-ID: sin6_scope_id should only be used if the address is link-local and otherwise ignored. Currently send6 uses the sin6_scope_id for flowi6_oif without a check of whether this is needed, so this can cause non-link local endpoints to use an incorrect device. Signed-off-by: Torin Carey --- drivers/net/wireguard/netlink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c index 67f962eb8b46..738041f72c2b 100644 --- a/drivers/net/wireguard/netlink.c +++ b/drivers/net/wireguard/netlink.c @@ -453,6 +453,8 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs) wg_socket_set_peer_endpoint(peer, &endpoint); } else if (len == sizeof(struct sockaddr_in6) && addr->sa_family == AF_INET6) { endpoint.addr6 = *(struct sockaddr_in6 *)addr; + if (!__ipv6_addr_needs_scope_id(ipv6_addr_type(&endpoint.addr6.sin6_addr))) + endpoint.addr6.sin6_scope_id = 0; wg_socket_set_peer_endpoint(peer, &endpoint); } } base-commit: 8f5ae30d69d7543eee0d70083daf4de8fe15d585 -- 2.48.1 From ast at fiberby.net Wed Sep 17 11:52:42 2025 From: ast at fiberby.net (=?UTF-8?Q?Asbj=C3=B8rn_Sloth_T=C3=B8nnesen?=) Date: Wed, 17 Sep 2025 11:52:42 -0000 Subject: [RFC net-next 00/14] wireguard: netlink: ynl conversion In-Reply-To: References: <20250904-wg-ynl-rfc@fiberby.net> Message-ID: On 9/16/25 3:51 PM, Jason A. Donenfeld wrote: > On Fri, Sep 5, 2025 at 12:03?AM Asbj?rn Sloth T?nnesen wrote: >> >> This series contains the wireguard changes needed to adopt >> an YNL-based generated netlink code. >> >> This RFC series is posted for reference, as it is referenced >> from the current v1 series of ynl preparations, which has to >> go in before this series can be submitted for net-next. > > I'm not actually convinced this makes anything better. It seems like > the code becomes more complicated and less obvious. What is the > benefit here? As is, I really don't like this direction. By adding an YNL spec, we lower the barrier for implementing and using the protocol especially from non-C languages. The specs are currently used for: - Documentation generation [1]. - Optional UAPI header generation. - Optional kernel netlink code generation. - In-tree user-space clients: - Auto-generated C library code. - Optional sample program using above C library. - Python client - ./tools/net/ynl/pyynl/cli.py. The generated kernel code is still committed in git, and is thus protected from accidental changes. When we can generate the UAPI from the spec., with only cosmetic differences it proves that the spec is correct. Same goes for generating the netlink policy generation. I have split up adopting the generated UAPI and netlink code, over many patches mostly to keep the diff readable, as the code moves would otherwise become interlaced. Including a sample program, makes it trivial to exercise the generated C library. This RFC is a bit more complicated, than v1 will be, as it includes an alternative implementation for patch 4 in patch 12, I had hoped those patches would have generated some comments. Right now it looks like, they will both be squashed into patch 3 in v1. I can also split this series up further, if you would prefer that. [1] https://docs.kernel.org/networking/netlink_spec/ From torin at tcarey.uk Thu Sep 18 12:33:03 2025 From: torin at tcarey.uk (Torin Carey) Date: Thu, 18 Sep 2025 12:33:03 -0000 Subject: [PATCH] wireguard: remove unnecessary use of ipv6_stub Message-ID: <20250918123234.297856-1-torin@tcarey.uk> ipv6_stub is required for cases where ipv6 may be compiled as a module and might not be loaded from a given context. wireguard has a Kconfig dependence of IPV6 || !IPV6 so will also be compiled as a module if ipv6 is, and wireguard already accesses a symbol of this module via ipv6_mod_enabled, so already has a module dependence on ipv6. Removal is desireable since it removes an unnecessary indirect branch, but also reduces the effort needed should ipv6_stub ever be modified/replaced. Signed-off-by: Torin Carey --- drivers/net/wireguard/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireguard/socket.c b/drivers/net/wireguard/socket.c index 253488f8c00f..593324d564d2 100644 --- a/drivers/net/wireguard/socket.c +++ b/drivers/net/wireguard/socket.c @@ -136,8 +136,8 @@ static int send6(struct wg_device *wg, struct sk_buff *skb, if (cache) dst_cache_reset(cache); } - dst = ipv6_stub->ipv6_dst_lookup_flow(sock_net(sock), sock, &fl, - NULL); + dst = ip6_dst_lookup_flow(sock_net(sock), sock, &fl, + NULL); if (IS_ERR(dst)) { ret = PTR_ERR(dst); net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n", base-commit: 8f5ae30d69d7543eee0d70083daf4de8fe15d585 -- 2.48.1 From lorenzo.stoakes at oracle.com Fri Sep 5 11:35:17 2025 From: lorenzo.stoakes at oracle.com (Lorenzo Stoakes) Date: Fri, 05 Sep 2025 11:35:17 -0000 Subject: [PATCH v2 19/37] mm/gup: remove record_subpages() In-Reply-To: <5090355d-546a-4d06-99e1-064354d156b5@redhat.com> References: <20250901150359.867252-1-david@redhat.com> <20250901150359.867252-20-david@redhat.com> <5090355d-546a-4d06-99e1-064354d156b5@redhat.com> Message-ID: On Fri, Sep 05, 2025 at 08:41:23AM +0200, David Hildenbrand wrote: > On 01.09.25 17:03, David Hildenbrand wrote: > > We can just cleanup the code by calculating the #refs earlier, > > so we can just inline what remains of record_subpages(). > > > > Calculate the number of references/pages ahead of times, and record them > > only once all our tests passed. > > > > Signed-off-by: David Hildenbrand So strange I thought I looked at this...! > > --- > > mm/gup.c | 25 ++++++++----------------- > > 1 file changed, 8 insertions(+), 17 deletions(-) > > > > diff --git a/mm/gup.c b/mm/gup.c > > index c10cd969c1a3b..f0f4d1a68e094 100644 > > --- a/mm/gup.c > > +++ b/mm/gup.c > > @@ -484,19 +484,6 @@ static inline void mm_set_has_pinned_flag(struct mm_struct *mm) > > #ifdef CONFIG_MMU > > #ifdef CONFIG_HAVE_GUP_FAST > > -static int record_subpages(struct page *page, unsigned long sz, > > - unsigned long addr, unsigned long end, > > - struct page **pages) > > -{ > > - int nr; > > - > > - page += (addr & (sz - 1)) >> PAGE_SHIFT; > > - for (nr = 0; addr != end; nr++, addr += PAGE_SIZE) > > - pages[nr] = page++; > > - > > - return nr; > > -} > > - > > /** > > * try_grab_folio_fast() - Attempt to get or pin a folio in fast path. > > * @page: pointer to page to be grabbed > > @@ -2967,8 +2954,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > > if (pmd_special(orig)) > > return 0; > > - page = pmd_page(orig); > > - refs = record_subpages(page, PMD_SIZE, addr, end, pages + *nr); > > + refs = (end - addr) >> PAGE_SHIFT; > > + page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT); > > folio = try_grab_folio_fast(page, refs, flags); > > if (!folio) > > @@ -2989,6 +2976,8 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > > } > > *nr += refs; > > + for (; refs; refs--) > > + *(pages++) = page++; > > folio_set_referenced(folio); > > return 1; > > } > > @@ -3007,8 +2996,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > > if (pud_special(orig)) > > return 0; > > - page = pud_page(orig); > > - refs = record_subpages(page, PUD_SIZE, addr, end, pages + *nr); > > + refs = (end - addr) >> PAGE_SHIFT; > > + page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT); > > folio = try_grab_folio_fast(page, refs, flags); > > if (!folio) > > @@ -3030,6 +3019,8 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > > } > > *nr += refs; > > + for (; refs; refs--) > > + *(pages++) = page++; > > folio_set_referenced(folio); > > return 1; > > } > > Okay, this code is nasty. We should rework this code to just return the nr and receive a the proper > pages pointer, getting rid of the "*nr" parameter. > > For the time being, the following should do the trick: > > commit bfd07c995814354f6b66c5b6a72e96a7aa9fb73b (HEAD -> nth_page) > Author: David Hildenbrand > Date: Fri Sep 5 08:38:43 2025 +0200 > > fixup: mm/gup: remove record_subpages() > pages is not adjusted by the caller, but idnexed by existing *nr. > Signed-off-by: David Hildenbrand > > diff --git a/mm/gup.c b/mm/gup.c > index 010fe56f6e132..22420f2069ee1 100644 > --- a/mm/gup.c > +++ b/mm/gup.c > @@ -2981,6 +2981,7 @@ static int gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp, unsigned long addr, > return 0; > } > + pages += *nr; > *nr += refs; > for (; refs; refs--) > *(pages++) = page++; > @@ -3024,6 +3025,7 @@ static int gup_fast_pud_leaf(pud_t orig, pud_t *pudp, unsigned long addr, > return 0; > } > + pages += *nr; > *nr += refs; > for (; refs; refs--) > *(pages++) = page++; This looks correct. But. This is VERY nasty. Before we'd call record_subpages() with pages + *nr, where it was clear we were offsetting by this, now we're making things imo way more confusing. This makes me less in love with this approach to be honest. But perhaps it's the least worst thing for now until we can do a bigger refactor... So since this seems correct to me, and for the sake of moving things forward (was this one patch dropped from mm-new or does mm-new just have an old version? Confused): Reviewed-by: Lorenzo Stoakes For this patch obviously with the fix applied. But can we PLEASE revisit this :) > > > -- > > Cheers > > David / dhildenb > Cheers, Lorenzo From donald.hunter at gmail.com Fri Sep 12 12:08:54 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 12 Sep 2025 12:08:54 -0000 Subject: [PATCH net-next v3 09/13] tools: ynl-gen: rename TypeArrayNest to TypeIndexedArray In-Reply-To: <20250911200508.79341-10-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-10-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > Since TypeArrayNest can now be used with many other sub-types > than nest, then rename it to TypeIndexedArray, to reduce > confusion. > > This patch continues the rename, that was started in commit > aa6485d813ad ("ynl: rename array-nest to indexed-array"), > when the YNL type was renamed. > > In order to get rid of all references to the old naming, > within ynl, then renaming some variables in _multi_parse(). > > This is a trivial patch with no behavioural changes intended. > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter From donald.hunter at gmail.com Fri Sep 12 12:08:56 2025 From: donald.hunter at gmail.com (Donald Hunter) Date: Fri, 12 Sep 2025 12:08:56 -0000 Subject: [PATCH net-next v3 11/13] tools: ynl: encode indexed-arrays In-Reply-To: <20250911200508.79341-12-ast@fiberby.net> References: <20250911200508.79341-1-ast@fiberby.net> <20250911200508.79341-12-ast@fiberby.net> Message-ID: Asbj?rn Sloth T?nnesen writes: > This patch adds support for encoding indexed-array > attributes with sub-type nest in pyynl. > > Signed-off-by: Asbj?rn Sloth T?nnesen Reviewed-by: Donald Hunter