Skip to content

Commit 58c24aa

Browse files
committed
trace: add lacp support
Add LACP protocol definitions and packet trace formatting to support debugging and monitoring of link aggregation. Define the LACP PDU wire format according to IEEE 802.3ad including the slow protocol subtype, TLV-based actor/partner/collector information, and terminator. The lacp_participant structure contains system priority, MAC address, aggregation key, port priority, port number, and state flags. All multi-byte fields use network byte order with proper packing and alignment attributes to match the on-wire format. LACP state flags encode the port's operational state in an 8-bit field: ACTIVE indicates spontaneous PDU transmission, FAST selects 1-second intervals versus 30-second slow mode, AGGREGATABLE marks the port as capable of aggregation, SYNCHRONIZED indicates matching configuration with the partner, COLLECTING and DISTRIBUTING show the mux machine state, while DEFAULTED and EXPIRED track timeout conditions. Extend packet tracing to decode LACP PDUs transmitted on the slow protocols ethertype. The trace formatter displays actor state flags as human-readable strings such as "active fast aggreg sync collect distrib" rather than raw hex values, simplifying protocol troubleshooting. Signed-off-by: Robin Jarry <[email protected]>
1 parent afef63a commit 58c24aa

File tree

3 files changed

+133
-2
lines changed

3 files changed

+133
-2
lines changed

modules/infra/datapath/gr_lacp.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
// Copyright (c) 2025 Robin Jarry
3+
4+
#pragma once
5+
6+
#include <gr_bitops.h>
7+
8+
#include <rte_ether.h>
9+
10+
#include <stdint.h>
11+
12+
// Slow Protocol Subtypes
13+
typedef enum : uint8_t {
14+
LACP_SUBTYPE = 1,
15+
} slow_subtype_t;
16+
17+
// LACP Version
18+
19+
typedef enum : uint8_t {
20+
LACP_VERSION_1 = 1,
21+
} lacp_version_t;
22+
23+
// LACP TLV Types
24+
typedef enum : uint8_t {
25+
LACP_TYPE_ACTOR = 1,
26+
LACP_TYPE_PARTNER = 2,
27+
LACP_TYPE_COLLECTOR = 3,
28+
LACP_TYPE_TERMINATOR = 0,
29+
} lacp_type_t;
30+
31+
#define LACP_LEN_ACTOR 20
32+
#define LACP_LEN_PARTNER 20
33+
#define LACP_LEN_COLLECTOR 16
34+
#define LACP_LEN_TERMINATOR 0
35+
36+
// LACP State Bits
37+
typedef enum : uint8_t {
38+
// If set, will spontaneously send LACP packets, else will
39+
// only do so when receiving LACP packets from a peer.
40+
LACP_STATE_ACTIVE = GR_BIT8(0),
41+
// If set, LACP_FAST_PERIOD and LACP_SHORT_TIMEOUT,
42+
// else LACP_SLOW_PERIOD and LACP_LONG_TIMEOUT.
43+
LACP_STATE_FAST = GR_BIT8(1),
44+
// The link is part of a bond.
45+
LACP_STATE_AGGREGATABLE = GR_BIT8(2),
46+
// System ID and key are in sync.
47+
LACP_STATE_SYNCHRONIZED = GR_BIT8(3),
48+
// Collecting indicates that the participant’s collector (the receive part
49+
// of the mux) is on. If set, it communicates Collecting.
50+
LACP_STATE_COLLECTING = GR_BIT8(4),
51+
// Distributing indicates that the participant’s distributor (the transmit part
52+
// of the mux) is not definitely off. If reset, it indicates Not Distributing.
53+
LACP_STATE_DISTRIBUTING = GR_BIT8(5),
54+
LACP_STATE_DEFAULTED = GR_BIT8(6),
55+
LACP_STATE_EXPIRED = GR_BIT8(7),
56+
} lacp_state_flags_t;
57+
58+
// LACP Timeouts (in seconds)
59+
#define LACP_FAST_PERIOD 1
60+
#define LACP_SLOW_PERIOD 30
61+
#define LACP_SHORT_TIMEOUT 3
62+
#define LACP_LONG_TIMEOUT 90
63+
64+
struct lacp_participant {
65+
rte_be16_t system_priority;
66+
struct rte_ether_addr system_mac;
67+
rte_be16_t key;
68+
rte_be16_t port_priority;
69+
rte_be16_t port_number;
70+
lacp_state_flags_t state;
71+
uint8_t __padding[3];
72+
} __rte_packed __rte_aligned(2);
73+
74+
struct lacp_pdu {
75+
slow_subtype_t subtype; // LACP_SUBTYPE
76+
lacp_version_t version; // LACP_VERSION_1
77+
78+
// Actor Information
79+
lacp_type_t actor_type; // LACP_TYPE_ACTOR
80+
uint8_t actor_len; // LACP_LEN_ACTOR
81+
struct lacp_participant actor;
82+
83+
// Partner Information
84+
lacp_type_t partner_type; // LACP_TYPE_PARTNER
85+
uint8_t partner_len; // LACP_LEN_PARTNER
86+
struct lacp_participant partner;
87+
88+
// Collector Information
89+
lacp_type_t collector_type; // LACP_TYPE_COLLECTOR
90+
uint8_t collector_len; // LACP_LEN_COLLECTOR
91+
rte_be16_t collector_max_delay;
92+
uint8_t __reserved[12];
93+
94+
// Terminator
95+
lacp_type_t terminator_type; // LACP_TYPE_TERMINATOR
96+
uint8_t terminator_len; // LACP_LEN_TERMINATOR
97+
uint8_t __padding[50]; // Pad to minimum frame size
98+
} __rte_packed __rte_aligned(2);

