github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/tools/xdp/cmd/tunnel.go (about) 1 // Copyright 2023 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cmd 16 17 import ( 18 "context" 19 _ "embed" 20 "fmt" 21 "path/filepath" 22 23 "github.com/google/subcommands" 24 "github.com/metacubex/gvisor/runsc/flag" 25 ) 26 27 // TunnelPinDir returns the directory to which eBPF objects will be pinned when 28 // xdp_loader is run against iface. 29 func TunnelPinDir(iface string) string { 30 return filepath.Join(bpffsDirPath, iface) 31 } 32 33 // TunnelHostMapPath returns the path where the eBPF map will be pinned when 34 // xdp_loader is run against iface. 35 func TunnelHostMapPath(iface string) string { 36 return filepath.Join(TunnelPinDir(iface), "tunnel_host_map") 37 } 38 39 // TunnelHostProgramPath returns the path where the eBPF program will be pinned 40 // when xdp_loader is run against iface. 41 func TunnelHostProgramPath(iface string) string { 42 return filepath.Join(TunnelPinDir(iface), "tunnel_host_program") 43 } 44 45 // TunnelHostLinkPath returns the path where the eBPF link will be pinned when 46 // xdp_loader is run against iface. 47 func TunnelHostLinkPath(iface string) string { 48 return filepath.Join(TunnelPinDir(iface), "tunnel_host_link") 49 } 50 51 // TunnelVethMapPath returns the path where the eBPF map should be pinned when 52 // xdp_loader is run against iface. 53 func TunnelVethMapPath(iface string) string { 54 return filepath.Join(TunnelPinDir(iface), "tunnel_veth_map") 55 } 56 57 // TunnelVethProgramPath returns the path where the eBPF program should be pinned 58 // when xdp_loader is run against iface. 59 func TunnelVethProgramPath(iface string) string { 60 return filepath.Join(TunnelPinDir(iface), "tunnel_veth_program") 61 } 62 63 // TunnelVethLinkPath returns the path where the eBPF link should be pinned when 64 // xdp_loader is run against iface. 65 func TunnelVethLinkPath(iface string) string { 66 return filepath.Join(TunnelPinDir(iface), "tunnel_veth_link") 67 } 68 69 //go:embed bpf/tunnel_host_ebpf.o 70 var tunnelHostProgram []byte 71 72 // TunnelCommand is a subcommand for tunneling traffic between two NICs. It is 73 // intended as a fast path between the host NIC and the veth of a container. 74 // 75 // SSH traffic is not tunneled. It is passed through to the Linux network stack. 76 type TunnelCommand struct { 77 device string 78 deviceIndex int 79 unpin bool 80 } 81 82 // Name implements subcommands.Command.Name. 83 func (*TunnelCommand) Name() string { 84 return "tunnel" 85 } 86 87 // Synopsis implements subcommands.Command.Synopsis. 88 func (*TunnelCommand) Synopsis() string { 89 return "Tunnel packets between two interfaces using AF_XDP. Pins eBPF objects in /sys/fs/bpf/<interface name>/." 90 } 91 92 // Usage implements subcommands.Command.Usage. 93 func (*TunnelCommand) Usage() string { 94 return "tunnel {-device <device> | -device-idx <device index>} [--unpin]" 95 } 96 97 // SetFlags implements subcommands.Command.SetFlags. 98 func (tn *TunnelCommand) SetFlags(fs *flag.FlagSet) { 99 fs.StringVar(&tn.device, "device", "", "which host device to attach to") 100 fs.IntVar(&tn.deviceIndex, "device-idx", 0, "which host device to attach to") 101 fs.BoolVar(&tn.unpin, "unpin", false, "unpin the map and program instead of pinning new ones; useful to reset state") 102 } 103 104 // Execute implements subcommands.Command.Execute. 105 func (tn *TunnelCommand) Execute(context.Context, *flag.FlagSet, ...any) subcommands.ExitStatus { 106 if err := tn.execute(); err != nil { 107 fmt.Printf("%v\n", err) 108 return subcommands.ExitFailure 109 } 110 return subcommands.ExitSuccess 111 } 112 113 func (tn *TunnelCommand) execute() error { 114 iface, err := getIface(tn.device, tn.deviceIndex) 115 if err != nil { 116 return fmt.Errorf("failed to get host iface: %v", err) 117 } 118 119 return installProgramAndMap(installProgramAndMapOpts{ 120 program: tunnelHostProgram, 121 iface: iface, 122 unpin: tn.unpin, 123 pinDir: RedirectPinDir(iface.Name), 124 mapPath: TunnelHostMapPath(iface.Name), 125 programPath: TunnelHostProgramPath(iface.Name), 126 linkPath: TunnelHostLinkPath(iface.Name), 127 }) 128 }