mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
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
6 changed files with 114 additions and 16 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ type configuration struct {
|
|||
Internal bool
|
||||
Parent string
|
||||
IpvlanMode string
|
||||
IpvlanFlag string
|
||||
CreatedSlaveLink bool
|
||||
Ipv4Subnets []*ipv4Subnet
|
||||
Ipv6Subnets []*ipv6Subnet
|
||||
|
|
Loading…
Add table
Reference in a new issue