network. Use when you need help with network.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add anubhavg-icpl/vibe --skill network --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Network?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-network)More formats (shields.io, HTML) on the badges page.
---
name: network
description: network. Use when you need help with network.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: program-types
---
# Network Program Types
## Related Guidance
- For cross-kernel compatibility checks, see `workflows/testing.md`.
- Network hooks interact with kernel packet metadata, sockets, devices, and routing objects. If any context field or kernel object is unclear, check Linux kernel source and kernel docs directly.
## Quick Choice
- Use `xdp` for the earliest, fastest drop/redirect path.
- Use `tc` when you need skb metadata or packet mutation inside the network stack.
- Use `tcx` on new kernels when multi-program ordering matters.
- Use `sk_skb` / `sk_msg` for socket-level stream or message redirection.
- Use `sk_lookup` or `sk_reuseport` for socket selection decisions.
- Use `flow_dissector` only when you need to control flow key extraction.
- Use `netfilter` when netfilter hook ordering matters more than XDP/TC placement.
## XDP (eXpress Data Path)
Earliest packet processing hook — runs in the NIC driver's RX path before the kernel network stack. Fastest possible packet processing.
**When to use it:**
- packet drop, pass, redirect, and early L3 forwarding
- high-rate filtering on the RX hot path
- AF_XDP, DEVMAP, or CPUMAP based pipelines
```c
SEC("xdp")
int handle_xdp(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end)
return XDP_DROP;
return XDP_PASS;
}
```
**Return codes:**
| Code | Meaning |
|------|---------|
| `XDP_PASS` | Send packet up the stack normally |
| `XDP_DROP` | Drop the packet silently |
| `XDP_TX` | Transmit back out the same interface |
| `XDP_REDIRECT` | Redirect to another interface or CPU |
| `XDP_ABORTED` | Drop with trace event (debugging only) |
**Attaching:**
```bash
# Generic mode (works everywhere, slower)
bpftool net attach xdp id <prog_id> dev eth0
# Native mode (requires driver support, fastest)
bpftool net attach xdp id <prog_id> dev eth0 # driver picks mode
# Detach
bpftool net detach xdp dev eth0
```
**Notes:**
- Always bounds-check packet data before access: `if (ptr + size > data_end) return XDP_DROP;`
- Cannot call `bpf_printk` in XDP without careful consideration — hot path
- Fragmented packets: `ctx->data` only contains the first fragment; handle with `bpf_xdp_adjust_head`
### XDP Routing Pattern — FIB Lookup + Redirect
The canonical pattern for XDP-based L3 forwarding: parse headers → FIB lookup → rewrite MACs/TTL → redirect.
```c
SEC("xdp")
int xdp_router(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end) return XDP_DROP;
struct iphdr *iph = (void *)(eth + 1);
if ((void *)(iph + 1) > data_end) return XDP_DROP;
// FIB lookup — resolves next-hop MAC + egress ifindex
struct bpf_fib_lookup fib = {
.family = AF_INET,
.tos = iph->tos,
.l4_protocol = iph->protocol,
.ipv4_src = iph->saddr,
.ipv4_dst = iph->daddr,
.ifindex = ctx->ingress_ifindex,
};
int rc = bpf_fib_lookup(ctx, &fib, sizeof(fib), 0);
if (rc != BPF_FIB_LKUP_RET_SUCCESS) return XDP_PASS;
// Rewrite L2 headers and decrement TTL
if (iph->ttl <= 1) return XDP_PASS; // let kernel send ICMP TTL exceeded
iph->ttl--;
// Efficient checksum update: add 0x0100 (decrement TTL by 1 in network order)
iph->check += bpf_htons(0x0100);
if (iph->check == 0) iph->check = 0xffff; // RFC 1624 carry
__builtin_memcpy(eth->h_dest, fib.dmac, ETH_ALEN);
__builtin_memcpy(eth->h_source, fib.smac, ETH_ALEN);
return bpf_redirect(fib.ifindex, 0);
}
```
**FIB lookup return codes:**
| Code | Meaning |
|------|---------|
| `BPF_FIB_LKUP_RET_SUCCESS` | Forward — use `fib.ifindex`, `fib.dmac`, `fib.smac` |
| `BPF_FIB_LKUP_RET_BLACKHOLE` | Drop |
| `BPF_FIB_LKUP_RET_UNREACHABLE` | No route — pass to stack |
| `BPF_FIB_LKUP_RET_NOT_FWDED` | Not forwarded (e.g. local delivery) |
| `BPF_FIB_LKUP_RET_FWD_DISABLED` | Forwarding disabled on interface |
| `BPF_FIB_LKUP_RET_NO_NEIGH` | Route found but no ARP/ND entry yet |
---
## TC / TCX (Traffic Control)
Runs inside the kernel network stack on both ingress and egress. Has access to socket metadata and can modify packet headers. TCX is the newer multi-prog version.
**When to use it:**
- packet rewriting inside the stack
- policy that needs skb metadata, marks, or socket identity
- `tcx` when ordered multi-prog chaining is important on new kernels
```c
// Classic TC
SEC("tc/ingress")
int handle_ingress(struct __sk_buff *skb) {
return TC_ACT_OK;
}
SEC("tc/egress")
int handle_egress(struct __sk_buff *skb) {
return TC_ACT_OK;
}
// TCX — preferred for new programs (supports ordered multi-program attachment)
SEC("tcx/ingress")
int handle_tcx_ingress(struct __sk_buff *skb) {
return TCX_NEXT; // pass to next program in chain
}
SEC("tcx/egress")
int handle_tcx_egress(struct __sk_buff *skb) {
return TCX_PASS;
}
```
**TC return codes:**
| Code | Meaning |
|------|---------|
| `TC_ACT_OK` / `TCX_PASS` | Pass packet |
| `TC_ACT_SHOT` / `TCX_DROP` | Drop packet |
| `TC_ACT_REDIRECT` | Redirect packet |
| `TCX_NEXT` | Pass to next program in the chain (TCX only) |
**Attaching classic TC:**
```bash
tc qdisc add dev eth0 clsact
tc filter add dev eth0 ingress bpf da obj prog.bpf.o sec tc/ingress
tc filter del dev eth0 ingress
```
**Attaching TCX (bpftool):**
```bash
bpftool net attach tcx ingress id <prog_id> dev eth0
bpftool net detach tcx ingress dev eth0
```
**Notes:**
- TC has access to `skb->mark`, `skb->priority`, socket cookie — richer metadata than XDP
- TCX supports stacking multiple programs; `TCX_NEXT` passes to next in chain
- Use `bpf_skb_store_bytes` / `bpf_l3_csum_replace` to modify headers
---
## sk_skb (Socket Buffer Stream)
Two-stage pipeline for intercepting TCP streams at the socket level. The stream_parser frames the data; stream_verdict decides what to do with each frame.
**When to use it:**
- TCP stream framing and redirection
- protocol-aware socket processing built around `SOCKMAP`
```c
SEC("sk_skb/stream_parser")
int handle_stream_parser(struct __sk_buff *skb) {
// return the length of the current message frame
return skb->len;
}
SEC("sk_skb/stream_verdict")
int handle_stream_verdict(struct __sk_buff *skb) {
// redirect to another socket, or pass/drop
return SK_PASS;
}
```
**Attaching:**
```c
// Requires a SOCKMAP to bind programs together
struct {
__uint(type, BPF_MAP_TYPE_SOCKMAP);
__type(key, int);
__type(value, int);
__uint(max_entries, 1);
} sock_map SEC(".maps");
// Userspace — attach via bpf_prog_attach
bpf_prog_attach(parser_fd, map_fd, BPF_SK_SKB_STREAM_PARSER, 0);
bpf_prog_attach(verdict_fd, map_fd, BPF_SK_SKB_STREAM_VERDICT, 0);
```
**Notes:**
- Use for protocol-aware socket redirection (e.g., Envoy sidecar acceleration)
- Works only on TCP sockets added to a SOCKMAP
- `stream_parser` must return the byte length of a complete message
---
## sk_msg (Socket Message)
Intercepts `sendmsg` calls. Can redirect messages between sockets without copying through userspace.
**When to use it:**
- send-path socket redirection
- zero-copy socket-to-socket forwarding
```c
SEC("sk_msg")
int handle_skmsg(struct sk_msg_md *msg) {
// inspect msg->data / msg->data_end
// bpf_msg_redirect_map to redirect to another socket
return SK_PASS;
}
```
**Notes:**
- Attach to a SOCKMAP or SOCKHASH via `bpf_prog_attach` with `BPF_SK_MSG_VERDICT`
- `bpf_msg_redirect_map(msg, &sock_map, key, 0)` redirects to the socket at `key`
- Zero-copy path: bypasses kernel TCP stack for socket-to-socket forwarding
---
## sk_lookup (Socket Lookup)
Overrides which socket receives an incoming packet. Runs during the kernel's socket lookup phase.
**When to use it:**
- custom incoming socket selection
- transparent service routing based on packet metadata
```c
SEC("sk_lookup")
int handle_sklookup(struct bpf_sk_lookup *ctx) {
struct bpf_sock *sk;
// look up a socket and assign it
sk = bpf_map_lookup_elem(&sock_map, &ctx->local_port);
if (sk) {
bpf_sk_assign(ctx, sk, 0);
bpf_sk_release(sk);
return SK_PASS;
}
return SK_PASS;
}
```
**Attaching:**
```bash
bpftool cgroup attach /sys/fs/cgroup/unified sk_lookup id <prog_id>
```
**Notes:**
- Useful for wildcard port handling — one program can route to different sockets based on custom logic
- `bpf_sk_assign` must be followed by `bpf_sk_release` to release the reference
- Attach to a cgroup, affects all sockets in that cgroup
---
## sk_reuseport
Load-balance incoming connections across `SO_REUSEPORT` sockets. Replaces the kernel's default hash-based selection.
**When to use it:**
- custom load balancing within a reuseport group
- reuseport-aware selection or migration logic
```c
SEC("sk_reuseport")
int handle_sk_reuseport(struct sk_reuseport_md *ctx) {
// ctx->hash, ctx->len, ctx->data available
// bpf_sk_select_reuseport to pick a socket
return SK_PASS;
}
// Migrate connections from closing sockets
SEC("sk_reuseport/migrate")
int handle_sk_reuseport_migrate(struct sk_reuseport_md *ctx) {
return SK_PASS;
}
```
**Notes:**
- Requires `SO_REUSEPORT` on all participating sockets
- Attach via `setsockopt(SO_ATTACH_REUSEPORT_EBPF)`
- `/migrate` variant handles connection migration when a socket leaves the group
---
## flow_dissector
Provides custom flow key extraction for traffic classification. Replaces the kernel's built-in flow dissector.
**When to use it:**
- custom flow-key extraction for classification-heavy networking stacks
- environments where kernel-default flow dissection is not enough
```c
SEC("flow_dissector")
int handle_dissector(struct __sk_buff *skb) {
// populate flow key fields
return BPF_OK;
}
```
**Notes:**
- Attach to root network namespace via `bpf_prog_attach` with `BPF_FLOW_DISSECTOR`
- Used by TC, RSS, and other kernel subsystems that need flow keys
- Only one flow dissector can be active at a time per netns
---
## netfilter
Integrates eBPF into the netfilter framework. Runs at standard netfilter hook points.
**When to use it:**
- netfilter integration is explicitly required
- hook ordering relative to netfilter matters
- you are already operating in a netfilter-oriented architecture
```c
SEC("netfilter")
int do_netfilter(struct bpf_nf_ctx *ctx) {
// ctx->skb available for packet inspection
return NF_ACCEPT;
}
```
**Return codes:** `NF_ACCEPT`, `NF_DROP`, `NF_STOLEN`
**Notes:**
- Attach via `bpf_program__attach_netfilter()` (libbpf) specifying hook, priority, and flags
- Available since kernel 6.4
- Less common than XDP/TC — use when you need netfilter hook ordering guarantees
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!