mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Add internal network support for bridge networks
Signed-off-by: Chun Chen <ramichen@tencent.com>
This commit is contained in:
parent
88040e2e05
commit
7b64b1c293
4 changed files with 89 additions and 40 deletions
|
@ -68,6 +68,7 @@ type networkConfiguration struct {
|
||||||
DefaultGatewayIPv6 net.IP
|
DefaultGatewayIPv6 net.IP
|
||||||
dbIndex uint64
|
dbIndex uint64
|
||||||
dbExists bool
|
dbExists bool
|
||||||
|
Internal bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// endpointConfiguration represents the user specified configuration for the sandbox endpoint
|
// 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
|
// from each of the other networks
|
||||||
func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) error {
|
func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) error {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
thisIface := n.config.BridgeName
|
thisConfig := n.config
|
||||||
n.Unlock()
|
n.Unlock()
|
||||||
|
|
||||||
|
if thisConfig.Internal {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Install the rules to isolate this networks against each of the other networks
|
// Install the rules to isolate this networks against each of the other networks
|
||||||
for _, o := range others {
|
for _, o := range others {
|
||||||
o.Lock()
|
o.Lock()
|
||||||
otherIface := o.config.BridgeName
|
otherConfig := o.config
|
||||||
o.Unlock()
|
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
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -483,7 +493,7 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati
|
||||||
|
|
||||||
if val, ok := option[netlabel.Internal]; ok {
|
if val, ok := option[netlabel.Internal]; ok {
|
||||||
if internal, ok := val.(bool); ok && internal {
|
if internal, ok := val.(bool); ok && internal {
|
||||||
return nil, &driverapi.ErrNotImplemented{}
|
config.Internal = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,38 +82,46 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt
|
||||||
IP: ipnet.IP.Mask(ipnet.Mask),
|
IP: ipnet.IP.Mask(ipnet.Mask),
|
||||||
Mask: ipnet.Mask,
|
Mask: ipnet.Mask,
|
||||||
}
|
}
|
||||||
if err = setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
|
if config.Internal {
|
||||||
return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
|
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 setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false)
|
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()
|
err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
|
return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true)
|
err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
|
return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true)
|
n.registerIptCleanFunc(func() error {
|
||||||
if err != nil {
|
return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
|
||||||
return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
|
})
|
||||||
|
|
||||||
|
n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ensureJumpRule("FORWARD", IsolationChain); err != nil {
|
if err := ensureJumpRule("FORWARD", IsolationChain); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
n.registerIptCleanFunc(func() error {
|
|
||||||
return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
|
|
||||||
})
|
|
||||||
|
|
||||||
n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName())
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,12 +320,26 @@ func ensureJumpRule(fromChain, toChain string) error {
|
||||||
|
|
||||||
func removeIPChains() {
|
func removeIPChains() {
|
||||||
for _, chainInfo := range []iptables.ChainInfo{
|
for _, chainInfo := range []iptables.ChainInfo{
|
||||||
iptables.ChainInfo{Name: DockerChain, Table: iptables.Nat},
|
{Name: DockerChain, Table: iptables.Nat},
|
||||||
iptables.ChainInfo{Name: DockerChain, Table: iptables.Filter},
|
{Name: DockerChain, Table: iptables.Filter},
|
||||||
iptables.ChainInfo{Name: IsolationChain, Table: iptables.Filter},
|
{Name: IsolationChain, Table: iptables.Filter},
|
||||||
} {
|
} {
|
||||||
if err := chainInfo.Remove(); err != nil {
|
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)
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -2352,10 +2352,3 @@ func TestParallel2(t *testing.T) {
|
||||||
func TestParallel3(t *testing.T) {
|
func TestParallel3(t *testing.T) {
|
||||||
runParallelTests(t, 3)
|
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,8 +20,10 @@ function test_single_network_connectivity() {
|
||||||
# Now test connectivity between all the containers using service names
|
# Now test connectivity between all the containers using service names
|
||||||
for i in `seq ${start} ${end}`;
|
for i in `seq ${start} ${end}`;
|
||||||
do
|
do
|
||||||
runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_${i}) \
|
if [ "${nw_name}" != "internal" ]; then
|
||||||
"ping -c 1 www.google.com"
|
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}`;
|
for j in `seq ${start} ${end}`;
|
||||||
do
|
do
|
||||||
if [ "$i" -eq "$j" ]; then
|
if [ "$i" -eq "$j" ]; then
|
||||||
|
@ -250,6 +252,7 @@ function test_single_network_connectivity() {
|
||||||
dnet_cmd $(inst_id2port 1) network rm br1
|
dnet_cmd $(inst_id2port 1) network rm br1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@test "Test bridge network global alias support" {
|
@test "Test bridge network global alias support" {
|
||||||
skip_for_circleci
|
skip_for_circleci
|
||||||
dnet_cmd $(inst_id2port 1) network create -d bridge br1
|
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
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue