Skip to content

Commit 420c4b1

Browse files
jukkarkartben
authored andcommitted
net: ethernet/vlan: Add support for embedding ll header
If Ethernet based network device driver is advertizing ETHERNET_EMBEDDED_LL_HEADER, then the L2 driver will can return the proper L2 header size for the network interface. This info is then used in TX to determine whether to have a separate net_buf for the link level header, or to embed the header to the same net_buf as the L2 payload. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 45ac1f9 commit 420c4b1

File tree

4 files changed

+133
-20
lines changed

4 files changed

+133
-20
lines changed

subsys/net/l2/ethernet/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ module-str = Log level for Ethernet L2 layer
1616
module-help = Enables Ethernet L2 to output debug messages.
1717
source "subsys/net/Kconfig.template.log_config.net"
1818

19+
config NET_L2_ETHERNET_RESERVE_HEADER
20+
bool "Reserve space for Ethernet header in first net_buf in TX"
21+
help
22+
If enabled, then reserve space for Ethernet header to the first
23+
net_buf when sending data. The default is still to have layer 2
24+
header in a separate net_buf. In RX side the Ethernet header
25+
is always part of the first net_buf.
26+
1927
config NET_L2_ETHERNET_MGMT
2028
bool "Ethernet network management interface"
2129
select NET_MGMT

subsys/net/l2/ethernet/ethernet.c

