firecracker-netns/internal/netlink/netlink.go

104 lines
2.2 KiB
Go

package netlink
import (
"antoine-roux.tk/projects/go/firecracker-netns/internal/netns"
"crypto/rand"
"fmt"
"github.com/vishvananda/netlink"
)
// inspired by https://github.com/containernetworking/plugins/blob/main/pkg/ip/link_linux.go#L57
type Peer struct {
link netlink.Link
netNs netns.NsHandle
}
type PairLink struct {
host Peer
guest Peer
}
func NewVethPair(ns netns.NsHandle) (pair *PairLink, error error) {
origins, err := netns.Get()
if err != nil {
return nil, err
}
err = netns.Set(ns)
if err != nil {
return nil, err
}
name, err := randomVethName()
if err != nil {
return nil, err
}
peerName, err := randomVethName()
if err != nil {
return nil, err
}
attrs := netlink.NewLinkAttrs()
attrs.Name = name
veth := &netlink.Veth{
LinkAttrs: attrs,
PeerName: peerName,
PeerNamespace: netlink.NsFd(origins.Fd),
}
if err := netlink.LinkAdd(veth); err != nil {
return nil, err
}
// Re-fetch the container link to get its creation-time parameters, e.g. index and mac
fmt.Println(name)
veth2, err := netlink.LinkByName(name)
if err != nil {
netlink.LinkDel(veth)
return nil, err
}
err = netns.Set(origins)
if err != nil {
return nil, err
}
fmt.Println(peerName)
veth1, err := netlink.LinkByName(peerName)
if err != nil {
netlink.LinkDel(veth)
return nil, err
}
return &PairLink{host: Peer{veth1, origins}, guest: Peer{veth2, ns}}, nil
}
// DeleteLink removes an interface link.
func (p *PairLink) DeleteLink() error {
err := netns.Set(p.host.netNs)
if err != nil {
return fmt.Errorf("set original Ns for deleting veth %q: %v", p.host.link.Attrs().Name, err)
}
if err := netlink.LinkDel(p.host.link); err != nil {
return fmt.Errorf("failed to delete %q: %v", p.host.link.Attrs().Name, err)
}
return nil
}
// randomVethName returns string "veth" with random prefix (hashed from entropy)
func randomVethName() (string, error) {
entropy := make([]byte, 4)
_, err := rand.Read(entropy)
if err != nil {
return "", fmt.Errorf("failed to generate random veth name: %v", err)
}
// NetworkManager (recent versions) will ignore veth devices that start with "veth"
return fmt.Sprintf("veth%x", entropy), nil
}