Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpftool: Specify XDP Hints ifname when loading program

Add ability to specify a network interface used to resolve XDP hints
kfuncs when loading program through bpftool.

Usage:

bpftool prog load [...] xdpmeta_dev <ifname>

Writing just 'dev <ifname>' instead of 'xdpmeta_dev' is a very probable
mistake that results in not very descriptive errors,
so 'bpftool prog load [...] dev <ifname>' syntax becomes deprecated,
followed by 'bpftool map create [...] dev <ifname>' for consistency.

Now, to offload program, execute:

bpftool prog load [...] offload_dev <ifname>

To offload map:

bpftool map create [...] offload_dev <ifname>

'dev <ifname>' still performs offloading in the commands above, but now
triggers a warning and is excluded from bash completion.

'xdpmeta_dev' and 'offload_dev' are mutually exclusive options, because
'xdpmeta_dev' basically makes a program device-bound without loading it
onto the said device. For now, offloaded programs cannot use XDP hints [0],
but if this changes, using 'offload_dev <ifname>' should cover this case.

[0] https://lore.kernel.org/bpf/a5a636cc-5b03-686f-4be0-000383b05cfc@linux.dev

Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Quentin Monnet <quentin@isovalent.com>
Link: https://lore.kernel.org/bpf/20230517160103.1088185-1-larysa.zaremba@intel.com

authored by

Larysa Zaremba and committed by
Daniel Borkmann
f46392ee 6cc385d2

