From 940e280b54195e76667df337e227ecd452462d2b Mon Sep 17 00:00:00 2001 From: Michel Machado Date: Fri, 18 Sep 2026 14:47:27 +0000 Subject: [PATCH 1/2] agents: expand commit-message guidelines The commit-message skill lacked rules for referencing functions and manual section numbers, which are consistently used across Gatekeeper's git history. Update the guidelines in .agents/skills/commit-message/SKILL.md to: 1. Require empty parentheses () after internal and project function names as well as function-like macros. 2. Require manual section numbers in parentheses after standard library functions (e.g. free(3), perror(3)), system calls (e.g. getrandom(2)), commands (e.g. ls(1)), and overview pages (e.g. capabilities(7)). 3. Clarify plain text conventions without Markdown backticks. 4. Detail subsystem prefix categories, subject casing exceptions, and issue reference formulas with real-world examples from the git log. --- .agents/skills/commit-message/SKILL.md | 140 +++++++++++++++++++++---- 1 file changed, 122 insertions(+), 18 deletions(-) diff --git a/.agents/skills/commit-message/SKILL.md b/.agents/skills/commit-message/SKILL.md index 2ea328e3..7ea5e379 100644 --- a/.agents/skills/commit-message/SKILL.md +++ b/.agents/skills/commit-message/SKILL.md @@ -20,23 +20,127 @@ All commit messages in Gatekeeper must follow the project's established conventi ## Rules 1. **Subsystem Prefix (``)**: - - Matches the affected subsystem or directory in lowercase. - - For modules under directories, use the path prefix (e.g. `lib/net`, `lib/fib`, `bpf`, `cps`, `debian`, `gk`, `gkctl`, `sol`). - - For top-level files or core changes, use the file or component name (e.g. `README`, `gatekeeper`, `Makefile`, `setup.sh`). + - Matches the affected subsystem, functional block, or directory in lowercase. + - **Libraries**: For modules under `lib/`, use the path prefix (e.g. `lib/net`, `lib/fib`, `lib/hash`, `lib/rib`, `lib/mailbox`, `lib/flow`, `lib/acl`). + - **Functional Blocks and Daemons**: Use the block or tool name in lowercase (e.g. `gk`, `gt`, `cps`, `sol`, `lls`, `ggu`, `dyc`, `gkctl`). + - **Supporting Subsystems**: `bpf`, `lua`, `log`, `style`, `debian`, `github`. + - **Core and Build**: For project-wide changes, build scripts, or documentation, use the component or filename (e.g. `gatekeeper`, `Makefile`, `setup.sh`, `README`, `.gitignore`, `dpdk`). + - **Isolated Files/Headers**: For changes isolated to a specific public header or standalone utility, use the file path or utility name (e.g. `include/gatekeeper_net.h`, `generate_if_map`). 2. **Subject Line**: - - Format: `: ` (separated by a colon and a single space). - - Start the summary with a lowercase letter (e.g. `lib/net: adjust dataroom based on MTU`, `README: update URLs to use HTTPS`). - - Use the imperative mood (e.g. `add`, `fix`, `update`, `remove`, not `added`, `fixes`, `updating`). - - Do not end the subject line with a period. - - Keep the subject line concise (under 72 characters). - -3. **Message Body**: - - Separate the subject from the body with a blank line. - - Wrap body text at 72 characters. - - Focus on *what* changed and *why*, rather than *how*. - - Mention relevant context, such as workarounds, affected dependencies, or environment conditions. - -4. **Issue References**: - - Use the project's standard closing phrase when applicable: - `This patch closes #.` + - **Format**: `: ` (separated by a colon and a single space). + - **Casing**: Start the summary with a lowercase letter (e.g. `lib/net: adjust dataroom based on MTU`), unless the first word is a case-sensitive code identifier, macro, or proper noun (e.g. `log: merge MAIN_LOG() into G_LOG()`, `style: rename lua_State from l to L`, `README: update URLs to use HTTPS`). + - **Mood**: Use the imperative mood (e.g. `add`, `fix`, `update`, `remove`, `adopt`, `avoid`, `replace`, `centralize`, `rewrite`, `drop`, not `added`, `fixes`, `updating`). + - **Punctuation**: Do not end the subject line with a period. + - **Length**: Keep the subject line concise (under 72 characters, ideally 50–60 characters). + - **Function and Manual References**: When mentioning functions or commands in the subject, adhere to the reference rules below (e.g. `gkctl: perror(3) already adds a newline`, `lib/net: set all RSS fields in check_if_rss()`). + +3. **Function, Command, and Symbol References**: + - **Internal / Project Functions**: + Always append empty parentheses `()` to function names and function-like macros: + - Examples: `check_if_rss()`, `create_pktmbuf_pool()`, `sol_stage2()`, `rte_gettid()`, `MAIN_LOG()`. + - **Standard Library Functions, System Calls, and System Commands**: + Always append the manual section number in parentheses after the name of standard library functions, POSIX functions, system calls, system commands, and OS capabilities: + - **Section 1 (User Commands)**: `ls(1)`, `grep(1)` + - **Section 2 (System Calls)**: `getrandom(2)`, `prctl(2)`, `umask(2)`, `lchown(2)`, `fchmod(2)`, `syscall(2)` + - **Section 3 (C / Library Functions)**: `free(3)`, `perror(3)`, `strncpy(3)`, `sscanf(3)` + - **Section 7 (Conventions / Overviews)**: `capabilities(7)` + - **Section 8 (System Administration Commands)**: `mount(8)`, `systemd(8)` + - **Types, Structs, and Macros**: + Mention types with their C specifiers (e.g. `struct gatekeeper_if`, `lua_State`, `rib_address_t`), and macros/constants in uppercase (e.g. `RTE_ETH_TX_OFFLOAD_MULTI_SEGS`, `PR_SET_KEEPCAPS`, `NULL`, `-EEXIST`). + - **Plain Text Style**: + Do not use Markdown backticks in commit messages. Write code identifiers, function names, file names, compiler options (e.g. `-Wstringop-truncation`), and directives (e.g. `#define _GNU_SOURCE`) as plain text. Single quotes (`'...'`) may be used for quoting exact phrases or shell commands where clarity is needed. + +4. **Message Body**: + - **Separation**: Separate the subject from the body with a blank line. + - **Line Wrapping**: Hard-wrap all body lines at 72 characters. + - **Structure**: + - State the problem, limitation, or background context first (e.g. what fails, what warning appears, or what behavior is missing). + - State the solution and technical rationale (what changed and why this approach was chosen). + - **Lists**: When breaking down multiple steps or changes, use numbered lists (`1. ...`, `2. ...`) or bullet points (`- ...`). + - **Diagnostics**: Compiler warnings, error messages, and log snippets may be included verbatim in the body to document the problem clearly. + +5. **Issue References**: + - **Closing Issues**: When closing an issue, use the project's standard formula at the end of the body (separated by a blank line): + ```text + This commit closes #. + ``` + or: + ```text + This patch closes #. + ``` + - **Closing Multiple Issues**: + ```text + This commit closes #, closes #, closes #. + ``` + - **Non-Closing References**: When referencing an issue without closing it: + ```text + See issue # for more information. + ``` + or: + ```text + This patch pushes issue # forward. + ``` + +## Examples + +### Example 1: Function name with `()` and standard library call with man section +```text +lib/fib: fib_free() must be okay with uninitialized FIBs + +When a Gatekeeper server is set to work with either IPv4 or +IPv6 only, fib_free() is called on an uninitialized FIB. +This patch avoids a segmentation fault by following the example of +free(3) that ignores NULL. +``` + +### Example 2: System calls with section numbers and numbered list +```text +cps: replace DPDK's KNI library with virtio-user + +File cps/main.c is the only user of functions kni_process_arp() and +kni_process_nd(). Moreover, the only relationship between +these functions and KNI is the fact that they process packets +read from KNI interfaces. + +This commit +1. moves kni_process_arp() and kni_process_nd() from + cps/kni.c to cps/main.c; +2. makes those functions static; and +3. renames those functions to process_arp() and process_nd(). + +DPDK dropped its KNI library at version 23.11. +This commit replaces DPDK's KNI library with virtio-user. + +This commit closes #481, closes #570, closes #585, closes #674. +``` + +### Example 3: System call in subject and body +```text +gatekeeper: call system call getrandom(2) directly + +When randomize_rss_key() was first written, +the system call getrandom(2) had no wrapper. + +This commit replaces syscall(2) with getrandom(2). +``` + +### Example 4: Compiler warning, plain text symbols, and issue closing +```text +lib/net: give an informative error when not enough queues + +While tuning the number of instances of the functional blocks, +the configuration may exceed the maximum number of queues that +the NICs support. When this happens, the error message in the log +is not informative. For example: + +Ethdev port_id=0 nb_rx_queues=43 > 8 +Main/0 2024-06-25 17:07:22 ERR init_iface(back): failed to configure interface (errno=22): Invalid argument + +This commit identifies the problem and gives a helpful error message: + +Main/0 2024-06-25 17:38:22 ERR check_if_queues(back): the current configuration requires 43 RX queues, but the interface supports at most 8 RX queues. It may be possible to reduce the number of instances of the GK or GT functional block to reduce the number of queues. If not, more capable NICs are needed. +Main/0 2024-06-25 17:38:22 ERR init_iface(back): interface doesn't support a critical hardware capability (errno=28): No space left on device + +This commit closes #620. +``` From 4b1cd665c9023b3e642a7292af0a06ea22cd58b6 Mon Sep 17 00:00:00 2001 From: Michel Machado Date: Fri, 18 Sep 2026 15:00:47 +0000 Subject: [PATCH 2/2] agents: add coding-style skill Gatekeeper follows DPDK's coding style guidelines, which are based on the Linux Kernel coding guidelines and FreeBSD kernel developer's manual style(9). However, agents assisting in the repository lacked explicit instructions and reference documentation on these conventions. Add an agent skill under .agents/skills/coding-style/ that documents the coding style requirements, referencing the official DPDK documentation at https://doc.dpdk.org/guides/contributing/coding_style.html. This skill provides: 1. An agent verification checklist covering indentation (hard tabs), line length limits, comment syntax, include order, and pointer/NULL conventions. 2. Comprehensive rules for C preprocessor directives, variable and structure declarations, function definitions and prototypes, control statements, operators, and casts. 3. Gatekeeper-specific idioms, including G_LOG() logging macros, RTE_BUILD_BUG_ON(), and RTE_VERIFY(). 4. Guidelines for Python (PEP 8) and Meson build files. --- .agents/skills/coding-style/SKILL.md | 483 +++++++++++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 .agents/skills/coding-style/SKILL.md diff --git a/.agents/skills/coding-style/SKILL.md b/.agents/skills/coding-style/SKILL.md new file mode 100644 index 00000000..c5d11b39 --- /dev/null +++ b/.agents/skills/coding-style/SKILL.md @@ -0,0 +1,483 @@ +--- +name: coding-style +description: Coding style rules and guidelines for Gatekeeper (following DPDK coding style). Use when writing, modifying, reviewing, or refactoring C code, header files, and build configurations in this repository. +--- + +# Gatekeeper Coding Style Guide + +Gatekeeper strictly follows the **DPDK Coding Style**, which is based on the Linux Kernel coding guidelines and the FreeBSD 7.2 Kernel Developer's Manual (`style(9)`), adapted for high-performance packet processing. + +## Reference + +- **Original DPDK Coding Style Documentation**: + https://doc.dpdk.org/guides/contributing/coding_style.html + +All agents writing, modifying, or reviewing C code in Gatekeeper must adhere to the rules and conventions below. + +--- + +## Agent Verification Checklist + +When generating or editing code, verify: +- [ ] **Indentation**: Hard tabs only for indentation (8-column width). Spaces used *only* for alignment. No spaces before tabs. +- [ ] **Line Length**: Lines do not exceed 80 characters (hard limit: 100 characters when strictly necessary for readability). +- [ ] **Whitespace**: No trailing whitespace on any line. Exactly one newline at the end of the file (no blank lines at file end). +- [ ] **Comments**: Only C-style comments `/* ... */` used. No C++ `//` comments. +- [ ] **Header Includes**: Ordered cleanly: libc/system first, DPDK (`rte_*`) second, third-party libraries third, local Gatekeeper headers last. +- [ ] **Header Guards**: Formatted as `#ifndef _FILE_H_`, `#define _FILE_H_`, and `#endif /* _FILE_H_ */`. +- [ ] **Pointers & Asterisks**: Asterisk attached to variable name: `struct foo *ptr;`, not `struct foo* ptr`. +- [ ] **NULL Checks**: Explicit comparisons against `NULL`: `if (p == NULL)` or `if (p != NULL)`. Never `if (!p)`. +- [ ] **Return Statements**: No parentheses around return value: `return 0;`, never `return (0);`. +- [ ] **Function Definitions**: Return type on its own line preceding the function name. Opening brace `{` on its own line. +- [ ] **Control Flow**: Space after keywords (`if`, `while`, `for`, `switch`). Single-statement bodies omit braces. `else` on the same line as closing brace `} else {`. +- [ ] **Casts & sizeof**: No space after cast `(type)val` or `sizeof(val)`. `sizeof` always has parentheses. No casting of `void *` pointers. + +--- + +## 1. Indentation and Whitespace + +### 1.1 Tabs vs Spaces +- Indentation uses **hard tabs** (`\t`). A tab stop is assumed to be **8 characters wide**. +- **Spaces are only for alignment** (e.g., aligning multiline expressions to matching parentheses, or aligning structure fields). +- Never use spaces for indentation. Never place spaces before tabs. + +### 1.2 Line Length +- Preferred line length is **at most 80 characters**, including comments. +- Lines up to **100 characters** are acceptable when splitting harms readability. +- When wrapping a long statement, put the operator at the end of the line and indent the continuation line. + +### 1.3 Control Statement Continuations +- When continuing conditions across multiple lines in `if`, `while`, or `for` statements, indent the continuation line with **two tabs** (or align with spaces to the opening parenthesis) so it is clearly distinguished from the statement body: + +```c +/* Good: double tab distinguishes condition from body */ +if (really_long_condition_variable_1 == really_long_condition_variable_2 && + flag_is_set) { + x = y + z; + a = b + c; +} + +/* Good: aligning with spaces to opening parenthesis */ +if (really_long_condition_variable_1 == really_long_condition_variable_2 && + flag_is_set) { + x = y + z; + a = b + c; +} +``` + +### 1.4 Trailing Whitespace and Newlines +- Do not leave trailing whitespace at the end of any line. +- Files must end with a single newline character. Do not leave blank lines at the end of a file. + +--- + +## 2. Comments + +### 2.1 Comment Style +- Use standard C comments `/* ... */`. **Do not use C++ style single-line comments (`//`)**. +- Single-line comments: + ```c + /* Most single-line comments look like this. */ + + /* * VERY important single-line comments look like this. */ + ``` +- Multi-line comments: + ```c + /* + * Multi-line comments look like this. Make them real sentences. Fill + * them so they look like real paragraphs. + */ + ``` +- Doxygen-like comments (`/** ... */`) must be used for documenting public APIs, interfaces, and exported functions. + +### 2.2 License Header +- Every file must begin with a license header comment. +- Followed by a blank line before any `#include` or preprocessor directives. + +--- + +## 3. Preprocessor Directives and Headers + +### 3.1 Header Include Order +Group includes into blocks separated by a single blank line, ordered as follows: +1. Standard C library / POSIX system headers (``, ``, ``) +2. DPDK headers (``, ``, ``) +3. Third-party library headers (e.g. Lua, BPF) +4. Local application-specific headers (`"gatekeeper_net.h"`, `"gatekeeper_flow.h"`) + +System and library headers use angle brackets `<...>`; local repository headers use double quotes `"..."`: + +```c +#include +#include +#include + +#include +#include +#include + +#include "gatekeeper_net.h" +#include "gatekeeper_main.h" +#include "gatekeeper_flow.h" +``` + +### 3.2 Header Guards +Headers must be protected against multiple inclusion using the standard format: + +```c +#ifndef _GATEKEEPER_FLOW_H_ +#define _GATEKEEPER_FLOW_H_ + +/* Code */ + +#endif /* _GATEKEEPER_FLOW_H_ */ +``` + +### 3.3 Macros +- Macro names for constants and "unsafe" macros (those with side effects) must be in **ALL_UPPERCASE**. +- Always enclose expressions in outer parentheses: + ```c + #define MAX_ITEMS (100) + #define CALC_OFFSET(base, idx) ((base) + ((idx) * sizeof(uint32_t))) + ``` +- Compound statements in macros must be wrapped in `do { ... } while (0)` without a trailing semicolon: + ```c + #define UPDATE_COUNTERS(cnt, delta) do { \ + (cnt)->pkts += (delta); \ + (cnt)->bytes += (delta) * 64; \ + } while (0) + ``` +- Prefer `enum` for sequential constants and `static inline` functions for logic over macros whenever possible for type-safety and compiler checking. + +### 3.4 Conditional Compilation +- Minimize `#ifdef` and conditional compilation. +- If conditionally compiled regions exceed 20 lines or involve nested directives, add a comment after `#else` and `#endif`: + ```c + #ifdef CONFIG_FEATURE_X + /* ... large block ... */ + #else /* !CONFIG_FEATURE_X */ + /* ... */ + #endif /* CONFIG_FEATURE_X */ + ``` + +--- + +## 4. Types, Naming, and Declarations + +### 4.1 Integer Types +- Always use fixed-width integer types from ``: `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`, `int8_t`, `int16_t`, `int32_t`, `int64_t`. +- Do not use old BSD-style types like `u_int32_t` or `u_char`. + +### 4.2 Variable and Identifier Naming +- Variable and function names must be in **lowercase with underscores** (`snake_case`). +- **Never** use `CamelCase` or `ALL_UPPERCASE` for variable or function names. +- Public/exported symbols should follow the project namespace conventions. + +### 4.3 Pointer Declarations +- The asterisk `*` attaches to the variable name, not the type name: + ```c + int *x; /* Correct: space before asterisk, no space after */ + int* x; /* Bad */ + int * const x; /* Correct: space after asterisk when qualifier follows */ + ``` + +### 4.4 Local Variable Declarations +- Multiple declarations per line are allowed, but do not exceed line length. +- If variables are initialized at declaration, put only **one variable per line**, or initialize only the last variable: + ```c + /* Bad: multiple initializations on one line */ + int i = 0, j = 0, k = 0; + + /* Good: one variable per line with initializer */ + char a = 0; + char b = 0; + + /* Good: only the last variable initialized */ + float x, y = 0.0; + ``` + +### 4.5 Structures and Unions +- **Avoid typedefs for structures**. Use `struct foo` directly instead of `typedef struct { ... } foo_t;`: + ```c + /* Good */ + struct gatekeeper_flow { + uint32_t id; + }; + struct gatekeeper_flow flow; + + /* Bad */ + typedef struct { + uint32_t id; + } gatekeeper_flow_t; + ``` +- **Member Ordering**: + 1. Order members by **use** (frequently accessed members together). + 2. Order by **size descending** (largest types first: 64-bit, then 32-bit, 16-bit, 8-bit) to minimize alignment padding. + 3. Order alphabetically within the same size category. +- Each member on its own line; align member names with spaces: + ```c + struct flow_entry { + struct flow_entry *next; /* List link */ + uint64_t pkts; /* Packet counter */ + uint32_t src; /* IPv4 source */ + uint32_t dst; /* IPv4 destination */ + uint16_t port; /* Layer 4 port */ + uint8_t proto; /* Protocol number */ + }; + ``` + +### 4.6 Enumerations +- Enumeration constants must be **ALL_UPPERCASE**. +- Enums should be used in preference to series of `#define` constants. + +--- + +## 5. Functions + +### 5.1 Function Definitions +- The **return type must be on its own line** preceding the function name. +- The **opening brace `{` must be on its own line** at column 0. +- Function body is indented with 1 tab: + +```c +/* Correct function definition */ +int +flow_cmp(const struct ip_flow *flow1, const struct ip_flow *flow2) +{ + if (flow1->proto != flow2->proto) + return flow1->proto == RTE_ETHER_TYPE_IPV4 ? -1 : 1; + + return memcmp(flow1, flow2, sizeof(*flow1)); +} +``` + +```c +/* Bad: return type on same line, brace on same line */ +int flow_cmp(const struct ip_flow *flow1, const struct ip_flow *flow2) { + /* ... */ +} +``` + +### 5.2 Function Prototypes +- Prototypes keep the return type and function name on the **same line**: + ```c + int flow_cmp(const struct ip_flow *flow1, const struct ip_flow *flow2); + ``` +- Parameter names must be included with their types (e.g. `void func(int fd);`, not `void func(int);`). +- Do not use old K&R function declarations or `__P` macros. + +### 5.3 Static and Inline Functions +- Any function local to a single `.c` file **must be declared `static`**. +- Functions declared in headers must be `static inline`: + ```c + static inline bool + flow_equal(const struct ip_flow *flow1, const struct ip_flow *flow2) + { + return flow_cmp(flow1, flow2) == 0; + } + ``` +- Prefer plain `static inline` and let the compiler optimize. Avoid `__rte_always_inline` unless strictly justified (e.g. constant-folding intrinsics or measured benchmarks). +- Mark cold paths (error recovery, slow path initialization) with `__rte_noinline` to reduce instruction cache pressure. + +--- + +## 6. Control Statements and Loops + +### 6.1 Keyword Spacing +- Always place a single space after control keywords: `if`, `while`, `for`, `switch`, `return`. +- Never put a space between a function name and opening parenthesis: + ```c + if (ret < 0) /* Correct */ + if(ret < 0) /* Bad */ + func(arg1, arg2); /* Correct */ + func (arg1, arg2); /* Bad */ + ``` + +### 6.2 Braces for Control Blocks +- **Omit braces** for single-statement control blocks: + ```c + /* Good */ + if (flow == NULL) + return -EINVAL; + + /* Bad */ + if (flow == NULL) { + return -EINVAL; + } + ``` +- Use braces if the single statement spans multiple lines, or for nested control statements. +- The `else` keyword is placed on the same line as the closing brace: + ```c + if (test) { + stmt1; + stmt2; + } else if (other) { + stmt3; + } else { + stmt4; + } + ``` + +### 6.3 Loops +- Infinite loops use `for (;;)`, not `while (1)`: + ```c + for (;;) { + /* Loop body */ + if (done) + break; + } + ``` + +### 6.4 Switch Statements +- Indent the `switch` statement, but do not indent the `case` labels. Indent the case body by 1 tab: + ```c + switch (proto) { + case IPPROTO_TCP: + handle_tcp(pkt); + break; + case IPPROTO_UDP: + handle_udp(pkt); + break; + case IPPROTO_ICMP: + handle_icmp(pkt); + /* FALLTHROUGH */ + default: + handle_other(pkt); + break; + } + ``` +- Cascade/fallthrough cases must have an explicit `/* FALLTHROUGH */` comment. + +--- + +## 7. Operators, Expressions, and Values + +### 7.1 Operator Spacing +- **Unary operators** take no spaces: `!x`, `~x`, `++i`, `--i`, `-val`, `&var`, `*ptr`. +- **Binary operators** have a space on both sides: `a + b`, `x == y`, `val <= limit`, `ptr && ptr->active`. +- **Member access operators** take no spaces: `s.member`, `p->member`. + +### 7.2 Parentheses +- Do not use redundant parentheses unless needed for operator precedence or clarity: + ```c + /* Good */ + if (a && b) + return x; + + /* Bad */ + if ((a) && (b)) + return (x); + ``` + +### 7.3 Casts and sizeof +- Do not place a space between a cast or `sizeof` and its operand: + ```c + uint64_t val = (uint64_t)raw_val; /* Correct */ + uint64_t val = (uint64_t) raw_val; /* Bad */ + + size = sizeof(struct ip_flow); /* Correct */ + size = sizeof (struct ip_flow); /* Bad */ + ``` +- Always write `sizeof` with parentheses: `sizeof(var)`, not `sizeof var`. + +### 7.4 NULL Comparisons and Booleans +- Compare pointers explicitly against `NULL`: + ```c + /* Good */ + if (ptr == NULL) + if (ptr != NULL) + + /* Bad */ + if (!ptr) + if (ptr) + ``` +- Only use `!` on boolean variables: + ```c + bool is_valid = check_validity(); + if (!is_valid) + return -EINVAL; + + /* For characters, compare to '\0' */ + if (*str == '\0') + return; + ``` + +### 7.5 Return Values +- **Never enclose return values in parentheses**: + ```c + return 0; /* Correct */ + return (0); /* Bad */ + return ret; /* Correct */ + return (ret); /* Bad */ + ``` +- **Do not cast `void *` return values**: + ```c + /* Good: no cast needed in C */ + struct ip_flow *f = malloc(sizeof(*f)); + struct ip_flow *f = rte_zmalloc("flow", sizeof(*f), 0); + + /* Bad */ + struct ip_flow *f = (struct ip_flow *)malloc(sizeof(*f)); + ``` +- Integer-returning functions should follow standard conventions: return `0` on success and `-1` (or negative error number `-errno`, e.g. `-EINVAL`) on failure. +- Functions processing packet bursts return the number of packets processed. +- Functions where error is impossible should return `void`. + +### 7.6 Branch Prediction +- In performance-critical data paths, use `likely()` and `unlikely()` macros from ``: + ```c + if (unlikely(flow == NULL)) + return -EINVAL; + + if (likely(pkt_count > 0)) + process_burst(pkts, pkt_count); + ``` +- Do not overuse `likely()`/`unlikely()` in non-performance-critical or control plane code. + +--- + +## 8. Gatekeeper Idioms & Best Practices + +### 8.1 Logging +- Gatekeeper uses structured logging macros `G_LOG()`: + ```c + G_LOG(ERR, "%s(): failed to initialize interface (errno=%d): %s\n", + __func__, errno, strerror(errno)); + ``` +- Use `unlikely(!G_LOG_CHECK(level))` to guard complex log string preparation when log output is conditionally suppressed. + +### 8.2 Compile-Time and Runtime Checks +- Use DPDK compile-time assertions where applicable: + ```c + RTE_BUILD_BUG_ON(sizeof(struct ip_flow) != 36); + ``` +- Use DPDK runtime verification for fatal invariant violations: + ```c + RTE_VERIFY(ret >= 0 && ret < (int)sizeof(buf)); + ``` + +### 8.3 Queues and Lists +- Use `` macros (`LIST_HEAD`, `LIST_ENTRY`, `TAILQ_HEAD`, `TAILQ_ENTRY`, etc.) for linked lists rather than custom pointer chasing. +- Use `rte_ring` lockless rings for multi-core packet/event passing across threads. + +--- + +## 9. Python and Build Files + +### 9.1 Python +- All Python code must comply with **PEP 8**. +- Maximum line length for Python code is **100 characters** (matching C guidelines). + +### 9.2 Meson Build Files +- Indentation uses **4 spaces** (no tabs in Meson files). +- Multi-line statements should use parentheses rather than escaping line breaks. +- Lists of files or dependencies must be **alphabetical**. +- Lists with more than 3 items must place **one entry per line**, with a trailing comma on the last entry: + ```meson + sources = files( + 'acl.c', + 'fib.c', + 'flow.c', + 'hash.c', + ) + ```