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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue