Re: [PATCH] Implementation of tap device for Ethernet level 2 in pfinet
Ralph Ronnquist <[email protected]> Fri, 31 Jul 2026 07:56:20 +1000
| Newsgroups | gmane.os.hurd.bugs |
|---|---|
| Message-ID | <amvIhPger5NDExkI@smulan> |
On Thu, Jul 30, 2026 at 11:32:09PM +0200, Samuel Thibault wrote:
> Hello,
>
> This looks nice :)
>
> Ralph Ronnquist, le jeu. 30 juil. 2026 19:57:02 +1000, a ecrit:
> > ---
> > pfinet/linux-src/include/linux/if_ether.h | 44 +++++++++++++
> > pfinet/linux-src/net/core/dev.c | 4 +-
> > pfinet/main.c | 2 +
> > pfinet/tunnel.c | 77 ++++++++++++++++++-----
> > 4 files changed, 110 insertions(+), 17 deletions(-)
> >
> > diff --git a/pfinet/linux-src/include/linux/if_ether.h b/pfinet/linux-src/include/linux/if_ether.h
> > index 99bb97fa2..efb566e05 100644
> > --- a/pfinet/linux-src/include/linux/if_ether.h
> > +++ b/pfinet/linux-src/include/linux/if_ether.h
> > @@ -87,6 +87,50 @@ struct ethhdr
> > unsigned short h_proto; /* packet type ID field */
> > };
> >
> > +/* Alternative Ethernet header with VLAN tagging. The header without
> > + VLAN tagging (the original header) is found in <net/ethernet.h>.
> > + This header modelling accounts for packets optionally having VLAN
> > + tagging inserted before the ether_type field.
> > +*/
> > +
> > +struct ethhdr_vlan
> > +{
> > + uint8_t h_dest[ETH_ALEN]; /* destination eth addr */
>
> Better make this header include <stdint.h> to make sure to have the
> definition of uint8_t etc.
>
> > + uint8_t h_source[ETH_ALEN]; /* source ether addr */
> > + uint16_t h_vlan_tag; /* htons( 0x8100 ) */
> > + uint16_t h_vlan_id; /* VLAN ID */
> > + uint16_t h_proto; /* packet type ID field */
> > +};
> > +
> > diff --git a/pfinet/linux-src/net/core/dev.c b/pfinet/linux-src/net/core/dev.c
> > index b47c50270..93e5aab1f 100644
> > --- a/pfinet/linux-src/net/core/dev.c
> > +++ b/pfinet/linux-src/net/core/dev.c
> > @@ -923,7 +923,9 @@ void net_bh(void)
> > */
> >
> > /* XXX until we figure out every place to modify.. */
> > - skb->h.raw = skb->nh.raw = skb->data;
> > + if ( skb->nh.raw < skb->data ||
> > + skb->nh.raw > skb->data + sizeof(struct ethhdr_vlan))
> > + skb->h.raw = skb->nh.raw = skb->data;
>
> This deserves getting its own patch with explanation why this if needs
> to be introduced like this, because it looks like putting brown tape on
> top of brown tape, and honestly looks ugly, because it is saying "if it
> looks bad, try to fix it".
>
> I guess you had to introduce it because it overwrites the pointers
> you have set in trivfs_S_io_write. But then as the comment says, we'd
> just need to "figure out every place to modify". There aren't that
> many since pfinet only has dummy, ethernet, and tunnel which use
> register_netdevice, and dummy does not produce frames, so it looks to me
> like you only need to fix ethernet.c's ethernet_demuxer into setting
> skb->h.raw and skb->nh.raw, and then just remove these lines in dev.c
> and be done rather than adding brown tape.
>
> > diff --git a/pfinet/tunnel.c b/pfinet/tunnel.c
> > index 4301d054f..6532cac5c 100644
> > --- a/pfinet/tunnel.c
> > +++ b/pfinet/tunnel.c
> > @@ -168,16 +175,17 @@ setup_tunnel_device (char *name, struct device **device)
> > tunnel_dev = tdev;
> >
> > *device = dev = &tdev->dev;
> > + dev->priv = tdev;
> > + skb_queue_head_init(&tdev->xq); // Initialise tdev->xq
>
> ? We already do this in tunnel_open. Either this is not needed, or it
> should be removed from tunnel_open. Also, why moving the initialization?
> Usually we rather keep the initialization of fields in the structure
> order, so initializing ->name would go first.
>
> > @@ -186,21 +194,44 @@ setup_tunnel_device (char *name, struct device **device)
> > + if ( strncmp( base_name, "tap", 3 ) == 0 ) {
> > + /* The setup for a tap is most similar the ethernet.c */
> > + dev->hard_header = eth_header;
> > + dev->rebuild_header = eth_rebuild_header;
> > + dev->hard_header_cache = eth_header_cache;
> > + dev->header_cache_update = eth_header_cache_update;
> > + dev->hard_header_parse = eth_header_parse;
> > + dev->hard_header_len = ETH_HLEN;
>
> It's nice that we can just reuse that :)
>
> > + // We *know* that ETH_ALEN == 6
> > + unsigned char num[ 4 ]; //
> > + sscanf( name, "tap%u", (unsigned int*)&num );
> > + memcpy( dev->dev_addr, (char[6]) {
> > + 0x06, 'T', num[3], num[2], num[1], num[0] }, 6 );
>
> I'd rather say cast the converse way: pass the address of what is sure
> to be an unsigned int to sscanf so we are sure it writes an unsigned
> int. And then cast into unsigned char * to forge a MAC address out of
> it.
>
> Why 06:54:...?
>
> > @@ -388,6 +421,10 @@ trivfs_S_io_write (struct trivfs_protid *cred,
> >
> > tdev = (struct tunnel_device *) cred->po->cntl->hook;
> >
> > + if ((tdev->dev.hard_header != 0) && (datalen < 18)) // small packet
>
> Why 18? There "could" be payloads with less than 4 bytes.
>
> Also, better use sizeof(struct ethhdr) rather than a hardcoded number
> without meaning.
>
> > + return EBADF;
>
> No, this is rather EINVAL. We use EBADF in the other cases because of a
> read/write mismatch.
I'm afraid I've run out of time for a while and won't be able to take
on pfinet maintenance. Perhaps someone is able to take it up and, with
needed changes, merges into the actual code base.
Ralph.