Skip to content

Commit

Permalink
Implement probing with vlan
Browse files Browse the repository at this point in the history
Prob on configurable vlan, later on we need to also configure
the privae bridge (zos) to use that configured vlan
  • Loading branch information
muhamadazmy committed Oct 18, 2023
1 parent 53eca45 commit 5f0f884
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 16 deletions.
6 changes: 5 additions & 1 deletion cmds/internet/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/vishvananda/netlink"

"github.com/threefoldtech/zos/pkg/app"
"github.com/threefoldtech/zos/pkg/environment"
"github.com/threefoldtech/zos/pkg/network/bootstrap"
"github.com/threefoldtech/zos/pkg/network/bridge"
"github.com/threefoldtech/zos/pkg/network/dhcp"
Expand Down Expand Up @@ -113,11 +114,14 @@ func check() error {
}

func configureZOS() error {

env := environment.MustGet()

f := func() error {
log.Info().Msg("Start network bootstrap")

ifaceConfigs, err := bootstrap.AnalyzeLinks(
bootstrap.RequiresIPv4,
bootstrap.RequiresIPv4.WithVlan(env.PrivVlan),
bootstrap.PhysicalFilter,
bootstrap.PluggedFilter)
if err != nil {
Expand Down
33 changes: 33 additions & 0 deletions pkg/environment/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"strconv"
"sync"

"slices"

"github.com/pkg/errors"
substrate "github.com/threefoldtech/tfchain/clients/tfchain-client-go"
"github.com/threefoldtech/zos/pkg"
Expand Down Expand Up @@ -37,6 +39,15 @@ type Environment struct {
GraphQL string

ExtendedConfigURL string

// private vlan to join
// if set, zos will use this as its priv vlan
PrivVlan *uint16

// pub vlan to join
// if set, zos will use this as it's pub vlan
// only in a single nic setup
PubVlan *uint16
}

// RunningMode type
Expand Down Expand Up @@ -250,6 +261,28 @@ func getEnvironmentFromParams(params kernel.Params) (Environment, error) {
env.FarmID = pkg.FarmID(id)
}

if vlan, found := params.GetOne("vlan:priv"); found {
if !slices.Contains([]string{"none", "untagged", "un"}, vlan) {
tag, err := strconv.ParseUint(vlan, 10, 16)
if err != nil {
return env, errors.Wrap(err, "failed to parse priv vlan value")
}
tagU16 := uint16(tag)
env.PrivVlan = &tagU16
}
}

if vlan, found := params.GetOne("vlan:pub"); found {
if !slices.Contains([]string{"none", "untagged", "un"}, vlan) {
tag, err := strconv.ParseUint(vlan, 10, 16)
if err != nil {
return env, errors.Wrap(err, "failed to parse pub vlan value")
}
tagU16 := uint16(tag)
env.PubVlan = &tagU16
}
}

// Checking if there environment variable
// override default settings

Expand Down
13 changes: 13 additions & 0 deletions pkg/kernel/kernel.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ func (k Params) Get(key string) ([]string, bool) {
return v, ok
}

func (k Params) GetOne(key string) (string, bool) {
all, found := k.Get(key)
if !found {
return "", false
}

if len(all) == 0 {
return "", false
}

return all[len(all)-1], true
}

// IsDebug checks if zos-debug is set
func (k Params) IsDebug() bool {
return k.Exists(Debug)
Expand Down
77 changes: 66 additions & 11 deletions pkg/network/bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,34 @@ type IfaceConfig struct {
}

// Requires tesll the analyser to wait for ip type
type Requires int
type Requires struct {
ipv4 bool
ipv6 bool
vlan *uint16
}

const (
var (
// RequiresIPv4 requires ipv4
RequiresIPv4 Requires = 1 << iota
RequiresIPv4 = Requires{ipv4: true}
// RequiresIPv6 requires ipv6
RequiresIPv6
RequiresIPv6 = Requires{ipv6: true}
)

func (r Requires) WithIPv4(b bool) Requires {
r.ipv4 = b
return r
}

func (r Requires) WithIPv6(b bool) Requires {
r.ipv6 = b
return r
}

func (r Requires) WithVlan(b *uint16) Requires {
r.vlan = b
return r
}

type byIP4 []IfaceConfig

func (a byIP4) Len() int { return len(a) }
Expand Down Expand Up @@ -118,7 +137,7 @@ filter:
defer cancel()
for _, link := range filtered {
wg.Add(1)
analyzeLink(ctx, &wg, ch, requires, link)
analyzeLinkAsync(ctx, &wg, ch, requires, link)
}

go func() {
Expand All @@ -138,8 +157,8 @@ filter:
return configs, nil
}

// AnalyzeLink gets information about link
func AnalyzeLink(ctx context.Context, requires Requires, link netlink.Link) (cfg IfaceConfig, err error) {
// analyzeLink gets information about link
func analyzeLink(ctx context.Context, requires Requires, link netlink.Link) (cfg IfaceConfig, err error) {
cfg.Name = link.Attrs().Name
if link.Attrs().MasterIndex != 0 {
// this is to avoid breaking setups if a link is
Expand Down Expand Up @@ -170,15 +189,51 @@ func AnalyzeLink(ctx context.Context, requires Requires, link netlink.Link) (cfg
}()

name := link.Attrs().Name

if err := options.Set(name, options.IPv6Disable(false)); err != nil {
return errors.Wrapf(err, "failed to enable ip6 on %s", name)
}

cfg.Name = name

if requires.vlan != nil {
vlanID := *requires.vlan
log.Debug().Uint32("vlan", uint32(vlanID)).Msg("setting up vlan interface for probing")
name = fmt.Sprintf("%s.%d", name, vlanID)
vl := netlink.Vlan{
LinkAttrs: netlink.LinkAttrs{
Name: name,
ParentIndex: link.Attrs().Index,
},
VlanId: int(vlanID),
VlanProtocol: netlink.VLAN_PROTOCOL_8021Q,
}

if err := netlink.LinkAdd(&vl); err != nil {
return errors.Wrap(err, "failed to create vlan link for probing")
}

link, err = netlink.LinkByName(name)
if err != nil {
return errors.Wrap(err, "failed to get vlan link for probing")
}

if err := netlink.LinkSetUp(link); err != nil {
return errors.Wrap(err, "failed to set up vlan link for probing")
}

defer func() {
_ = netlink.LinkDel(link)
}()
}

if err := options.Set(name, options.IPv6Disable(false)); err != nil {
return errors.Wrapf(err, "failed to enable ip6 on %s", name)
}

log.Info().Str("interface", name).Msg("start DHCP probe")

if requires&RequiresIPv4 != 0 {
if requires.ipv4 {
// requires IPv4
probe, err := dhcp.Probe(ctx, name)
if err != nil {
Expand Down Expand Up @@ -213,7 +268,7 @@ func AnalyzeLink(ctx context.Context, requires Requires, link netlink.Link) (cfg
}
}

if (requires&RequiresIPv6 == 0) || addrs6.Len() != 0 {
if !requires.ipv6 || addrs6.Len() != 0 {
break loop
}

Expand All @@ -233,10 +288,10 @@ type analyzeResult struct {
err error
}

func analyzeLink(ctx context.Context, wg *sync.WaitGroup, out chan<- analyzeResult, requires Requires, link netlink.Link) {
func analyzeLinkAsync(ctx context.Context, wg *sync.WaitGroup, out chan<- analyzeResult, requires Requires, link netlink.Link) {
go func() {
defer wg.Done()
cfg, err := AnalyzeLink(ctx, requires, link)
cfg, err := analyzeLink(ctx, requires, link)
out <- analyzeResult{cfg, err}
}()
}
Expand Down
8 changes: 4 additions & 4 deletions pkg/network/options/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,31 @@ func (s *sysOption) apply(inf string) error {
// IPv6Disable disabled Ipv6 on interface
func IPv6Disable(f bool) Option {
return &sysOption{
key: "net.ipv6.conf.%s.disable_ipv6",
key: "net/ipv6/conf/%s/disable_ipv6",
val: flag(f),
}
}

// ProxyArp sets proxy arp on interface
func ProxyArp(f bool) Option {
return &sysOption{
key: "net.ipv4.conf.%s.proxy_arp",
key: "net/ipv4/conf/%s/proxy_arp",
val: flag(f),
}
}

// AcceptRA enables or disables forwarding for ipv6
func AcceptRA(f RouterAdvertisements) Option {
return &sysOption{
key: "net.ipv6.conf.%s.accept_ra",
key: "net/ipv6/conf/%s/accept_ra",
val: fmt.Sprintf("%d", f),
}
}

// LearnDefaultRouteInRA Learn default router in Router Advertisement.
func LearnDefaultRouteInRA(f bool) Option {
return &sysOption{
key: "net.ipv6.conf.%s.accept_ra_defrtr",
key: "net/ipv6/conf/%s/accept_ra_defrtr",
val: flag(f),
}
}

0 comments on commit 5f0f884

Please sign in to comment.