Merge pull request #42542 from zhangyoufu/libnetwork-ipvlan-enhance

drivers/ipvlan: add ipvlan_flag option, support l3s ipvlan_mode
This commit is contained in:
Brian Goff 2022-06-30 13:13:28 -07:00 committed by GitHub
commit 3e7e81b68f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 114 additions and 16 deletions

View File

@ -17,14 +17,20 @@ const (
vethLen = 7
containerVethPrefix = "eth"
vethPrefix = "veth"
ipvlanType = "ipvlan" // driver type name
modeL2 = "l2" // ipvlan mode l2 is the default
modeL3 = "l3" // ipvlan L3 mode
parentOpt = "parent" // parent interface -o parent
modeOpt = "_mode" // ipvlan mode ux opt suffix
)
var driverModeOpt = ipvlanType + modeOpt // mode -o ipvlan_mode
ipvlanType = "ipvlan" // driver type name
parentOpt = "parent" // parent interface -o parent
driverModeOpt = ipvlanType + "_mode" // mode -o ipvlan_mode
driverFlagOpt = ipvlanType + "_flag" // flag -o ipvlan_flag
modeL2 = "l2" // ipvlan L2 mode (default)
modeL3 = "l3" // ipvlan L3 mode
modeL3S = "l3s" // ipvlan L3S mode
flagBridge = "bridge" // ipvlan flag bridge (default)
flagPrivate = "private" // ipvlan flag private
flagVepa = "vepa" // ipvlan flag vepa
)
type endpointTable map[string]*endpoint

View File

@ -43,7 +43,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return fmt.Errorf("error generating an interface name: %v", err)
}
// create the netlink ipvlan interface
vethName, err := createIPVlan(containerIfName, n.config.Parent, n.config.IpvlanMode)
vethName, err := createIPVlan(containerIfName, n.config.Parent, n.config.IpvlanMode, n.config.IpvlanFlag)
if err != nil {
return err
}
@ -54,7 +54,8 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return fmt.Errorf("could not find endpoint with id %s", eid)
}
if !n.config.Internal {
if n.config.IpvlanMode == modeL3 {
switch n.config.IpvlanMode {
case modeL3, modeL3S:
// disable gateway services to add a default gw using dev eth0 only
jinfo.DisableGatewayService()
defaultRoute, err := ifaceGateway(defaultV4RouteCidr)
@ -62,7 +63,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return err
}
if err := jinfo.AddStaticRoute(defaultRoute.Destination, defaultRoute.RouteType, defaultRoute.NextHop); err != nil {
return fmt.Errorf("failed to set an ipvlan l3 mode ipv4 default gateway: %v", err)
return fmt.Errorf("failed to set an ipvlan l3/l3s mode ipv4 default gateway: %v", err)
}
logrus.Debugf("Ipvlan Endpoint Joined with IPv4_Addr: %s, Ipvlan_Mode: %s, Parent: %s",
ep.addr.IP.String(), n.config.IpvlanMode, n.config.Parent)
@ -73,13 +74,12 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return err
}
if err = jinfo.AddStaticRoute(default6Route.Destination, default6Route.RouteType, default6Route.NextHop); err != nil {
return fmt.Errorf("failed to set an ipvlan l3 mode ipv6 default gateway: %v", err)
return fmt.Errorf("failed to set an ipvlan l3/l3s mode ipv6 default gateway: %v", err)
}
logrus.Debugf("Ipvlan Endpoint Joined with IPv6_Addr: %s, Ipvlan_Mode: %s, Parent: %s",
ep.addrv6.IP.String(), n.config.IpvlanMode, n.config.Parent)
}
}
if n.config.IpvlanMode == modeL2 {
case modeL2:
// parse and correlate the endpoint v4 address with the available v4 subnets
if len(n.config.Ipv4Subnets) > 0 {
s := n.getSubnetforIPv4(ep.addr)

View File

@ -50,9 +50,23 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo
config.IpvlanMode = modeL2
case modeL3:
config.IpvlanMode = modeL3
case modeL3S:
config.IpvlanMode = modeL3S
default:
return fmt.Errorf("requested ipvlan mode '%s' is not valid, 'l2' mode is the ipvlan driver default", config.IpvlanMode)
}
// verify the ipvlan flag from -o ipvlan_flag option
switch config.IpvlanFlag {
case "", flagBridge:
// default to bridge if -o ipvlan_flag is empty
config.IpvlanFlag = flagBridge
case flagPrivate:
config.IpvlanFlag = flagPrivate
case flagVepa:
config.IpvlanFlag = flagVepa
default:
return fmt.Errorf("requested ipvlan flag '%s' is not valid, 'bridge' is the ipvlan driver default", config.IpvlanFlag)
}
// loopback is not a valid parent link
if config.Parent == "lo" {
return fmt.Errorf("loopback interface is not a valid %s parent link", ipvlanType)
@ -234,6 +248,9 @@ func (config *configuration) fromOptions(labels map[string]string) error {
case driverModeOpt:
// parse driver option '-o ipvlan_mode'
config.IpvlanMode = value
case driverFlagOpt:
// parse driver option '-o ipvlan_flag'
config.IpvlanFlag = value
}
}
return nil

View File

@ -20,12 +20,17 @@ const (
)
// createIPVlan Create the ipvlan slave specifying the source name
func createIPVlan(containerIfName, parent, ipvlanMode string) (string, error) {
// Set the ipvlan mode. Default is bridge mode
func createIPVlan(containerIfName, parent, ipvlanMode, ipvlanFlag string) (string, error) {
// Set the ipvlan mode and flag. Default is L2 bridge
mode, err := setIPVlanMode(ipvlanMode)
if err != nil {
return "", fmt.Errorf("Unsupported %s ipvlan mode: %v", ipvlanMode, err)
}
// Set the ipvlan flag. Default is bridge
flag, err := setIPVlanFlag(ipvlanFlag)
if err != nil {
return "", fmt.Errorf("Unsupported %s ipvlan flag: %v", ipvlanFlag, err)
}
// verify the Docker host interface acting as the macvlan parent iface exists
if !parentExists(parent) {
return "", fmt.Errorf("the requested parent interface %s was not found on the Docker host", parent)
@ -42,6 +47,7 @@ func createIPVlan(containerIfName, parent, ipvlanMode string) (string, error) {
ParentIndex: parentLink.Attrs().Index,
},
Mode: mode,
Flag: flag,
}
if err := ns.NlHandle().LinkAdd(ipvlan); err != nil {
// If a user creates a macvlan and ipvlan on same parent, only one slave iface can be active at a time.
@ -51,18 +57,34 @@ func createIPVlan(containerIfName, parent, ipvlanMode string) (string, error) {
return ipvlan.Attrs().Name, nil
}
// setIPVlanMode setter for one of the two ipvlan port types
// setIPVlanMode setter for one of the three ipvlan port types
func setIPVlanMode(mode string) (netlink.IPVlanMode, error) {
switch mode {
case modeL2:
return netlink.IPVLAN_MODE_L2, nil
case modeL3:
return netlink.IPVLAN_MODE_L3, nil
case modeL3S:
return netlink.IPVLAN_MODE_L3S, nil
default:
return 0, fmt.Errorf("Unknown ipvlan mode: %s", mode)
}
}
// setIPVlanFlag setter for one of the three ipvlan port flags
func setIPVlanFlag(flag string) (netlink.IPVlanFlag, error) {
switch flag {
case flagBridge:
return netlink.IPVLAN_FLAG_BRIDGE, nil
case flagPrivate:
return netlink.IPVLAN_FLAG_PRIVATE, nil
case flagVepa:
return netlink.IPVLAN_FLAG_VEPA, nil
default:
return 0, fmt.Errorf("unknown ipvlan flag: %s", flag)
}
}
// parentExists check if the specified interface exists in the default namespace
func parentExists(ifaceStr string) bool {
_, err := ns.NlHandle().LinkByName(ifaceStr)

View File

@ -71,6 +71,14 @@ func TestSetIPVlanMode(t *testing.T) {
if mode != netlink.IPVLAN_MODE_L3 {
t.Fatalf("expected %d got %d", netlink.IPVLAN_MODE_L3, mode)
}
// test ipvlan l3s mode
mode, err = setIPVlanMode(modeL3S)
if err != nil {
t.Fatalf("error parsing %v vlan mode: %v", mode, err)
}
if mode != netlink.IPVLAN_MODE_L3S {
t.Fatalf("expected %d got %d", netlink.IPVLAN_MODE_L3S, mode)
}
// test invalid mode
mode, err = setIPVlanMode("foo")
if err == nil {
@ -88,3 +96,47 @@ func TestSetIPVlanMode(t *testing.T) {
t.Fatalf("expected 0 got %d", mode)
}
}
// TestSetIPVlanFlag tests the ipvlan flag setter
func TestSetIPVlanFlag(t *testing.T) {
// test ipvlan bridge flag
flag, err := setIPVlanFlag(flagBridge)
if err != nil {
t.Fatalf("error parsing %v vlan flag: %v", flag, err)
}
if flag != netlink.IPVLAN_FLAG_BRIDGE {
t.Fatalf("expected %d got %d", netlink.IPVLAN_FLAG_BRIDGE, flag)
}
// test ipvlan private flag
flag, err = setIPVlanFlag(flagPrivate)
if err != nil {
t.Fatalf("error parsing %v vlan flag: %v", flag, err)
}
if flag != netlink.IPVLAN_FLAG_PRIVATE {
t.Fatalf("expected %d got %d", netlink.IPVLAN_FLAG_PRIVATE, flag)
}
// test ipvlan vepa flag
flag, err = setIPVlanFlag(flagVepa)
if err != nil {
t.Fatalf("error parsing %v vlan flag: %v", flag, err)
}
if flag != netlink.IPVLAN_FLAG_VEPA {
t.Fatalf("expected %d got %d", netlink.IPVLAN_FLAG_VEPA, flag)
}
// test invalid flag
flag, err = setIPVlanFlag("foo")
if err == nil {
t.Fatal("invalid ipvlan flag should have returned an error")
}
if flag != 0 {
t.Fatalf("expected 0 got %d", flag)
}
// test null flag
flag, err = setIPVlanFlag("")
if err == nil {
t.Fatal("invalid ipvlan flag should have returned an error")
}
if flag != 0 {
t.Fatalf("expected 0 got %d", flag)
}
}

View File

@ -30,6 +30,7 @@ type configuration struct {
Internal bool
Parent string
IpvlanMode string
IpvlanFlag string
CreatedSlaveLink bool
Ipv4Subnets []*ipv4Subnet
Ipv6Subnets []*ipv6Subnet