From 7f63b480045ec7999500667d01e4f03c01eb74db Mon Sep 17 00:00:00 2001 From: steiler Date: Thu, 29 Jun 2023 09:21:46 +0200 Subject: [PATCH 01/22] implement new Links format --- clab/clab.go | 10 +-- clab/config.go | 4 +- types/link.go | 156 +++++++++++++++++++++++++++++++++++++++++ types/link_common.go | 22 ++++++ types/link_host.go | 41 +++++++++++ types/link_mac.go | 9 +++ types/link_macvlan.go | 21 ++++++ types/link_macvtap.go | 21 ++++++ types/link_mgmt-net.go | 38 ++++++++++ types/link_veth.go | 46 ++++++++++++ types/topology.go | 4 +- 11 files changed, 364 insertions(+), 8 deletions(-) create mode 100644 types/link.go create mode 100644 types/link_common.go create mode 100644 types/link_host.go create mode 100644 types/link_mac.go create mode 100644 types/link_macvlan.go create mode 100644 types/link_macvtap.go create mode 100644 types/link_mgmt-net.go create mode 100644 types/link_veth.go diff --git a/clab/clab.go b/clab/clab.go index cd2499125..465afe15d 100644 --- a/clab/clab.go +++ b/clab/clab.go @@ -142,7 +142,7 @@ func filterClabNodes(c *CLab, nodeFilter []string) error { log.Infof("Applying node filter: %q", nodeFilter) // newNodes := make(map[string]*types.NodeDefinition, len(c.Config.Topology.Nodes)) - newLinks := make([]*types.LinkConfig, 0, len(c.Config.Topology.Links)) + newLinks := make([]*types.LinkConfig, 0, len(c.Config.Topology.RawLinks)) // filter nodes for name := range c.Config.Topology.Nodes { @@ -153,17 +153,17 @@ func filterClabNodes(c *CLab, nodeFilter []string) error { } // filter links - for _, l := range c.Config.Topology.Links { + for _, l := range c.Config.Topology.RawLinks { // get the endpoints of the link and extract the node names // to remove the links which have either side in the node filter - splitEpAside := strings.Split(l.Endpoints[0], ":") + splitEpAside := strings.Split(l.Instance.Endpoints[0], ":") if len(splitEpAside) != 2 { continue } epA := splitEpAside[0] - splitEpBside := strings.Split(l.Endpoints[1], ":") + splitEpBside := strings.Split(l.Instance.Endpoints[1], ":") if len(splitEpBside) != 2 { continue } @@ -176,7 +176,7 @@ func filterClabNodes(c *CLab, nodeFilter []string) error { // if both endpoints of a link belong to the node filter, keep the link if containsAside && containsBside { log.Debugf("Including link %+v", l) - newLinks = append(newLinks, l) + newLinks = append(newLinks, l.Instance) } } // replace the original collection of links with the links that have both endpoints in the node filter diff --git a/clab/config.go b/clab/config.go index 18a6fee97..9e4caf71a 100644 --- a/clab/config.go +++ b/clab/config.go @@ -124,9 +124,9 @@ func (c *CLab) parseTopology() error { return err } } - for i, l := range c.Config.Topology.Links { + for i, l := range c.Config.Topology.RawLinks { // i represents the endpoint integer and l provide the link struct - c.Links[i] = c.NewLink(l) + c.Links[i] = c.NewLink(l.Instance) } // set any containerlab defaults after we've parsed the input diff --git a/types/link.go b/types/link.go new file mode 100644 index 000000000..7b3dd9594 --- /dev/null +++ b/types/link.go @@ -0,0 +1,156 @@ +package types + +import ( + "errors" + "fmt" + "strings" + + "gopkg.in/yaml.v2" +) + +type LinkCommonParams struct { + Mtu int `yaml:"mtu,omitempty"` + Labels map[string]string `yaml:"labels,omitempty"` + Vars map[string]interface{} `yaml:"vars,omitempty"` +} + +type RawLinkType struct { + Type string `yaml:"type"` + // Instance interface{} + Instance *LinkConfig +} + +type LinkDefinitionType string + +const ( + LinkTypeVEth LinkDefinitionType = "veth" + LinkTypeMgmtNet LinkDefinitionType = "mgmt-net" + LinkTypeMacVLan LinkDefinitionType = "macvlan" + LinkTypeMacVTap LinkDefinitionType = "macvtap" + LinkTypeHost LinkDefinitionType = "host" + + LinkTypeDeprecate LinkDefinitionType = "DEPRECATE" +) + +type RawLinkTypeAlias RawLinkType + +func ParseLinkType(s string) (LinkDefinitionType, error) { + switch strings.TrimSpace(strings.ToLower(s)) { + case string(LinkTypeMacVLan): + return LinkTypeMacVLan, nil + case string(LinkTypeMacVTap): + return LinkTypeMacVTap, nil + case string(LinkTypeVEth): + return LinkTypeVEth, nil + case string(LinkTypeMgmtNet): + return LinkTypeMgmtNet, nil + case string(LinkTypeDeprecate): + return LinkTypeDeprecate, nil + default: + return "", fmt.Errorf("unable to parse %q as LinkType", s) + } +} + +func (rlt *RawLinkTypeAlias) GetType() (LinkDefinitionType, error) { + return ParseLinkType(rlt.Type) +} + +var _ yaml.Unmarshaler = &RawLinkType{} + +func (r *RawLinkType) UnmarshalYAML(unmarshal func(interface{}) error) error { + var rtAlias RawLinkTypeAlias + + err := unmarshal(&rtAlias) + // Strict unmarshalling, as we do with containerlab will cause the + // Links sections to fail. The unmarshal call will throw a yaml.TypeError + // This section we don't want strict, so if error is not nil but the error type is + // yaml.TypeError, we will continue + var e *yaml.TypeError + if err != nil && errors.As(err, &e) { + return err + } + + r.Type = rtAlias.Type + + switch strings.ToLower(rtAlias.Type) { + case "veth": + var l RawVEthLink + err := unmarshal(&l) + if err != nil { + return err + } + r.Instance = l.ToLinkConfig() + case "mgmt-net": + var l RawMgmtNetLink + err := unmarshal(&l) + if err != nil { + return err + } + r.Instance = l.ToLinkConfig() + case "host": + var l RawHostLink + err := unmarshal(&l) + if err != nil { + return err + } + r.Instance = l.ToLinkConfig() + case "macvlan": + var l RawMacVLanLink + err := unmarshal(&l) + if err != nil { + return err + } + r.Instance = l.ToLinkConfig() + case "macvtap": + var l RawMacVTapLink + err := unmarshal(&l) + if err != nil { + return err + } + r.Instance = l.ToLinkConfig() + default: + // try to parse the depricate format + var l LinkConfig + err := unmarshal(&l) + if err != nil { + return err + } + r.Type = "DEPRECATE" + r.Instance, err = deprecateLinkConversion(&l) + if err != nil { + return err + } + } + + return nil +} + +func deprecateLinkConversion(lc *LinkConfig) (*LinkConfig, error) { + // check two endpoints defined + if len(lc.Endpoints) != 2 { + return nil, fmt.Errorf("endpoint definition should consist of exactly 2 entries. %d provided", len(lc.Endpoints)) + } + for _, v := range lc.Endpoints { + parts := strings.SplitN(v, ":", 2) + node := parts[0] + + lt, err := ParseLinkType(node) + if err != nil { + // if the link type parsing from the node name did fail + // we continue, since the node name is not like veth or macvlan or the like + continue + } + + // if the node name is equal to a LinkType, we check the Type and only allow the depricated format + // for old types. New once we force to use the new link format. + switch lt { + case LinkTypeMgmtNet: + continue + case LinkTypeHost: + continue + case LinkTypeMacVLan, LinkTypeMacVTap: + return nil, fmt.Errorf("Link type %q needs to be defined in new link format", string(lt)) + } + } + return lc, nil +} diff --git a/types/link_common.go b/types/link_common.go new file mode 100644 index 000000000..c81413fbe --- /dev/null +++ b/types/link_common.go @@ -0,0 +1,22 @@ +package types + +type EndpointRaw struct { + Node string `yaml:"node"` + Iface string `yaml:"interface"` + Mac string `yaml:"mac"` +} + +// func extractHostNodeInterfaceData(lc *LinkConfig, specialEPIndex int) (host string, hostIf string, node string, nodeIf string) { +// // the index of the node is the specialEndpointIndex +1 modulo 2 +// nodeindex := (specialEPIndex + 1) % 2 + +// hostData := strings.SplitN(lc.Endpoints[specialEPIndex], ":", 2) +// nodeData := strings.SplitN(lc.Endpoints[nodeindex], ":", 2) + +// host = hostData[0] +// hostIf = hostData[1] +// node = nodeData[0] +// nodeIf = nodeData[1] + +// return host, hostIf, node, nodeIf +// } diff --git a/types/link_host.go b/types/link_host.go new file mode 100644 index 000000000..c627c1cb0 --- /dev/null +++ b/types/link_host.go @@ -0,0 +1,41 @@ +package types + +import "fmt" + +type RawHostLink struct { + LinkCommonParams `yaml:",inline"` + HostInterface string `yaml:"host-interface"` + Node string `yaml:"node"` + NodeInterface string `yaml:"node-interface"` +} + +func (r *RawHostLink) ToLinkConfig() *LinkConfig { + lc := &LinkConfig{ + Vars: r.Vars, + Labels: r.Labels, + MTU: r.Mtu, + Endpoints: make([]string, 2), + } + + lc.Endpoints[0] = fmt.Sprintf("%s:%s", r.Node, r.NodeInterface) + lc.Endpoints[1] = fmt.Sprintf("%s:%s", "host", r.HostInterface) + + return lc +} + +// func hostFromLinkConfig(lc *LinkConfig, specialEPIndex int) (*RawHostLink, error) { +// _, hostIf, node, nodeIf := extractHostNodeInterfaceData(lc, specialEPIndex) + +// result := &RawHostLink{ +// RawLinkType: RawLinkType{ +// Type: string(LinkTypeHost), +// Labels: lc.Labels, +// Vars: lc.Vars, +// Instance: nil, +// }, +// HostInterface: hostIf, +// Node: node, +// NodeInterface: nodeIf, +// } +// return result, nil +// } diff --git a/types/link_mac.go b/types/link_mac.go new file mode 100644 index 000000000..0e4c1410b --- /dev/null +++ b/types/link_mac.go @@ -0,0 +1,9 @@ +package types + +type rawMacVXType struct { + LinkCommonParams `yaml:",inline"` + HostInterface string `yaml:"host-interface"` + Node string `yaml:"node"` + NodeInterface string `yaml:"node-interface"` + NodeInterfaceMAC string `yaml:"mac"` +} diff --git a/types/link_macvlan.go b/types/link_macvlan.go new file mode 100644 index 000000000..be3a90db5 --- /dev/null +++ b/types/link_macvlan.go @@ -0,0 +1,21 @@ +package types + +import "fmt" + +type RawMacVLanLink struct { + rawMacVXType `yaml:",inline"` +} + +func (r *RawMacVLanLink) ToLinkConfig() *LinkConfig { + lc := &LinkConfig{ + Vars: r.Vars, + Labels: r.Labels, + MTU: r.Mtu, + Endpoints: make([]string, 2), + } + + lc.Endpoints[0] = fmt.Sprintf("%s:%s", r.Node, r.NodeInterface) + lc.Endpoints[1] = fmt.Sprintf("%s:%s", "macvlan", r.HostInterface) + + return lc +} diff --git a/types/link_macvtap.go b/types/link_macvtap.go new file mode 100644 index 000000000..daa66bb1c --- /dev/null +++ b/types/link_macvtap.go @@ -0,0 +1,21 @@ +package types + +import "fmt" + +type RawMacVTapLink struct { + rawMacVXType `yaml:",inline"` +} + +func (r *RawMacVTapLink) ToLinkConfig() *LinkConfig { + lc := &LinkConfig{ + Vars: r.Vars, + Labels: r.Labels, + MTU: r.Mtu, + Endpoints: make([]string, 2), + } + + lc.Endpoints[0] = fmt.Sprintf("%s:%s", r.Node, r.NodeInterface) + lc.Endpoints[1] = fmt.Sprintf("%s:%s", "macvtap", r.HostInterface) + + return lc +} diff --git a/types/link_mgmt-net.go b/types/link_mgmt-net.go new file mode 100644 index 000000000..8f437735b --- /dev/null +++ b/types/link_mgmt-net.go @@ -0,0 +1,38 @@ +package types + +import "fmt" + +type RawMgmtNetLink struct { + LinkCommonParams `yaml:",inline"` + HostInterface string `yaml:"host-interface"` + Endpoint *EndpointRaw `yaml:"endpoint"` +} + +func (r *RawMgmtNetLink) ToLinkConfig() *LinkConfig { + lc := &LinkConfig{ + Vars: r.Vars, + Labels: r.Labels, + MTU: r.Mtu, + Endpoints: make([]string, 2), + } + + lc.Endpoints[0] = fmt.Sprintf("%s:%s", r.Endpoint.Node, r.Endpoint.Iface) + lc.Endpoints[1] = fmt.Sprintf("%s:%s", "mgmt-net", r.HostInterface) + + return lc +} + +// func mgmtNetFromLinkConfig(lc *LinkConfig, specialEPIndex int) (*RawMgmtNetLink, error) { +// _, hostIf, node, nodeIf := extractHostNodeInterfaceData(lc, specialEPIndex) + +// result := &RawMgmtNetLink{ +// RawLinkType: RawLinkType{Type: string(LinkTypeMgmtNet), Labels: lc.Labels, Vars: lc.Vars, Instance: nil}, +// HostInterface: hostIf, +// Endpoint: &EndpointRaw{ +// Node: node, +// Iface: nodeIf, +// Mac: "", +// }, +// } +// return result, nil +// } diff --git a/types/link_veth.go b/types/link_veth.go new file mode 100644 index 000000000..8a136f441 --- /dev/null +++ b/types/link_veth.go @@ -0,0 +1,46 @@ +package types + +import "fmt" + +type RawVEthLink struct { + LinkCommonParams `yaml:",inline"` + Endpoints []*EndpointRaw `yaml:"endpoints"` +} + +func (r *RawVEthLink) ToLinkConfig() *LinkConfig { + lc := &LinkConfig{ + Vars: r.Vars, + Labels: r.Labels, + MTU: r.Mtu, + Endpoints: []string{}, + } + for _, e := range r.Endpoints { + lc.Endpoints = append(lc.Endpoints, fmt.Sprintf("%s:%s", e.Node, e.Iface)) + } + return lc +} + +// func vEthFromLinkConfig(lc *LinkConfig) (*RawVEthLink, error) { +// nodeA, nodeAIf, nodeB, nodeBIf := extractHostNodeInterfaceData(lc, 0) + +// result := &RawVEthLink{ +// RawLinkType: RawLinkType{ +// Type: string(LinkTypeVEth), +// Labels: lc.Labels, +// Vars: lc.Vars, +// Instance: nil, +// }, +// Mtu: lc.MTU, +// Endpoints: []*EndpointRaw{ +// { +// Node: nodeA, +// Iface: nodeAIf, +// }, +// { +// Node: nodeB, +// Iface: nodeBIf, +// }, +// }, +// } +// return result, nil +// } diff --git a/types/topology.go b/types/topology.go index f940298af..efccffb42 100644 --- a/types/topology.go +++ b/types/topology.go @@ -10,7 +10,8 @@ type Topology struct { Defaults *NodeDefinition `yaml:"defaults,omitempty"` Kinds map[string]*NodeDefinition `yaml:"kinds,omitempty"` Nodes map[string]*NodeDefinition `yaml:"nodes,omitempty"` - Links []*LinkConfig `yaml:"links,omitempty"` + RawLinks []*RawLinkType `yaml:"links,omitempty"` + Links []*LinkConfig `yaml:"-"` } func NewTopology() *Topology { @@ -18,6 +19,7 @@ func NewTopology() *Topology { Defaults: new(NodeDefinition), Kinds: make(map[string]*NodeDefinition), Nodes: make(map[string]*NodeDefinition), + RawLinks: make([]*RawLinkType, 0), Links: make([]*LinkConfig, 0), } } From 9388f89c1a10143a75a8936bb806f1737d35b775 Mon Sep 17 00:00:00 2001 From: steiler Date: Thu, 29 Jun 2023 10:31:32 +0200 Subject: [PATCH 02/22] fixing RawLink to Link and unmarshall error --- clab/clab.go | 8 ++++---- clab/file.go | 6 ++++++ types/link.go | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/clab/clab.go b/clab/clab.go index 465afe15d..8ed90698b 100644 --- a/clab/clab.go +++ b/clab/clab.go @@ -153,17 +153,17 @@ func filterClabNodes(c *CLab, nodeFilter []string) error { } // filter links - for _, l := range c.Config.Topology.RawLinks { + for _, l := range c.Config.Topology.Links { // get the endpoints of the link and extract the node names // to remove the links which have either side in the node filter - splitEpAside := strings.Split(l.Instance.Endpoints[0], ":") + splitEpAside := strings.Split(l.Endpoints[0], ":") if len(splitEpAside) != 2 { continue } epA := splitEpAside[0] - splitEpBside := strings.Split(l.Instance.Endpoints[1], ":") + splitEpBside := strings.Split(l.Endpoints[1], ":") if len(splitEpBside) != 2 { continue } @@ -176,7 +176,7 @@ func filterClabNodes(c *CLab, nodeFilter []string) error { // if both endpoints of a link belong to the node filter, keep the link if containsAside && containsBside { log.Debugf("Including link %+v", l) - newLinks = append(newLinks, l.Instance) + newLinks = append(newLinks, l) } } // replace the original collection of links with the links that have both endpoints in the node filter diff --git a/clab/file.go b/clab/file.go index 68ae95ab3..d6216caa3 100644 --- a/clab/file.go +++ b/clab/file.go @@ -80,6 +80,12 @@ func (c *CLab) GetTopology(topo, varsFile string) error { return fmt.Errorf("%w\nConsult with release notes to see if any fields were changed/removed", err) } + // move RawLink Instance to Link + c.Config.Topology.Links = make([]*types.LinkConfig, len(c.Config.Topology.RawLinks)) + for idx, l := range c.Config.Topology.RawLinks { + c.Config.Topology.Links[idx] = l.Instance + } + c.Config.Topology.ImportEnvs() return nil diff --git a/types/link.go b/types/link.go index 7b3dd9594..69226e343 100644 --- a/types/link.go +++ b/types/link.go @@ -66,7 +66,7 @@ func (r *RawLinkType) UnmarshalYAML(unmarshal func(interface{}) error) error { // This section we don't want strict, so if error is not nil but the error type is // yaml.TypeError, we will continue var e *yaml.TypeError - if err != nil && errors.As(err, &e) { + if err != nil && !errors.As(err, &e) { return err } From 3a9feef24219141939f4aed3f4a78669a2bb2ae4 Mon Sep 17 00:00:00 2001 From: steiler Date: Thu, 29 Jun 2023 11:40:10 +0200 Subject: [PATCH 03/22] update & tests --- types/link.go | 6 +- types/link_host.go | 7 +- types/link_mac.go | 6 +- types/link_macvlan.go | 2 +- types/link_macvtap.go | 2 +- types/link_test.go | 248 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 259 insertions(+), 12 deletions(-) create mode 100644 types/link_test.go diff --git a/types/link.go b/types/link.go index 69226e343..34b956b9a 100644 --- a/types/link.go +++ b/types/link.go @@ -29,7 +29,7 @@ const ( LinkTypeMacVTap LinkDefinitionType = "macvtap" LinkTypeHost LinkDefinitionType = "host" - LinkTypeDeprecate LinkDefinitionType = "DEPRECATE" + LinkTypeDeprecate LinkDefinitionType = "deprecate" ) type RawLinkTypeAlias RawLinkType @@ -44,6 +44,8 @@ func ParseLinkType(s string) (LinkDefinitionType, error) { return LinkTypeVEth, nil case string(LinkTypeMgmtNet): return LinkTypeMgmtNet, nil + case string(LinkTypeHost): + return LinkTypeHost, nil case string(LinkTypeDeprecate): return LinkTypeDeprecate, nil default: @@ -115,7 +117,7 @@ func (r *RawLinkType) UnmarshalYAML(unmarshal func(interface{}) error) error { if err != nil { return err } - r.Type = "DEPRECATE" + r.Type = string(LinkTypeDeprecate) r.Instance, err = deprecateLinkConversion(&l) if err != nil { return err diff --git a/types/link_host.go b/types/link_host.go index c627c1cb0..f1e66fbfe 100644 --- a/types/link_host.go +++ b/types/link_host.go @@ -4,9 +4,8 @@ import "fmt" type RawHostLink struct { LinkCommonParams `yaml:",inline"` - HostInterface string `yaml:"host-interface"` - Node string `yaml:"node"` - NodeInterface string `yaml:"node-interface"` + HostInterface string `yaml:"host-interface"` + Endpoint *EndpointRaw `yaml:"endpoint"` } func (r *RawHostLink) ToLinkConfig() *LinkConfig { @@ -17,7 +16,7 @@ func (r *RawHostLink) ToLinkConfig() *LinkConfig { Endpoints: make([]string, 2), } - lc.Endpoints[0] = fmt.Sprintf("%s:%s", r.Node, r.NodeInterface) + lc.Endpoints[0] = fmt.Sprintf("%s:%s", r.Endpoint.Node, r.Endpoint.Iface) lc.Endpoints[1] = fmt.Sprintf("%s:%s", "host", r.HostInterface) return lc diff --git a/types/link_mac.go b/types/link_mac.go index 0e4c1410b..5a78e6abf 100644 --- a/types/link_mac.go +++ b/types/link_mac.go @@ -2,8 +2,6 @@ package types type rawMacVXType struct { LinkCommonParams `yaml:",inline"` - HostInterface string `yaml:"host-interface"` - Node string `yaml:"node"` - NodeInterface string `yaml:"node-interface"` - NodeInterfaceMAC string `yaml:"mac"` + HostInterface string `yaml:"host-interface"` + Endpoint *EndpointRaw `yaml:"endpoint"` } diff --git a/types/link_macvlan.go b/types/link_macvlan.go index be3a90db5..c78e6e193 100644 --- a/types/link_macvlan.go +++ b/types/link_macvlan.go @@ -14,7 +14,7 @@ func (r *RawMacVLanLink) ToLinkConfig() *LinkConfig { Endpoints: make([]string, 2), } - lc.Endpoints[0] = fmt.Sprintf("%s:%s", r.Node, r.NodeInterface) + lc.Endpoints[0] = fmt.Sprintf("%s:%s", r.Endpoint.Node, r.Endpoint.Iface) lc.Endpoints[1] = fmt.Sprintf("%s:%s", "macvlan", r.HostInterface) return lc diff --git a/types/link_macvtap.go b/types/link_macvtap.go index daa66bb1c..9699618e0 100644 --- a/types/link_macvtap.go +++ b/types/link_macvtap.go @@ -14,7 +14,7 @@ func (r *RawMacVTapLink) ToLinkConfig() *LinkConfig { Endpoints: make([]string, 2), } - lc.Endpoints[0] = fmt.Sprintf("%s:%s", r.Node, r.NodeInterface) + lc.Endpoints[0] = fmt.Sprintf("%s:%s", r.Endpoint.Node, r.Endpoint.Iface) lc.Endpoints[1] = fmt.Sprintf("%s:%s", "macvtap", r.HostInterface) return lc diff --git a/types/link_test.go b/types/link_test.go new file mode 100644 index 000000000..a752bddb3 --- /dev/null +++ b/types/link_test.go @@ -0,0 +1,248 @@ +package types + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "gopkg.in/yaml.v2" +) + +func TestParseLinkType(t *testing.T) { + type args struct { + s string + } + tests := []struct { + name string + args args + want LinkDefinitionType + wantErr bool + }{ + { + name: "link type host", + args: args{ + s: string(LinkTypeHost), + }, + want: LinkTypeHost, + wantErr: false, + }, + { + name: "link type veth", + args: args{ + s: string(LinkTypeVEth), + }, + want: LinkTypeVEth, + wantErr: false, + }, + { + name: "link type macvlan", + args: args{ + s: string(LinkTypeMacVLan), + }, + want: LinkTypeMacVLan, + wantErr: false, + }, + { + name: "link type macvtap", + args: args{ + s: string(LinkTypeMacVTap), + }, + want: LinkTypeMacVTap, + wantErr: false, + }, + { + name: "link type mgmt-net", + args: args{ + s: string(LinkTypeMgmtNet), + }, + want: LinkTypeMgmtNet, + wantErr: false, + }, + { + name: "link type deprecate", + args: args{ + s: string(LinkTypeDeprecate), + }, + want: LinkTypeDeprecate, + wantErr: false, + }, + { + name: "link type UNKNOWN", + args: args{ + s: "foobar", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseLinkType(tt.args.s) + if (err != nil) != tt.wantErr { + t.Errorf("ParseLinkType() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("ParseLinkType() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUnmarshalRawLinksYaml(t *testing.T) { + type args struct { + yaml []byte + } + tests := []struct { + name string + args args + want RawLinkType + wantErr bool + }{ + { + name: "legacy link", + args: args{ + yaml: []byte(` + endpoints: + - "srl1:e1-5" + - "srl2:e1-5" + `), + }, + wantErr: false, + want: RawLinkType{ + Type: string(LinkTypeDeprecate), + Instance: &LinkConfig{ + Endpoints: []string{ + "srl1:e1-5", + "srl2:e1-5", + }, + }, + }, + }, + { + name: "mgmt-net link", + args: args{ + yaml: []byte(` + type: mgmt-net + host-interface: srl1_e1-5 + endpoint: + node: srl1 + interface: e1-5 + `), + }, + wantErr: false, + want: RawLinkType{ + Type: string(LinkTypeMgmtNet), + Instance: &LinkConfig{ + Endpoints: []string{ + "srl1:e1-5", + "mgmt-net:srl1_e1-5", + }, + }, + }, + }, + { + name: "host link", + args: args{ + yaml: []byte(` + type: host + host-interface: srl1_e1-5 + endpoint: + node: srl1 + interface: e1-5 + `), + }, + wantErr: false, + want: RawLinkType{ + Type: string(LinkTypeHost), + Instance: &LinkConfig{ + Endpoints: []string{ + "srl1:e1-5", + "host:srl1_e1-5", + }, + }, + }, + }, + { + name: "macvlan link", + args: args{ + yaml: []byte(` + type: macvlan + host-interface: srl1_e1-5 + endpoint: + node: srl1 + interface: e1-5 + `), + }, + wantErr: false, + want: RawLinkType{ + Type: string(LinkTypeMacVLan), + Instance: &LinkConfig{ + Endpoints: []string{ + "srl1:e1-5", + "macvlan:srl1_e1-5", + }, + }, + }, + }, + { + name: "macvtap link", + args: args{ + yaml: []byte(` + type: macvtap + host-interface: srl1_e1-5 + endpoint: + node: srl1 + interface: e1-5 + `), + }, + wantErr: false, + want: RawLinkType{ + Type: string(LinkTypeMacVTap), + Instance: &LinkConfig{ + Endpoints: []string{ + "srl1:e1-5", + "macvtap:srl1_e1-5", + }, + }, + }, + }, + { + name: "macvtap link legacy format", + args: args{ + yaml: []byte(` + endpoints: + - "srl1:e1-5" + - "macvtap:e1-5" + `), + }, + wantErr: true, + }, + { + name: "macvlan link legacy format", + args: args{ + yaml: []byte(` + endpoints: + - "srl1:e1-5" + - "macvlan:e1-5" + `), + }, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var rl RawLinkType + err := yaml.Unmarshal(tt.args.yaml, &rl) + if (err != nil) != tt.wantErr { + t.Errorf("RawLinkType Unmarshal() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if diff := cmp.Diff(rl, tt.want); diff != "" { + t.Errorf("RawLinkType Unmarshal() = %v, want %v, diff:\n%s", rl, tt.want, diff) + return + } + } + }) + } +} From cbd503f752826db81285cbf51559d64c25850c10 Mon Sep 17 00:00:00 2001 From: steiler Date: Mon, 3 Jul 2023 14:46:16 +0200 Subject: [PATCH 04/22] update --- clab/clab.go | 37 +++---------- clab/clab_test.go | 128 ++++++++++++++++++++++++++++++++++----------- clab/config.go | 16 +++--- clab/file.go | 6 --- cmd/generate.go | 16 +++--- types/link.go | 12 ++--- types/link_test.go | 14 ++--- types/topology.go | 20 +++---- types/types.go | 4 ++ 9 files changed, 148 insertions(+), 105 deletions(-) diff --git a/clab/clab.go b/clab/clab.go index 8ed90698b..447b602be 100644 --- a/clab/clab.go +++ b/clab/clab.go @@ -141,9 +141,6 @@ func filterClabNodes(c *CLab, nodeFilter []string) error { log.Infof("Applying node filter: %q", nodeFilter) - // newNodes := make(map[string]*types.NodeDefinition, len(c.Config.Topology.Nodes)) - newLinks := make([]*types.LinkConfig, 0, len(c.Config.Topology.RawLinks)) - // filter nodes for name := range c.Config.Topology.Nodes { if exists := slices.Contains(nodeFilter, name); !exists { @@ -153,35 +150,15 @@ func filterClabNodes(c *CLab, nodeFilter []string) error { } // filter links - for _, l := range c.Config.Topology.Links { - // get the endpoints of the link and extract the node names - // to remove the links which have either side in the node filter - splitEpAside := strings.Split(l.Endpoints[0], ":") - if len(splitEpAside) != 2 { - continue - } - - epA := splitEpAside[0] - - splitEpBside := strings.Split(l.Endpoints[1], ":") - if len(splitEpBside) != 2 { - continue - } - - epB := splitEpBside[0] - - containsAside := slices.Contains(nodeFilter, epA) - containsBside := slices.Contains(nodeFilter, epB) - - // if both endpoints of a link belong to the node filter, keep the link - if containsAside && containsBside { - log.Debugf("Including link %+v", l) - newLinks = append(newLinks, l) + for id, l := range c.Links { + for _, nodeName := range []string{l.A.Node.ShortName, l.B.Node.ShortName} { + // if both endpoints of a link belong to the node filter, keep the link + if !slices.Contains(nodeFilter, nodeName) { + delete(c.Links, id) + break + } } } - // replace the original collection of links with the links that have both endpoints in the node filter - c.Config.Topology.Links = newLinks - return nil } diff --git a/clab/clab_test.go b/clab/clab_test.go index 324420122..2690ce839 100644 --- a/clab/clab_test.go +++ b/clab/clab_test.go @@ -260,6 +260,22 @@ func Test_filterClabNodes(t *testing.T) { }, "two nodes, one link between them, one filter node": { c: &CLab{ + Links: map[int]*types.Link{ + 0: { + A: &types.Endpoint{ + Node: &types.NodeConfig{ + ShortName: "node1", + }, + EndpointName: "eth1", + }, + B: &types.Endpoint{ + Node: &types.NodeConfig{ + ShortName: "node2", + }, + EndpointName: "eth2", + }, + }, + }, Config: &Config{ Topology: &types.Topology{ Nodes: map[string]*types.NodeDefinition{ @@ -270,14 +286,8 @@ func Test_filterClabNodes(t *testing.T) { Kind: "linux", }, }, - Links: []*types.LinkConfig{ - { - Endpoints: []string{"node1:eth1", "node2:eth2"}, - }, - }, }, - }, - }, + }}, nodesFilter: []string{"node1"}, wantNodes: []string{"node1"}, wantLinks: [][]string{}, @@ -285,6 +295,22 @@ func Test_filterClabNodes(t *testing.T) { }, "two nodes, one link between them, no filter": { c: &CLab{ + Links: map[int]*types.Link{ + 0: { + A: &types.Endpoint{ + Node: &types.NodeConfig{ + ShortName: "node1", + }, + EndpointName: "eth1", + }, + B: &types.Endpoint{ + Node: &types.NodeConfig{ + ShortName: "node2", + }, + EndpointName: "eth1", + }, + }, + }, Config: &Config{ Topology: &types.Topology{ Nodes: map[string]*types.NodeDefinition{ @@ -295,11 +321,6 @@ func Test_filterClabNodes(t *testing.T) { Kind: "linux", }, }, - Links: []*types.LinkConfig{ - { - Endpoints: []string{"node1:eth1", "node2:eth1"}, - }, - }, }, }, }, @@ -310,6 +331,36 @@ func Test_filterClabNodes(t *testing.T) { }, "three nodes, two links, two nodes in the filter": { c: &CLab{ + Links: map[int]*types.Link{ + 0: { + A: &types.Endpoint{ + Node: &types.NodeConfig{ + ShortName: "node1", + }, + EndpointName: "eth1", + }, + B: &types.Endpoint{ + Node: &types.NodeConfig{ + ShortName: "node2", + }, + EndpointName: "eth1", + }, + }, + 1: { + A: &types.Endpoint{ + Node: &types.NodeConfig{ + ShortName: "node2", + }, + EndpointName: "eth2", + }, + B: &types.Endpoint{ + Node: &types.NodeConfig{ + ShortName: "node3", + }, + EndpointName: "eth2", + }, + }, + }, Config: &Config{ Topology: &types.Topology{ Nodes: map[string]*types.NodeDefinition{ @@ -323,14 +374,6 @@ func Test_filterClabNodes(t *testing.T) { Kind: "linux", }, }, - Links: []*types.LinkConfig{ - { - Endpoints: []string{"node1:eth1", "node2:eth1"}, - }, - { - Endpoints: []string{"node2:eth2", "node3:eth2"}, - }, - }, }, }, }, @@ -341,6 +384,36 @@ func Test_filterClabNodes(t *testing.T) { }, "three nodes, two links, one nodes in the filter": { c: &CLab{ + Links: map[int]*types.Link{ + 0: { + A: &types.Endpoint{ + Node: &types.NodeConfig{ + ShortName: "node1", + }, + EndpointName: "eth1", + }, + B: &types.Endpoint{ + Node: &types.NodeConfig{ + ShortName: "node2", + }, + EndpointName: "eth1", + }, + }, + 1: { + A: &types.Endpoint{ + Node: &types.NodeConfig{ + ShortName: "node2", + }, + EndpointName: "eth2", + }, + B: &types.Endpoint{ + Node: &types.NodeConfig{ + ShortName: "node3", + }, + EndpointName: "eth2", + }, + }, + }, Config: &Config{ Topology: &types.Topology{ Nodes: map[string]*types.NodeDefinition{ @@ -354,14 +427,6 @@ func Test_filterClabNodes(t *testing.T) { Kind: "linux", }, }, - Links: []*types.LinkConfig{ - { - Endpoints: []string{"node1:eth1", "node2:eth1"}, - }, - { - Endpoints: []string{"node2:eth2", "node3:eth2"}, - }, - }, }, }, }, @@ -395,6 +460,7 @@ func Test_filterClabNodes(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { + err := filterClabNodes(tt.c, tt.nodesFilter) if (err != nil) != tt.wantErr { t.Log("hey", tt.c.Config.Topology.Nodes) @@ -413,9 +479,9 @@ func Test_filterClabNodes(t *testing.T) { // sort the nodes to make the test deterministic slices.Sort(filteredNodes) - filteredLinks := make([][]string, 0, len(tt.c.Config.Topology.Links)) - for _, l := range tt.c.Config.Topology.Links { - filteredLinks = append(filteredLinks, l.Endpoints) + filteredLinks := make([][]string, 0, len(tt.c.Links)) + for _, l := range tt.c.Links { + filteredLinks = append(filteredLinks, []string{l.A.String(), l.B.String()}) } if cmp.Diff(filteredNodes, tt.wantNodes) != "" { diff --git a/clab/config.go b/clab/config.go index 9e4caf71a..d77932ab7 100644 --- a/clab/config.go +++ b/clab/config.go @@ -124,7 +124,7 @@ func (c *CLab) parseTopology() error { return err } } - for i, l := range c.Config.Topology.RawLinks { + for i, l := range c.Config.Topology.LinkDefinition { // i represents the endpoint integer and l provide the link struct c.Links[i] = c.NewLink(l.Instance) } @@ -435,15 +435,13 @@ func (c *CLab) verifyLinks() error { endpoints := map[string]struct{}{} // dups accumulates duplicate links dups := []string{} - for _, lc := range c.Config.Topology.Links { - for _, e := range lc.Endpoints { - if err := checkEndpoint(e); err != nil { - return err - } - if _, ok := endpoints[e]; ok { - dups = append(dups, e) + for _, lc := range c.Links { + for _, e := range []*types.Endpoint{lc.A, lc.B} { + e_string := e.String() + if _, ok := endpoints[e_string]; ok { + dups = append(dups, e_string) } - endpoints[e] = struct{}{} + endpoints[e_string] = struct{}{} } } if len(dups) != 0 { diff --git a/clab/file.go b/clab/file.go index d6216caa3..68ae95ab3 100644 --- a/clab/file.go +++ b/clab/file.go @@ -80,12 +80,6 @@ func (c *CLab) GetTopology(topo, varsFile string) error { return fmt.Errorf("%w\nConsult with release notes to see if any fields were changed/removed", err) } - // move RawLink Instance to Link - c.Config.Topology.Links = make([]*types.LinkConfig, len(c.Config.Topology.RawLinks)) - for idx, l := range c.Config.Topology.RawLinks { - c.Config.Topology.Links[idx] = l.Instance - } - c.Config.Topology.ImportEnvs() return nil diff --git a/cmd/generate.go b/cmd/generate.go index f90d57ce1..911d41265 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -214,12 +214,16 @@ func generateTopologyConfig(name, network, ipv4range, ipv6range string, Type: nodes[i+1].typ, } } - config.Topology.Links = append(config.Topology.Links, &types.LinkConfig{ - Endpoints: []string{ - node1 + ":" + fmt.Sprintf(interfaceFormat[nodes[i].kind], k+1+interfaceOffset), - node2 + ":" + fmt.Sprintf(interfaceFormat[nodes[i+1].kind], j+1), - }, - }) + config.Topology.LinkDefinition = append(config.Topology.LinkDefinition, + &types.LinkDefinition{ + Type: string(types.LinkTypeVEth), + Instance: &types.LinkConfig{ + Endpoints: []string{ + node1 + ":" + fmt.Sprintf(interfaceFormat[nodes[i].kind], k+1+interfaceOffset), + node2 + ":" + fmt.Sprintf(interfaceFormat[nodes[i+1].kind], j+1), + }, + }, + }) } } } diff --git a/types/link.go b/types/link.go index 34b956b9a..adb4688bc 100644 --- a/types/link.go +++ b/types/link.go @@ -14,7 +14,7 @@ type LinkCommonParams struct { Vars map[string]interface{} `yaml:"vars,omitempty"` } -type RawLinkType struct { +type LinkDefinition struct { Type string `yaml:"type"` // Instance interface{} Instance *LinkConfig @@ -32,7 +32,7 @@ const ( LinkTypeDeprecate LinkDefinitionType = "deprecate" ) -type RawLinkTypeAlias RawLinkType +type LinkDefinitionAlias LinkDefinition func ParseLinkType(s string) (LinkDefinitionType, error) { switch strings.TrimSpace(strings.ToLower(s)) { @@ -53,14 +53,14 @@ func ParseLinkType(s string) (LinkDefinitionType, error) { } } -func (rlt *RawLinkTypeAlias) GetType() (LinkDefinitionType, error) { +func (rlt *LinkDefinitionAlias) GetType() (LinkDefinitionType, error) { return ParseLinkType(rlt.Type) } -var _ yaml.Unmarshaler = &RawLinkType{} +var _ yaml.Unmarshaler = &LinkDefinition{} -func (r *RawLinkType) UnmarshalYAML(unmarshal func(interface{}) error) error { - var rtAlias RawLinkTypeAlias +func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error { + var rtAlias LinkDefinitionAlias err := unmarshal(&rtAlias) // Strict unmarshalling, as we do with containerlab will cause the diff --git a/types/link_test.go b/types/link_test.go index a752bddb3..dba4e86de 100644 --- a/types/link_test.go +++ b/types/link_test.go @@ -94,7 +94,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { tests := []struct { name string args args - want RawLinkType + want LinkDefinition wantErr bool }{ { @@ -107,7 +107,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { `), }, wantErr: false, - want: RawLinkType{ + want: LinkDefinition{ Type: string(LinkTypeDeprecate), Instance: &LinkConfig{ Endpoints: []string{ @@ -129,7 +129,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { `), }, wantErr: false, - want: RawLinkType{ + want: LinkDefinition{ Type: string(LinkTypeMgmtNet), Instance: &LinkConfig{ Endpoints: []string{ @@ -151,7 +151,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { `), }, wantErr: false, - want: RawLinkType{ + want: LinkDefinition{ Type: string(LinkTypeHost), Instance: &LinkConfig{ Endpoints: []string{ @@ -173,7 +173,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { `), }, wantErr: false, - want: RawLinkType{ + want: LinkDefinition{ Type: string(LinkTypeMacVLan), Instance: &LinkConfig{ Endpoints: []string{ @@ -195,7 +195,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { `), }, wantErr: false, - want: RawLinkType{ + want: LinkDefinition{ Type: string(LinkTypeMacVTap), Instance: &LinkConfig{ Endpoints: []string{ @@ -231,7 +231,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var rl RawLinkType + var rl LinkDefinition err := yaml.Unmarshal(tt.args.yaml, &rl) if (err != nil) != tt.wantErr { t.Errorf("RawLinkType Unmarshal() error = %v, wantErr %v", err, tt.wantErr) diff --git a/types/topology.go b/types/topology.go index efccffb42..4f7efe3e3 100644 --- a/types/topology.go +++ b/types/topology.go @@ -7,20 +7,20 @@ import ( // Topology represents a lab topology. type Topology struct { - Defaults *NodeDefinition `yaml:"defaults,omitempty"` - Kinds map[string]*NodeDefinition `yaml:"kinds,omitempty"` - Nodes map[string]*NodeDefinition `yaml:"nodes,omitempty"` - RawLinks []*RawLinkType `yaml:"links,omitempty"` - Links []*LinkConfig `yaml:"-"` + Defaults *NodeDefinition `yaml:"defaults,omitempty"` + Kinds map[string]*NodeDefinition `yaml:"kinds,omitempty"` + Nodes map[string]*NodeDefinition `yaml:"nodes,omitempty"` + LinkDefinition []*LinkDefinition `yaml:"links,omitempty"` + //LinkConfigs []*LinkConfig `yaml:"-"` } func NewTopology() *Topology { return &Topology{ - Defaults: new(NodeDefinition), - Kinds: make(map[string]*NodeDefinition), - Nodes: make(map[string]*NodeDefinition), - RawLinks: make([]*RawLinkType, 0), - Links: make([]*LinkConfig, 0), + Defaults: new(NodeDefinition), + Kinds: make(map[string]*NodeDefinition), + Nodes: make(map[string]*NodeDefinition), + LinkDefinition: make([]*LinkDefinition, 0), + //LinkConfigs: make([]*LinkConfig, 0), } } diff --git a/types/types.go b/types/types.go index 9793d13dc..b7d1e66b8 100644 --- a/types/types.go +++ b/types/types.go @@ -38,6 +38,10 @@ type Endpoint struct { MAC string } +func (e *Endpoint) String() string { + return fmt.Sprintf("%s:%s", e.Node.ShortName, e.EndpointName) +} + // MgmtNet struct defines the management network options. type MgmtNet struct { Network string `yaml:"network,omitempty" json:"network,omitempty"` // container runtime network name From edda5f5e16b3badbce1faf93336eed44057dfb15 Mon Sep 17 00:00:00 2001 From: steiler Date: Mon, 3 Jul 2023 14:54:04 +0200 Subject: [PATCH 05/22] update --- types/topology.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/types/topology.go b/types/topology.go index 4f7efe3e3..84b24ce61 100644 --- a/types/topology.go +++ b/types/topology.go @@ -11,7 +11,6 @@ type Topology struct { Kinds map[string]*NodeDefinition `yaml:"kinds,omitempty"` Nodes map[string]*NodeDefinition `yaml:"nodes,omitempty"` LinkDefinition []*LinkDefinition `yaml:"links,omitempty"` - //LinkConfigs []*LinkConfig `yaml:"-"` } func NewTopology() *Topology { @@ -20,7 +19,6 @@ func NewTopology() *Topology { Kinds: make(map[string]*NodeDefinition), Nodes: make(map[string]*NodeDefinition), LinkDefinition: make([]*LinkDefinition, 0), - //LinkConfigs: make([]*LinkConfig, 0), } } From 1845aa8cc2b5b727d054fe3087c496c2ef20b1ed Mon Sep 17 00:00:00 2001 From: steiler Date: Mon, 3 Jul 2023 20:06:38 +0200 Subject: [PATCH 06/22] remove checkendpoint --- clab/config.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/clab/config.go b/clab/config.go index d77932ab7..b1599f7ff 100644 --- a/clab/config.go +++ b/clab/config.go @@ -590,15 +590,6 @@ func (c *CLab) verifyRootNetnsInterfaceUniqueness() error { return nil } -// checkEndpoint runs checks on the endpoint syntax. -func checkEndpoint(e string) error { - split := strings.Split(e, ":") - if len(split) != 2 { - return fmt.Errorf("malformed endpoint definition: %s", e) - } - return nil -} - // resolveBindPaths resolves the host paths in a bind string, such as /hostpath:/remotepath(:options) string // it allows host path to have `~` and relative path to an absolute path // the list of binds will be changed in place. From 7eac9c5a8561929000cf3ca33fca50fcd829f203 Mon Sep 17 00:00:00 2001 From: steiler Date: Tue, 4 Jul 2023 09:16:45 +0200 Subject: [PATCH 07/22] custom marshaller for LinkDefnition --- types/link.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/types/link.go b/types/link.go index adb4688bc..7529f1831 100644 --- a/types/link.go +++ b/types/link.go @@ -59,6 +59,10 @@ func (rlt *LinkDefinitionAlias) GetType() (LinkDefinitionType, error) { var _ yaml.Unmarshaler = &LinkDefinition{} +func (r *LinkDefinition) MarshalYAML() (interface{}, error) { + return r.Instance, nil +} + func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error { var rtAlias LinkDefinitionAlias From 289340c616fa4630ec4c07a1749a1d45401de82f Mon Sep 17 00:00:00 2001 From: steiler Date: Tue, 4 Jul 2023 10:38:41 +0200 Subject: [PATCH 08/22] fix generate command --- clab/config.go | 2 +- cmd/generate.go | 2 +- types/link.go | 69 ++++++++++++++++++++++++++++++-------------- types/link_common.go | 26 +++++++++-------- types/link_test.go | 10 +++---- types/link_veth.go | 54 +++++++++++++++++++--------------- 6 files changed, 100 insertions(+), 63 deletions(-) diff --git a/clab/config.go b/clab/config.go index b1599f7ff..abc7b92ac 100644 --- a/clab/config.go +++ b/clab/config.go @@ -126,7 +126,7 @@ func (c *CLab) parseTopology() error { } for i, l := range c.Config.Topology.LinkDefinition { // i represents the endpoint integer and l provide the link struct - c.Links[i] = c.NewLink(l.Instance) + c.Links[i] = c.NewLink(&l.LinkConfig) } // set any containerlab defaults after we've parsed the input diff --git a/cmd/generate.go b/cmd/generate.go index 911d41265..7f44f6477 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -217,7 +217,7 @@ func generateTopologyConfig(name, network, ipv4range, ipv6range string, config.Topology.LinkDefinition = append(config.Topology.LinkDefinition, &types.LinkDefinition{ Type: string(types.LinkTypeVEth), - Instance: &types.LinkConfig{ + LinkConfig: types.LinkConfig{ Endpoints: []string{ node1 + ":" + fmt.Sprintf(interfaceFormat[nodes[i].kind], k+1+interfaceOffset), node2 + ":" + fmt.Sprintf(interfaceFormat[nodes[i+1].kind], j+1), diff --git a/types/link.go b/types/link.go index 7529f1831..6953cac51 100644 --- a/types/link.go +++ b/types/link.go @@ -17,7 +17,7 @@ type LinkCommonParams struct { type LinkDefinition struct { Type string `yaml:"type"` // Instance interface{} - Instance *LinkConfig + LinkConfig } type LinkDefinitionType string @@ -29,6 +29,7 @@ const ( LinkTypeMacVTap LinkDefinitionType = "macvtap" LinkTypeHost LinkDefinitionType = "host" + // legacy link definifion LinkTypeDeprecate LinkDefinitionType = "deprecate" ) @@ -59,8 +60,26 @@ func (rlt *LinkDefinitionAlias) GetType() (LinkDefinitionType, error) { var _ yaml.Unmarshaler = &LinkDefinition{} +// MarshalYAML used when writing topology files via the generate command. +// for now this falls back to convertig the LinkConfig into a +// RawVEthLink. Such that the generated LinkConfigs adhere to the new LinkDefinition +// format instead of the depricated one. func (r *LinkDefinition) MarshalYAML() (interface{}, error) { - return r.Instance, nil + + rawVEth, err := vEthFromLinkConfig(&r.LinkConfig) + if err != nil { + return nil, err + } + + x := struct { + RawVEthLink `yaml:",inline"` + Type string `yaml:"type"` + }{ + RawVEthLink: *rawVEth, + Type: string(LinkTypeVEth), + } + + return x, nil } func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error { @@ -78,54 +97,62 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error r.Type = rtAlias.Type - switch strings.ToLower(rtAlias.Type) { - case "veth": + lt, err := ParseLinkType(rtAlias.Type) + if err != nil { + return err + } + + switch lt { + case LinkTypeVEth: var l RawVEthLink err := unmarshal(&l) - if err != nil { + if err != nil && !errors.As(err, &e) { return err } - r.Instance = l.ToLinkConfig() - case "mgmt-net": + r.LinkConfig = *l.ToLinkConfig() + case LinkTypeMgmtNet: var l RawMgmtNetLink err := unmarshal(&l) - if err != nil { + if err != nil && !errors.As(err, &e) { return err } - r.Instance = l.ToLinkConfig() - case "host": + r.LinkConfig = *l.ToLinkConfig() + case LinkTypeHost: var l RawHostLink err := unmarshal(&l) - if err != nil { + if err != nil && !errors.As(err, &e) { return err } - r.Instance = l.ToLinkConfig() - case "macvlan": + r.LinkConfig = *l.ToLinkConfig() + case LinkTypeMacVLan: var l RawMacVLanLink err := unmarshal(&l) - if err != nil { + if err != nil && !errors.As(err, &e) { return err } - r.Instance = l.ToLinkConfig() - case "macvtap": + r.LinkConfig = *l.ToLinkConfig() + case LinkTypeMacVTap: var l RawMacVTapLink err := unmarshal(&l) - if err != nil { + if err != nil && !errors.As(err, &e) { return err } - r.Instance = l.ToLinkConfig() - default: + r.LinkConfig = *l.ToLinkConfig() + case LinkTypeDeprecate: // try to parse the depricate format var l LinkConfig err := unmarshal(&l) - if err != nil { + if err != nil && !errors.As(err, &e) { return err } r.Type = string(LinkTypeDeprecate) - r.Instance, err = deprecateLinkConversion(&l) + lc, err := deprecateLinkConversion(&l) + r.LinkConfig = *lc if err != nil { return err } + default: + return fmt.Errorf("unknown link type %q", lt) } return nil diff --git a/types/link_common.go b/types/link_common.go index c81413fbe..1ac73e618 100644 --- a/types/link_common.go +++ b/types/link_common.go @@ -1,22 +1,24 @@ package types +import "strings" + type EndpointRaw struct { Node string `yaml:"node"` Iface string `yaml:"interface"` - Mac string `yaml:"mac"` + Mac string `yaml:"mac,omitempty"` } -// func extractHostNodeInterfaceData(lc *LinkConfig, specialEPIndex int) (host string, hostIf string, node string, nodeIf string) { -// // the index of the node is the specialEndpointIndex +1 modulo 2 -// nodeindex := (specialEPIndex + 1) % 2 +func extractHostNodeInterfaceData(lc *LinkConfig, specialEPIndex int) (host string, hostIf string, node string, nodeIf string) { + // the index of the node is the specialEndpointIndex +1 modulo 2 + nodeindex := (specialEPIndex + 1) % 2 -// hostData := strings.SplitN(lc.Endpoints[specialEPIndex], ":", 2) -// nodeData := strings.SplitN(lc.Endpoints[nodeindex], ":", 2) + hostData := strings.SplitN(lc.Endpoints[specialEPIndex], ":", 2) + nodeData := strings.SplitN(lc.Endpoints[nodeindex], ":", 2) -// host = hostData[0] -// hostIf = hostData[1] -// node = nodeData[0] -// nodeIf = nodeData[1] + host = hostData[0] + hostIf = hostData[1] + node = nodeData[0] + nodeIf = nodeData[1] -// return host, hostIf, node, nodeIf -// } + return host, hostIf, node, nodeIf +} diff --git a/types/link_test.go b/types/link_test.go index dba4e86de..c45ec09e1 100644 --- a/types/link_test.go +++ b/types/link_test.go @@ -109,7 +109,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { wantErr: false, want: LinkDefinition{ Type: string(LinkTypeDeprecate), - Instance: &LinkConfig{ + LinkConfig: LinkConfig{ Endpoints: []string{ "srl1:e1-5", "srl2:e1-5", @@ -131,7 +131,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { wantErr: false, want: LinkDefinition{ Type: string(LinkTypeMgmtNet), - Instance: &LinkConfig{ + LinkConfig: LinkConfig{ Endpoints: []string{ "srl1:e1-5", "mgmt-net:srl1_e1-5", @@ -153,7 +153,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { wantErr: false, want: LinkDefinition{ Type: string(LinkTypeHost), - Instance: &LinkConfig{ + LinkConfig: LinkConfig{ Endpoints: []string{ "srl1:e1-5", "host:srl1_e1-5", @@ -175,7 +175,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { wantErr: false, want: LinkDefinition{ Type: string(LinkTypeMacVLan), - Instance: &LinkConfig{ + LinkConfig: LinkConfig{ Endpoints: []string{ "srl1:e1-5", "macvlan:srl1_e1-5", @@ -197,7 +197,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { wantErr: false, want: LinkDefinition{ Type: string(LinkTypeMacVTap), - Instance: &LinkConfig{ + LinkConfig: LinkConfig{ Endpoints: []string{ "srl1:e1-5", "macvtap:srl1_e1-5", diff --git a/types/link_veth.go b/types/link_veth.go index 8a136f441..37aac4de1 100644 --- a/types/link_veth.go +++ b/types/link_veth.go @@ -7,6 +7,17 @@ type RawVEthLink struct { Endpoints []*EndpointRaw `yaml:"endpoints"` } +func (r *RawVEthLink) MarshalYAML() (interface{}, error) { + x := struct { + Type string `yaml:"type"` + RawVEthLink `yaml:",inline"` + }{ + Type: string(LinkTypeVEth), + RawVEthLink: *r, + } + return x, nil +} + func (r *RawVEthLink) ToLinkConfig() *LinkConfig { lc := &LinkConfig{ Vars: r.Vars, @@ -20,27 +31,24 @@ func (r *RawVEthLink) ToLinkConfig() *LinkConfig { return lc } -// func vEthFromLinkConfig(lc *LinkConfig) (*RawVEthLink, error) { -// nodeA, nodeAIf, nodeB, nodeBIf := extractHostNodeInterfaceData(lc, 0) +func vEthFromLinkConfig(lc *LinkConfig) (*RawVEthLink, error) { + nodeA, nodeAIf, nodeB, nodeBIf := extractHostNodeInterfaceData(lc, 0) -// result := &RawVEthLink{ -// RawLinkType: RawLinkType{ -// Type: string(LinkTypeVEth), -// Labels: lc.Labels, -// Vars: lc.Vars, -// Instance: nil, -// }, -// Mtu: lc.MTU, -// Endpoints: []*EndpointRaw{ -// { -// Node: nodeA, -// Iface: nodeAIf, -// }, -// { -// Node: nodeB, -// Iface: nodeBIf, -// }, -// }, -// } -// return result, nil -// } + result := &RawVEthLink{ + LinkCommonParams: LinkCommonParams{ + Labels: lc.Labels, + Vars: lc.Vars, + }, + Endpoints: []*EndpointRaw{ + { + Node: nodeA, + Iface: nodeAIf, + }, + { + Node: nodeB, + Iface: nodeBIf, + }, + }, + } + return result, nil +} From 1c531c577b65628ff7de2b8eaf37916ad45a21c2 Mon Sep 17 00:00:00 2001 From: steiler Date: Tue, 4 Jul 2023 11:56:10 +0200 Subject: [PATCH 09/22] fix --- types/link.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/types/link.go b/types/link.go index 6953cac51..0a83ab523 100644 --- a/types/link.go +++ b/types/link.go @@ -95,11 +95,18 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error return err } - r.Type = rtAlias.Type + var lt LinkDefinitionType - lt, err := ParseLinkType(rtAlias.Type) - if err != nil { - return err + if rtAlias.Type == "" { + lt = LinkTypeDeprecate + r.Type = string(LinkTypeDeprecate) + } else { + r.Type = rtAlias.Type + + lt, err = ParseLinkType(rtAlias.Type) + if err != nil { + return err + } } switch lt { @@ -142,15 +149,15 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error // try to parse the depricate format var l LinkConfig err := unmarshal(&l) - if err != nil && !errors.As(err, &e) { + if err != nil { return err } r.Type = string(LinkTypeDeprecate) lc, err := deprecateLinkConversion(&l) - r.LinkConfig = *lc if err != nil { return err } + r.LinkConfig = *lc default: return fmt.Errorf("unknown link type %q", lt) } From 3b516d951f95e4dfa890abad3452fdb0f06e3b98 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Fri, 7 Jul 2023 10:54:48 +0300 Subject: [PATCH 10/22] applied format --- clab/clab_test.go | 4 ++-- types/link.go | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/clab/clab_test.go b/clab/clab_test.go index 2690ce839..eb3c4ea70 100644 --- a/clab/clab_test.go +++ b/clab/clab_test.go @@ -287,7 +287,8 @@ func Test_filterClabNodes(t *testing.T) { }, }, }, - }}, + }, + }, nodesFilter: []string{"node1"}, wantNodes: []string{"node1"}, wantLinks: [][]string{}, @@ -460,7 +461,6 @@ func Test_filterClabNodes(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { - err := filterClabNodes(tt.c, tt.nodesFilter) if (err != nil) != tt.wantErr { t.Log("hey", tt.c.Config.Topology.Nodes) diff --git a/types/link.go b/types/link.go index 0a83ab523..3cb5136bc 100644 --- a/types/link.go +++ b/types/link.go @@ -29,7 +29,7 @@ const ( LinkTypeMacVTap LinkDefinitionType = "macvtap" LinkTypeHost LinkDefinitionType = "host" - // legacy link definifion + // legacy link definifion. LinkTypeDeprecate LinkDefinitionType = "deprecate" ) @@ -65,7 +65,6 @@ var _ yaml.Unmarshaler = &LinkDefinition{} // RawVEthLink. Such that the generated LinkConfigs adhere to the new LinkDefinition // format instead of the depricated one. func (r *LinkDefinition) MarshalYAML() (interface{}, error) { - rawVEth, err := vEthFromLinkConfig(&r.LinkConfig) if err != nil { return nil, err From a82434248de95142e3a9e4a1d62c5a0d8bd15379 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Sat, 8 Jul 2023 00:02:58 +0300 Subject: [PATCH 11/22] rename struct field to Links --- clab/config.go | 2 +- cmd/generate.go | 2 +- types/topology.go | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/clab/config.go b/clab/config.go index abc7b92ac..ed953d6b8 100644 --- a/clab/config.go +++ b/clab/config.go @@ -124,7 +124,7 @@ func (c *CLab) parseTopology() error { return err } } - for i, l := range c.Config.Topology.LinkDefinition { + for i, l := range c.Config.Topology.Links { // i represents the endpoint integer and l provide the link struct c.Links[i] = c.NewLink(&l.LinkConfig) } diff --git a/cmd/generate.go b/cmd/generate.go index 7f44f6477..8842c159a 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -214,7 +214,7 @@ func generateTopologyConfig(name, network, ipv4range, ipv6range string, Type: nodes[i+1].typ, } } - config.Topology.LinkDefinition = append(config.Topology.LinkDefinition, + config.Topology.Links = append(config.Topology.Links, &types.LinkDefinition{ Type: string(types.LinkTypeVEth), LinkConfig: types.LinkConfig{ diff --git a/types/topology.go b/types/topology.go index 84b24ce61..059f3b80f 100644 --- a/types/topology.go +++ b/types/topology.go @@ -7,18 +7,18 @@ import ( // Topology represents a lab topology. type Topology struct { - Defaults *NodeDefinition `yaml:"defaults,omitempty"` - Kinds map[string]*NodeDefinition `yaml:"kinds,omitempty"` - Nodes map[string]*NodeDefinition `yaml:"nodes,omitempty"` - LinkDefinition []*LinkDefinition `yaml:"links,omitempty"` + Defaults *NodeDefinition `yaml:"defaults,omitempty"` + Kinds map[string]*NodeDefinition `yaml:"kinds,omitempty"` + Nodes map[string]*NodeDefinition `yaml:"nodes,omitempty"` + Links []*LinkDefinition `yaml:"links,omitempty"` } func NewTopology() *Topology { return &Topology{ - Defaults: new(NodeDefinition), - Kinds: make(map[string]*NodeDefinition), - Nodes: make(map[string]*NodeDefinition), - LinkDefinition: make([]*LinkDefinition, 0), + Defaults: new(NodeDefinition), + Kinds: make(map[string]*NodeDefinition), + Nodes: make(map[string]*NodeDefinition), + Links: make([]*LinkDefinition, 0), } } From 2c8d65b96a61365ed18c58a7729fd503db2acc32 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Mon, 10 Jul 2023 19:00:10 +0300 Subject: [PATCH 12/22] use Legacy link type name instead of deprecated --- types/link.go | 19 +++++++++++-------- types/link_test.go | 6 +++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/types/link.go b/types/link.go index 3cb5136bc..6c4e65d2b 100644 --- a/types/link.go +++ b/types/link.go @@ -14,12 +14,14 @@ type LinkCommonParams struct { Vars map[string]interface{} `yaml:"vars,omitempty"` } +// LinkDefinition represents a link definition in the topology file. type LinkDefinition struct { Type string `yaml:"type"` // Instance interface{} LinkConfig } +// LinkDefinitionType represents the type of a link definition. type LinkDefinitionType string const ( @@ -29,8 +31,9 @@ const ( LinkTypeMacVTap LinkDefinitionType = "macvtap" LinkTypeHost LinkDefinitionType = "host" - // legacy link definifion. - LinkTypeDeprecate LinkDefinitionType = "deprecate" + // LinkTypeLegacy is a link definition where link types + // are encoded in the endpoint definition as string. + LinkTypeLegacy LinkDefinitionType = "legacy" ) type LinkDefinitionAlias LinkDefinition @@ -47,8 +50,8 @@ func ParseLinkType(s string) (LinkDefinitionType, error) { return LinkTypeMgmtNet, nil case string(LinkTypeHost): return LinkTypeHost, nil - case string(LinkTypeDeprecate): - return LinkTypeDeprecate, nil + case string(LinkTypeLegacy): + return LinkTypeLegacy, nil default: return "", fmt.Errorf("unable to parse %q as LinkType", s) } @@ -97,8 +100,8 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error var lt LinkDefinitionType if rtAlias.Type == "" { - lt = LinkTypeDeprecate - r.Type = string(LinkTypeDeprecate) + lt = LinkTypeLegacy + r.Type = string(LinkTypeLegacy) } else { r.Type = rtAlias.Type @@ -144,14 +147,14 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error return err } r.LinkConfig = *l.ToLinkConfig() - case LinkTypeDeprecate: + case LinkTypeLegacy: // try to parse the depricate format var l LinkConfig err := unmarshal(&l) if err != nil { return err } - r.Type = string(LinkTypeDeprecate) + r.Type = string(LinkTypeLegacy) lc, err := deprecateLinkConversion(&l) if err != nil { return err diff --git a/types/link_test.go b/types/link_test.go index c45ec09e1..d4d4f4ae4 100644 --- a/types/link_test.go +++ b/types/link_test.go @@ -60,9 +60,9 @@ func TestParseLinkType(t *testing.T) { { name: "link type deprecate", args: args{ - s: string(LinkTypeDeprecate), + s: string(LinkTypeLegacy), }, - want: LinkTypeDeprecate, + want: LinkTypeLegacy, wantErr: false, }, { @@ -108,7 +108,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { }, wantErr: false, want: LinkDefinition{ - Type: string(LinkTypeDeprecate), + Type: string(LinkTypeLegacy), LinkConfig: LinkConfig{ Endpoints: []string{ "srl1:e1-5", From e26c355edfe226a576e557f685fd7c7eed15d894 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Mon, 10 Jul 2023 21:09:04 +0300 Subject: [PATCH 13/22] use temp struct with inline yaml to avoid using alias and hiding errors --- types/link.go | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/types/link.go b/types/link.go index 6c4e65d2b..15489c6e8 100644 --- a/types/link.go +++ b/types/link.go @@ -1,7 +1,6 @@ package types import ( - "errors" "fmt" "strings" @@ -36,8 +35,6 @@ const ( LinkTypeLegacy LinkDefinitionType = "legacy" ) -type LinkDefinitionAlias LinkDefinition - func ParseLinkType(s string) (LinkDefinitionType, error) { switch strings.TrimSpace(strings.ToLower(s)) { case string(LinkTypeMacVLan): @@ -57,10 +54,6 @@ func ParseLinkType(s string) (LinkDefinitionType, error) { } } -func (rlt *LinkDefinitionAlias) GetType() (LinkDefinitionType, error) { - return ParseLinkType(rlt.Type) -} - var _ yaml.Unmarshaler = &LinkDefinition{} // MarshalYAML used when writing topology files via the generate command. @@ -85,27 +78,27 @@ func (r *LinkDefinition) MarshalYAML() (interface{}, error) { } func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error { - var rtAlias LinkDefinitionAlias - - err := unmarshal(&rtAlias) - // Strict unmarshalling, as we do with containerlab will cause the - // Links sections to fail. The unmarshal call will throw a yaml.TypeError - // This section we don't want strict, so if error is not nil but the error type is - // yaml.TypeError, we will continue - var e *yaml.TypeError - if err != nil && !errors.As(err, &e) { + // alias struct to avoid recursion and pass strict yaml unmarshalling + // we don't care about the embedded LinkConfig, as we only need to unmarshal + // the type field. + var a struct { + Type string `yaml:"type"` + LinkConfig `yaml:",inline"` + } + err := unmarshal(&a) + if err != nil { return err } var lt LinkDefinitionType - if rtAlias.Type == "" { + if a.Type == "" { lt = LinkTypeLegacy r.Type = string(LinkTypeLegacy) } else { - r.Type = rtAlias.Type + r.Type = a.Type - lt, err = ParseLinkType(rtAlias.Type) + lt, err = ParseLinkType(a.Type) if err != nil { return err } @@ -115,35 +108,35 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error case LinkTypeVEth: var l RawVEthLink err := unmarshal(&l) - if err != nil && !errors.As(err, &e) { + if err != nil { return err } r.LinkConfig = *l.ToLinkConfig() case LinkTypeMgmtNet: var l RawMgmtNetLink err := unmarshal(&l) - if err != nil && !errors.As(err, &e) { + if err != nil { return err } r.LinkConfig = *l.ToLinkConfig() case LinkTypeHost: var l RawHostLink err := unmarshal(&l) - if err != nil && !errors.As(err, &e) { + if err != nil { return err } r.LinkConfig = *l.ToLinkConfig() case LinkTypeMacVLan: var l RawMacVLanLink err := unmarshal(&l) - if err != nil && !errors.As(err, &e) { + if err != nil { return err } r.LinkConfig = *l.ToLinkConfig() case LinkTypeMacVTap: var l RawMacVTapLink err := unmarshal(&l) - if err != nil && !errors.As(err, &e) { + if err != nil { return err } r.LinkConfig = *l.ToLinkConfig() From c29dae1b8e5414129b008f616bc69477ba8ec0f5 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Mon, 10 Jul 2023 22:30:52 +0300 Subject: [PATCH 14/22] add type field to link structs to comply with yaml strict checking --- types/link.go | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/types/link.go b/types/link.go index 15489c6e8..9afb34b61 100644 --- a/types/link.go +++ b/types/link.go @@ -82,8 +82,9 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error // we don't care about the embedded LinkConfig, as we only need to unmarshal // the type field. var a struct { - Type string `yaml:"type"` - LinkConfig `yaml:",inline"` + Type string `yaml:"type"` + // Throwaway endpoints field, as we don't care about it. + Endpoints any `yaml:"endpoints"` } err := unmarshal(&a) if err != nil { @@ -106,49 +107,69 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error switch lt { case LinkTypeVEth: - var l RawVEthLink + var l struct { + // the Type field is injected artificially + // to allow strict yaml parsing to work. + Type string `yaml:"type"` + RawVEthLink `yaml:",inline"` + } err := unmarshal(&l) if err != nil { return err } - r.LinkConfig = *l.ToLinkConfig() + r.LinkConfig = *l.RawVEthLink.ToLinkConfig() case LinkTypeMgmtNet: - var l RawMgmtNetLink + var l struct { + Type string `yaml:"type"` + RawMgmtNetLink `yaml:",inline"` + } err := unmarshal(&l) if err != nil { return err } - r.LinkConfig = *l.ToLinkConfig() + r.LinkConfig = *l.RawMgmtNetLink.ToLinkConfig() case LinkTypeHost: - var l RawHostLink + var l struct { + Type string `yaml:"type"` + RawHostLink `yaml:",inline"` + } err := unmarshal(&l) if err != nil { return err } - r.LinkConfig = *l.ToLinkConfig() + r.LinkConfig = *l.RawHostLink.ToLinkConfig() case LinkTypeMacVLan: - var l RawMacVLanLink + var l struct { + Type string `yaml:"type"` + RawMacVLanLink `yaml:",inline"` + } err := unmarshal(&l) if err != nil { return err } - r.LinkConfig = *l.ToLinkConfig() + r.LinkConfig = *l.RawMacVLanLink.ToLinkConfig() case LinkTypeMacVTap: - var l RawMacVTapLink + var l struct { + Type string `yaml:"type"` + RawMacVTapLink `yaml:",inline"` + } err := unmarshal(&l) if err != nil { return err } - r.LinkConfig = *l.ToLinkConfig() + r.LinkConfig = *l.RawMacVTapLink.ToLinkConfig() case LinkTypeLegacy: // try to parse the depricate format - var l LinkConfig + var l struct { + Type string `yaml:"type"` + LinkConfig `yaml:",inline"` + } err := unmarshal(&l) if err != nil { return err } r.Type = string(LinkTypeLegacy) - lc, err := deprecateLinkConversion(&l) + lc, err := deprecateLinkConversion(&l.LinkConfig) if err != nil { return err } From 256e4e19c312cf9553de431c450c628bd228ae03 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Sun, 16 Jul 2023 08:40:51 +0300 Subject: [PATCH 15/22] use linkDefinition when creating a new link --- clab/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clab/config.go b/clab/config.go index ed953d6b8..e44a0938b 100644 --- a/clab/config.go +++ b/clab/config.go @@ -126,7 +126,7 @@ func (c *CLab) parseTopology() error { } for i, l := range c.Config.Topology.Links { // i represents the endpoint integer and l provide the link struct - c.Links[i] = c.NewLink(&l.LinkConfig) + c.Links[i] = c.NewLink(l) } // set any containerlab defaults after we've parsed the input @@ -326,8 +326,8 @@ func (c *CLab) processStartupConfig(nodeCfg *types.NodeConfig) error { return nil } -// NewLink initializes a new link object. -func (c *CLab) NewLink(l *types.LinkConfig) *types.Link { +// NewLink initializes a new link object from the link definition provided via topology file. +func (c *CLab) NewLink(l *types.LinkDefinition) *types.Link { if len(l.Endpoints) != 2 { log.Fatalf("endpoint %q has wrong syntax, unexpected number of items", l.Endpoints) // skipcq: RVV-A0003 } From 4694d376a339d6796c7a3c344d38c6aef3ed72ce Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Sun, 16 Jul 2023 09:20:59 +0300 Subject: [PATCH 16/22] added comments to verifyLinks --- clab/config.go | 7 +++++-- types/types.go | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/clab/config.go b/clab/config.go index e44a0938b..f88e82738 100644 --- a/clab/config.go +++ b/clab/config.go @@ -404,6 +404,7 @@ func (c *CLab) NewEndpoint(e string) *types.Endpoint { } // CheckTopologyDefinition runs topology checks and returns any errors found. +// This function runs after topology file is parsed and all nodes/links are initialized. func (c *CLab) CheckTopologyDefinition(ctx context.Context) error { var err error @@ -431,12 +432,14 @@ func (c *CLab) CheckTopologyDefinition(ctx context.Context) error { return nil } +// verifyLinks checks if all the endpoints in the links section of the topology file +// appear only once. func (c *CLab) verifyLinks() error { endpoints := map[string]struct{}{} // dups accumulates duplicate links dups := []string{} - for _, lc := range c.Links { - for _, e := range []*types.Endpoint{lc.A, lc.B} { + for _, l := range c.Links { + for _, e := range []*types.Endpoint{l.A, l.B} { e_string := e.String() if _, ok := endpoints[e_string]; ok { dups = append(dups, e_string) diff --git a/types/types.go b/types/types.go index b7d1e66b8..81a67864e 100644 --- a/types/types.go +++ b/types/types.go @@ -38,6 +38,7 @@ type Endpoint struct { MAC string } +// String returns a string representation of the endpoint. func (e *Endpoint) String() string { return fmt.Sprintf("%s:%s", e.Node.ShortName, e.EndpointName) } From cd2143820a914325b3b983a7c29f30234f817690 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Sun, 16 Jul 2023 09:55:47 +0300 Subject: [PATCH 17/22] rename to LinkTypeBrief --- types/link.go | 32 +++++++++++++++++++------------- types/link_test.go | 6 +++--- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/types/link.go b/types/link.go index 9afb34b61..d681be9ef 100644 --- a/types/link.go +++ b/types/link.go @@ -7,6 +7,7 @@ import ( "gopkg.in/yaml.v2" ) +// LinkCommonParams represents the common parameters for all link types. type LinkCommonParams struct { Mtu int `yaml:"mtu,omitempty"` Labels map[string]string `yaml:"labels,omitempty"` @@ -16,7 +17,6 @@ type LinkCommonParams struct { // LinkDefinition represents a link definition in the topology file. type LinkDefinition struct { Type string `yaml:"type"` - // Instance interface{} LinkConfig } @@ -30,9 +30,10 @@ const ( LinkTypeMacVTap LinkDefinitionType = "macvtap" LinkTypeHost LinkDefinitionType = "host" - // LinkTypeLegacy is a link definition where link types - // are encoded in the endpoint definition as string. - LinkTypeLegacy LinkDefinitionType = "legacy" + // LinkTypeBrief is a link definition where link types + // are encoded in the endpoint definition as string and allow users + // to quickly type out link endpoints in a yaml file. + LinkTypeBrief LinkDefinitionType = "brief" ) func ParseLinkType(s string) (LinkDefinitionType, error) { @@ -47,8 +48,8 @@ func ParseLinkType(s string) (LinkDefinitionType, error) { return LinkTypeMgmtNet, nil case string(LinkTypeHost): return LinkTypeHost, nil - case string(LinkTypeLegacy): - return LinkTypeLegacy, nil + case string(LinkTypeBrief): + return LinkTypeBrief, nil default: return "", fmt.Errorf("unable to parse %q as LinkType", s) } @@ -93,9 +94,10 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error var lt LinkDefinitionType + // if no type is specified, we assume that brief notation of a link definition is used. if a.Type == "" { - lt = LinkTypeLegacy - r.Type = string(LinkTypeLegacy) + lt = LinkTypeBrief + r.Type = string(LinkTypeBrief) } else { r.Type = a.Type @@ -158,21 +160,25 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error return err } r.LinkConfig = *l.RawMacVTapLink.ToLinkConfig() - case LinkTypeLegacy: - // try to parse the depricate format + case LinkTypeBrief: + // brief link's endpoint format var l struct { Type string `yaml:"type"` LinkConfig `yaml:",inline"` } + err := unmarshal(&l) if err != nil { return err } - r.Type = string(LinkTypeLegacy) - lc, err := deprecateLinkConversion(&l.LinkConfig) + + r.Type = string(LinkTypeBrief) + + lc, err := briefLinkConversion(&l.LinkConfig) if err != nil { return err } + r.LinkConfig = *lc default: return fmt.Errorf("unknown link type %q", lt) @@ -181,7 +187,7 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error return nil } -func deprecateLinkConversion(lc *LinkConfig) (*LinkConfig, error) { +func briefLinkConversion(lc *LinkConfig) (*LinkConfig, error) { // check two endpoints defined if len(lc.Endpoints) != 2 { return nil, fmt.Errorf("endpoint definition should consist of exactly 2 entries. %d provided", len(lc.Endpoints)) diff --git a/types/link_test.go b/types/link_test.go index d4d4f4ae4..f0a6bca8f 100644 --- a/types/link_test.go +++ b/types/link_test.go @@ -60,9 +60,9 @@ func TestParseLinkType(t *testing.T) { { name: "link type deprecate", args: args{ - s: string(LinkTypeLegacy), + s: string(LinkTypeBrief), }, - want: LinkTypeLegacy, + want: LinkTypeBrief, wantErr: false, }, { @@ -108,7 +108,7 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { }, wantErr: false, want: LinkDefinition{ - Type: string(LinkTypeLegacy), + Type: string(LinkTypeBrief), LinkConfig: LinkConfig{ Endpoints: []string{ "srl1:e1-5", From 1d9bcb73c4f50d50138a8cf3324a50608ec703db Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Sun, 16 Jul 2023 10:10:38 +0300 Subject: [PATCH 18/22] sort dups array for deterministic error message --- clab/config.go | 1 + 1 file changed, 1 insertion(+) diff --git a/clab/config.go b/clab/config.go index f88e82738..71e79f318 100644 --- a/clab/config.go +++ b/clab/config.go @@ -448,6 +448,7 @@ func (c *CLab) verifyLinks() error { } } if len(dups) != 0 { + sort.Strings(dups) // sort for deterministic error message return fmt.Errorf("endpoints %q appeared more than once in the links section of the topology file", dups) } return nil From 7c84c533747f3301d3978ee85deebb051462c867 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Sun, 16 Jul 2023 12:15:42 +0300 Subject: [PATCH 19/22] added method comments --- types/link.go | 20 ++++++++++++-------- types/link_test.go | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/types/link.go b/types/link.go index d681be9ef..0e69f2306 100644 --- a/types/link.go +++ b/types/link.go @@ -36,7 +36,8 @@ const ( LinkTypeBrief LinkDefinitionType = "brief" ) -func ParseLinkType(s string) (LinkDefinitionType, error) { +// parseLinkType parses a string representation of a link type into a LinkDefinitionType. +func parseLinkType(s string) (LinkDefinitionType, error) { switch strings.TrimSpace(strings.ToLower(s)) { case string(LinkTypeMacVLan): return LinkTypeMacVLan, nil @@ -55,12 +56,13 @@ func ParseLinkType(s string) (LinkDefinitionType, error) { } } -var _ yaml.Unmarshaler = &LinkDefinition{} +var _ yaml.Unmarshaler = (*LinkDefinition)(nil) +var _ yaml.Marshaler = (*LinkDefinition)(nil) -// MarshalYAML used when writing topology files via the generate command. -// for now this falls back to convertig the LinkConfig into a -// RawVEthLink. Such that the generated LinkConfigs adhere to the new LinkDefinition -// format instead of the depricated one. +// MarshalYAML serializes LinkDefinition (e.g when used with generate command). +// As of now it falls back to converting the LinkConfig into a +// RawVEthLink, such that the generated LinkConfigs adhere to the new LinkDefinition +// format instead of the brief one. func (r *LinkDefinition) MarshalYAML() (interface{}, error) { rawVEth, err := vEthFromLinkConfig(&r.LinkConfig) if err != nil { @@ -78,6 +80,8 @@ func (r *LinkDefinition) MarshalYAML() (interface{}, error) { return x, nil } +// UnmarshalYAML deserializes links passed via topology file into LinkDefinition struct. +// It supports both the brief and specific link type notations. func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error { // alias struct to avoid recursion and pass strict yaml unmarshalling // we don't care about the embedded LinkConfig, as we only need to unmarshal @@ -101,7 +105,7 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error } else { r.Type = a.Type - lt, err = ParseLinkType(a.Type) + lt, err = parseLinkType(a.Type) if err != nil { return err } @@ -196,7 +200,7 @@ func briefLinkConversion(lc *LinkConfig) (*LinkConfig, error) { parts := strings.SplitN(v, ":", 2) node := parts[0] - lt, err := ParseLinkType(node) + lt, err := parseLinkType(node) if err != nil { // if the link type parsing from the node name did fail // we continue, since the node name is not like veth or macvlan or the like diff --git a/types/link_test.go b/types/link_test.go index f0a6bca8f..dd9dc742c 100644 --- a/types/link_test.go +++ b/types/link_test.go @@ -75,7 +75,7 @@ func TestParseLinkType(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := ParseLinkType(tt.args.s) + got, err := parseLinkType(tt.args.s) if (err != nil) != tt.wantErr { t.Errorf("ParseLinkType() error = %v, wantErr %v", err, tt.wantErr) return From 1b9397bcf90b1fb9b7a73784d8097da43588dc40 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Wed, 19 Jul 2023 13:26:24 +0300 Subject: [PATCH 20/22] remove brief link conversion --- types/link.go | 37 +------------------------------------ types/link_test.go | 22 ---------------------- 2 files changed, 1 insertion(+), 58 deletions(-) diff --git a/types/link.go b/types/link.go index 0e69f2306..d61531c5a 100644 --- a/types/link.go +++ b/types/link.go @@ -178,45 +178,10 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error r.Type = string(LinkTypeBrief) - lc, err := briefLinkConversion(&l.LinkConfig) - if err != nil { - return err - } - - r.LinkConfig = *lc + r.LinkConfig = l.LinkConfig default: return fmt.Errorf("unknown link type %q", lt) } return nil } - -func briefLinkConversion(lc *LinkConfig) (*LinkConfig, error) { - // check two endpoints defined - if len(lc.Endpoints) != 2 { - return nil, fmt.Errorf("endpoint definition should consist of exactly 2 entries. %d provided", len(lc.Endpoints)) - } - for _, v := range lc.Endpoints { - parts := strings.SplitN(v, ":", 2) - node := parts[0] - - lt, err := parseLinkType(node) - if err != nil { - // if the link type parsing from the node name did fail - // we continue, since the node name is not like veth or macvlan or the like - continue - } - - // if the node name is equal to a LinkType, we check the Type and only allow the depricated format - // for old types. New once we force to use the new link format. - switch lt { - case LinkTypeMgmtNet: - continue - case LinkTypeHost: - continue - case LinkTypeMacVLan, LinkTypeMacVTap: - return nil, fmt.Errorf("Link type %q needs to be defined in new link format", string(lt)) - } - } - return lc, nil -} diff --git a/types/link_test.go b/types/link_test.go index dd9dc742c..d6c06c861 100644 --- a/types/link_test.go +++ b/types/link_test.go @@ -205,28 +205,6 @@ func TestUnmarshalRawLinksYaml(t *testing.T) { }, }, }, - { - name: "macvtap link legacy format", - args: args{ - yaml: []byte(` - endpoints: - - "srl1:e1-5" - - "macvtap:e1-5" - `), - }, - wantErr: true, - }, - { - name: "macvlan link legacy format", - args: args{ - yaml: []byte(` - endpoints: - - "srl1:e1-5" - - "macvlan:e1-5" - `), - }, - wantErr: true, - }, } for _, tt := range tests { From b8e4ecda23049259e91b9b435baeafe2045bd541 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Wed, 19 Jul 2023 13:49:18 +0300 Subject: [PATCH 21/22] removed custom unmarshaller for links also made generate to use implicit brief format --- cmd/generate.go | 2 +- types/link.go | 26 ++------------------------ types/link_common.go | 17 ----------------- types/link_veth.go | 22 ---------------------- 4 files changed, 3 insertions(+), 64 deletions(-) diff --git a/cmd/generate.go b/cmd/generate.go index 8842c159a..07fcd5dfe 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -216,7 +216,7 @@ func generateTopologyConfig(name, network, ipv4range, ipv6range string, } config.Topology.Links = append(config.Topology.Links, &types.LinkDefinition{ - Type: string(types.LinkTypeVEth), + // Type: string(types.LinkTypeBrief), LinkConfig: types.LinkConfig{ Endpoints: []string{ node1 + ":" + fmt.Sprintf(interfaceFormat[nodes[i].kind], k+1+interfaceOffset), diff --git a/types/link.go b/types/link.go index d61531c5a..ae53463ab 100644 --- a/types/link.go +++ b/types/link.go @@ -16,8 +16,8 @@ type LinkCommonParams struct { // LinkDefinition represents a link definition in the topology file. type LinkDefinition struct { - Type string `yaml:"type"` - LinkConfig + Type string `yaml:"type,omitempty"` + LinkConfig `yaml:",inline"` } // LinkDefinitionType represents the type of a link definition. @@ -57,28 +57,6 @@ func parseLinkType(s string) (LinkDefinitionType, error) { } var _ yaml.Unmarshaler = (*LinkDefinition)(nil) -var _ yaml.Marshaler = (*LinkDefinition)(nil) - -// MarshalYAML serializes LinkDefinition (e.g when used with generate command). -// As of now it falls back to converting the LinkConfig into a -// RawVEthLink, such that the generated LinkConfigs adhere to the new LinkDefinition -// format instead of the brief one. -func (r *LinkDefinition) MarshalYAML() (interface{}, error) { - rawVEth, err := vEthFromLinkConfig(&r.LinkConfig) - if err != nil { - return nil, err - } - - x := struct { - RawVEthLink `yaml:",inline"` - Type string `yaml:"type"` - }{ - RawVEthLink: *rawVEth, - Type: string(LinkTypeVEth), - } - - return x, nil -} // UnmarshalYAML deserializes links passed via topology file into LinkDefinition struct. // It supports both the brief and specific link type notations. diff --git a/types/link_common.go b/types/link_common.go index 1ac73e618..d18c3447e 100644 --- a/types/link_common.go +++ b/types/link_common.go @@ -1,24 +1,7 @@ package types -import "strings" - type EndpointRaw struct { Node string `yaml:"node"` Iface string `yaml:"interface"` Mac string `yaml:"mac,omitempty"` } - -func extractHostNodeInterfaceData(lc *LinkConfig, specialEPIndex int) (host string, hostIf string, node string, nodeIf string) { - // the index of the node is the specialEndpointIndex +1 modulo 2 - nodeindex := (specialEPIndex + 1) % 2 - - hostData := strings.SplitN(lc.Endpoints[specialEPIndex], ":", 2) - nodeData := strings.SplitN(lc.Endpoints[nodeindex], ":", 2) - - host = hostData[0] - hostIf = hostData[1] - node = nodeData[0] - nodeIf = nodeData[1] - - return host, hostIf, node, nodeIf -} diff --git a/types/link_veth.go b/types/link_veth.go index 37aac4de1..2345daad3 100644 --- a/types/link_veth.go +++ b/types/link_veth.go @@ -30,25 +30,3 @@ func (r *RawVEthLink) ToLinkConfig() *LinkConfig { } return lc } - -func vEthFromLinkConfig(lc *LinkConfig) (*RawVEthLink, error) { - nodeA, nodeAIf, nodeB, nodeBIf := extractHostNodeInterfaceData(lc, 0) - - result := &RawVEthLink{ - LinkCommonParams: LinkCommonParams{ - Labels: lc.Labels, - Vars: lc.Vars, - }, - Endpoints: []*EndpointRaw{ - { - Node: nodeA, - Iface: nodeAIf, - }, - { - Node: nodeB, - Iface: nodeBIf, - }, - }, - } - return result, nil -} From 06e7e25315c99ce3880cc3336dc36fa5c5812929 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Wed, 19 Jul 2023 14:07:34 +0300 Subject: [PATCH 22/22] renamed raw link types --- types/{link_common.go => endpoint.go} | 0 types/link.go | 20 ++++++++++---------- types/link_host.go | 23 ++++------------------- types/link_mac.go | 7 ------- types/link_macvlan.go | 10 +++++++--- types/link_macvtap.go | 10 +++++++--- types/link_mgmt-net.go | 19 ++----------------- types/link_veth.go | 12 +++++++----- 8 files changed, 37 insertions(+), 64 deletions(-) rename types/{link_common.go => endpoint.go} (100%) delete mode 100644 types/link_mac.go diff --git a/types/link_common.go b/types/endpoint.go similarity index 100% rename from types/link_common.go rename to types/endpoint.go diff --git a/types/link.go b/types/link.go index ae53463ab..b78b4b3ad 100644 --- a/types/link.go +++ b/types/link.go @@ -95,53 +95,53 @@ func (r *LinkDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error // the Type field is injected artificially // to allow strict yaml parsing to work. Type string `yaml:"type"` - RawVEthLink `yaml:",inline"` + LinkVEthRaw `yaml:",inline"` } err := unmarshal(&l) if err != nil { return err } - r.LinkConfig = *l.RawVEthLink.ToLinkConfig() + r.LinkConfig = *l.LinkVEthRaw.ToLinkConfig() case LinkTypeMgmtNet: var l struct { Type string `yaml:"type"` - RawMgmtNetLink `yaml:",inline"` + LinkMgmtNetRaw `yaml:",inline"` } err := unmarshal(&l) if err != nil { return err } - r.LinkConfig = *l.RawMgmtNetLink.ToLinkConfig() + r.LinkConfig = *l.LinkMgmtNetRaw.ToLinkConfig() case LinkTypeHost: var l struct { Type string `yaml:"type"` - RawHostLink `yaml:",inline"` + LinkHostRaw `yaml:",inline"` } err := unmarshal(&l) if err != nil { return err } - r.LinkConfig = *l.RawHostLink.ToLinkConfig() + r.LinkConfig = *l.LinkHostRaw.ToLinkConfig() case LinkTypeMacVLan: var l struct { Type string `yaml:"type"` - RawMacVLanLink `yaml:",inline"` + LinkMACVLANRaw `yaml:",inline"` } err := unmarshal(&l) if err != nil { return err } - r.LinkConfig = *l.RawMacVLanLink.ToLinkConfig() + r.LinkConfig = *l.LinkMACVLANRaw.ToLinkConfig() case LinkTypeMacVTap: var l struct { Type string `yaml:"type"` - RawMacVTapLink `yaml:",inline"` + LinkMACVTAPRaw `yaml:",inline"` } err := unmarshal(&l) if err != nil { return err } - r.LinkConfig = *l.RawMacVTapLink.ToLinkConfig() + r.LinkConfig = *l.LinkMACVTAPRaw.ToLinkConfig() case LinkTypeBrief: // brief link's endpoint format var l struct { diff --git a/types/link_host.go b/types/link_host.go index f1e66fbfe..ca1007659 100644 --- a/types/link_host.go +++ b/types/link_host.go @@ -2,13 +2,15 @@ package types import "fmt" -type RawHostLink struct { +// LinkHostRaw is the raw (string) representation of a host link as defined in the topology file. +type LinkHostRaw struct { LinkCommonParams `yaml:",inline"` HostInterface string `yaml:"host-interface"` Endpoint *EndpointRaw `yaml:"endpoint"` } -func (r *RawHostLink) ToLinkConfig() *LinkConfig { +// ToLinkConfig converts the raw link into a LinkConfig. +func (r *LinkHostRaw) ToLinkConfig() *LinkConfig { lc := &LinkConfig{ Vars: r.Vars, Labels: r.Labels, @@ -21,20 +23,3 @@ func (r *RawHostLink) ToLinkConfig() *LinkConfig { return lc } - -// func hostFromLinkConfig(lc *LinkConfig, specialEPIndex int) (*RawHostLink, error) { -// _, hostIf, node, nodeIf := extractHostNodeInterfaceData(lc, specialEPIndex) - -// result := &RawHostLink{ -// RawLinkType: RawLinkType{ -// Type: string(LinkTypeHost), -// Labels: lc.Labels, -// Vars: lc.Vars, -// Instance: nil, -// }, -// HostInterface: hostIf, -// Node: node, -// NodeInterface: nodeIf, -// } -// return result, nil -// } diff --git a/types/link_mac.go b/types/link_mac.go deleted file mode 100644 index 5a78e6abf..000000000 --- a/types/link_mac.go +++ /dev/null @@ -1,7 +0,0 @@ -package types - -type rawMacVXType struct { - LinkCommonParams `yaml:",inline"` - HostInterface string `yaml:"host-interface"` - Endpoint *EndpointRaw `yaml:"endpoint"` -} diff --git a/types/link_macvlan.go b/types/link_macvlan.go index c78e6e193..4ebec3fad 100644 --- a/types/link_macvlan.go +++ b/types/link_macvlan.go @@ -2,11 +2,15 @@ package types import "fmt" -type RawMacVLanLink struct { - rawMacVXType `yaml:",inline"` +// LinkMACVLANRaw is the raw (string) representation of a macvlan link as defined in the topology file. +type LinkMACVLANRaw struct { + LinkCommonParams `yaml:",inline"` + HostInterface string `yaml:"host-interface"` + Endpoint *EndpointRaw `yaml:"endpoint"` } -func (r *RawMacVLanLink) ToLinkConfig() *LinkConfig { +// ToLinkConfig converts the raw link into a LinkConfig. +func (r *LinkMACVLANRaw) ToLinkConfig() *LinkConfig { lc := &LinkConfig{ Vars: r.Vars, Labels: r.Labels, diff --git a/types/link_macvtap.go b/types/link_macvtap.go index 9699618e0..6ba4f5380 100644 --- a/types/link_macvtap.go +++ b/types/link_macvtap.go @@ -2,11 +2,15 @@ package types import "fmt" -type RawMacVTapLink struct { - rawMacVXType `yaml:",inline"` +// LinkMACVTAPRaw is the raw (string) representation of a macvtap link as defined in the topology file. +type LinkMACVTAPRaw struct { + LinkCommonParams `yaml:",inline"` + HostInterface string `yaml:"host-interface"` + Endpoint *EndpointRaw `yaml:"endpoint"` } -func (r *RawMacVTapLink) ToLinkConfig() *LinkConfig { +// ToLinkConfig converts the raw link into a LinkConfig. +func (r *LinkMACVTAPRaw) ToLinkConfig() *LinkConfig { lc := &LinkConfig{ Vars: r.Vars, Labels: r.Labels, diff --git a/types/link_mgmt-net.go b/types/link_mgmt-net.go index 8f437735b..1e463eaed 100644 --- a/types/link_mgmt-net.go +++ b/types/link_mgmt-net.go @@ -2,13 +2,13 @@ package types import "fmt" -type RawMgmtNetLink struct { +type LinkMgmtNetRaw struct { LinkCommonParams `yaml:",inline"` HostInterface string `yaml:"host-interface"` Endpoint *EndpointRaw `yaml:"endpoint"` } -func (r *RawMgmtNetLink) ToLinkConfig() *LinkConfig { +func (r *LinkMgmtNetRaw) ToLinkConfig() *LinkConfig { lc := &LinkConfig{ Vars: r.Vars, Labels: r.Labels, @@ -21,18 +21,3 @@ func (r *RawMgmtNetLink) ToLinkConfig() *LinkConfig { return lc } - -// func mgmtNetFromLinkConfig(lc *LinkConfig, specialEPIndex int) (*RawMgmtNetLink, error) { -// _, hostIf, node, nodeIf := extractHostNodeInterfaceData(lc, specialEPIndex) - -// result := &RawMgmtNetLink{ -// RawLinkType: RawLinkType{Type: string(LinkTypeMgmtNet), Labels: lc.Labels, Vars: lc.Vars, Instance: nil}, -// HostInterface: hostIf, -// Endpoint: &EndpointRaw{ -// Node: node, -// Iface: nodeIf, -// Mac: "", -// }, -// } -// return result, nil -// } diff --git a/types/link_veth.go b/types/link_veth.go index 2345daad3..1e0939c7e 100644 --- a/types/link_veth.go +++ b/types/link_veth.go @@ -2,23 +2,25 @@ package types import "fmt" -type RawVEthLink struct { +// LinkVEthRaw is the raw (string) representation of a veth link as defined in the topology file. +type LinkVEthRaw struct { LinkCommonParams `yaml:",inline"` Endpoints []*EndpointRaw `yaml:"endpoints"` } -func (r *RawVEthLink) MarshalYAML() (interface{}, error) { +func (r *LinkVEthRaw) MarshalYAML() (interface{}, error) { x := struct { Type string `yaml:"type"` - RawVEthLink `yaml:",inline"` + LinkVEthRaw `yaml:",inline"` }{ Type: string(LinkTypeVEth), - RawVEthLink: *r, + LinkVEthRaw: *r, } return x, nil } -func (r *RawVEthLink) ToLinkConfig() *LinkConfig { +// ToLinkConfig converts the raw link into a LinkConfig. +func (r *LinkVEthRaw) ToLinkConfig() *LinkConfig { lc := &LinkConfig{ Vars: r.Vars, Labels: r.Labels,