Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

can: add CAN skb extension infrastructure

To remove the private CAN bus skb headroom infrastructure 8 bytes need to
be stored in the skb. The skb extensions are a common pattern and an easy
and efficient way to hold private data travelling along with the skb. We
only need the skb_ext_add() and skb_ext_find() functions to allocate and
access CAN specific content as the skb helpers to copy/clone/free skbs
automatically take care of skb extensions and their final removal.

This patch introduces the complete CAN skb extensions infrastructure:
- add struct can_skb_ext in new file include/net/can.h
- add include/net/can.h in MAINTAINERS
- add SKB_EXT_CAN to skbuff.c and skbuff.h
- select SKB_EXTENSIONS in Kconfig when CONFIG_CAN is enabled
- check for existing CAN skb extensions in can_rcv() in af_can.c
- add CAN skb extensions allocation at every skb_alloc() location
- duplicate the skb extensions if cloning outgoing skbs (framelen/gw_hops)
- introduce can_skb_ext_add() and can_skb_ext_find() helpers

The patch also corrects an indention issue in the original code from 2018:
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202602010426.PnGrYAk3-lkp@intel.com/
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20260201-can_skb_ext-v8-2-3635d790fe8b@hartkopp.net
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Oliver Hartkopp and committed by
Paolo Abeni
96ea3a1e d4fb6514