modules/infra/datapath/gr_trace.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#pragma once
66

77
#include <gr_icmp6.h>
8+
#include <gr_lacp.h>
89

910
#include <rte_arp.h>
1011
#include <rte_icmp.h>
@@ -40,6 +41,8 @@ int eth_type_format(char *buf, size_t len, rte_be16_t type);
4041

4142
int trace_arp_format(char *buf, size_t len, const struct rte_arp_hdr *, size_t data_len);
4243

44+
int trace_lacp_format(char *buf, size_t len, const struct lacp_pdu *, size_t data_len);
45+
4346
int trace_ip_format(char *buf, size_t len, const struct rte_ipv4_hdr *, size_t data_len);
4447

4548
int trace_ip6_format(char *buf, size_t len, const struct rte_ipv6_hdr *, size_t data_len);

modules/infra/datapath/trace.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <gr_eth.h>
55
#include <gr_graph.h>
66
#include <gr_icmp6.h>
7+
#include <gr_lacp.h>
78
#include <gr_log.h>
89
#include <gr_macro.h>
910
#include <gr_mbuf.h>
@@ -124,6 +125,31 @@ int trace_arp_format(char *buf, size_t len, const struct rte_arp_hdr *arp, size_
124125
return snprintf(buf, len, "opcode=%u", rte_be_to_cpu_16(arp->arp_opcode));
125126
}
126127

128+
int trace_lacp_format(char *buf, size_t len, const struct lacp_pdu *lacp, size_t /*data_len*/) {
129+
size_t n = 0;
130+
131+
if (lacp->actor.state & LACP_STATE_ACTIVE)
132+
SAFE_BUF(snprintf, len, "%s%s", n > 0 ? " " : "", "active");
133+
if (lacp->actor.state & LACP_STATE_FAST)
134+
SAFE_BUF(snprintf, len, "%s%s", n > 0 ? " " : "", "fast");
135+
if (lacp->actor.state & LACP_STATE_AGGREGATABLE)
136+
SAFE_BUF(snprintf, len, "%s%s", n > 0 ? " " : "", "aggreg");
137+
if (lacp->actor.state & LACP_STATE_SYNCHRONIZED)
138+
SAFE_BUF(snprintf, len, "%s%s", n > 0 ? " " : "", "sync");
139+
if (lacp->actor.state & LACP_STATE_COLLECTING)
140+
SAFE_BUF(snprintf, len, "%s%s", n > 0 ? " " : "", "collect");
141+
if (lacp->actor.state & LACP_STATE_DISTRIBUTING)
142+
SAFE_BUF(snprintf, len, "%s%s", n > 0 ? " " : "", "distrib");
143+
if (lacp->actor.state & LACP_STATE_DEFAULTED)
144+
SAFE_BUF(snprintf, len, "%s%s", n > 0 ? " " : "", "fault");
145+
if (lacp->actor.state & LACP_STATE_EXPIRED)
146+
SAFE_BUF(snprintf, len, "%s%s", n > 0 ? " " : "", "expired");
147+
148+
return n;
149+
err:
150+
return -1;
151+
}
152+
127153
int trace_ip_format(char *buf, size_t len, const struct rte_ipv4_hdr *ip, size_t /*data_len*/) {
128154
ip4_addr_t src = ip->src_addr;
129155
ip4_addr_t dst = ip->dst_addr;
@@ -528,9 +554,13 @@ void trace_log_packet(const struct rte_mbuf *m, const char *node, const char *if
528554
case RTE_BE16(RTE_ETHER_TYPE_MPLS):
529555
SAFE_BUF(snprintf, sizeof(buf), " / MPLS");
530556
break;
531-
case RTE_BE16(RTE_ETHER_TYPE_SLOW):
532-
SAFE_BUF(snprintf, sizeof(buf), " / LACP");
557+
case RTE_BE16(RTE_ETHER_TYPE_SLOW): {
558+
const struct lacp_pdu *lacp;
559+
lacp = rte_pktmbuf_mtod_offset(m, const struct lacp_pdu *, offset);
560+
SAFE_BUF(snprintf, sizeof(buf), " / LACP ");
561+
SAFE_BUF(trace_lacp_format, sizeof(buf), lacp, sizeof(*lacp));
533562
break;
563+
}
534564
default:
535565
SAFE_BUF(snprintf, sizeof(buf), " type=");
536566
SAFE_BUF(eth_type_format, sizeof(buf), ether_type);

0 commit comments

Comments
 (0)