mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
Use Linux BPF extensions to locate the offset of the VXLAN header within the packet so that the same BPF program works with VXLAN packets received over either IPv4 or IPv6. Signed-off-by: Cory Snider <csnider@mirantis.com>
64 lines
2.4 KiB
Go
64 lines
2.4 KiB
Go
package overlay
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"golang.org/x/net/bpf"
|
|
)
|
|
|
|
// vniMatchBPF returns a BPF program suitable for passing to the iptables and
|
|
// ip6tables 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{
|
|
// Load offset of UDP payload into X.
|
|
bpf.LoadExtension{Num: bpf.ExtPayloadOffset}, // ld poff
|
|
bpf.TAX{}, // tax
|
|
|
|
bpf.LoadIndirect{Off: 4, Size: 4}, // ld [x + 4] ; Load VXLAN ID into top 24 bits of A
|
|
bpf.ALUOpConstant{Op: bpf.ALUOpShiftRight, Val: 8}, // rsh #8 ; A >>= 8
|
|
bpf.JumpIf{Cond: bpf.JumpEqual, Val: vni, SkipTrue: 1}, // jeq $vni, 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()
|
|
}
|
|
|
|
// matchVXLAN 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 matchVXLAN(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}
|
|
}
|