Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ygg in zmachines #1320

Merged
merged 7 commits into from
Jun 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/container/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,6 @@ func (c *Module) Watch(ctx context.Context) {
}

log.Err(err).Msg("error while watching events from containerd")
<-time.After(3 * time.Second)
}
}
2 changes: 1 addition & 1 deletion pkg/flist/flist.go
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ func (f *flistModule) Unmount(name string) error {
}

if f.valid(mountpoint) == ErrAlreadyMounted {
if err := f.system.Unmount(mountpoint, syscall.MNT_DETACH); err != nil {
if err := f.system.Unmount(mountpoint, 0); err != nil {
log.Error().Err(err).Str("path", mountpoint).Msg("fail to umount flist")
}
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/flist/flist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func TestMountUnmount(t *testing.T) {
os.Remove(cmder.m["pid"])
strg.On("ReleaseFilesystem", mock.Anything, filepath.Base(mnt)).Return(nil)

sys.On("Unmount", mnt, syscall.MNT_DETACH).Return(nil)
sys.On("Unmount", mnt, 0).Return(nil)

err = flister.Unmount(name)
require.NoError(t, err)
Expand Down Expand Up @@ -203,7 +203,7 @@ func TestMountUnmountRO(t *testing.T) {
os.Remove(cmder.m["pid"])
strg.On("ReleaseFilesystem", mock.Anything, filepath.Base(mnt)).Return(nil)

sys.On("Unmount", mnt, syscall.MNT_DETACH).Return(nil)
sys.On("Unmount", mnt, 0).Return(nil)

err = flister.Unmount(name)
require.NoError(t, err)
Expand Down
5 changes: 5 additions & 0 deletions pkg/gridtypes/zos/zmachine.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type MachineInterface struct {
type MachineNetwork struct {
PublicIP gridtypes.Name `json:"public_ip"`
Interfaces []MachineInterface `json:"interfaces"`
Planetary bool `json:"planetary"`
}

// Challenge builder
Expand All @@ -29,6 +30,10 @@ func (n *MachineNetwork) Challenge(w io.Writer) error {
return err
}

if _, err := fmt.Fprintf(w, "%t", n.Planetary); err != nil {
return err
}

for _, inf := range n.Interfaces {
if _, err := fmt.Fprintf(w, "%s", inf.Network); err != nil {
return err
Expand Down
39 changes: 28 additions & 11 deletions pkg/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ type ContainerNetworkConfig struct {
YggdrasilIP bool
}

// YggdrasilTap structure
type YggdrasilTap struct {
Name string
HW net.HardwareAddr
IP net.IPNet
Gateway net.IPNet
}

//Networker is the interface for the network module
type Networker interface {
// Ready return nil is networkd is ready to operate
Expand All @@ -37,15 +45,17 @@ type Networker interface {
// Delete a network resource
DeleteNR(Network) error

// Join a network (with network id) will create a new isolated namespace
// that is hooked to the network bridge with a veth pair, and assign it a
// new IP from the network resource range. The method return the new namespace
// name.
// The member name specifies the name of the member, and must be unique
// The NetID is the network id to join
Join(networkdID NetID, containerID string, cfg ContainerNetworkConfig) (join Member, err error)
// Leave delete a container nameapce created by Join
Leave(networkdID NetID, containerID string) (err error)
// deprecated all uses taps now

// // Join a network (with network id) will create a new isolated namespace
// // that is hooked to the network bridge with a veth pair, and assign it a
// // new IP from the network resource range. The method return the new namespace
// // name.
// // The member name specifies the name of the member, and must be unique
// // The NetID is the network id to join
// Join(networkdID NetID, containerID string, cfg ContainerNetworkConfig) (join Member, err error)
// // Leave delete a container nameapce created by Join
// Leave(networkdID NetID, containerID string) (err error)

// ZDBPrepare creates a network namespace with a macvlan interface into it
// to allow the 0-db container to be publicly accessible
Expand All @@ -58,9 +68,12 @@ type Networker interface {
// for zdb is rewind. ns param is the namespace return by the ZDBPrepare
ZDBDestroy(ns string) error

// SetupTap sets up a tap device in the network namespace for the networkID. It is hooked
// SetupPrivTap sets up a tap device in the network namespace for the networkID. It is hooked
// to the network bridge. The name of the tap interface is returned
SetupTap(networkID NetID, name string) (string, error)
SetupPrivTap(networkID NetID, name string) (string, error)

// SetupYggTap sets up a tap device in the host namespace for the yggdrasil ip
SetupYggTap(name string) (YggdrasilTap, error)

// TapExists checks if the tap device with the given name exists already
TapExists(name string) (bool, error)
Expand Down Expand Up @@ -117,12 +130,16 @@ type Networker interface {

WireguardPorts() ([]uint, error)

// Public Config

// Set node public namespace config
SetPublicConfig(cfg PublicConfig) error

// Get node public namespace config
GetPublicConfig() (PublicConfig, error)

// Monitoring methods

// ZOSAddresses monitoring streams for ZOS bridge IPs
ZOSAddresses(ctx context.Context) <-chan NetlinkAddresses

Expand Down
160 changes: 42 additions & 118 deletions pkg/network/networker.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,123 +128,6 @@ func (n *networker) WireguardPorts() ([]uint, error) {
return n.portSet.List()
}

func (n *networker) Join(networkdID pkg.NetID, containerID string, cfg pkg.ContainerNetworkConfig) (join pkg.Member, err error) {
// TODO:
// 1- Make sure this network id is actually deployed
// 2- Check if the requested network config is doable
// 3- Create a new namespace, then create a veth pair inside this namespace
// 4- Hook one end to the NR bridge
// 5- Assign IP to the veth endpoint inside the namespace.
// 6- return the namespace name

log.Info().Str("network-id", string(networkdID)).Msg("joining network")

localNR, err := n.networkOf(string(networkdID))
if err != nil {
return join, errors.Wrapf(err, "couldn't load network with id (%s)", networkdID)
}

ipv4Only, err := n.ndmz.IsIPv4Only()
if err != nil {
return join, errors.Wrap(err, "failed to check ipv6 support")
}
if cfg.PublicIP6 && ipv4Only {
return join, errors.Errorf("this node runs in IPv4 only mode and you asked for a public IPv6. Impossible to fulfill the request")
}

netRes, err := nr.New(localNR)
if err != nil {
return join, errors.Wrap(err, "failed to load network resource")
}

ips := make([]net.IP, len(cfg.IPs))
for i, addr := range cfg.IPs {
ips[i] = net.ParseIP(addr)
}

join, err = netRes.Join(nr.ContainerConfig{
ContainerID: containerID,
IPs: ips,
PublicIP6: cfg.PublicIP6,
IPv4Only: ipv4Only,
})
if err != nil {
return join, errors.Wrap(err, "failed to load network resource")
}

netNs, err := namespace.GetByName(join.Namespace)
if err != nil {
return join, errors.Wrap(err, "failed to found a valid network interface to use as parent for 0-db container")
}
defer netNs.Close()

if cfg.PublicIP6 {
hw := ifaceutil.HardwareAddrFromInputBytes([]byte(containerID))
if err = n.createMacVlan("pub", public.PublicBridge, hw, nil, nil, netNs); err != nil {
return join, errors.Wrap(err, "failed to create public macvlan interface")
}
}

if cfg.YggdrasilIP {
var (
ips []*net.IPNet
routes []*netlink.Route
)

hw := ifaceutil.HardwareAddrFromInputBytes([]byte("ygg:" + containerID))
ip, err := n.ygg.SubnetFor(hw)
if err != nil {
return join, err
}

ips = []*net.IPNet{
{
IP: ip,
Mask: net.CIDRMask(64, 128),
},
}
join.YggdrasilIP = ip

gw, err := n.ygg.Gateway()
if err != nil {
return join, err
}

routes = []*netlink.Route{
{
Dst: &net.IPNet{
IP: net.ParseIP("200::"),
Mask: net.CIDRMask(7, 128),
},
Gw: gw.IP,
// LinkIndex:... this is set by macvlan.Install
},
}

if err := n.createMacVlan("ygg", types.YggBridge, hw, ips, routes, netNs); err != nil {
return join, errors.Wrap(err, "failed to create yggdrasil macvlan interface")
}
}

return join, nil
}

func (n *networker) Leave(networkdID pkg.NetID, containerID string) error {
log.Info().Str("network-id", string(networkdID)).Msg("leaving network")

localNR, err := n.networkOf(string(networkdID))
if err != nil {
return errors.Wrapf(err, "couldn't load network with id (%s)", networkdID)
}

netRes, err := nr.New(localNR)
if err != nil {
return errors.Wrap(err, "failed to load network resource")
}

return netRes.Leave(containerID)
}

// ZDBPrepare sends a macvlan interface into the
// network namespace of a ZDB container
func (n networker) ZDBPrepare(id string) (string, error) {
Expand Down Expand Up @@ -355,7 +238,7 @@ func (n networker) createMacVlan(iface string, master string, hw net.HardwareAdd

// SetupTap interface in the network resource. We only allow 1 tap interface to be
// set up per NR currently
func (n *networker) SetupTap(networkID pkg.NetID, name string) (string, error) {
func (n *networker) SetupPrivTap(networkID pkg.NetID, name string) (string, error) {
log.Info().Str("network-id", string(networkID)).Msg("Setting up tap interface")

localNR, err := n.networkOf(string(networkID))
Expand All @@ -378,6 +261,10 @@ func (n *networker) SetupTap(networkID pkg.NetID, name string) (string, error) {
return "", errors.Wrap(err, "could not get network namespace tap device name")
}

if ifaceutil.Exists(tapIface, nil) {
return tapIface, nil
}

_, err = tuntap.CreateTap(tapIface, bridgeName)

return tapIface, err
Expand Down Expand Up @@ -431,6 +318,43 @@ func (n *networker) SetupPubTap(pubIPReservationID string) (string, error) {
return tapIface, err
}

// SetupYggTap sets up a tap device in the host namespace for the yggdrasil ip
func (n *networker) SetupYggTap(name string) (tap pkg.YggdrasilTap, err error) {
log.Info().Str("pubip-res-id", string(name)).Msg("Setting up public tap interface")

tapIface, err := tapName(name)
if err != nil {
return tap, errors.Wrap(err, "could not get network namespace tap device name")
}

tap.Name = tapIface

hw := ifaceutil.HardwareAddrFromInputBytes([]byte("ygg:" + name))
tap.HW = hw
ip, err := n.ygg.SubnetFor(hw)
if err != nil {
return tap, err
}

tap.IP = net.IPNet{
IP: ip,
Mask: net.CIDRMask(64, 128),
}

gw, err := n.ygg.Gateway()
if err != nil {
return tap, err
}

tap.Gateway = gw
if ifaceutil.Exists(tapIface, nil) {
return tap, nil
}

_, err = tuntap.CreateTap(tapIface, types.YggBridge)
return tap, err
}

// PubTapExists checks if the tap device for the public network exists already
func (n *networker) PubTapExists(pubIPReservationID string) (bool, error) {
log.Info().Str("pubip-res-id", string(pubIPReservationID)).Msg("Checking if public tap interface exists")
Expand Down
Loading