Re: [RFC PATCH v5 3/5] can: dev: add CAN XL support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





On 19.07.22 17:16, Vincent Mailhol wrote:
On Tue 19 Jul. 2022 at 23:38, Oliver Hartkopp <socketcan@xxxxxxxxxxxx> wrote:


No confusion.

The API to the user space is 'truncated' option only.

The data structure inside the kernel sizeof(struct can[|fd|xl]_frame).

See:
https://lore.kernel.org/linux-can/4c79233f-1301-d5c7-7698-38d39d8702aa@xxxxxxxxxxxx/

---8<---

As the sk_buffs are only allocated once and are not copied inside the
kernel there should be no remarkable drawbacks whether we allocate
CAN_MTU skbs or CANXL_MTU skbs.

AFAICS both skbs will fit into a single page.

This is true. A page is at least 4k. So the 2k + alpha will easily fit.
But the page is not the smallest chunk that can return malloc, c.f.
KMALLOC_MIN_SIZE:
https://elixir.bootlin.com/linux/latest/source/include/linux/slab.h#L279

Also, more than the page size, my concern are the cache misses,
especially when memsetting to zero the full canxl frame. As far as I
understand, cloning an skb does not copy the payload (only increment a
reference to it) so the echo_skb thing should not be impacted.
That said, I am not able to tell whether or not this will have a
noticeable impact (I have some feeling it might but can not assert
it). If this looks good for the people who have the expertise in
kernel performances, then I am fine.

The more I think about our discussion and your remark that we were somehow going back to the V2 patch set the more I wonder if this would be a good idea.

IMO using the struct canxl_frame (including 2048 byte) and allowing truncated sizes can be handled inside the kernel safely.

And with V2 we only allocate the needed size for the sk_buff - without any memsetting.

When user space gets a truncated frame -> fine

When the user forges some CAN XL frame where the length value does not match the spec and the size does not fit the length -> -EINVAL

So there is no uninitialized data also.

And even the user space side to handle a mix of CAN frame types is pretty simple IMO:

union {
        struct can_frame cc;
        struct canfd_frame fd;
        struct canxl_frame xl;
} can;

nbytes = read(s, &can.xl, sizeof(struct canxl_frame));
if (nbytes < 0) {
        perror("read");
        return 1;
}
printf("nbytes = %d\n", nbytes);

if (nbytes < CANXL_HDR_SZ + CANXL_MIN_DLEN) {
        fprintf(stderr, "read: no CAN frame\n");
        return 1;
}

if (can.xl.flags & CANXL_XLF) {
         if (nbytes != CANXL_HDR_SZ + can.xl.len) {
                printf("nbytes = %d\n", nbytes);
                perror("read canxl_frame");
                continue;
         }
         /* process CAN XL frames */
         printf("canxl frame prio %03X len %d flags %d\n",
                 can.xl.prio, can.xl.len, can.xl.flags);
         continue;
}

if (nbytes != sizeof(struct can_frame) &&
    nbytes != sizeof(struct canfd_frame)) {
        fprintf(stderr, "read: incomplete CAN(FD) frame\n");
        return 1;
}

/* process CAN/FD frames */

Working with partially filled data structures is a known pattern for CAN and CAN FD.

We only optimize the transfer from/to kernel space with truncated read/write operations.

¯\_(ツ)_/¯


Maybe even better:

         switch(ntohs(skb->protocol)) {
         case ETH_P_CAN:
                /* ... */
         case ETH_P_CANFD:
                /* ... */
         case ETH_P_CANXL:
                 /* ... */
         default:
                 /* ... */
         }

Yes ... updated my next patch.

Best regards,
Oliver



[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux