Selaa lähdekoodia

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

drivers/ipvlan: add ipvlan_flag option, support l3s ipvlan_mode
Brian Goff 3 vuotta sitten
vanhempi
commit
3e7e81b68f

+ 13 - 7
libnetwork/drivers/ipvlan/ipvlan.go

@@ -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
 

+ 6 - 6
libnetwork/drivers/ipvlan/ipvlan_joinleave.go

@@ -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)

+ 17 - 0
libnetwork/drivers/ipvlan/ipvlan_network.go

@@ -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

+ 25 - 3
libnetwork/drivers/ipvlan/ipvlan_setup.go

@@ -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)

+ 52 - 0
libnetwork/drivers/ipvlan/ipvlan_setup_test.go

@@ -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)
+	}
+}

+ 1 - 0
libnetwork/drivers/ipvlan/ipvlan_store.go

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