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

docs for network light #2397

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
Draft

docs for network light #2397

wants to merge 18 commits into from

Conversation

ashraffouda
Copy link
Collaborator

Signed-off-by: Ashraf Fouda ashraf.m.fouda@gmail.com### Description

Describe the changes introduced by this PR and what does it affect

Changes

List of changes this PR includes

Related Issues

List of related issues

Checklist

  • Tests included
  • Build pass
  • Documentation
  • Code format and docstring

Copy link
Member

@muhamadazmy muhamadazmy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't cover all the PR because of its size. But i think I have left enough comments for the first iteration.

I think using the Light prefix might not be the best approach. Maybe use a version instead? so it's future proof

Comment on lines 117 to 122
.arg(
Arg::with_name("light")
.short("l")
.takes_value(false)
.help("run in light mode, will use the bootstrap:development.flist"),
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The light flag same as the runmode should be parsed from the kernel cmdline arguments not from the bootstrap command arguments.

@@ -16,6 +16,7 @@ func ensureHostFw(ctx context.Context) error {
nft 'add table inet filter'
nft 'add table arp filter'
nft 'add table bridge filter'
nft 'add table nat'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really think this entire file can completely replaced now with a .nft file basically rewrite this as a ruleset (similar to what we have under nft/rules.nft)

It's way cleaner than executing individual commands


// getVmMetrics will collect network consumption every 5 min and store
// it in the rrd database.
func (r *Reporter) getGwMetrics(ctx context.Context, slot rrd.Slot) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will probably be re-added

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we decided to postpone gw and qsfs for later versions of zos light

test: zbusdebug --module network
exec: netlightd --broker unix:///var/run/redis.sock --root /var/cache/modules/networkd

# test: zbusdebug --module network
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still have to have something here to let other modules know that this networking is ready. I am sure netlightd also has a "zbus" service which means we can use the same test command but with different module name (if the module name was changed even)

@@ -321,6 +321,10 @@ func getEnvironmentFromParams(params kernel.Params) (Environment, error) {
if e := os.Getenv("ZOS_BIN_REPO"); e != "" {
env.BinRepo = e
}
env.Light = false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This of course is not needed, since the zero value for bool in Go is false.

// NetworkLightType type
NetworkLightType gridtypes.WorkloadType = "network-light"
// ZDBLightType type
ZDBLightType gridtypes.WorkloadType = "zdb-light"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need zdb-light? is it because it doesn't have ygg IP?

I think we should only use the "-light" suffix if the data type for input or output changes (like vm and network) but I don't believe this applies to zdb

}

// myceliumIpSeed is 6 bytes
func (r *Resource) AttachPrivate(id string, vmIp net.IP) (device pkg.TapDevice, err error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't figure out if this an idempotent function or not. But it's usually important that such functions to be idempotent so recreation doesn't happen if the service was restarted for example

Name string
Mac net.HardwareAddr
IP *net.IPNet
Gateway *net.IPNet
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be Routes instead so we can also have custom routes not only default GW. It's needed with mycelium for example and in other cases where custom routing is required

rename zdblight to zdb and do some hardening

Signed-off-by: Ashraf Fouda <ashraf.m.fouda@gmail.com>
Copy link
Member

@muhamadazmy muhamadazmy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ashraffouda for the great work. I still have few comments in case you are interested

@@ -26,15 +26,19 @@ fn bootstrap_zos(cfg: &config::Config) -> Result<()> {
let flist = match &cfg.runmode {
RunMode::Prod => match &cfg.version {
Version::V3 => "zos:production-3:latest.flist",
_ => bail!("unsupported version in old style"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's safe to completely remove the old style from code since ALL environments have been updated to new style. We needed to keep the old style for a while because bootstrap is shared between all environments (since it's part of base image) because some envs used new style and others didn't.

Anyway, you can assume that old style does no longer exist

if err := nft.Apply(rules, ""); err != nil {
return fmt.Errorf("failed to apply host nft rules: %w", err)
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

close the rules file here

@@ -0,0 +1,29 @@
add table inet filter;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant with this is to make it similar to other rules.nft (in the same PR here style. It doesn't have commands but instead the complete structure of the rule set

It contains simply the output of running nft list ruleset

If you don't get what I mean let me explain over DM

if err := nft.Apply(rules, nsName); err != nil {
return nil, fmt.Errorf("failed to apply nft rules for namespace '%s': %w", name, err)
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

close rules file here

Name string
Mac net.HardwareAddr
IP *net.IPNet
Routes []Route
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is Route defined

Comment on lines +203 to +206
envName := mode.String()
if u.boot.Version().Major == 4 {
envName = fmt.Sprintf("%s-light", envName)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a fork and the entire fork knows that this is version 4. Hence you can always assume the envName to be "-light" without even the need to check for the major version

@@ -24,43 +23,6 @@ const (
cloudConsoleBin = "cloud-console"
)

// startCloudConsole Starts the cloud console for the vm on it's private network ip
func (m *Machine) startCloudConsole(ctx context.Context, namespace string, networkAddr net.IPNet, machineIP net.IPNet, ptyPath string, logs string) (string, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the cloud console can stay since the user network will always have a mycelium IP. the console can still work over the mycelium IP in case the VM is not reachable for any reason.

  • So the ip of the vm is the VM private ip (private range)
  • The console listen port is calculated the same way
  • The console IP itself is the mycelium IP assigned to this user mycelium instance.

@@ -131,12 +93,16 @@ func (m *Machine) Run(ctx context.Context, socket, logs string) (pkg.MachineInfo

for _, nic := range m.Interfaces {
var typ InterfaceType
typ, _, err = nic.getType()
typ, idx, err := nic.getType()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you do Attach on the resource, you should create a tap device (not macvtap) which makes it easier to attach it to CH command line. The macvtap case was only used for public IPs specifically.

}
_, getLinkErr := netlink.LinkByName(tapName)
if getLinkErr != nil {
mtap, err := macvtap.CreateMACvTap(tapName, privateNetBr, hw)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We create TAP devices for VMs not Macvtap. this makes it un0necessary complex to pass this device to the VM when it can just be a tap device

myBr := fmt.Sprintf("m%s", r.name)
hw := ifaceutil.HardwareAddrFromInputBytes([]byte(tapName))

_, err = macvtap.CreateMACvTap(tapName, myBr, hw)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for mycelium this can perfectly be a tap device (not macvtap) hence it becomes simpler to pass to the cloud-hypervisor command line

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

macvtaps or macvlans are a disaster if they're more than one with a bridge interface as parent.
Somewhere since that dummy necessity version, macvlans have problems ... what they specifically are, I'm not sure yet, but I suspect seen that macvlans are also bridges in a lighter version, they don't cooperate well with regular bridges

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I felt like since the https://bugzilla.kernel.org/show_bug.cgi?id=214631 bug, macvlans went worse and worse over time.
probably because of their infrequent use.
let's see how much work it is, but I guess

@@ -199,42 +187,14 @@ func (p *Manager) virtualMachineProvisionImpl(ctx context.Context, wl *gridtypes
if err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

according to https://github.com/threefoldtech/zos/pull/2397/files#diff-21cf55cfe1ba697c2e7be4ae50cbe646bca4331061bba94ebc35fb5f7d05ca98R162-R165

we only have/use one private network, why still looping all net interfaces instead of using the only used one?

networkInfo.Ifaces = append(networkInfo.Ifaces, inf)
result.PlanetaryIP = inf.IPs[0].IP.String()
}

if config.Network.Mycelium != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it allowed to not have mycelium?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is not allowed according to the specs, CMIIW


var _ pkg.NetworkerLight = (*networker)(nil)

func NewNetworker() (pkg.NetworkerLight, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it common to add er to the struct in zos?
because er suffix usually used for interface, not struct

Comment on lines +227 to +245
var addrs []netlink.Addr

if err = netNs.Do(func(_ ns.NetNS) error {
link, err := netlink.LinkByName(infPrivate)
if err != nil {
return err
}
addrs, err = netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return err
}
return nil
}); err != nil {
return
}
if len(addrs) != 1 {
return device, fmt.Errorf("expect addresses on private interface to be 1 got %d", len(addrs))
}
gw := addrs[0].IPNet
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for readability, i think we can move this block into separate func, maybe something like:
getAndValidateAddr()

And maybe including the code to get the namespace

nsName := fmt.Sprintf("n%s", r.name)
	netNs, err := namespace.GetByName(nsName)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think the code below it can also be included

if !gw.Contains(vmIp) {
		return device, fmt.Errorf("ip not in range")
	}

Mask: gw.Mask,
}
_, getLinkErr := netlink.LinkByName(tapName)
if getLinkErr != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so, is it OK if the tap already exists?

}

func inspectMycelium(seed []byte) (inspection MyceliumInspection, err error) {
// we check if the file exists before we do inspect because mycelium will create a random seed
Copy link
Member

@iwanbk iwanbk Aug 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we check if the file exists

can't find the check

return inspection, fmt.Errorf("failed to write seed: %w", err)
}

tmp.Close()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to the above of the if block?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants