Переглянути джерело

Add internal network support for bridge networks

Signed-off-by: Chun Chen <ramichen@tencent.com>
Chun Chen 9 роки тому
батько
коміт
7b64b1c293

+ 15 - 5
libnetwork/drivers/bridge/bridge.go

@@ -68,6 +68,7 @@ type networkConfiguration struct {
 	DefaultGatewayIPv6 net.IP
 	dbIndex            uint64
 	dbExists           bool
+	Internal           bool
 }
 
 // endpointConfiguration represents the user specified configuration for the sandbox endpoint
@@ -280,16 +281,25 @@ func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) {
 // from each of the other networks
 func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) error {
 	n.Lock()
-	thisIface := n.config.BridgeName
+	thisConfig := n.config
 	n.Unlock()
 
+	if thisConfig.Internal {
+		return nil
+	}
+
 	// Install the rules to isolate this networks against each of the other networks
 	for _, o := range others {
 		o.Lock()
-		otherIface := o.config.BridgeName
+		otherConfig := o.config
 		o.Unlock()
-		if thisIface != otherIface {
-			if err := setINC(thisIface, otherIface, enable); err != nil {
+
+		if otherConfig.Internal {
+			continue
+		}
+
+		if thisConfig.BridgeName != otherConfig.BridgeName {
+			if err := setINC(thisConfig.BridgeName, otherConfig.BridgeName, enable); err != nil {
 				return err
 			}
 		}
@@ -483,7 +493,7 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati
 
 	if val, ok := option[netlabel.Internal]; ok {
 		if internal, ok := val.(bool); ok && internal {
-			return nil, &driverapi.ErrNotImplemented{}
+			config.Internal = true
 		}
 	}
 

+ 48 - 26
libnetwork/drivers/bridge/setup_ip_tables.go

@@ -82,38 +82,46 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt
 		IP:   ipnet.IP.Mask(ipnet.Mask),
 		Mask: ipnet.Mask,
 	}
-	if err = setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
-		return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
-	}
-	n.registerIptCleanFunc(func() error {
-		return setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false)
-	})
+	if config.Internal {
+		if err = setupInternalNetworkRules(config.BridgeName, maskedAddrv4, true); err != nil {
+			return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
+		}
+		n.registerIptCleanFunc(func() error {
+			return setupInternalNetworkRules(config.BridgeName, maskedAddrv4, false)
+		})
+	} else {
+		if err = setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
+			return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
+		}
+		n.registerIptCleanFunc(func() error {
+			return setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false)
+		})
+		natChain, filterChain, _, err := n.getDriverChains()
+		if err != nil {
+			return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
+		}
 
-	natChain, filterChain, _, err := n.getDriverChains()
-	if err != nil {
-		return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
-	}
+		err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true)
+		if err != nil {
+			return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
+		}
 
-	err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true)
-	if err != nil {
-		return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
-	}
+		err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true)
+		if err != nil {
+			return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
+		}
 
-	err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true)
-	if err != nil {
-		return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
+		n.registerIptCleanFunc(func() error {
+			return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
+		})
+
+		n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName())
 	}
 
 	if err := ensureJumpRule("FORWARD", IsolationChain); err != nil {
 		return err
 	}
 
-	n.registerIptCleanFunc(func() error {
-		return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
-	})
-
-	n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName())
-
 	return nil
 }
 
@@ -312,12 +320,26 @@ func ensureJumpRule(fromChain, toChain string) error {
 
 func removeIPChains() {
 	for _, chainInfo := range []iptables.ChainInfo{
-		iptables.ChainInfo{Name: DockerChain, Table: iptables.Nat},
-		iptables.ChainInfo{Name: DockerChain, Table: iptables.Filter},
-		iptables.ChainInfo{Name: IsolationChain, Table: iptables.Filter},
+		{Name: DockerChain, Table: iptables.Nat},
+		{Name: DockerChain, Table: iptables.Filter},
+		{Name: IsolationChain, Table: iptables.Filter},
 	} {
 		if err := chainInfo.Remove(); err != nil {
 			logrus.Warnf("Failed to remove existing iptables entries in table %s chain %s : %v", chainInfo.Table, chainInfo.Name, err)
 		}
 	}
 }
+
+func setupInternalNetworkRules(bridgeIface string, addr net.Addr, insert bool) error {
+	var (
+		inDropRule  = iptRule{table: iptables.Filter, chain: IsolationChain, args: []string{"-i", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"}}
+		outDropRule = iptRule{table: iptables.Filter, chain: IsolationChain, args: []string{"-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"}}
+	)
+	if err := programChainRule(inDropRule, "DROP INCOMING", insert); err != nil {
+		return err
+	}
+	if err := programChainRule(outDropRule, "DROP OUTGOING", insert); err != nil {
+		return err
+	}
+	return nil
+}

+ 0 - 7
libnetwork/libnetwork_test.go

@@ -2352,10 +2352,3 @@ func TestParallel2(t *testing.T) {
 func TestParallel3(t *testing.T) {
 	runParallelTests(t, 3)
 }
-
-func TestNetworkInternal(t *testing.T) {
-	_, err := controller.NewNetwork(bridgeNetType, "testnetworkinternal", libnetwork.NetworkOptionInternalNetwork())
-	if err == nil || err.Error() != (&driverapi.ErrNotImplemented{}).Error() {
-		t.Fatal("bridge network can't be internal")
-	}
-}

+ 26 - 2
libnetwork/test/integration/dnet/bridge.bats

@@ -20,8 +20,10 @@ function test_single_network_connectivity() {
     # Now test connectivity between all the containers using service names
     for i in `seq ${start} ${end}`;
     do
-	runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_${i}) \
-	     "ping -c 1 www.google.com"
+    if [ "${nw_name}" != "internal" ]; then
+		runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_${i}) \
+		     "ping -c 1 www.google.com"
+    fi
 	for j in `seq ${start} ${end}`;
 	do
 	    if [ "$i" -eq "$j" ]; then
@@ -250,6 +252,7 @@ function test_single_network_connectivity() {
     dnet_cmd $(inst_id2port 1) network rm br1
 }
 
+
 @test "Test bridge network global alias support" {
     skip_for_circleci
     dnet_cmd $(inst_id2port 1) network create -d bridge br1
@@ -279,3 +282,24 @@ function test_single_network_connectivity() {
 
     dnet_cmd $(inst_id2port 1) network rm br1
 }
+
+@test "Test bridge network internal network" {
+    skip_for_circleci
+
+    echo $(docker ps)
+    dnet_cmd $(inst_id2port 1) network create -d bridge --internal internal
+    dnet_cmd $(inst_id2port 1) container create container_1
+    # connects to internal network, confirm it can't conmunicate with outside world
+    net_connect 1 container_1 internal
+    run runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_1) "ping -c 1 www.google.com"
+    [[ "$output" == *"1 packets transmitted, 0 packets received, 100% packet loss"* ]]
+    net_disconnect 1 container_1 internal
+    # connects to bridge network, confirm it can conmunicate with outside world
+    net_connect 1 container_1 bridge
+    runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_1) "ping -c 1 www.google.com"
+    net_disconnect 1 container_1 bridge
+    dnet_cmd $(inst_id2port 1) container rm container_1
+    # test conmunications within internal network
+    test_single_network_connectivity internal 3
+    dnet_cmd $(inst_id2port 1) network rm internal
+}