gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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  	"gvisor.dev/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  }