Add internal network support for bridge networks

Signed-off-by: Chun Chen <ramichen@tencent.com>
This commit is contained in:
Chun Chen 2016-01-06 21:06:23 +08:00
parent 88040e2e05
commit 7b64b1c293
4 changed files with 89 additions and 40 deletions

View file

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

View file

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

View file

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

View file

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