+64 -20
+4 -4
tools/bpf/bpftool/Documentation/bpftool-map.rst
··· 28 28 | **bpftool** **map** { **show** | **list** } [*MAP*] 29 29 | **bpftool** **map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* \ 30 30 | **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**inner_map** *MAP*] \ 31 - | [**dev** *NAME*] 31 + | [**offload_dev** *NAME*] 32 32 | **bpftool** **map dump** *MAP* 33 33 | **bpftool** **map update** *MAP* [**key** *DATA*] [**value** *VALUE*] [*UPDATE_FLAGS*] 34 34 | **bpftool** **map lookup** *MAP* [**key** *DATA*] ··· 73 73 maps. On such kernels bpftool will automatically emit this 74 74 information as well. 75 75 76 - **bpftool map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**inner_map** *MAP*] [**dev** *NAME*] 76 + **bpftool map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**inner_map** *MAP*] [**offload_dev** *NAME*] 77 77 Create a new map with given parameters and pin it to *bpffs* 78 78 as *FILE*. 79 79 ··· 86 86 kernel needs it to collect metadata related to the inner maps 87 87 that the new map will work with. 88 88 89 - Keyword **dev** expects a network interface name, and is used 90 - to request hardware offload for the map. 89 + Keyword **offload_dev** expects a network interface name, 90 + and is used to request hardware offload for the map. 91 91 92 92 **bpftool map dump** *MAP* 93 93 Dump all entries in a given *MAP*. In case of **name**,
+7 -4
tools/bpf/bpftool/Documentation/bpftool-prog.rst
··· 31 31 | **bpftool** **prog dump xlated** *PROG* [{ **file** *FILE* | [**opcodes**] [**linum**] [**visual**] }] 32 32 | **bpftool** **prog dump jited** *PROG* [{ **file** *FILE* | [**opcodes**] [**linum**] }] 33 33 | **bpftool** **prog pin** *PROG* *FILE* 34 - | **bpftool** **prog** { **load** | **loadall** } *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] [**pinmaps** *MAP_DIR*] [**autoattach**] 34 + | **bpftool** **prog** { **load** | **loadall** } *OBJ* *PATH* [**type** *TYPE*] [**map** { **idx** *IDX* | **name** *NAME* } *MAP*] [{ **offload_dev** | **xdpmeta_dev** } *NAME*] [**pinmaps** *MAP_DIR*] [**autoattach**] 35 35 | **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*] 36 36 | **bpftool** **prog detach** *PROG* *ATTACH_TYPE* [*MAP*] 37 37 | **bpftool** **prog tracelog** ··· 129 129 contain a dot character ('.'), which is reserved for future 130 130 extensions of *bpffs*. 131 131 132 - **bpftool prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] [**pinmaps** *MAP_DIR*] [**autoattach**] 132 + **bpftool prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** { **idx** *IDX* | **name** *NAME* } *MAP*] [{ **offload_dev** | **xdpmeta_dev** } *NAME*] [**pinmaps** *MAP_DIR*] [**autoattach**] 133 133 Load bpf program(s) from binary *OBJ* and pin as *PATH*. 134 134 **bpftool prog load** pins only the first program from the 135 135 *OBJ* as *PATH*. **bpftool prog loadall** pins all programs ··· 143 143 to be replaced in the ELF file counting from 0, while *NAME* 144 144 allows to replace a map by name. *MAP* specifies the map to 145 145 use, referring to it by **id** or through a **pinned** file. 146 - If **dev** *NAME* is specified program will be loaded onto 147 - given networking device (offload). 146 + If **offload_dev** *NAME* is specified program will be loaded 147 + onto given networking device (offload). 148 + If **xdpmeta_dev** *NAME* is specified program will become 149 + device-bound without offloading, this facilitates access 150 + to XDP metadata. 148 151 Optional **pinmaps** argument can be provided to pin all 149 152 maps under *MAP_DIR* directory. 150 153
+4 -3
tools/bpf/bpftool/bash-completion/bpftool
··· 278 278 _bpftool_get_prog_tags 279 279 return 0 280 280 ;; 281 - dev) 281 + dev|offload_dev|xdpmeta_dev) 282 282 _sysfs_get_netdevs 283 283 return 0 284 284 ;; ··· 508 508 ;; 509 509 *) 510 510 COMPREPLY=( $( compgen -W "map" -- "$cur" ) ) 511 - _bpftool_once_attr 'type dev pinmaps autoattach' 511 + _bpftool_once_attr 'type pinmaps autoattach' 512 + _bpftool_one_of_list 'offload_dev xdpmeta_dev' 512 513 return 0 513 514 ;; 514 515 esac ··· 734 733 esac 735 734 ;; 736 735 *) 737 - _bpftool_once_attr 'type key value entries name flags dev' 736 + _bpftool_once_attr 'type key value entries name flags offload_dev' 738 737 if _bpftool_search_list 'array_of_maps' 'hash_of_maps'; then 739 738 _bpftool_once_attr 'inner_map' 740 739 fi
+6 -1
tools/bpf/bpftool/map.c
··· 1287 1287 "flags")) 1288 1288 goto exit; 1289 1289 } else if (is_prefix(*argv, "dev")) { 1290 + p_info("Warning: 'bpftool map create [...] dev <ifname>' syntax is deprecated.\n" 1291 + "Going further, please use 'offload_dev <ifname>' to request hardware offload for the map."); 1292 + goto offload_dev; 1293 + } else if (is_prefix(*argv, "offload_dev")) { 1294 + offload_dev: 1290 1295 NEXT_ARG(); 1291 1296 1292 1297 if (attr.map_ifindex) { ··· 1436 1431 "Usage: %1$s %2$s { show | list } [MAP]\n" 1437 1432 " %1$s %2$s create FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n" 1438 1433 " entries MAX_ENTRIES name NAME [flags FLAGS] \\\n" 1439 - " [inner_map MAP] [dev NAME]\n" 1434 + " [inner_map MAP] [offload_dev NAME]\n" 1440 1435 " %1$s %2$s dump MAP\n" 1441 1436 " %1$s %2$s update MAP [key DATA] [value VALUE] [UPDATE_FLAGS]\n" 1442 1437 " %1$s %2$s lookup MAP [key DATA]\n"
+43 -8
tools/bpf/bpftool/prog.c
··· 1517 1517 struct bpf_program *prog = NULL, *pos; 1518 1518 unsigned int old_map_fds = 0; 1519 1519 const char *pinmaps = NULL; 1520 + __u32 xdpmeta_ifindex = 0; 1521 + __u32 offload_ifindex = 0; 1520 1522 bool auto_attach = false; 1521 1523 struct bpf_object *obj; 1522 1524 struct bpf_map *map; 1523 1525 const char *pinfile; 1524 1526 unsigned int i, j; 1525 - __u32 ifindex = 0; 1526 1527 const char *file; 1527 1528 int idx, err; 1528 1529 ··· 1615 1614 map_replace[old_map_fds].fd = fd; 1616 1615 old_map_fds++; 1617 1616 } else if (is_prefix(*argv, "dev")) { 1617 + p_info("Warning: 'bpftool prog load [...] dev <ifname>' syntax is deprecated.\n" 1618 + "Going further, please use 'offload_dev <ifname>' to offload program to device.\n" 1619 + "For applications using XDP hints only, use 'xdpmeta_dev <ifname>'."); 1620 + goto offload_dev; 1621 + } else if (is_prefix(*argv, "offload_dev")) { 1622 + offload_dev: 1618 1623 NEXT_ARG(); 1619 1624 1620 - if (ifindex) { 1621 - p_err("offload device already specified"); 1625 + if (offload_ifindex) { 1626 + p_err("offload_dev already specified"); 1627 + goto err_free_reuse_maps; 1628 + } else if (xdpmeta_ifindex) { 1629 + p_err("xdpmeta_dev and offload_dev are mutually exclusive"); 1622 1630 goto err_free_reuse_maps; 1623 1631 } 1624 1632 if (!REQ_ARGS(1)) 1625 1633 goto err_free_reuse_maps; 1626 1634 1627 - ifindex = if_nametoindex(*argv); 1628 - if (!ifindex) { 1635 + offload_ifindex = if_nametoindex(*argv); 1636 + if (!offload_ifindex) { 1637 + p_err("unrecognized netdevice '%s': %s", 1638 + *argv, strerror(errno)); 1639 + goto err_free_reuse_maps; 1640 + } 1641 + NEXT_ARG(); 1642 + } else if (is_prefix(*argv, "xdpmeta_dev")) { 1643 + NEXT_ARG(); 1644 + 1645 + if (xdpmeta_ifindex) { 1646 + p_err("xdpmeta_dev already specified"); 1647 + goto err_free_reuse_maps; 1648 + } else if (offload_ifindex) { 1649 + p_err("xdpmeta_dev and offload_dev are mutually exclusive"); 1650 + goto err_free_reuse_maps; 1651 + } 1652 + if (!REQ_ARGS(1)) 1653 + goto err_free_reuse_maps; 1654 + 1655 + xdpmeta_ifindex = if_nametoindex(*argv); 1656 + if (!xdpmeta_ifindex) { 1629 1657 p_err("unrecognized netdevice '%s': %s", 1630 1658 *argv, strerror(errno)); 1631 1659 goto err_free_reuse_maps; ··· 1701 1671 goto err_close_obj; 1702 1672 } 1703 1673 1704 - bpf_program__set_ifindex(pos, ifindex); 1674 + if (prog_type == BPF_PROG_TYPE_XDP && xdpmeta_ifindex) { 1675 + bpf_program__set_flags(pos, BPF_F_XDP_DEV_BOUND_ONLY); 1676 + bpf_program__set_ifindex(pos, xdpmeta_ifindex); 1677 + } else { 1678 + bpf_program__set_ifindex(pos, offload_ifindex); 1679 + } 1705 1680 if (bpf_program__type(pos) != prog_type) 1706 1681 bpf_program__set_type(pos, prog_type); 1707 1682 bpf_program__set_expected_attach_type(pos, expected_attach_type); ··· 1744 1709 idx = 0; 1745 1710 bpf_object__for_each_map(map, obj) { 1746 1711 if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY) 1747 - bpf_map__set_ifindex(map, ifindex); 1712 + bpf_map__set_ifindex(map, offload_ifindex); 1748 1713 1749 1714 if (j < old_map_fds && idx == map_replace[j].idx) { 1750 1715 err = bpf_map__reuse_fd(map, map_replace[j++].fd); ··· 2451 2416 " %1$s %2$s dump jited PROG [{ file FILE | [opcodes] [linum] }]\n" 2452 2417 " %1$s %2$s pin PROG FILE\n" 2453 2418 " %1$s %2$s { load | loadall } OBJ PATH \\\n" 2454 - " [type TYPE] [dev NAME] \\\n" 2419 + " [type TYPE] [{ offload_dev | xdpmeta_dev } NAME] \\\n" 2455 2420 " [map { idx IDX | name NAME } MAP]\\\n" 2456 2421 " [pinmaps MAP_DIR]\n" 2457 2422 " [autoattach]\n"