On Thu, Oct 12, 2017 at 1:58 PM, Anton Ivanov <anton.iva...@cambridgegreys.com> wrote: > > > On 10/12/17 18:25, Willem de Bruijn wrote: >> >> On Thu, Oct 12, 2017 at 12:30 PM, Willem de Bruijn >> <willemdebruijn.ker...@gmail.com> wrote: >>> >>> On Thu, Oct 12, 2017 at 11:44 AM, Anton Ivanov >>> <anton.iva...@cambridgegreys.com> wrote: >>>> >>>> Found it. >>>> >>>> Two bugs canceling each other. >>>> The bind sequence in: psock_txring_vnet.c is wrong. >>>> >>>> It does the following addr.sll_protocol = htons(ETH_P_IP); >>>> before calling bind. >>>> >>>> If you set addr.sll_protocol to ETH_P_ALL where it should have been in >>>> the >>>> first place the test program blows up with -ENOBUFS >>> >>> There is no such requirement that the socket should bind to ETH_P_ALL. > > > There is no requirement to bind to ETH_P_IP either and most code examples > going back more than 10 years to the days of TCP Illustrated use ALL.
For send only sockets, it is often advised to pass 0 as protocol to socket(), so as to avoid having to spend cycles on packet reception at all. Commit c72219b75fde ("packet: infer protocol from ethernet header if unset") explicitly added logic to infer skb->protocol for this common case of sockets, if using rings. > I just did the v6 test - if you bind with ETH_P_IP GSO on TCPv6 is broken > and returns NOBUF and vice versa. Given that skb->protocol is set from proto, that is indeed not expected to work. >>>> I think what is happening is that this value is taken into account when >>>> looking at "what should I use to segment it with" in skb_mac_gso_segment >>>> which is invoked at the end of the verification chain which starts in >>>> packet_direct_xmit in af_packet.c >>> >>> packet_snd sets skb->protocol based on the protocol that the packet >>> socket is bound to. Binding to ETH_P_IP is the right choice here. >> >> To avoid having to open multiple sockets for different protocols, >> sockaddr_ll can also be passed in the msg_name argument on >> each call. > > > Does not work for vnet headers - it honors what you bound with. I tried to > bind with ETH_ALL and pass ETH_P_IP as an arg and it ENOBUF-ed Odd. The code for looking up proto in packet_snd looks fairly straightforward: /* * Get and verify the address. */ if (likely(saddr == NULL)) { dev = packet_cached_dev_get(po); proto = po->num; addr = NULL; } else { err = -EINVAL; if (msg->msg_namelen < sizeof(struct sockaddr_ll)) goto out; if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr))) goto out; proto = saddr->sll_protocol; addr = saddr->sll_addr; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); } followed later by skb->protocol = proto; skb->dev = dev;