€•m®Œsphinx.addnodes”Œdocument”“”)�”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)�”}”(hhh]”(hŒ pending_xref”“”)�”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…”�”}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ%/translations/zh_CN/networking/devmem”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)�”}”(hhh]”hŒChinese (Traditional)”…”�”}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ%/translations/zh_TW/networking/devmem”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒItalian”…”�”}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ%/translations/it_IT/networking/devmem”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒJapanese”…”�”}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ%/translations/ja_JP/networking/devmem”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒKorean”…”�”}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ%/translations/ko_KR/networking/devmem”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒPortuguese (Brazilian)”…”�”}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ%/translations/pt_BR/networking/devmem”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒSpanish”…”�”}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ%/translations/sp_SP/networking/devmem”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒcomment”“”)�”}”(hŒ SPDX-License-Identifier: GPL-2.0”h]”hŒ SPDX-License-Identifier: GPL-2.0”…”�”}”hh·sbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1hµhhh²hh³Œ?/var/lib/git/docbuild/linux/Documentation/networking/devmem.rst”h´KubhŒsection”“”)�”}”(hhh]”(hŒtitle”“”)�”}”(hŒDevice Memory TCP”h]”hŒDevice Memory TCP”…”�”}”(hhÏh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhhÊh²hh³hÇh´KubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒIntro”h]”hŒIntro”…”�”}”(hhàh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhhÝh²hh³hÇh´K ubhŒ paragraph”“”)�”}”(hŒ‘Device memory TCP (devmem TCP) enables receiving data directly into device memory (dmabuf). The feature is currently implemented for TCP sockets.”h]”hŒ‘Device memory TCP (devmem TCP) enables receiving data directly into device memory (dmabuf). The feature is currently implemented for TCP sockets.”…”�”}”(hhðh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K hhÝh²hubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒ Opportunity”h]”hŒ Opportunity”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhhþh²hh³hÇh´Kubhï)�”}”(hŒ²A large number of data transfers have device memory as the source and/or destination. Accelerators drastically increased the prevalence of such transfers. Some examples include:”h]”hŒ²A large number of data transfers have device memory as the source and/or destination. Accelerators drastically increased the prevalence of such transfers. Some examples include:”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Khhþh²hubhŒ bullet_list”“”)�”}”(hhh]”(hŒ list_item”“”)�”}”(hŒ]Distributed training, where ML accelerators, such as GPUs on different hosts, exchange data. ”h]”hï)�”}”(hŒ\Distributed training, where ML accelerators, such as GPUs on different hosts, exchange data.”h]”hŒ\Distributed training, where ML accelerators, such as GPUs on different hosts, exchange data.”…”�”}”(hj(h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Khj$ubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hjh²hh³hÇh´Nubj#)�”}”(hŒ�Distributed raw block storage applications transfer large amounts of data with remote SSDs. Much of this data does not require host processing. ”h]”hï)�”}”(hŒ�Distributed raw block storage applications transfer large amounts of data with remote SSDs. Much of this data does not require host processing.”h]”hŒ�Distributed raw block storage applications transfer large amounts of data with remote SSDs. Much of this data does not require host processing.”…”�”}”(hj@h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Khj<ubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hjh²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ-”uh1jh³hÇh´Khhþh²hubhï)�”}”(hŒÀTypically the Device-to-Device data transfers in the network are implemented as the following low-level operations: Device-to-Host copy, Host-to-Host network transfer, and Host-to-Device copy.”h]”hŒÀTypically the Device-to-Device data transfers in the network are implemented as the following low-level operations: Device-to-Host copy, Host-to-Host network transfer, and Host-to-Device copy.”…”�”}”(hj\h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Khhþh²hubhï)�”}”(hŒ·The flow involving host copies is suboptimal, especially for bulk data transfers, and can put significant strains on system resources such as host memory bandwidth and PCIe bandwidth.”h]”hŒ·The flow involving host copies is suboptimal, especially for bulk data transfers, and can put significant strains on system resources such as host memory bandwidth and PCIe bandwidth.”…”�”}”(hjjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K hhþh²hubhï)�”}”(hŒ”Devmem TCP optimizes this use case by implementing socket APIs that enable the user to receive incoming network packets directly into device memory.”h]”hŒ”Devmem TCP optimizes this use case by implementing socket APIs that enable the user to receive incoming network packets directly into device memory.”…”�”}”(hjxh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K$hhþh²hubhï)�”}”(hŒ:Packet payloads go directly from the NIC to device memory.”h]”hŒ:Packet payloads go directly from the NIC to device memory.”…”�”}”(hj†h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K'hhþh²hubhï)�”}”(hŒƒPacket headers go to host memory and are processed by the TCP/IP stack normally. The NIC must support header split to achieve this.”h]”hŒƒPacket headers go to host memory and are processed by the TCP/IP stack normally. The NIC must support header split to achieve this.”…”�”}”(hj”h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K)hhþh²hubhï)�”}”(hŒ Advantages:”h]”hŒ Advantages:”…”�”}”(hj¢h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K,hhþh²hubj)�”}”(hhh]”(j#)�”}”(hŒiAlleviate host memory bandwidth pressure, compared to existing network-transfer + device-copy semantics. ”h]”hï)�”}”(hŒhAlleviate host memory bandwidth pressure, compared to existing network-transfer + device-copy semantics.”h]”hŒhAlleviate host memory bandwidth pressure, compared to existing network-transfer + device-copy semantics.”…”�”}”(hj·h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K.hj³ubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hj°h²hh³hÇh´Nubj#)�”}”(hŒ°Alleviate PCIe bandwidth pressure, by limiting data transfer to the lowest level of the PCIe tree, compared to the traditional path which sends data through the root complex. ”h]”hï)�”}”(hŒ®Alleviate PCIe bandwidth pressure, by limiting data transfer to the lowest level of the PCIe tree, compared to the traditional path which sends data through the root complex.”h]”hŒ®Alleviate PCIe bandwidth pressure, by limiting data transfer to the lowest level of the PCIe tree, compared to the traditional path which sends data through the root complex.”…”�”}”(hjÏh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K1hjËubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hj°h²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”jZj[uh1jh³hÇh´K.hhþh²hubeh}”(h]”Œ opportunity”ah ]”h"]”Œ opportunity”ah$]”h&]”uh1hÈhhÝh²hh³hÇh´KubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒ More Info”h]”hŒ More Info”…”�”}”(hjôh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjñh²hh³hÇh´K7ubhŒ block_quote”“”)�”}”(hŒÝslides, video https://netdevconf.org/0x17/sessions/talk/device-memory-tcp.html patchset [PATCH net-next v24 00/13] Device Memory TCP https://lore.kernel.org/netdev/20240831004313.3713467-1-almasrymina@google.com/ ”h]”hŒdefinition_list”“”)�”}”(hhh]”(hŒdefinition_list_item”“”)�”}”(hŒOslides, video https://netdevconf.org/0x17/sessions/talk/device-memory-tcp.html ”h]”(hŒterm”“”)�”}”(hŒ slides, video”h]”hŒ slides, video”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÇh´K:hjubhŒ definition”“”)�”}”(hhh]”hï)�”}”(hŒ@https://netdevconf.org/0x17/sessions/talk/device-memory-tcp.html”h]”hŒ reference”“”)�”}”(hj*h]”hŒ@https://netdevconf.org/0x17/sessions/talk/device-memory-tcp.html”…”�”}”(hj.h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”j*uh1j,hj(ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K:hj%ubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hjubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K:hj ubj)�”}”(hŒ‡patchset [PATCH net-next v24 00/13] Device Memory TCP https://lore.kernel.org/netdev/20240831004313.3713467-1-almasrymina@google.com/ ”h]”(j)�”}”(hŒpatchset”h]”hŒpatchset”…”�”}”(hjRh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÇh´K?hjNubj$)�”}”(hhh]”hï)�”}”(hŒ|[PATCH net-next v24 00/13] Device Memory TCP https://lore.kernel.org/netdev/20240831004313.3713467-1-almasrymina@google.com/”h]”(hŒ-[PATCH net-next v24 00/13] Device Memory TCP ”…”�”}”(hjch²hh³Nh´Nubj-)�”}”(hŒOhttps://lore.kernel.org/netdev/20240831004313.3713467-1-almasrymina@google.com/”h]”hŒOhttps://lore.kernel.org/netdev/20240831004313.3713467-1-almasrymina@google.com/”…”�”}”(hjkh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”jmuh1j,hjcubeh}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K=hj`ubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hjNubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K?hj ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÇh´K9hjñh²hubeh}”(h]”Œ more-info”ah ]”h"]”Œ more info”ah$]”h&]”uh1hÈhhÝh²hh³hÇh´K7ubeh}”(h]”Œintro”ah ]”h"]”Œintro”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´K ubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒ RX Interface”h]”hŒ RX Interface”…”�”}”(hj«h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj¨h²hh³hÇh´KBubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒExample”h]”hŒExample”…”�”}”(hj¼h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj¹h²hh³hÇh´KFubhï)�”}”(hŒs./tools/testing/selftests/drivers/net/hw/ncdevmem:do_server shows an example of setting up the RX path of this API.”h]”hŒs./tools/testing/selftests/drivers/net/hw/ncdevmem:do_server shows an example of setting up the RX path of this API.”…”�”}”(hjÊh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´KHhj¹h²hubeh}”(h]”Œexample”ah ]”h"]”h$]”Œexample”ah&]”uh1hÈhj¨h²hh³hÇh´KFŒ referenced”KubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒ NIC Setup”h]”hŒ NIC Setup”…”�”}”(hjäh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjáh²hh³hÇh´KMubhï)�”}”(hŒHHeader split, flow steering, & RSS are required features for devmem TCP.”h]”hŒHHeader split, flow steering, & RSS are required features for devmem TCP.”…”�”}”(hjòh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´KOhjáh²hubhï)�”}”(hŒzHeader split is used to split incoming packets into a header buffer in host memory, and a payload buffer in device memory.”h]”hŒzHeader split is used to split incoming packets into a header buffer in host memory, and a payload buffer in device memory.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´KQhjáh²hubhï)�”}”(hŒlFlow steering & RSS are used to ensure that only flows targeting devmem land on an RX queue bound to devmem.”h]”hŒlFlow steering & RSS are used to ensure that only flows targeting devmem land on an RX queue bound to devmem.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´KThjáh²hubhï)�”}”(hŒ%Enable header split & flow steering::”h]”hŒ$Enable header split & flow steering:”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´KWhjáh²hubhŒ literal_block”“”)�”}”(hŒj# enable header split ethtool -G eth1 tcp-data-split on # enable flow steering ethtool -K eth1 ntuple on”h]”hŒj# enable header split ethtool -G eth1 tcp-data-split on # enable flow steering ethtool -K eth1 ntuple on”…”�”}”hj,sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´KYhjáh²hubhï)�”}”(hŒ]Configure RSS to steer all traffic away from the target RX queue (queue 15 in this example)::”h]”hŒ\Configure RSS to steer all traffic away from the target RX queue (queue 15 in this example):”…”�”}”(hj:h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K`hjáh²hubj+)�”}”(hŒðtool --set-rxfh-indir eth1 equal 15”h]”hŒðtool --set-rxfh-indir eth1 equal 15”…”�”}”hjHsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´Kchjáh²hubhï)�”}”(hŒ]The user must bind a dmabuf to any number of RX queues on a given NIC using the netlink API::”h]”hŒ\The user must bind a dmabuf to any number of RX queues on a given NIC using the netlink API:”…”�”}”(hjVh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Kfhjáh²hubj+)�”}”(hXë/* Bind dmabuf to NIC RX queue 15 */ struct netdev_queue_id *queues; queues = netdev_queue_id_alloc(1); netdev_queue_id_set_type(&queues[0], NETDEV_QUEUE_TYPE_RX); netdev_queue_id_set_id(&queues[0], 15); *ys = ynl_sock_create(&ynl_netdev_family, &yerr); req = netdev_bind_rx_req_alloc(); netdev_bind_rx_req_set_ifindex(req, 1 /* ifindex */); netdev_bind_rx_req_set_fd(req, dmabuf_fd); __netdev_bind_rx_req_set_queues(req, queues, 1); rsp = netdev_bind_rx(*ys, req); dmabuf_id = rsp->id;”h]”hXë/* Bind dmabuf to NIC RX queue 15 */ struct netdev_queue_id *queues; queues = netdev_queue_id_alloc(1); netdev_queue_id_set_type(&queues[0], NETDEV_QUEUE_TYPE_RX); netdev_queue_id_set_id(&queues[0], 15); *ys = ynl_sock_create(&ynl_netdev_family, &yerr); req = netdev_bind_rx_req_alloc(); netdev_bind_rx_req_set_ifindex(req, 1 /* ifindex */); netdev_bind_rx_req_set_fd(req, dmabuf_fd); __netdev_bind_rx_req_set_queues(req, queues, 1); rsp = netdev_bind_rx(*ys, req); dmabuf_id = rsp->id;”…”�”}”hjdsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´Kihjáh²hubhï)�”}”(hŒ`The netlink API returns a dmabuf_id: a unique ID that refers to this dmabuf that has been bound.”h]”hŒ`The netlink API returns a dmabuf_id: a unique ID that refers to this dmabuf that has been bound.”…”�”}”(hjrh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K|hjáh²hubhï)�”}”(hŒÌThe user can unbind the dmabuf from the netdevice by closing the netlink socket that established the binding. We do this so that the binding is automatically unbound even if the userspace process crashes.”h]”hŒÌThe user can unbind the dmabuf from the netdevice by closing the netlink socket that established the binding. We do this so that the binding is automatically unbound even if the userspace process crashes.”…”�”}”(hj€h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Khjáh²hubhï)�”}”(hŒáNote that any reasonably well-behaved dmabuf from any exporter should work with devmem TCP, even if the dmabuf is not actually backed by devmem. An example of this is udmabuf, which wraps user memory (non-devmem) in a dmabuf.”h]”hŒáNote that any reasonably well-behaved dmabuf from any exporter should work with devmem TCP, even if the dmabuf is not actually backed by devmem. An example of this is udmabuf, which wraps user memory (non-devmem) in a dmabuf.”…”�”}”(hjŽh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Kƒhjáh²hubeh}”(h]”Œ nic-setup”ah ]”h"]”h$]”Œ nic setup”ah&]”uh1hÈhj¨h²hh³hÇh´KMjàKubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒ Socket Setup”h]”hŒ Socket Setup”…”�”}”(hj§h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj¤h²hh³hÇh´K‰ubhï)�”}”(hŒ>The socket must be flow steered to the dmabuf bound RX queue::”h]”hŒ=The socket must be flow steered to the dmabuf bound RX queue:”…”�”}”(hjµh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K‹hj¤h²hubj+)�”}”(hŒ+ethtool -N eth1 flow-type tcp4 ... queue 15”h]”hŒ+ethtool -N eth1 flow-type tcp4 ... queue 15”…”�”}”hjÃsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´K�hj¤h²hubeh}”(h]”Œ socket-setup”ah ]”h"]”h$]”Œ socket setup”ah&]”uh1hÈhj¨h²hh³hÇh´K‰jàKubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒReceiving data”h]”hŒReceiving data”…”�”}”(hjÜh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjÙh²hh³hÇh´K‘ubhï)�”}”(hŒ‹The user application must signal to the kernel that it is capable of receiving devmem data by passing the MSG_SOCK_DEVMEM flag to recvmsg::”h]”hŒŠThe user application must signal to the kernel that it is capable of receiving devmem data by passing the MSG_SOCK_DEVMEM flag to recvmsg:”…”�”}”(hjêh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K“hjÙh²hubj+)�”}”(hŒ)ret = recvmsg(fd, &msg, MSG_SOCK_DEVMEM);”h]”hŒ)ret = recvmsg(fd, &msg, MSG_SOCK_DEVMEM);”…”�”}”hjøsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´K–hjÙh²hubhï)�”}”(hŒ`Applications that do not specify the MSG_SOCK_DEVMEM flag will receive an EFAULT on devmem data.”h]”hŒ`Applications that do not specify the MSG_SOCK_DEVMEM flag will receive an EFAULT on devmem data.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K˜hjÙh²hubhï)�”}”(hŒ–Devmem data is received directly into the dmabuf bound to the NIC in 'NIC Setup', and the kernel signals such to the user via the SCM_DEVMEM_* cmsgs::”h]”hŒ™Devmem data is received directly into the dmabuf bound to the NIC in ‘NIC Setup’, and the kernel signals such to the user via the SCM_DEVMEM_* cmsgs:”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K›hjÙh²hubj+)�”}”(hX<for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) { if (cm->cmsg_level != SOL_SOCKET || (cm->cmsg_type != SCM_DEVMEM_DMABUF && cm->cmsg_type != SCM_DEVMEM_LINEAR)) continue; dmabuf_cmsg = (struct dmabuf_cmsg *)CMSG_DATA(cm); if (cm->cmsg_type == SCM_DEVMEM_DMABUF) { /* Frag landed in dmabuf. * * dmabuf_cmsg->dmabuf_id is the dmabuf the * frag landed on. * * dmabuf_cmsg->frag_offset is the offset into * the dmabuf where the frag starts. * * dmabuf_cmsg->frag_size is the size of the * frag. * * dmabuf_cmsg->frag_token is a token used to * refer to this frag for later freeing. */ struct dmabuf_token token; token.token_start = dmabuf_cmsg->frag_token; token.token_count = 1; continue; } if (cm->cmsg_type == SCM_DEVMEM_LINEAR) /* Frag landed in linear buffer. * * dmabuf_cmsg->frag_size is the size of the * frag. */ continue; }”h]”hX<for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) { if (cm->cmsg_level != SOL_SOCKET || (cm->cmsg_type != SCM_DEVMEM_DMABUF && cm->cmsg_type != SCM_DEVMEM_LINEAR)) continue; dmabuf_cmsg = (struct dmabuf_cmsg *)CMSG_DATA(cm); if (cm->cmsg_type == SCM_DEVMEM_DMABUF) { /* Frag landed in dmabuf. * * dmabuf_cmsg->dmabuf_id is the dmabuf the * frag landed on. * * dmabuf_cmsg->frag_offset is the offset into * the dmabuf where the frag starts. * * dmabuf_cmsg->frag_size is the size of the * frag. * * dmabuf_cmsg->frag_token is a token used to * refer to this frag for later freeing. */ struct dmabuf_token token; token.token_start = dmabuf_cmsg->frag_token; token.token_count = 1; continue; } if (cm->cmsg_type == SCM_DEVMEM_LINEAR) /* Frag landed in linear buffer. * * dmabuf_cmsg->frag_size is the size of the * frag. */ continue; }”…”�”}”hj"sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´KžhjÙh²hubhï)�”}”(hŒ!Applications may receive 2 cmsgs:”h]”hŒ!Applications may receive 2 cmsgs:”…”�”}”(hj0h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´KÆhjÙh²hubj)�”}”(hhh]”(j#)�”}”(hŒ\SCM_DEVMEM_DMABUF: this indicates the fragment landed in the dmabuf indicated by dmabuf_id. ”h]”hï)�”}”(hŒ[SCM_DEVMEM_DMABUF: this indicates the fragment landed in the dmabuf indicated by dmabuf_id.”h]”hŒ[SCM_DEVMEM_DMABUF: this indicates the fragment landed in the dmabuf indicated by dmabuf_id.”…”�”}”(hjEh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´KÈhjAubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hj>h²hh³hÇh´Nubj#)�”}”(hŒäSCM_DEVMEM_LINEAR: this indicates the fragment landed in the linear buffer. This typically happens when the NIC is unable to split the packet at the header boundary, such that part (or all) of the payload landed in host memory. ”h]”hï)�”}”(hŒãSCM_DEVMEM_LINEAR: this indicates the fragment landed in the linear buffer. This typically happens when the NIC is unable to split the packet at the header boundary, such that part (or all) of the payload landed in host memory.”h]”hŒãSCM_DEVMEM_LINEAR: this indicates the fragment landed in the linear buffer. This typically happens when the NIC is unable to split the packet at the header boundary, such that part (or all) of the payload landed in host memory.”…”�”}”(hj]h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´KËhjYubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hj>h²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”jZj[uh1jh³hÇh´KÈhjÙh²hubhï)�”}”(hŒŒApplications may receive no SO_DEVMEM_* cmsgs. That indicates non-devmem, regular TCP data that landed on an RX queue not bound to a dmabuf.”h]”hŒŒApplications may receive no SO_DEVMEM_* cmsgs. That indicates non-devmem, regular TCP data that landed on an RX queue not bound to a dmabuf.”…”�”}”(hjwh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´KÐhjÙh²hubeh}”(h]”Œreceiving-data”ah ]”h"]”Œreceiving data”ah$]”h&]”uh1hÈhj¨h²hh³hÇh´K‘ubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒ Freeing frags”h]”hŒ Freeing frags”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj�h²hh³hÇh´KÕubhï)�”}”(hŒ¥Frags received via SCM_DEVMEM_DMABUF are pinned by the kernel while the user processes the frag. The user must return the frag to the kernel via SO_DEVMEM_DONTNEED::”h]”hŒ¤Frags received via SCM_DEVMEM_DMABUF are pinned by the kernel while the user processes the frag. The user must return the frag to the kernel via SO_DEVMEM_DONTNEED:”…”�”}”(hjžh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´K×hj�h²hubj+)�”}”(hŒdret = setsockopt(client_fd, SOL_SOCKET, SO_DEVMEM_DONTNEED, &token, sizeof(token));”h]”hŒdret = setsockopt(client_fd, SOL_SOCKET, SO_DEVMEM_DONTNEED, &token, sizeof(token));”…”�”}”hj¬sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´KÛhj�h²hubhï)�”}”(hŒ¼The user must ensure the tokens are returned to the kernel in a timely manner. Failure to do so will exhaust the limited dmabuf that is bound to the RX queue and will lead to packet drops.”h]”hŒ¼The user must ensure the tokens are returned to the kernel in a timely manner. Failure to do so will exhaust the limited dmabuf that is bound to the RX queue and will lead to packet drops.”…”�”}”(hjºh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´KÞhj�h²hubhï)�”}”(hŒåThe user must pass no more than 128 tokens, with no more than 1024 total frags among the token->token_count across all the tokens. If the user provides more than 1024 frags, the kernel will free up to 1024 frags and return early.”h]”hŒåThe user must pass no more than 128 tokens, with no more than 1024 total frags among the token->token_count across all the tokens. If the user provides more than 1024 frags, the kernel will free up to 1024 frags and return early.”…”�”}”(hjÈh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Kâhj�h²hubhï)�”}”(hŒ‹The kernel returns the number of actual frags freed. The number of frags freed can be less than the tokens provided by the user in case of:”h]”hŒ‹The kernel returns the number of actual frags freed. The number of frags freed can be less than the tokens provided by the user in case of:”…”�”}”(hjÖh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Kæhj�h²hubhŒenumerated_list”“”)�”}”(hhh]”(j#)�”}”(hŒan internal kernel leak bug.”h]”hï)�”}”(hjëh]”hŒan internal kernel leak bug.”…”�”}”(hjíh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Kéhjéubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hjæh²hh³hÇh´Nubj#)�”}”(hŒ&the user passed more than 1024 frags. ”h]”hï)�”}”(hŒ%the user passed more than 1024 frags.”h]”hŒ%the user passed more than 1024 frags.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Kêhjubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hjæh²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”Œenumtype”Œ loweralpha”Œprefix”Œ(”Œsuffix”Œ)”uh1jähj�h²hh³hÇh´Kéubeh}”(h]”Œ freeing-frags”ah ]”h"]”Œ freeing frags”ah$]”h&]”uh1hÈhj¨h²hh³hÇh´KÕubeh}”(h]”Œ rx-interface”ah ]”h"]”Œ rx interface”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KBubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒ TX Interface”h]”hŒ TX Interface”…”�”}”(hj7h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj4h²hh³hÇh´KíubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒExample”h]”hŒExample”…”�”}”(hjHh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjEh²hh³hÇh´Kñubhï)�”}”(hŒs./tools/testing/selftests/drivers/net/hw/ncdevmem:do_client shows an example of setting up the TX path of this API.”h]”hŒs./tools/testing/selftests/drivers/net/hw/ncdevmem:do_client shows an example of setting up the TX path of this API.”…”�”}”(hjVh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´KóhjEh²hubeh}”(h]”Œid1”ah ]”h"]”h$]”jÞah&]”uh1hÈhj4h²hh³hÇh´KñjàKubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒ NIC Setup”h]”hŒ NIC Setup”…”�”}”(hjnh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjkh²hh³hÇh´Køubhï)�”}”(hŒEThe user must bind a TX dmabuf to a given NIC using the netlink API::”h]”hŒDThe user must bind a TX dmabuf to a given NIC using the netlink API:”…”�”}”(hj|h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Kúhjkh²hubj+)�”}”(hXMstruct netdev_bind_tx_req *req = NULL; struct netdev_bind_tx_rsp *rsp = NULL; struct ynl_error yerr; *ys = ynl_sock_create(&ynl_netdev_family, &yerr); req = netdev_bind_tx_req_alloc(); netdev_bind_tx_req_set_ifindex(req, ifindex); netdev_bind_tx_req_set_fd(req, dmabuf_fd); rsp = netdev_bind_tx(*ys, req); tx_dmabuf_id = rsp->id;”h]”hXMstruct netdev_bind_tx_req *req = NULL; struct netdev_bind_tx_rsp *rsp = NULL; struct ynl_error yerr; *ys = ynl_sock_create(&ynl_netdev_family, &yerr); req = netdev_bind_tx_req_alloc(); netdev_bind_tx_req_set_ifindex(req, ifindex); netdev_bind_tx_req_set_fd(req, dmabuf_fd); rsp = netdev_bind_tx(*ys, req); tx_dmabuf_id = rsp->id;”…”�”}”hjŠsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´Kühjkh²hubhï)�”}”(hŒ`The netlink API returns a dmabuf_id: a unique ID that refers to this dmabuf that has been bound.”h]”hŒ`The netlink API returns a dmabuf_id: a unique ID that refers to this dmabuf that has been bound.”…”�”}”(hj˜h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M hjkh²hubhï)�”}”(hŒÌThe user can unbind the dmabuf from the netdevice by closing the netlink socket that established the binding. We do this so that the binding is automatically unbound even if the userspace process crashes.”h]”hŒÌThe user can unbind the dmabuf from the netdevice by closing the netlink socket that established the binding. We do this so that the binding is automatically unbound even if the userspace process crashes.”…”�”}”(hj¦h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Mhjkh²hubhï)�”}”(hŒáNote that any reasonably well-behaved dmabuf from any exporter should work with devmem TCP, even if the dmabuf is not actually backed by devmem. An example of this is udmabuf, which wraps user memory (non-devmem) in a dmabuf.”h]”hŒáNote that any reasonably well-behaved dmabuf from any exporter should work with devmem TCP, even if the dmabuf is not actually backed by devmem. An example of this is udmabuf, which wraps user memory (non-devmem) in a dmabuf.”…”�”}”(hj´h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Mhjkh²hubeh}”(h]”Œid2”ah ]”h"]”h$]”j¢ah&]”uh1hÈhj4h²hh³hÇh´KøjàKubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒ Socket Setup”h]”hŒ Socket Setup”…”�”}”(hjÌh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjÉh²hh³hÇh´Mubhï)�”}”(hŒÀThe user application must use MSG_ZEROCOPY flag when sending devmem TCP. Devmem cannot be copied by the kernel, so the semantics of the devmem TX are similar to the semantics of MSG_ZEROCOPY::”h]”hŒ¿The user application must use MSG_ZEROCOPY flag when sending devmem TCP. Devmem cannot be copied by the kernel, so the semantics of the devmem TX are similar to the semantics of MSG_ZEROCOPY:”…”�”}”(hjÚh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´MhjÉh²hubj+)�”}”(hŒBsetsockopt(socket_fd, SOL_SOCKET, SO_ZEROCOPY, &opt, sizeof(opt));”h]”hŒBsetsockopt(socket_fd, SOL_SOCKET, SO_ZEROCOPY, &opt, sizeof(opt));”…”�”}”hjèsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´MhjÉh²hubhï)�”}”(hŒ‚It is also recommended that the user binds the TX socket to the same interface the dma-buf has been bound to via SO_BINDTODEVICE::”h]”hŒ�It is also recommended that the user binds the TX socket to the same interface the dma-buf has been bound to via SO_BINDTODEVICE:”…”�”}”(hjöh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´MhjÉh²hubj+)�”}”(hŒOsetsockopt(socket_fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname) + 1);”h]”hŒOsetsockopt(socket_fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname) + 1);”…”�”}”hjsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´M"hjÉh²hubeh}”(h]”Œid3”ah ]”h"]”h$]”j×ah&]”uh1hÈhj4h²hh³hÇh´MjàKubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒ Sending data”h]”hŒ Sending data”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjh²hh³hÇh´M&ubhï)�”}”(hŒ5Devmem data is sent using the SCM_DEVMEM_DMABUF cmsg.”h]”hŒ5Devmem data is sent using the SCM_DEVMEM_DMABUF cmsg.”…”�”}”(hj*h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M(hjh²hubhï)�”}”(hŒ&The user should create a msghdr where,”h]”hŒ&The user should create a msghdr where,”…”�”}”(hj8h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M*hjh²hubj)�”}”(hhh]”(j#)�”}”(hŒCiov_base is set to the offset into the dmabuf to start sending from”h]”hï)�”}”(hjKh]”hŒCiov_base is set to the offset into the dmabuf to start sending from”…”�”}”(hjMh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M,hjIubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hjFh²hh³hÇh´Nubj#)�”}”(hŒAiov_len is set to the number of bytes to be sent from the dmabuf ”h]”hï)�”}”(hŒ@iov_len is set to the number of bytes to be sent from the dmabuf”h]”hŒ@iov_len is set to the number of bytes to be sent from the dmabuf”…”�”}”(hjdh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M-hj`ubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hjFh²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”jZŒ*”uh1jh³hÇh´M,hjh²hubhï)�”}”(hŒBThe user passes the dma-buf id to send from as a u32 cmsg payload.”h]”hŒBThe user passes the dma-buf id to send from as a u32 cmsg payload.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M/hjh²hubhï)�”}”(hŒ˜The example below sends 1024 bytes from offset 100 into the dmabuf, and 2048 from offset 2000 into the dmabuf. The dmabuf to send from is tx_dmabuf_id::”h]”hŒ—The example below sends 1024 bytes from offset 100 into the dmabuf, and 2048 from offset 2000 into the dmabuf. The dmabuf to send from is tx_dmabuf_id:”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M1hjh²hubj+)�”}”(hX(char ctrl_data[CMSG_SPACE(sizeof(__u32))]; struct msghdr msg = {}; struct cmsghdr *cmsg; struct iovec iov[2]; iov[0].iov_base = (void*)100; iov[0].iov_len = 1024; iov[1].iov_base = (void*)2000; iov[1].iov_len = 2048; msg.msg_iov = iov; msg.msg_iovlen = 2; msg.msg_control = ctrl_data; msg.msg_controllen = sizeof(ctrl_data); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_DEVMEM_DMABUF; cmsg->cmsg_len = CMSG_LEN(sizeof(__u32)); *((__u32 *)CMSG_DATA(cmsg)) = tx_dmabuf_id; sendmsg(socket_fd, &msg, MSG_ZEROCOPY);”h]”hX(char ctrl_data[CMSG_SPACE(sizeof(__u32))]; struct msghdr msg = {}; struct cmsghdr *cmsg; struct iovec iov[2]; iov[0].iov_base = (void*)100; iov[0].iov_len = 1024; iov[1].iov_base = (void*)2000; iov[1].iov_len = 2048; msg.msg_iov = iov; msg.msg_iovlen = 2; msg.msg_control = ctrl_data; msg.msg_controllen = sizeof(ctrl_data); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_DEVMEM_DMABUF; cmsg->cmsg_len = CMSG_LEN(sizeof(__u32)); *((__u32 *)CMSG_DATA(cmsg)) = tx_dmabuf_id; sendmsg(socket_fd, &msg, MSG_ZEROCOPY);”…”�”}”hj›sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´M4hjh²hubeh}”(h]”Œ sending-data”ah ]”h"]”Œ sending data”ah$]”h&]”uh1hÈhj4h²hh³hÇh´M&ubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒReusing TX dmabufs”h]”hŒReusing TX dmabufs”…”�”}”(hj´h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj±h²hh³hÇh´MOubhï)�”}”(hX)Similar to MSG_ZEROCOPY with regular memory, the user should not modify the contents of the dma-buf while a send operation is in progress. This is because the kernel does not keep a copy of the dmabuf contents. Instead, the kernel will pin and send data from the buffer available to the userspace.”h]”hX)Similar to MSG_ZEROCOPY with regular memory, the user should not modify the contents of the dma-buf while a send operation is in progress. This is because the kernel does not keep a copy of the dmabuf contents. Instead, the kernel will pin and send data from the buffer available to the userspace.”…”�”}”(hjÂh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´MQhj±h²hubhï)�”}”(hŒcJust as in MSG_ZEROCOPY, the kernel notifies the userspace of send completions using MSG_ERRQUEUE::”h]”hŒbJust as in MSG_ZEROCOPY, the kernel notifies the userspace of send completions using MSG_ERRQUEUE:”…”�”}”(hjÐh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´MVhj±h²hubj+)�”}”(hX‹int64_t tstop = gettimeofday_ms() + waittime_ms; char control[CMSG_SPACE(100)] = {}; struct sock_extended_err *serr; struct msghdr msg = {}; struct cmsghdr *cm; int retries = 10; __u32 hi, lo; msg.msg_control = control; msg.msg_controllen = sizeof(control); while (gettimeofday_ms() < tstop) { if (!do_poll(fd)) continue; ret = recvmsg(fd, &msg, MSG_ERRQUEUE); for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) { serr = (void *)CMSG_DATA(cm); hi = serr->ee_data; lo = serr->ee_info; fprintf(stdout, "tx complete [%d,%d]\n", lo, hi); } }”h]”hX‹int64_t tstop = gettimeofday_ms() + waittime_ms; char control[CMSG_SPACE(100)] = {}; struct sock_extended_err *serr; struct msghdr msg = {}; struct cmsghdr *cm; int retries = 10; __u32 hi, lo; msg.msg_control = control; msg.msg_controllen = sizeof(control); while (gettimeofday_ms() < tstop) { if (!do_poll(fd)) continue; ret = recvmsg(fd, &msg, MSG_ERRQUEUE); for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) { serr = (void *)CMSG_DATA(cm); hi = serr->ee_data; lo = serr->ee_info; fprintf(stdout, "tx complete [%d,%d]\n", lo, hi); } }”…”�”}”hjÞsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´MYhj±h²hubhï)�”}”(hŒ[After the associated sendmsg has been completed, the dmabuf can be reused by the userspace.”h]”hŒ[After the associated sendmsg has been completed, the dmabuf can be reused by the userspace.”…”�”}”(hjìh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Mshj±h²hubeh}”(h]”Œreusing-tx-dmabufs”ah ]”h"]”Œreusing tx dmabufs”ah$]”h&]”uh1hÈhj4h²hh³hÇh´MOubeh}”(h]”Œ tx-interface”ah ]”h"]”Œ tx interface”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KíubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒImplementation & Caveats”h]”hŒImplementation & Caveats”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj h²hh³hÇh´MxubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒUnreadable skbs”h]”hŒUnreadable skbs”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjh²hh³hÇh´M{ubhï)�”}”(hŒ€Devmem payloads are inaccessible to the kernel processing the packets. This results in a few quirks for payloads of devmem skbs:”h]”hŒ€Devmem payloads are inaccessible to the kernel processing the packets. This results in a few quirks for payloads of devmem skbs:”…”�”}”(hj,h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M}hjh²hubj)�”}”(hhh]”(j#)�”}”(hŒlLoopback is not functional. Loopback relies on copying the payload, which is not possible with devmem skbs. ”h]”hï)�”}”(hŒkLoopback is not functional. Loopback relies on copying the payload, which is not possible with devmem skbs.”h]”hŒkLoopback is not functional. Loopback relies on copying the payload, which is not possible with devmem skbs.”…”�”}”(hjAh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M€hj=ubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hj:h²hh³hÇh´Nubj#)�”}”(hŒ%Software checksum calculation fails. ”h]”hï)�”}”(hŒ$Software checksum calculation fails.”h]”hŒ$Software checksum calculation fails.”…”�”}”(hjYh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´MƒhjUubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hj:h²hh³hÇh´Nubj#)�”}”(hŒ7TCP Dump and bpf can't access devmem packet payloads. ”h]”hï)�”}”(hŒ5TCP Dump and bpf can't access devmem packet payloads.”h]”hŒ7TCP Dump and bpf can’t access devmem packet payloads.”…”�”}”(hjqh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M…hjmubah}”(h]”h ]”h"]”h$]”h&]”uh1j"hj:h²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”jZj[uh1jh³hÇh´M€hjh²hubeh}”(h]”Œunreadable-skbs”ah ]”h"]”Œunreadable skbs”ah$]”h&]”uh1hÈhj h²hh³hÇh´M{ubeh}”(h]”Œimplementation-caveats”ah ]”h"]”Œimplementation & caveats”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´MxubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒTesting”h]”hŒTesting”…”�”}”(hjžh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj›h²hh³hÇh´M‰ubhï)�”}”(hŒyMore realistic example code can be found in the kernel source under ``tools/testing/selftests/drivers/net/hw/ncdevmem.c``”h]”(hŒDMore realistic example code can be found in the kernel source under ”…”�”}”(hj¬h²hh³Nh´NubhŒliteral”“”)�”}”(hŒ5``tools/testing/selftests/drivers/net/hw/ncdevmem.c``”h]”hŒ1tools/testing/selftests/drivers/net/hw/ncdevmem.c”…”�”}”(hj¶h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j´hj¬ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M‹hj›h²hubhï)�”}”(hŒnncdevmem is a devmem TCP netcat. It works very similarly to netcat, but receives data directly into a udmabuf.”h]”hŒnncdevmem is a devmem TCP netcat. It works very similarly to netcat, but receives data directly into a udmabuf.”…”�”}”(hjÊh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´MŽhj›h²hubhï)�”}”(hŒ‡To run ncdevmem, you need to run it on a server on the machine under test, and you need to run netcat on a peer to provide the TX data.”h]”hŒ‡To run ncdevmem, you need to run it on a server on the machine under test, and you need to run netcat on a peer to provide the TX data.”…”�”}”(hjØh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M‘hj›h²hubhï)�”}”(hŒªncdevmem has a validation mode as well that expects a repeating pattern of incoming data and validates it as such. For example, you can launch ncdevmem on the server by::”h]”hŒ©ncdevmem has a validation mode as well that expects a repeating pattern of incoming data and validates it as such. For example, you can launch ncdevmem on the server by:”…”�”}”(hjæh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´M”hj›h²hubj+)�”}”(hŒBncdevmem -s -c -f -l -p 5201 -v 7”h]”hŒBncdevmem -s -c -f -l -p 5201 -v 7”…”�”}”hjôsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´M˜hj›h²hubhï)�”}”(hŒVOn client side, use regular netcat to send TX data to ncdevmem process on the server::”h]”hŒUOn client side, use regular netcat to send TX data to ncdevmem process on the server:”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîh³hÇh´Mšhj›h²hubj+)�”}”(hŒoyes $(echo -e \\x01\\x02\\x03\\x04\\x05\\x06) | \ tr \\n \\0 | head -c 5G | nc 5201 -p 5201”h]”hŒoyes $(echo -e \\x01\\x02\\x03\\x04\\x05\\x06) | \ tr \\n \\0 | head -c 5G | nc 5201 -p 5201”…”�”}”hjsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j*h³hÇh´M�hj›h²hubeh}”(h]”Œtesting”ah ]”h"]”Œtesting”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´M‰ubeh}”(h]”Œdevice-memory-tcp”ah ]”h"]”Œdevice memory tcp”ah$]”h&]”uh1hÈhhh²hh³hÇh´Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÇuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)�”}”(hÍNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”jQŒerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÇŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”(j+j(j¥j¢jîjëj�jšj1j.Œexample”NŒ nic setup”NŒ socket setup”NjŠj‡j)j&jjj®j«jÿjüj˜j•j�j�j#j uŒ nametypes”}”(j+‰j¥‰jî‰j�‰j1‰j•‰j–‰j—‰jЉj)‰j‰j®‰jÿ‰j˜‰j�‰j#‰uh}”(j(hÊj¢hÝjëhþjšjñj.j¨jÚj¹jžjájÓj¤j‡jÙj&j�jj4jfjEjÄjkjjÉj«jjüj±j•j j�jj j›uŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”j_Ks…”R”Œparse_messages”]”(hŒsystem_message”“”)�”}”(hhh]”hï)�”}”(hŒ*Duplicate implicit target name: "example".”h]”hŒ.Duplicate implicit target name: “exampleâ€�.”…”�”}”(hj»h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj¸ubah}”(h]”h ]”h"]”h$]”h&]”jfaŒlevel”KŒtype”ŒINFO”Œsource”hÇŒline”Kñuh1j¶hjEh²hh³hÇh´Kñubj·)�”}”(hhh]”hï)�”}”(hŒ,Duplicate implicit target name: "nic setup".”h]”hŒ0Duplicate implicit target name: “nic setupâ€�.”…”�”}”(hj×h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjÔubah}”(h]”h ]”h"]”h$]”h&]”jÄaŒlevel”KŒtype”jÑŒsource”hÇŒline”Køuh1j¶hjkh²hh³hÇh´Køubj·)�”}”(hhh]”hï)�”}”(hŒ/Duplicate implicit target name: "socket setup".”h]”hŒ3Duplicate implicit target name: “socket setupâ€�.”…”�”}”(hjòh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjïubah}”(h]”h ]”h"]”h$]”h&]”jaŒlevel”KŒtype”jÑŒsource”hÇŒline”Muh1j¶hjÉh²hh³hÇh´MubeŒtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nh²hub.