Add support for in-container master for macvlans

Signed-off-by: mmirecki <mmirecki@redhat.com>
This commit is contained in:
mmirecki 2023-01-18 14:48:47 +01:00
parent c4d24e80d6
commit ac7cf82531
2 changed files with 621 additions and 516 deletions

View File

@ -41,6 +41,7 @@ type NetConf struct {
Mode string `json:"mode"` Mode string `json:"mode"`
MTU int `json:"mtu"` MTU int `json:"mtu"`
Mac string `json:"mac,omitempty"` Mac string `json:"mac,omitempty"`
LinkContNs bool `json:"linkInContainer,omitempty"`
RuntimeConfig struct { RuntimeConfig struct {
Mac string `json:"mac,omitempty"` Mac string `json:"mac,omitempty"`
@ -79,13 +80,36 @@ func getDefaultRouteInterfaceName() (string, error) {
return "", fmt.Errorf("no default route interface found") return "", fmt.Errorf("no default route interface found")
} }
func loadConf(bytes []byte, envArgs string) (*NetConf, string, error) { func getNamespacedDefaultRouteInterfaceName(namespace string, inContainer bool) (string, error) {
if !inContainer {
return getDefaultRouteInterfaceName()
}
netns, err := ns.GetNS(namespace)
if err != nil {
return "", fmt.Errorf("failed to open netns %q: %v", netns, err)
}
defer netns.Close()
var defaultRouteInterface string
err = netns.Do(func(_ ns.NetNS) error {
defaultRouteInterface, err = getDefaultRouteInterfaceName()
if err != nil {
return err
}
return nil
})
if err != nil {
return "", err
}
return defaultRouteInterface, nil
}
func loadConf(args *skel.CmdArgs, envArgs string) (*NetConf, string, error) {
n := &NetConf{} n := &NetConf{}
if err := json.Unmarshal(bytes, n); err != nil { if err := json.Unmarshal(args.StdinData, n); err != nil {
return nil, "", fmt.Errorf("failed to load netconf: %v", err) return nil, "", fmt.Errorf("failed to load netconf: %v", err)
} }
if n.Master == "" { if n.Master == "" {
defaultRouteInterface, err := getDefaultRouteInterfaceName() defaultRouteInterface, err := getNamespacedDefaultRouteInterfaceName(args.Netns, n.LinkContNs)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
@ -93,7 +117,7 @@ func loadConf(bytes []byte, envArgs string) (*NetConf, string, error) {
} }
// check existing and MTU of master interface // check existing and MTU of master interface
masterMTU, err := getMTUByName(n.Master) masterMTU, err := getMTUByName(n.Master, args.Netns, n.LinkContNs)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
@ -120,8 +144,23 @@ func loadConf(bytes []byte, envArgs string) (*NetConf, string, error) {
return n, n.CNIVersion, nil return n, n.CNIVersion, nil
} }
func getMTUByName(ifName string) (int, error) { func getMTUByName(ifName string, namespace string, inContainer bool) (int, error) {
link, err := netlink.LinkByName(ifName) var link netlink.Link
var err error
if inContainer {
netns, err := ns.GetNS(namespace)
if err != nil {
return 0, fmt.Errorf("failed to open netns %q: %v", netns, err)
}
defer netns.Close()
err = netns.Do(func(_ ns.NetNS) error {
link, err = netlink.LinkByName(ifName)
return err
})
} else {
link, err = netlink.LinkByName(ifName)
}
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -166,7 +205,15 @@ func createMacvlan(conf *NetConf, ifName string, netns ns.NetNS) (*current.Inter
return nil, err return nil, err
} }
m, err := netlink.LinkByName(conf.Master) var m netlink.Link
if conf.LinkContNs {
err = netns.Do(func(_ ns.NetNS) error {
m, err = netlink.LinkByName(conf.Master)
return err
})
} else {
m, err = netlink.LinkByName(conf.Master)
}
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to lookup master %q: %v", conf.Master, err) return nil, fmt.Errorf("failed to lookup master %q: %v", conf.Master, err)
} }
@ -198,7 +245,16 @@ func createMacvlan(conf *NetConf, ifName string, netns ns.NetNS) (*current.Inter
Mode: mode, Mode: mode,
} }
if err := netlink.LinkAdd(mv); err != nil { if conf.LinkContNs {
err = netns.Do(func(_ ns.NetNS) error {
return netlink.LinkAdd(mv)
})
} else {
if err = netlink.LinkAdd(mv); err != nil {
return nil, fmt.Errorf("failed to create macvlan: %v", err)
}
}
if err != nil {
return nil, fmt.Errorf("failed to create macvlan: %v", err) return nil, fmt.Errorf("failed to create macvlan: %v", err)
} }
@ -228,7 +284,7 @@ func createMacvlan(conf *NetConf, ifName string, netns ns.NetNS) (*current.Inter
} }
func cmdAdd(args *skel.CmdArgs) error { func cmdAdd(args *skel.CmdArgs) error {
n, cniVersion, err := loadConf(args.StdinData, args.Args) n, cniVersion, err := loadConf(args, args.Args)
if err != nil { if err != nil {
return err return err
} }
@ -329,7 +385,7 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
func cmdDel(args *skel.CmdArgs) error { func cmdDel(args *skel.CmdArgs) error {
n, _, err := loadConf(args.StdinData, args.Args) n, _, err := loadConf(args, args.Args)
if err != nil { if err != nil {
return err return err
} }
@ -378,7 +434,7 @@ func main() {
func cmdCheck(args *skel.CmdArgs) error { func cmdCheck(args *skel.CmdArgs) error {
n, _, err := loadConf(args.StdinData, args.Args) n, _, err := loadConf(args, args.Args)
if err != nil { if err != nil {
return err return err
} }
@ -429,7 +485,15 @@ func cmdCheck(args *skel.CmdArgs) error {
contMap.Sandbox, args.Netns) contMap.Sandbox, args.Netns)
} }
m, err := netlink.LinkByName(n.Master) var m netlink.Link
if n.LinkContNs {
err = netns.Do(func(_ ns.NetNS) error {
m, err = netlink.LinkByName(n.Master)
return err
})
} else {
m, err = netlink.LinkByName(n.Master)
}
if err != nil { if err != nil {
return fmt.Errorf("failed to lookup master %q: %v", n.Master, err) return fmt.Errorf("failed to lookup master %q: %v", n.Master, err)
} }

View File

@ -38,6 +38,7 @@ import (
) )
const MASTER_NAME = "eth0" const MASTER_NAME = "eth0"
const MASTER_NAME_INCONTAINER = "eth1"
type Net struct { type Net struct {
Name string `json:"name"` Name string `json:"name"`
@ -54,6 +55,7 @@ type Net struct {
DNS types.DNS `json:"dns"` DNS types.DNS `json:"dns"`
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"` RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
PrevResult types100.Result `json:"-"` PrevResult types100.Result `json:"-"`
LinkContNs bool `json:"linkInContainer"`
} }
func buildOneConfig(netName string, cniVersion string, orig *Net, prevResult types.Result) (*Net, error) { func buildOneConfig(netName string, cniVersion string, orig *Net, prevResult types.Result) (*Net, error) {
@ -216,6 +218,22 @@ var _ = Describe("macvlan Operations", func() {
return nil return nil
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = targetNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
// Add master
err = netlink.LinkAdd(&netlink.Dummy{
LinkAttrs: netlink.LinkAttrs{
Name: MASTER_NAME_INCONTAINER,
},
})
Expect(err).NotTo(HaveOccurred())
_, err = netlink.LinkByName(MASTER_NAME_INCONTAINER)
Expect(err).NotTo(HaveOccurred())
return nil
})
Expect(err).NotTo(HaveOccurred())
}) })
AfterEach(func() { AfterEach(func() {
@ -225,7 +243,17 @@ var _ = Describe("macvlan Operations", func() {
Expect(targetNS.Close()).To(Succeed()) Expect(targetNS.Close()).To(Succeed())
Expect(testutils.UnmountNS(targetNS)).To(Succeed()) Expect(testutils.UnmountNS(targetNS)).To(Succeed())
}) })
f, t := false, true
for _, inContainer := range []*bool{&f, &t, nil} {
isInContainer := inContainer
masterInterface := MASTER_NAME
if inContainer != nil && *inContainer {
masterInterface = MASTER_NAME_INCONTAINER
}
linkInContainer := ""
if isInContainer != nil {
linkInContainer = fmt.Sprintf("\"linkInContainer\": %t,", *isInContainer)
}
for _, ver := range testutils.AllSpecVersions { for _, ver := range testutils.AllSpecVersions {
// Redefine ver inside for scope so real value is picked up by each dynamically defined It() // Redefine ver inside for scope so real value is picked up by each dynamically defined It()
// See Gingkgo's "Patterns for dynamically generating tests" documentation. // See Gingkgo's "Patterns for dynamically generating tests" documentation.
@ -238,9 +266,10 @@ var _ = Describe("macvlan Operations", func() {
Name: "testConfig", Name: "testConfig",
Type: "macvlan", Type: "macvlan",
}, },
Master: MASTER_NAME, Master: masterInterface,
Mode: "bridge", Mode: "bridge",
MTU: 1500, MTU: 1500,
LinkContNs: isInContainer != nil && *isInContainer,
} }
err := originalNS.Do(func(ns.NetNS) error { err := originalNS.Do(func(ns.NetNS) error {
@ -272,12 +301,13 @@ var _ = Describe("macvlan Operations", func() {
"name": "mynet", "name": "mynet",
"type": "macvlan", "type": "macvlan",
"master": "%s", "master": "%s",
%s
"ipam": { "ipam": {
"type": "host-local", "type": "host-local",
"subnet": "10.1.2.0/24", "subnet": "10.1.2.0/24",
"dataDir": "%s" "dataDir": "%s"
} }
}`, ver, MASTER_NAME, dataDir) }`, ver, masterInterface, linkInContainer, dataDir)
args := &skel.CmdArgs{ args := &skel.CmdArgs{
ContainerID: "dummy", ContainerID: "dummy",
@ -352,12 +382,13 @@ var _ = Describe("macvlan Operations", func() {
"name": "mynet", "name": "mynet",
"type": "macvlan", "type": "macvlan",
"master": "%s", "master": "%s",
%s
"ipam": { "ipam": {
"type": "host-local", "type": "host-local",
"subnet": "10.1.2.0/24", "subnet": "10.1.2.0/24",
"dataDir": "%s" "dataDir": "%s"
} }
}`, ver, MASTER_NAME, dataDir) }`, ver, masterInterface, linkInContainer, dataDir)
args := &skel.CmdArgs{ args := &skel.CmdArgs{
ContainerID: "dummy", ContainerID: "dummy",
@ -387,8 +418,9 @@ var _ = Describe("macvlan Operations", func() {
"name": "mynet", "name": "mynet",
"type": "macvlan", "type": "macvlan",
"master": "%s", "master": "%s",
%s
"ipam": {} "ipam": {}
}`, ver, MASTER_NAME) }`, ver, masterInterface, linkInContainer)
args := &skel.CmdArgs{ args := &skel.CmdArgs{
ContainerID: "dummy", ContainerID: "dummy",
@ -463,12 +495,13 @@ var _ = Describe("macvlan Operations", func() {
"name": "macvlanTestv4", "name": "macvlanTestv4",
"type": "macvlan", "type": "macvlan",
"master": "%s", "master": "%s",
%s
"ipam": { "ipam": {
"type": "host-local", "type": "host-local",
"ranges": [[ {"subnet": "10.1.2.0/24", "gateway": "10.1.2.1"} ]], "ranges": [[ {"subnet": "10.1.2.0/24", "gateway": "10.1.2.1"} ]],
"dataDir": "%s" "dataDir": "%s"
} }
}`, ver, MASTER_NAME, dataDir) }`, ver, masterInterface, linkInContainer, dataDir)
args := &skel.CmdArgs{ args := &skel.CmdArgs{
ContainerID: "dummy", ContainerID: "dummy",
@ -576,12 +609,13 @@ var _ = Describe("macvlan Operations", func() {
"cniVersion": "%s", "cniVersion": "%s",
"name": "mynet", "name": "mynet",
"type": "macvlan", "type": "macvlan",
%s
"ipam": { "ipam": {
"type": "host-local", "type": "host-local",
"subnet": "10.1.2.0/24", "subnet": "10.1.2.0/24",
"dataDir": "%s" "dataDir": "%s"
} }
}`, ver, dataDir) }`, ver, linkInContainer, dataDir)
args := &skel.CmdArgs{ args := &skel.CmdArgs{
ContainerID: "dummy", ContainerID: "dummy",
@ -589,12 +623,16 @@ var _ = Describe("macvlan Operations", func() {
IfName: IFNAME, IfName: IFNAME,
StdinData: []byte(conf), StdinData: []byte(conf),
} }
currentNs := originalNS
if isInContainer != nil && *isInContainer {
currentNs = targetNS
}
// Make MASTER_NAME as default route interface // Make master as default route interface
err := originalNS.Do(func(ns.NetNS) error { err := currentNs.Do(func(ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
link, err := netlink.LinkByName(MASTER_NAME) link, err := netlink.LinkByName(masterInterface)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = netlink.LinkSetUp(link) err = netlink.LinkSetUp(link)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -686,8 +724,9 @@ var _ = Describe("macvlan Operations", func() {
"name": "mynet", "name": "mynet",
"type": "macvlan", "type": "macvlan",
"master": "%s", "master": "%s",
%s
"ipam": {} "ipam": {}
}`, ver, MASTER_NAME) }`, ver, masterInterface, linkInContainer)
args := &skel.CmdArgs{ args := &skel.CmdArgs{
ContainerID: "dummy", ContainerID: "dummy",
@ -771,8 +810,9 @@ var _ = Describe("macvlan Operations", func() {
"name": "mynet", "name": "mynet",
"type": "macvlan", "type": "macvlan",
"master": "%s", "master": "%s",
%s
"ipam": {} "ipam": {}
}`, ver, MASTER_NAME) }`, ver, masterInterface, linkInContainer)
args := &skel.CmdArgs{ args := &skel.CmdArgs{
ContainerID: "dummy", ContainerID: "dummy",
@ -840,4 +880,5 @@ var _ = Describe("macvlan Operations", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
} }
}
}) })