Skip to content

Commit

Permalink
ygg in zmachines (#1320)
Browse files Browse the repository at this point in the history
* initial commit

* wip: refactor network setup

* WIP: create the yggdrasil tab

* support ygg ips

* fixes to ci

* set default args

* fix tests
  • Loading branch information
muhamadazmy authored Jun 23, 2021
1 parent 1d2effb commit ab62e8f
Show file tree
Hide file tree
Showing 12 changed files with 359 additions and 358 deletions.
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

0 comments on commit ab62e8f

Please sign in to comment.