+219 -14
+1
MAINTAINERS
··· 5634 5634 F: include/linux/can/can-ml.h 5635 5635 F: include/linux/can/core.h 5636 5636 F: include/linux/can/skb.h 5637 + F: include/net/can.h 5637 5638 F: include/net/netns/can.h 5638 5639 F: include/uapi/linux/can.h 5639 5640 F: include/uapi/linux/can/bcm.h
+45 -11
drivers/net/can/dev/skb.c
··· 6 6 7 7 #include <linux/can/dev.h> 8 8 #include <linux/module.h> 9 + #include <net/can.h> 9 10 10 11 #define MOD_DESC "CAN device driver interface" 11 12 ··· 208 207 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) 209 208 { 210 209 struct sk_buff *skb; 210 + struct can_skb_ext *csx; 211 211 212 212 skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + 213 213 sizeof(struct can_frame)); 214 - if (unlikely(!skb)) { 215 - *cf = NULL; 214 + if (unlikely(!skb)) 215 + goto out_error_cc; 216 216 217 - return NULL; 217 + csx = can_skb_ext_add(skb); 218 + if (!csx) { 219 + kfree_skb(skb); 220 + goto out_error_cc; 218 221 } 219 222 220 223 skb->protocol = htons(ETH_P_CAN); ··· 228 223 *cf = skb_put_zero(skb, sizeof(struct can_frame)); 229 224 230 225 return skb; 226 + 227 + out_error_cc: 228 + *cf = NULL; 229 + 230 + return NULL; 231 231 } 232 232 EXPORT_SYMBOL_GPL(alloc_can_skb); 233 233 ··· 240 230 struct canfd_frame **cfd) 241 231 { 242 232 struct sk_buff *skb; 233 + struct can_skb_ext *csx; 243 234 244 235 skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + 245 236 sizeof(struct canfd_frame)); 246 - if (unlikely(!skb)) { 247 - *cfd = NULL; 237 + if (unlikely(!skb)) 238 + goto out_error_fd; 248 239 249 - return NULL; 240 + csx = can_skb_ext_add(skb); 241 + if (!csx) { 242 + kfree_skb(skb); 243 + goto out_error_fd; 250 244 } 251 245 252 246 skb->protocol = htons(ETH_P_CANFD); ··· 263 249 (*cfd)->flags = CANFD_FDF; 264 250 265 251 return skb; 252 + 253 + out_error_fd: 254 + *cfd = NULL; 255 + 256 + return NULL; 266 257 } 267 258 EXPORT_SYMBOL_GPL(alloc_canfd_skb); 268 259 ··· 276 257 unsigned int data_len) 277 258 { 278 259 struct sk_buff *skb; 260 + struct can_skb_ext *csx; 279 261 280 262 if (data_len < CANXL_MIN_DLEN || data_len > CANXL_MAX_DLEN) 281 - goto out_error; 263 + goto out_error_xl; 282 264 283 265 skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + 284 266 CANXL_HDR_SIZE + data_len); 285 267 if (unlikely(!skb)) 286 - goto out_error; 268 + goto out_error_xl; 269 + 270 + csx = can_skb_ext_add(skb); 271 + if (!csx) { 272 + kfree_skb(skb); 273 + goto out_error_xl; 274 + } 287 275 288 276 skb->protocol = htons(ETH_P_CANXL); 289 277 init_can_skb_reserve(skb); ··· 304 278 305 279 return skb; 306 280 307 - out_error: 281 + out_error_xl: 308 282 *cxl = NULL; 309 283 310 284 return NULL; ··· 329 303 /* Check for outgoing skbs that have not been created by the CAN subsystem */ 330 304 static bool can_skb_headroom_valid(struct net_device *dev, struct sk_buff *skb) 331 305 { 306 + struct can_skb_ext *csx = can_skb_ext_find(skb); 307 + 332 308 /* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */ 333 309 if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv))) 334 310 return false; 335 311 336 312 /* af_packet does not apply CAN skb specific settings */ 337 - if (skb->ip_summed == CHECKSUM_NONE) { 338 - /* init headroom */ 313 + if (skb->ip_summed == CHECKSUM_NONE || !csx) { 314 + /* init CAN skb content */ 315 + if (!csx) { 316 + csx = can_skb_ext_add(skb); 317 + if (!csx) 318 + return false; 319 + } 320 + 339 321 can_skb_prv(skb)->ifindex = dev->ifindex; 340 322 341 323 skb->ip_summed = CHECKSUM_UNNECESSARY;
+13
drivers/net/can/vxcan.c
··· 21 21 #include <linux/can/vxcan.h> 22 22 #include <linux/can/can-ml.h> 23 23 #include <linux/slab.h> 24 + #include <net/can.h> 24 25 #include <net/rtnetlink.h> 25 26 26 27 #define DRV_NAME "vxcan" ··· 40 39 struct vxcan_priv *priv = netdev_priv(dev); 41 40 struct net_device *peer; 42 41 struct net_device_stats *peerstats, *srcstats = &dev->stats; 42 + struct can_skb_ext *csx; 43 43 struct sk_buff *skb; 44 44 unsigned int len; 45 45 ··· 62 60 consume_skb(oskb); 63 61 } else { 64 62 kfree_skb(oskb); 63 + goto out_unlock; 64 + } 65 + 66 + /* the cloned skb points to the skb extension of the already cloned 67 + * oskb with an increased refcount. skb_ext_add() creates a copy to 68 + * separate the skb extension data which is needed to start with a 69 + * fresh can_gw_hops counter in the other namespace. 70 + */ 71 + csx = skb_ext_add(skb, SKB_EXT_CAN); 72 + if (!csx) { 73 + kfree_skb(skb); 65 74 goto out_unlock; 66 75 } 67 76
+17
include/linux/can/skb.h
··· 14 14 #include <linux/types.h> 15 15 #include <linux/skbuff.h> 16 16 #include <linux/can.h> 17 + #include <net/can.h> 17 18 #include <net/sock.h> 18 19 19 20 void can_flush_echo_skb(struct net_device *dev); ··· 67 66 static inline void can_skb_reserve(struct sk_buff *skb) 68 67 { 69 68 skb_reserve(skb, sizeof(struct can_skb_priv)); 69 + } 70 + 71 + static inline struct can_skb_ext *can_skb_ext_add(struct sk_buff *skb) 72 + { 73 + struct can_skb_ext *csx = skb_ext_add(skb, SKB_EXT_CAN); 74 + 75 + /* skb_ext_add() returns uninitialized space */ 76 + if (csx) 77 + csx->can_gw_hops = 0; 78 + 79 + return csx; 80 + } 81 + 82 + static inline struct can_skb_ext *can_skb_ext_find(struct sk_buff *skb) 83 + { 84 + return skb_ext_find(skb, SKB_EXT_CAN); 70 85 } 71 86 72 87 static inline void can_skb_set_owner(struct sk_buff *skb, struct sock *sk)
+3
include/linux/skbuff.h
··· 4990 4990 #if IS_ENABLED(CONFIG_INET_PSP) 4991 4991 SKB_EXT_PSP, 4992 4992 #endif 4993 + #if IS_ENABLED(CONFIG_CAN) 4994 + SKB_EXT_CAN, 4995 + #endif 4993 4996 SKB_EXT_NUM, /* must be last */ 4994 4997 }; 4995 4998
+28
include/net/can.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ 2 + /* 3 + * net/can.h 4 + * 5 + * Definitions for the CAN network socket buffer extensions 6 + * 7 + * Copyright (C) 2026 Oliver Hartkopp <socketcan@hartkopp.net> 8 + * 9 + */ 10 + 11 + #ifndef _NET_CAN_H 12 + #define _NET_CAN_H 13 + 14 + /** 15 + * struct can_skb_ext - skb extensions for CAN specific content 16 + * @can_iif: ifindex of the first interface the CAN frame appeared on 17 + * @can_framelen: cached echo CAN frame length for bql 18 + * @can_gw_hops: can-gw CAN frame time-to-live counter 19 + * @can_ext_flags: CAN skb extensions flags 20 + */ 21 + struct can_skb_ext { 22 + int can_iif; 23 + u16 can_framelen; 24 + u8 can_gw_hops; 25 + u8 can_ext_flags; 26 + }; 27 + 28 + #endif /* _NET_CAN_H */
+1
net/can/Kconfig
··· 5 5 6 6 menuconfig CAN 7 7 tristate "CAN bus subsystem support" 8 + select SKB_EXTENSIONS 8 9 help 9 10 Controller Area Network (CAN) is a slow (up to 1Mbit/s) serial 10 11 communications protocol. Development of the CAN bus started in
+6 -3
net/can/af_can.c
··· 687 687 static int can_rcv(struct sk_buff *skb, struct net_device *dev, 688 688 struct packet_type *pt, struct net_device *orig_dev) 689 689 { 690 - if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || !can_is_can_skb(skb))) { 690 + if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || 691 + !can_skb_ext_find(skb) || !can_is_can_skb(skb))) { 691 692 pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d\n", 692 693 dev->type, skb->len); 693 694 ··· 703 702 static int canfd_rcv(struct sk_buff *skb, struct net_device *dev, 704 703 struct packet_type *pt, struct net_device *orig_dev) 705 704 { 706 - if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || !can_is_canfd_skb(skb))) { 705 + if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || 706 + !can_skb_ext_find(skb) || !can_is_canfd_skb(skb))) { 707 707 pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d\n", 708 708 dev->type, skb->len); 709 709 ··· 719 717 static int canxl_rcv(struct sk_buff *skb, struct net_device *dev, 720 718 struct packet_type *pt, struct net_device *orig_dev) 721 719 { 722 - if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || !can_is_canxl_skb(skb))) { 720 + if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || 721 + !can_skb_ext_find(skb) || !can_is_canxl_skb(skb))) { 723 722 pr_warn_once("PF_CAN: dropped non conform CAN XL skbuff: dev type %d, len %d\n", 724 723 dev->type, skb->len); 725 724
+15
net/can/bcm.c
··· 59 59 #include <linux/can/bcm.h> 60 60 #include <linux/slab.h> 61 61 #include <linux/spinlock.h> 62 + #include <net/can.h> 62 63 #include <net/sock.h> 63 64 #include <net/net_namespace.h> 64 65 ··· 292 291 static void bcm_can_tx(struct bcm_op *op) 293 292 { 294 293 struct sk_buff *skb; 294 + struct can_skb_ext *csx; 295 295 struct net_device *dev; 296 296 struct canfd_frame *cf; 297 297 int err; ··· 315 313 skb = alloc_skb(op->cfsiz + sizeof(struct can_skb_priv), gfp_any()); 316 314 if (!skb) 317 315 goto out; 316 + 317 + csx = can_skb_ext_add(skb); 318 + if (!csx) { 319 + kfree_skb(skb); 320 + goto out; 321 + } 318 322 319 323 can_skb_reserve(skb); 320 324 can_skb_prv(skb)->ifindex = dev->ifindex; ··· 1325 1317 int cfsiz) 1326 1318 { 1327 1319 struct sk_buff *skb; 1320 + struct can_skb_ext *csx; 1328 1321 struct net_device *dev; 1329 1322 int err; 1330 1323 ··· 1336 1327 skb = alloc_skb(cfsiz + sizeof(struct can_skb_priv), GFP_KERNEL); 1337 1328 if (!skb) 1338 1329 return -ENOMEM; 1330 + 1331 + csx = can_skb_ext_add(skb); 1332 + if (!csx) { 1333 + kfree_skb(skb); 1334 + return -ENOMEM; 1335 + } 1339 1336 1340 1337 can_skb_reserve(skb); 1341 1338
+17
net/can/gw.c
··· 55 55 #include <linux/can/core.h> 56 56 #include <linux/can/skb.h> 57 57 #include <linux/can/gw.h> 58 + #include <net/can.h> 58 59 #include <net/rtnetlink.h> 59 60 #include <net/net_namespace.h> 60 61 #include <net/sock.h> ··· 460 459 struct cgw_job *gwj = (struct cgw_job *)data; 461 460 struct canfd_frame *cf; 462 461 struct sk_buff *nskb; 462 + struct can_skb_ext *csx, *ncsx; 463 463 struct cf_mod *mod; 464 464 int modidx = 0; 465 465 ··· 472 470 if (!can_is_can_skb(skb)) 473 471 return; 474 472 } 473 + 474 + csx = can_skb_ext_find(skb); 475 + if (!csx) 476 + return; 475 477 476 478 /* Do not handle CAN frames routed more than 'max_hops' times. 477 479 * In general we should never catch this delimiter which is intended ··· 520 514 nskb = skb_clone(skb, GFP_ATOMIC); 521 515 522 516 if (!nskb) { 517 + gwj->dropped_frames++; 518 + return; 519 + } 520 + 521 + /* the cloned/copied nskb points to the skb extension of the original 522 + * skb with an increased refcount. skb_ext_add() creates a copy to 523 + * separate the skb extension data to modify the can_gw_hops. 524 + */ 525 + ncsx = skb_ext_add(nskb, SKB_EXT_CAN); 526 + if (!ncsx) { 527 + kfree_skb(nskb); 523 528 gwj->dropped_frames++; 524 529 return; 525 530 }
+25
net/can/isotp.c
··· 69 69 #include <linux/can/skb.h> 70 70 #include <linux/can/isotp.h> 71 71 #include <linux/slab.h> 72 + #include <net/can.h> 72 73 #include <net/sock.h> 73 74 #include <net/net_namespace.h> 74 75 ··· 215 214 { 216 215 struct net_device *dev; 217 216 struct sk_buff *nskb; 217 + struct can_skb_ext *csx; 218 218 struct canfd_frame *ncf; 219 219 struct isotp_sock *so = isotp_sk(sk); 220 220 int can_send_ret; ··· 223 221 nskb = alloc_skb(so->ll.mtu + sizeof(struct can_skb_priv), gfp_any()); 224 222 if (!nskb) 225 223 return 1; 224 + 225 + csx = can_skb_ext_add(nskb); 226 + if (!csx) { 227 + kfree_skb(nskb); 228 + return 1; 229 + } 226 230 227 231 dev = dev_get_by_index(sock_net(sk), so->ifindex); 228 232 if (!dev) { ··· 770 762 { 771 763 struct sock *sk = &so->sk; 772 764 struct sk_buff *skb; 765 + struct can_skb_ext *csx; 773 766 struct net_device *dev; 774 767 struct canfd_frame *cf; 775 768 int can_send_ret; ··· 783 774 skb = alloc_skb(so->ll.mtu + sizeof(struct can_skb_priv), GFP_ATOMIC); 784 775 if (!skb) { 785 776 dev_put(dev); 777 + return; 778 + } 779 + 780 + csx = can_skb_ext_add(skb); 781 + if (!csx) { 782 + kfree_skb(skb); 783 + netdev_put(dev, NULL); 786 784 return; 787 785 } 788 786 ··· 954 938 struct sock *sk = sock->sk; 955 939 struct isotp_sock *so = isotp_sk(sk); 956 940 struct sk_buff *skb; 941 + struct can_skb_ext *csx; 957 942 struct net_device *dev; 958 943 struct canfd_frame *cf; 959 944 int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0; ··· 1019 1002 msg->msg_flags & MSG_DONTWAIT, &err); 1020 1003 if (!skb) { 1021 1004 dev_put(dev); 1005 + goto err_out_drop; 1006 + } 1007 + 1008 + csx = can_skb_ext_add(skb); 1009 + if (!csx) { 1010 + kfree_skb(skb); 1011 + netdev_put(dev, NULL); 1012 + err = -ENOMEM; 1022 1013 goto err_out_drop; 1023 1014 } 1024 1015
+9
net/can/j1939/socket.c
··· 17 17 #include <linux/can/skb.h> 18 18 #include <linux/errqueue.h> 19 19 #include <linux/if_arp.h> 20 + #include <net/can.h> 20 21 21 22 #include "j1939-priv.h" 22 23 ··· 885 884 struct j1939_sock *jsk = j1939_sk(sk); 886 885 struct j1939_sk_buff_cb *skcb; 887 886 struct sk_buff *skb; 887 + struct can_skb_ext *csx; 888 888 int ret; 889 889 890 890 skb = sock_alloc_send_skb(sk, ··· 896 894 msg->msg_flags & MSG_DONTWAIT, &ret); 897 895 if (!skb) 898 896 goto failure; 897 + 898 + csx = can_skb_ext_add(skb); 899 + if (!csx) { 900 + kfree_skb(skb); 901 + ret = -ENOMEM; 902 + goto failure; 903 + } 899 904 900 905 can_skb_reserve(skb); 901 906 can_skb_prv(skb)->ifindex = ndev->ifindex;
+26
net/can/j1939/transport.c
··· 9 9 // Oleksij Rempel <kernel@pengutronix.de> 10 10 11 11 #include <linux/can/skb.h> 12 + #include <net/can.h> 12 13 13 14 #include "j1939-priv.h" 14 15 ··· 592 591 bool swap_src_dst) 593 592 { 594 593 struct sk_buff *skb; 594 + struct can_skb_ext *csx; 595 595 struct j1939_sk_buff_cb *skcb; 596 596 597 597 skb = alloc_skb(sizeof(struct can_frame) + sizeof(struct can_skb_priv), 598 598 GFP_ATOMIC); 599 599 if (unlikely(!skb)) 600 600 return ERR_PTR(-ENOMEM); 601 + 602 + csx = can_skb_ext_add(skb); 603 + if (!csx) { 604 + kfree_skb(skb); 605 + return ERR_PTR(-ENOMEM); 606 + } 601 607 602 608 skb->dev = priv->ndev; 603 609 can_skb_reserve(skb); ··· 1055 1047 1056 1048 skb = skb_clone(se_skb, GFP_ATOMIC); 1057 1049 if (!skb) { 1050 + ret = -ENOMEM; 1051 + goto out_free; 1052 + } 1053 + 1054 + /* the cloned skb points to the skb extension of the original se_skb 1055 + * with an increased refcount. skb_ext_add() creates a copy to 1056 + * separate the skb extension data which is needed to modify the 1057 + * can_framelen in can_put_echo_skb(). 1058 + */ 1059 + if (!skb_ext_add(skb, SKB_EXT_CAN)) { 1060 + kfree_skb(skb); 1058 1061 ret = -ENOMEM; 1059 1062 goto out_free; 1060 1063 } ··· 1544 1525 const struct j1939_sk_buff_cb *rel_skcb) 1545 1526 { 1546 1527 struct sk_buff *skb; 1528 + struct can_skb_ext *csx; 1547 1529 struct j1939_sk_buff_cb *skcb; 1548 1530 struct j1939_session *session; 1549 1531 1550 1532 skb = alloc_skb(size + sizeof(struct can_skb_priv), GFP_ATOMIC); 1551 1533 if (unlikely(!skb)) 1552 1534 return NULL; 1535 + 1536 + csx = can_skb_ext_add(skb); 1537 + if (!csx) { 1538 + kfree_skb(skb); 1539 + return NULL; 1540 + } 1553 1541 1554 1542 skb->dev = priv->ndev; 1555 1543 can_skb_reserve(skb);
+9
net/can/raw.c
··· 53 53 #include <linux/can/core.h> 54 54 #include <linux/can/skb.h> 55 55 #include <linux/can/raw.h> 56 + #include <net/can.h> 56 57 #include <net/sock.h> 57 58 #include <net/net_namespace.h> 58 59 ··· 919 918 struct raw_sock *ro = raw_sk(sk); 920 919 struct sockcm_cookie sockc; 921 920 struct sk_buff *skb; 921 + struct can_skb_ext *csx; 922 922 struct net_device *dev; 923 923 unsigned int txmtu; 924 924 int ifindex; ··· 957 955 msg->msg_flags & MSG_DONTWAIT, &err); 958 956 if (!skb) 959 957 goto put_dev; 958 + 959 + csx = can_skb_ext_add(skb); 960 + if (!csx) { 961 + kfree_skb(skb); 962 + err = -ENOMEM; 963 + goto put_dev; 964 + } 960 965 961 966 can_skb_reserve(skb); 962 967 can_skb_prv(skb)->ifindex = dev->ifindex;
+4
net/core/skbuff.c
··· 78 78 #include <net/mpls.h> 79 79 #include <net/mptcp.h> 80 80 #include <net/mctp.h> 81 + #include <net/can.h> 81 82 #include <net/page_pool/helpers.h> 82 83 #include <net/psp/types.h> 83 84 #include <net/dropreason.h> ··· 5139 5138 #endif 5140 5139 #if IS_ENABLED(CONFIG_INET_PSP) 5141 5140 [SKB_EXT_PSP] = SKB_EXT_CHUNKSIZEOF(struct psp_skb_ext), 5141 + #endif 5142 + #if IS_ENABLED(CONFIG_CAN) 5143 + [SKB_EXT_CAN] = SKB_EXT_CHUNKSIZEOF(struct can_skb_ext), 5142 5144 #endif 5143 5145 }; 5144 5146