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 Tue 19 Jul. 2022 at 23:38, Oliver Hartkopp <socketcan@xxxxxxxxxxxx> wrote:
> On 19.07.22 16:11, Vincent Mailhol wrote:
> > On Tue. 19 Jul. 2022, 20:44, Oliver Hartkopp <socketcan@xxxxxxxxxxxx> wrote:
> >> Extend the CAN device driver infrastructure to handle CAN XL frames.
> >> This especially addresses the increased data length which is extended
> >> to uint16 for CAN XL.
> >>
> >> Signed-off-by: Oliver Hartkopp <socketcan@xxxxxxxxxxxx>
> >> ---
> >>   drivers/net/can/dev/rx-offload.c |  2 +-
> >>   drivers/net/can/dev/skb.c        | 49 ++++++++++++++++++++++++++------
> >>   include/linux/can/skb.h          |  5 +++-
> >>   3 files changed, 45 insertions(+), 11 deletions(-)
> >>
> >> diff --git a/drivers/net/can/dev/rx-offload.c b/drivers/net/can/dev/rx-offload.c
> >> index a32a01c172d4..8505e547e922 100644
> >> --- a/drivers/net/can/dev/rx-offload.c
> >> +++ b/drivers/net/can/dev/rx-offload.c
> >> @@ -245,11 +245,11 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
> >>                                           unsigned int *frame_len_ptr)
> >>   {
> >>          struct net_device *dev = offload->dev;
> >>          struct net_device_stats *stats = &dev->stats;
> >>          struct sk_buff *skb;
> >> -       u8 len;
> >> +       unsigned int len;
> >>          int err;
> >>
> >>          skb = __can_get_echo_skb(dev, idx, &len, frame_len_ptr);
> >>          if (!skb)
> >>                  return 0;
> >> diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
> >> index 8bb62dd864c8..8531e0c39d1c 100644
> >> --- a/drivers/net/can/dev/skb.c
> >> +++ b/drivers/net/can/dev/skb.c
> >> @@ -53,11 +53,12 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
> >>          BUG_ON(idx >= priv->echo_skb_max);
> >>
> >>          /* check flag whether this packet has to be looped back */
> >>          if (!(dev->flags & IFF_ECHO) ||
> >>              (skb->protocol != htons(ETH_P_CAN) &&
> >> -            skb->protocol != htons(ETH_P_CANFD))) {
> >> +            skb->protocol != htons(ETH_P_CANFD) &&
> >> +            skb->protocol != htons(ETH_P_CANXL))) {
> >>                  kfree_skb(skb);
> >>                  return 0;
> >>          }
> >>
> >>          if (!priv->echo_skb[idx]) {
> >> @@ -86,12 +87,12 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
> >>          return 0;
> >>   }
> >>   EXPORT_SYMBOL_GPL(can_put_echo_skb);
> >>
> >>   struct sk_buff *
> >> -__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr,
> >> -                  unsigned int *frame_len_ptr)
> >> +__can_get_echo_skb(struct net_device *dev, unsigned int idx,
> >> +                  unsigned int *len_ptr, unsigned int *frame_len_ptr)
> >>   {
> >>          struct can_priv *priv = netdev_priv(dev);
> >>
> >>          if (idx >= priv->echo_skb_max) {
> >>                  netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
> >> @@ -103,17 +104,13 @@ __can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr,
> >>                  /* Using "struct canfd_frame::len" for the frame
> >>                   * length is supported on both CAN and CANFD frames.
> >>                   */
> >>                  struct sk_buff *skb = priv->echo_skb[idx];
> >>                  struct can_skb_priv *can_skb_priv = can_skb_prv(skb);
> >> -               struct canfd_frame *cf = (struct canfd_frame *)skb->data;
> >>
> >>                  /* get the real payload length for netdev statistics */
> >> -               if (cf->can_id & CAN_RTR_FLAG)
> >> -                       *len_ptr = 0;
> >> -               else
> >> -                       *len_ptr = cf->len;
> >> +               *len_ptr = can_skb_get_data_len(skb);
> >>
> >>                  if (frame_len_ptr)
> >>                          *frame_len_ptr = can_skb_priv->frame_len;
> >>
> >>                  priv->echo_skb[idx] = NULL;
> >> @@ -139,11 +136,11 @@ __can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr,
> >>    */
> >>   unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx,
> >>                                unsigned int *frame_len_ptr)
> >>   {
> >>          struct sk_buff *skb;
> >> -       u8 len;
> >> +       unsigned int len;
> >>
> >>          skb = __can_get_echo_skb(dev, idx, &len, frame_len_ptr);
> >>          if (!skb)
> >>                  return 0;
> >>
> >> @@ -244,10 +241,41 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
> >>
> >>          return skb;
> >>   }
> >>   EXPORT_SYMBOL_GPL(alloc_canfd_skb);
> >>
> >> +struct sk_buff *alloc_canxl_skb(struct net_device *dev,
> >> +                               struct canxl_frame **cfx)
> >> +{
> >> +       struct sk_buff *skb;
> >> +
> >> +       skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
> >> +                              sizeof(struct canxl_frame));
> >
> > I am confused. In this message:
> > https://lore.kernel.org/linux-can/3dcc85f8-2c02-dfe5-de23-d022f3fc56be@xxxxxxxxxxxx/
> > you said that you "vote for selecting the 'truncated' option only"
> > (which is OK with me). But here, you are allocating the full size. If
> > we always want truncated frames, shouldn't we allocate the exact size
> > frame length here?
>
> 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.

> ---8<---
>
> It is just easier and safe.
>
> (..)
>
> >> @@ -302,10 +330,13 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
> >>                          goto inval_skb;
> >>          } else if (skb->protocol == htons(ETH_P_CANFD)) {
> >>                  if (unlikely(skb->len != CANFD_MTU ||
> >>                               cfd->len > CANFD_MAX_DLEN))
> >>                          goto inval_skb;
> >> +       } else if (skb->protocol == htons(ETH_P_CANXL)) {
> >
> > Nitpick but with the growing list, I would see a switch
> > (skb->protocol) rather than the cascade of if.
> >
> >> +               if (unlikely(!can_is_canxl_skb(skb)))
> >> +                       goto inval_skb;
> >>          } else {
> >
> > default:
> >
> >>                  goto inval_skb;
> >>          }
>
> Yes. Good idea!
>
> Will change that.

Maybe even better:

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



[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