Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor of docker PR #11405 #336

Merged
merged 1 commit into from
Jul 9, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions drivers/bridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,9 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err

// Add inter-network communication rules.
{config.EnableIPTables, setupNetworkIsolationRules},

//Configure bridge networking filtering if ICC is off and IP tables are enabled
{!config.EnableICC && config.EnableIPTables, setupBridgeNetFiltering},
} {
if step.Condition {
bridgeSetup.queueStep(step.Fn)
Expand Down
162 changes: 162 additions & 0 deletions drivers/bridge/setup_bridgenetfiltering.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package bridge

import (
"fmt"
"io/ioutil"
"os"
"syscall"

"github.com/Sirupsen/logrus"
)

// Enumeration type saying which versions of IP protocol to process.
type ipVersion int

const (
ipvnone ipVersion = iota
ipv4
ipv6
ipvboth
)

//Gets the IP version in use ( [ipv4], [ipv6] or [ipv4 and ipv6] )
func getIPVersion(config *networkConfiguration) ipVersion {
ipVersion := ipv4
if config.FixedCIDRv6 != nil || config.EnableIPv6 {
ipVersion |= ipv6
}
return ipVersion
}

func setupBridgeNetFiltering(config *networkConfiguration, i *bridgeInterface) error {
err := checkBridgeNetFiltering(config, i)
if err != nil {
if ptherr, ok := err.(*os.PathError); ok {
if errno, ok := ptherr.Err.(syscall.Errno); ok && errno == syscall.ENOENT {
if isRunningInContainer() {
logrus.Warnf("running inside docker container, ignoring missing kernel params: %v", err)
err = nil
} else {
err = fmt.Errorf("please ensure that br_netfilter kernel module is loaded")
}
}
}
if err != nil {
return fmt.Errorf("cannot restrict inter-container communication: %v", err)
}
}
return nil
}

//Enable bridge net filtering if ip forwarding is enabled. See github issue #11404
func checkBridgeNetFiltering(config *networkConfiguration, i *bridgeInterface) error {
ipVer := getIPVersion(config)
iface := config.BridgeName
doEnable := func(ipVer ipVersion) error {
var ipVerName string
if ipVer == ipv4 {
ipVerName = "IPv4"
} else {
ipVerName = "IPv6"
}
enabled, err := isPacketForwardingEnabled(ipVer, iface)
if err != nil {
logrus.Warnf("failed to check %s forwarding: %v", ipVerName, err)
} else if enabled {
enabled, err := getKernelBoolParam(getBridgeNFKernelParam(ipVer))
if err != nil || enabled {
return err
}
return setKernelBoolParam(getBridgeNFKernelParam(ipVer), true)
}
return nil
}

switch ipVer {
case ipv4, ipv6:
return doEnable(ipVer)
case ipvboth:
v4err := doEnable(ipv4)
v6err := doEnable(ipv6)
if v4err == nil {
return v6err
}
return v4err
default:
return nil
}
}

// Get kernel param path saying whether IPv${ipVer} traffic is being forwarded
// on particular interface. Interface may be specified for IPv6 only. If
// `iface` is empty, `default` will be assumed, which represents default value
// for new interfaces.
func getForwardingKernelParam(ipVer ipVersion, iface string) string {
switch ipVer {
case ipv4:
return "/proc/sys/net/ipv4/ip_forward"
case ipv6:
if iface == "" {
iface = "default"
}
return fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/forwarding", iface)
default:
return ""
}
}

// Get kernel param path saying whether bridged IPv${ipVer} traffic shall be
// passed to ip${ipVer}tables' chains.
func getBridgeNFKernelParam(ipVer ipVersion) string {
switch ipVer {
case ipv4:
return "/proc/sys/net/bridge/bridge-nf-call-iptables"
case ipv6:
return "/proc/sys/net/bridge/bridge-nf-call-ip6tables"
default:
return ""
}
}

//Gets the value of the kernel parameters located at the given path
func getKernelBoolParam(path string) (bool, error) {
enabled := false
line, err := ioutil.ReadFile(path)
if err != nil {
return false, err
}
if len(line) > 0 {
enabled = line[0] == '1'
}
return enabled, err
}

//Sets the value of the kernel parameter located at the given path
func setKernelBoolParam(path string, on bool) error {
value := byte('0')
if on {
value = byte('1')
}
return ioutil.WriteFile(path, []byte{value, '\n'}, 0644)
}

//Checks to see if packet forwarding is enabled
func isPacketForwardingEnabled(ipVer ipVersion, iface string) (bool, error) {
switch ipVer {
case ipv4, ipv6:
return getKernelBoolParam(getForwardingKernelParam(ipVer, iface))
case ipvboth:
enabled, err := getKernelBoolParam(getForwardingKernelParam(ipv4, ""))
if err != nil || !enabled {
return enabled, err
}
return getKernelBoolParam(getForwardingKernelParam(ipv6, iface))
default:
return true, nil
}
}

func isRunningInContainer() bool {
_, err := os.Stat("/.dockerinit")
return !os.IsNotExist(err)
}
12 changes: 12 additions & 0 deletions drivers/bridge/setup_bridgenetfiltering_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package bridge

import "testing"

func TestIPConstantValues(t *testing.T) {
if ipv4|ipv6 != ipvboth {
t.Fatalf("bitwise or of ipv4(%04b) and ipv6(%04b) must yield ipvboth(%04b)", ipv4, ipv6, ipvboth)
}
if ipvboth&(^(ipv4 | ipv6)) != ipvnone {
t.Fatalf("ipvboth(%04b) with unset ipv4(%04b) and ipv6(%04b) bits shall equal to ipvnone", ipvboth, ipv4, ipv6)
}
}