-
Notifications
You must be signed in to change notification settings - Fork 18.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
libnet/d/overlay: add BPF-powered VNI matcher
Some newer distros such as RHEL 9 have stopped making the xt_u32 kernel module available with the kernels they ship. They do ship the xt_bpf kernel module, which can do everything xt_u32 can and more. Add an alternative implementation of the iptables match rule which uses xt_bpf to implement exactly the same logic as the u32 filter using a BPF program. Try programming the BPF-powered rules as a fallback when programming the u32-powered rules fails. Signed-off-by: Cory Snider <[email protected]> (cherry picked from commit 105b983) Signed-off-by: Cory Snider <[email protected]>
- Loading branch information
Showing
5 changed files
with
112 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package overlay | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"golang.org/x/net/bpf" | ||
) | ||
|
||
// vniMatchBPF returns a BPF program suitable for passing to the iptables bpf | ||
// match which matches on the VXAN Network ID of encapsulated packets. The | ||
// program assumes that it will be used in a rule which only matches UDP | ||
// datagrams. | ||
func vniMatchBPF(vni uint32) []bpf.RawInstruction { | ||
asm, err := bpf.Assemble([]bpf.Instruction{ | ||
bpf.LoadMemShift{Off: 0}, // ldx 4*([0] & 0xf) ; Load length of IPv4 header into X | ||
bpf.LoadIndirect{Off: 12, Size: 4}, // ld [x + 12] ; Load VXLAN ID (UDP header + 4 bytes) into A | ||
bpf.ALUOpConstant{Op: bpf.ALUOpAnd, Val: 0xffffff00}, // and #0xffffff00 ; VXLAN ID is in top 24 bits | ||
bpf.JumpIf{Cond: bpf.JumpEqual, Val: vni << 8, SkipTrue: 1}, // jeq ($vni << 8), match | ||
bpf.RetConstant{Val: 0}, // ret #0 | ||
bpf.RetConstant{Val: ^uint32(0)}, // match: ret #-1 | ||
}) | ||
// bpf.Assemble() only errors if an instruction is invalid. As the only variable | ||
// part of the program is an instruction value for which the entire range is | ||
// valid, whether the program can be successfully assembled is independent of | ||
// the input. Given that the only recourse is to fix this function and | ||
// recompile, there's little value in bubbling the error up to the caller. | ||
if err != nil { | ||
panic(err) | ||
} | ||
return asm | ||
} | ||
|
||
// marshalXTBPF marshals a BPF program into the "decimal" byte code format | ||
// which is suitable for passing to the [iptables bpf match]. | ||
// | ||
// iptables -m bpf --bytecode | ||
// | ||
// [iptables bpf match]: https://ipset.netfilter.org/iptables-extensions.man.html#lbAH | ||
func marshalXTBPF(prog []bpf.RawInstruction) string { //nolint:unused | ||
var b strings.Builder | ||
fmt.Fprintf(&b, "%d", len(prog)) | ||
for _, ins := range prog { | ||
fmt.Fprintf(&b, ",%d %d %d %d", ins.Op, ins.Jt, ins.Jf, ins.K) | ||
} | ||
return b.String() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package overlay | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func FuzzVNIMatchBPFDoesNotPanic(f *testing.F) { | ||
for _, seed := range []uint32{0, 1, 42, 0xfffffe, 0xffffff, 0xfffffffe, 0xffffffff} { | ||
f.Add(seed) | ||
} | ||
f.Fuzz(func(t *testing.T, vni uint32) { | ||
_ = vniMatchBPF(vni) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package overlay | ||
|
||
import ( | ||
"strconv" | ||
) | ||
|
||
// matchVXLANWithBPF returns an iptables rule fragment which matches VXLAN | ||
// datagrams with the given destination port and VXLAN Network ID utilizing the | ||
// xt_bpf netfilter kernel module. The returned slice's backing array is | ||
// guaranteed not to alias any other slice's. | ||
func matchVXLANWithBPF(port, vni uint32) []string { | ||
dport := strconv.FormatUint(uint64(port), 10) | ||
vniMatch := marshalXTBPF(vniMatchBPF(vni)) | ||
|
||
// https://ipset.netfilter.org/iptables-extensions.man.html#lbAH | ||
return []string{"-p", "udp", "--dport", dport, "-m", "bpf", "--bytecode", vniMatch} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters