Merge pull request #42542 from zhangyoufu/libnetwork-ipvlan-enhance
drivers/ipvlan: add ipvlan_flag option, support l3s ipvlan_mode
This commit is contained in:
commit
3e7e81b68f
|
@ -17,14 +17,20 @@ const (
|
||||||
vethLen = 7
|
vethLen = 7
|
||||||
containerVethPrefix = "eth"
|
containerVethPrefix = "eth"
|
||||||
vethPrefix = "veth"
|
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
|
type endpointTable map[string]*endpoint
|
||||||
|
|
||||||
|
|
|
@ -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)
|
return fmt.Errorf("error generating an interface name: %v", err)
|
||||||
}
|
}
|
||||||
// create the netlink ipvlan interface
|
// 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 {
|
if err != nil {
|
||||||
return err
|
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)
|
return fmt.Errorf("could not find endpoint with id %s", eid)
|
||||||
}
|
}
|
||||||
if !n.config.Internal {
|
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
|
// disable gateway services to add a default gw using dev eth0 only
|
||||||
jinfo.DisableGatewayService()
|
jinfo.DisableGatewayService()
|
||||||
defaultRoute, err := ifaceGateway(defaultV4RouteCidr)
|
defaultRoute, err := ifaceGateway(defaultV4RouteCidr)
|
||||||
|
@ -62,7 +63,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := jinfo.AddStaticRoute(defaultRoute.Destination, defaultRoute.RouteType, defaultRoute.NextHop); err != nil {
|
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",
|
logrus.Debugf("Ipvlan Endpoint Joined with IPv4_Addr: %s, Ipvlan_Mode: %s, Parent: %s",
|
||||||
ep.addr.IP.String(), n.config.IpvlanMode, n.config.Parent)
|
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
|
return err
|
||||||
}
|
}
|
||||||
if err = jinfo.AddStaticRoute(default6Route.Destination, default6Route.RouteType, default6Route.NextHop); err != nil {
|
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",
|
logrus.Debugf("Ipvlan Endpoint Joined with IPv6_Addr: %s, Ipvlan_Mode: %s, Parent: %s",
|
||||||
ep.addrv6.IP.String(), n.config.IpvlanMode, n.config.Parent)
|
ep.addrv6.IP.String(), n.config.IpvlanMode, n.config.Parent)
|
||||||
}
|
}
|
||||||
}
|
case modeL2:
|
||||||
if n.config.IpvlanMode == modeL2 {
|
|
||||||
// parse and correlate the endpoint v4 address with the available v4 subnets
|
// parse and correlate the endpoint v4 address with the available v4 subnets
|
||||||
if len(n.config.Ipv4Subnets) > 0 {
|
if len(n.config.Ipv4Subnets) > 0 {
|
||||||
s := n.getSubnetforIPv4(ep.addr)
|
s := n.getSubnetforIPv4(ep.addr)
|
||||||
|
|
|
@ -50,9 +50,23 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo
|
||||||
config.IpvlanMode = modeL2
|
config.IpvlanMode = modeL2
|
||||||
case modeL3:
|
case modeL3:
|
||||||
config.IpvlanMode = modeL3
|
config.IpvlanMode = modeL3
|
||||||
|
case modeL3S:
|
||||||
|
config.IpvlanMode = modeL3S
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("requested ipvlan mode '%s' is not valid, 'l2' mode is the ipvlan driver default", config.IpvlanMode)
|
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
|
// loopback is not a valid parent link
|
||||||
if config.Parent == "lo" {
|
if config.Parent == "lo" {
|
||||||
return fmt.Errorf("loopback interface is not a valid %s parent link", ipvlanType)
|
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:
|
case driverModeOpt:
|
||||||
// parse driver option '-o ipvlan_mode'
|
// parse driver option '-o ipvlan_mode'
|
||||||
config.IpvlanMode = value
|
config.IpvlanMode = value
|
||||||
|
case driverFlagOpt:
|
||||||
|
// parse driver option '-o ipvlan_flag'
|
||||||
|
config.IpvlanFlag = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -20,12 +20,17 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// createIPVlan Create the ipvlan slave specifying the source name
|
// createIPVlan Create the ipvlan slave specifying the source name
|
||||||
func createIPVlan(containerIfName, parent, ipvlanMode string) (string, error) {
|
func createIPVlan(containerIfName, parent, ipvlanMode, ipvlanFlag string) (string, error) {
|
||||||
// Set the ipvlan mode. Default is bridge mode
|
// Set the ipvlan mode and flag. Default is L2 bridge
|
||||||
mode, err := setIPVlanMode(ipvlanMode)
|
mode, err := setIPVlanMode(ipvlanMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Unsupported %s ipvlan mode: %v", ipvlanMode, err)
|
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
|
// verify the Docker host interface acting as the macvlan parent iface exists
|
||||||
if !parentExists(parent) {
|
if !parentExists(parent) {
|
||||||
return "", fmt.Errorf("the requested parent interface %s was not found on the Docker host", 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,
|
ParentIndex: parentLink.Attrs().Index,
|
||||||
},
|
},
|
||||||
Mode: mode,
|
Mode: mode,
|
||||||
|
Flag: flag,
|
||||||
}
|
}
|
||||||
if err := ns.NlHandle().LinkAdd(ipvlan); err != nil {
|
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.
|
// 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
|
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) {
|
func setIPVlanMode(mode string) (netlink.IPVlanMode, error) {
|
||||||
switch mode {
|
switch mode {
|
||||||
case modeL2:
|
case modeL2:
|
||||||
return netlink.IPVLAN_MODE_L2, nil
|
return netlink.IPVLAN_MODE_L2, nil
|
||||||
case modeL3:
|
case modeL3:
|
||||||
return netlink.IPVLAN_MODE_L3, nil
|
return netlink.IPVLAN_MODE_L3, nil
|
||||||
|
case modeL3S:
|
||||||
|
return netlink.IPVLAN_MODE_L3S, nil
|
||||||
default:
|
default:
|
||||||
return 0, fmt.Errorf("Unknown ipvlan mode: %s", mode)
|
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
|
// parentExists check if the specified interface exists in the default namespace
|
||||||
func parentExists(ifaceStr string) bool {
|
func parentExists(ifaceStr string) bool {
|
||||||
_, err := ns.NlHandle().LinkByName(ifaceStr)
|
_, err := ns.NlHandle().LinkByName(ifaceStr)
|
||||||
|
|
|
@ -71,6 +71,14 @@ func TestSetIPVlanMode(t *testing.T) {
|
||||||
if mode != netlink.IPVLAN_MODE_L3 {
|
if mode != netlink.IPVLAN_MODE_L3 {
|
||||||
t.Fatalf("expected %d got %d", netlink.IPVLAN_MODE_L3, mode)
|
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
|
// test invalid mode
|
||||||
mode, err = setIPVlanMode("foo")
|
mode, err = setIPVlanMode("foo")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -88,3 +96,47 @@ func TestSetIPVlanMode(t *testing.T) {
|
||||||
t.Fatalf("expected 0 got %d", mode)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ type configuration struct {
|
||||||
Internal bool
|
Internal bool
|
||||||
Parent string
|
Parent string
|
||||||
IpvlanMode string
|
IpvlanMode string
|
||||||
|
IpvlanFlag string
|
||||||
CreatedSlaveLink bool
|
CreatedSlaveLink bool
|
||||||
Ipv4Subnets []*ipv4Subnet
|
Ipv4Subnets []*ipv4Subnet
|
||||||
Ipv6Subnets []*ipv6Subnet
|
Ipv6Subnets []*ipv6Subnet
|
||||||
|
|
Loading…
Reference in New Issue