Lines changed: 94 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -518,27 +518,79 @@ static bool ethernet_fill_in_dst_on_ipv6_mcast(struct net_pkt *pkt,
518518
#define ethernet_fill_in_dst_on_ipv6_mcast(...) false
519519
#endif /* CONFIG_NET_IPV6 */
520520

521+
static inline size_t get_reserve_ll_header_size(struct net_if *iface)
522+
{
523+
bool is_vlan = false;
524+
525+
#if defined(CONFIG_NET_VLAN)
526+
if (net_if_l2(iface) == &NET_L2_GET_NAME(VIRTUAL)) {
527+
iface = net_eth_get_vlan_main(iface);
528+
is_vlan = true;
529+
}
530+
#endif
531+
532+
if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
533+
return 0U;
534+
}
535+
536+
if (!IS_ENABLED(CONFIG_NET_L2_ETHERNET_RESERVE_HEADER)) {
537+
return 0U;
538+
}
539+
540+
if (is_vlan) {
541+
return sizeof(struct net_eth_vlan_hdr);
542+
} else {
543+
return sizeof(struct net_eth_hdr);
544+
}
545+
}
546+
521547
static struct net_buf *ethernet_fill_header(struct ethernet_context *ctx,
522548
struct net_if *iface,
523549
struct net_pkt *pkt,
524550
uint32_t ptype)
525551
{
552+
struct net_if *orig_iface = iface;
526553
struct net_buf *hdr_frag;
527554
struct net_eth_hdr *hdr;
528-
size_t hdr_len = IS_ENABLED(CONFIG_NET_VLAN) ?
529-
sizeof(struct net_eth_vlan_hdr) :
530-
sizeof(struct net_eth_hdr);
555+
size_t reserve_ll_header;
556+
size_t hdr_len;
557+
bool is_vlan;
558+
559+
is_vlan = IS_ENABLED(CONFIG_NET_VLAN) &&
560+
net_eth_is_vlan_enabled(ctx, iface) &&
561+
net_pkt_vlan_tag(pkt) != NET_VLAN_TAG_UNSPEC;
562+
if (is_vlan) {
563+
orig_iface = net_eth_get_vlan_iface(iface, net_pkt_vlan_tag(pkt));
564+
}
531565

532-
hdr_frag = net_pkt_get_frag(pkt, hdr_len, NET_BUF_TIMEOUT);
533-
if (!hdr_frag) {
534-
return NULL;
566+
reserve_ll_header = get_reserve_ll_header_size(orig_iface);
567+
if (reserve_ll_header > 0) {
568+
hdr_len = reserve_ll_header;
569+
hdr_frag = pkt->buffer;
570+
571+
NET_DBG("Making room for link header %zd bytes", hdr_len);
572+
573+
/* Make room for the header */
574+
net_buf_push(pkt->buffer, hdr_len);
575+
} else {
576+
hdr_len = IS_ENABLED(CONFIG_NET_VLAN) ?
577+
sizeof(struct net_eth_vlan_hdr) :
578+
sizeof(struct net_eth_hdr);
579+
580+
hdr_frag = net_pkt_get_frag(pkt, hdr_len, NET_BUF_TIMEOUT);
581+
if (!hdr_frag) {
582+
return NULL;
583+
}
535584
}
536585

537-
if (IS_ENABLED(CONFIG_NET_VLAN) &&
538-
net_eth_is_vlan_enabled(ctx, iface) &&
539-
net_pkt_vlan_tag(pkt) != NET_VLAN_TAG_UNSPEC) {
586+
if (is_vlan) {
540587
struct net_eth_vlan_hdr *hdr_vlan;
541588

589+
if (reserve_ll_header == 0U) {
590+
hdr_len = sizeof(struct net_eth_vlan_hdr);
591+
net_buf_add(hdr_frag, hdr_len);
592+
}
593+
542594
hdr_vlan = (struct net_eth_vlan_hdr *)(hdr_frag->data);
543595

544596
if (ptype == htons(NET_ETH_PTYPE_ARP) ||
@@ -554,15 +606,19 @@ static struct net_buf *ethernet_fill_header(struct ethernet_context *ctx,
554606
hdr_vlan->type = ptype;
555607
hdr_vlan->vlan.tpid = htons(NET_ETH_PTYPE_VLAN);
556608
hdr_vlan->vlan.tci = htons(net_pkt_vlan_tci(pkt));
557-
net_buf_add(hdr_frag, sizeof(struct net_eth_vlan_hdr));
558609

559610
print_vlan_ll_addrs(pkt, ntohs(hdr_vlan->type),
560611
net_pkt_vlan_tci(pkt),
561-
hdr_frag->len,
612+
hdr_len,
562613
&hdr_vlan->src, &hdr_vlan->dst, false);
563614
} else {
564615
hdr = (struct net_eth_hdr *)(hdr_frag->data);
565616

617+
if (reserve_ll_header == 0U) {
618+
hdr_len = sizeof(struct net_eth_hdr);
619+
net_buf_add(hdr_frag, hdr_len);
620+
}
621+
566622
if (ptype == htons(NET_ETH_PTYPE_ARP) ||
567623
(!ethernet_fill_in_dst_on_ipv4_mcast(pkt, &hdr->dst) &&
568624
!ethernet_fill_in_dst_on_ipv6_mcast(pkt, &hdr->dst))) {
@@ -574,13 +630,14 @@ static struct net_buf *ethernet_fill_header(struct ethernet_context *ctx,
574630
sizeof(struct net_eth_addr));
575631

576632
hdr->type = ptype;
577-
net_buf_add(hdr_frag, sizeof(struct net_eth_hdr));
578633

579634
print_ll_addrs(pkt, ntohs(hdr->type),
580-
hdr_frag->len, &hdr->src, &hdr->dst);
635+
hdr_len, &hdr->src, &hdr->dst);
581636
}
582637

583-
net_pkt_frag_insert(pkt, hdr_frag);
638+
if (reserve_ll_header == 0U) {
639+
net_pkt_frag_insert(pkt, hdr_frag);
640+
}
584641

585642
return hdr_frag;
586643
}
@@ -605,14 +662,19 @@ static void ethernet_update_tx_stats(struct net_if *iface, struct net_pkt *pkt)
605662

606663
static void ethernet_remove_l2_header(struct net_pkt *pkt)
607664
{
665+
size_t reserve = get_reserve_ll_header_size(net_pkt_iface(pkt));
608666
struct net_buf *buf;
609667

610668
/* Remove the buffer added in ethernet_fill_header() */
611-
buf = pkt->buffer;
612-
pkt->buffer = buf->frags;
613-
buf->frags = NULL;
669+
if (reserve == 0U) {
670+
buf = pkt->buffer;
671+
pkt->buffer = buf->frags;
672+
buf->frags = NULL;
614673

615-
net_pkt_frag_unref(buf);
674+
net_pkt_frag_unref(buf);
675+
} else {
676+
net_buf_pull(pkt->buffer, reserve);
677+
}
616678
}
617679

618680
static int ethernet_send(struct net_if *iface, struct net_pkt *pkt)
@@ -813,8 +875,21 @@ enum net_l2_flags ethernet_flags(struct net_if *iface)
813875
return ctx->ethernet_l2_flags;
814876
}
815877

878+
#if defined(CONFIG_NET_L2_ETHERNET_RESERVE_HEADER)
879+
static int ethernet_l2_alloc(struct net_if *iface, struct net_pkt *pkt,
880+
size_t size, enum net_ip_protocol proto,
881+
k_timeout_t timeout)
882+
{
883+
return net_pkt_alloc_buffer_with_reserve(pkt, size,
884+
get_reserve_ll_header_size(iface),
885+
proto, timeout);
886+
}
887+
#else
888+
#define ethernet_l2_alloc NULL
889+
#endif
890+
816891
NET_L2_INIT(ETHERNET_L2, ethernet_recv, ethernet_send, ethernet_enable,
817-
ethernet_flags);
892+
ethernet_flags, ethernet_l2_alloc);
818893

819894
static void carrier_on_off(struct k_work *work)
820895
{

subsys/net/l2/ethernet/vlan.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,22 @@ static enum net_verdict vlan_interface_recv(struct net_if *iface,
610610
return NET_OK;
611611
}
612612

613+
int vlan_alloc_buffer(struct net_if *iface, struct net_pkt *pkt,
614+
size_t size, uint16_t proto, k_timeout_t timeout)
615+
{
616+
enum virtual_interface_caps caps;
617+
int ret = 0;
618+
619+
caps = net_virtual_get_iface_capabilities(iface);
620+
if (caps & VIRTUAL_INTERFACE_VLAN) {
621+
ret = net_pkt_alloc_buffer_with_reserve(pkt, size,
622+
sizeof(struct net_eth_vlan_hdr),
623+
proto, timeout);
624+
}
625+
626+
return ret;
627+
}
628+
613629
static int vlan_interface_attach(struct net_if *vlan_iface,
614630
struct net_if *iface)
615631
{

subsys/net/l2/virtual/virtual.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,22 @@ enum net_l2_flags virtual_flags(struct net_if *iface)
165165
return ctx->virtual_l2_flags;
166166
}
167167

168+
#if defined(CONFIG_NET_L2_ETHERNET_RESERVE_HEADER) && defined(CONFIG_NET_VLAN)
169+
extern int vlan_alloc_buffer(struct net_if *iface, struct net_pkt *pkt,
170+
size_t size, uint16_t proto, k_timeout_t timeout);
171+
172+
static int virtual_l2_alloc(struct net_if *iface, struct net_pkt *pkt,
173+
size_t size, enum net_ip_protocol proto,
174+
k_timeout_t timeout)
175+
{
176+
return vlan_alloc_buffer(iface, pkt, size, proto, timeout);
177+
}
178+
#else
179+
#define virtual_l2_alloc NULL
180+
#endif
181+
168182
NET_L2_INIT(VIRTUAL_L2, virtual_recv, virtual_send, virtual_enable,
169-
virtual_flags);
183+
virtual_flags, virtual_l2_alloc);
170184

171185
static void random_linkaddr(uint8_t *linkaddr, size_t len)
172186
{

0 commit comments

Comments
 (0)