Merge pull request #2327 from weaveworks/issues/1960-mcast-option

Add an option to disable multicast route per-network

Fixes #1960.
This commit is contained in:
Matthias Radestock committed 2016-06-06 15:49:09 +01:00
commit 7ffbeead8d
6 files changed
+129 -30

No files matched your search

+88 -12
View File
@@ -2,9 +2,11 @@ package plugin
import (
"fmt"
"strconv"
"sync"
"github.com/docker/libnetwork/drivers/remote/api"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/types"
"github.com/vishvananda/netlink"
@@ -15,18 +17,28 @@ import (
"github.com/weaveworks/weave/plugin/skel"
)
type driver struct {
scope string
noMulticastRoute bool
sync.RWMutex
endpoints map[string]struct{}
const (
MulticastOption = "works.weave.multicast"
)
type network struct {
hasMulticastRoute bool
}
func New(client *docker.Client, weave *weaveapi.Client, scope string, noMulticastRoute bool) (skel.Driver, error) {
type driver struct {
scope string
docker *docker.Client
sync.RWMutex
endpoints map[string]struct{}
networks map[string]network
}
func New(client *docker.Client, weave *weaveapi.Client, scope string) (skel.Driver, error) {
driver := &driver{
noMulticastRoute: noMulticastRoute,
scope: scope,
endpoints: make(map[string]struct{}),
scope: scope,
docker: client,
endpoints: make(map[string]struct{}),
networks: make(map[string]network),
}
_, err := NewWatcher(client, weave, driver)
@@ -49,11 +61,33 @@ func (driver *driver) GetCapabilities() (*api.GetCapabilityResponse, error) {
func (driver *driver) CreateNetwork(create *api.CreateNetworkRequest) error {
driver.logReq("CreateNetwork", create, create.NetworkID)
_, err := driver.setupNetworkInfo(create.NetworkID, stringOptions(create))
return err
}
// Deal with excessively-generic way the options get decoded from JSON
func stringOptions(create *api.CreateNetworkRequest) map[string]string {
if create.Options != nil {
if data, found := create.Options[netlabel.GenericData]; found {
if options, ok := data.(map[string]interface{}); ok {
out := make(map[string]string, len(options))
for key, value := range options {
if str, ok := value.(string); ok {
out[key] = str
}
}
return out
}
}
}
return nil
}
func (driver *driver) DeleteNetwork(delete *api.DeleteNetworkRequest) error {
driver.logReq("DeleteNetwork", delete, delete.NetworkID)
func (driver *driver) DeleteNetwork(delreq *api.DeleteNetworkRequest) error {
driver.logReq("DeleteNetwork", delreq, delreq.NetworkID)
driver.Lock()
delete(driver.networks, delreq.NetworkID)
driver.Unlock()
return nil
}
@@ -96,6 +130,10 @@ func (driver *driver) EndpointInfo(req *api.EndpointInfoRequest) (*api.EndpointI
func (driver *driver) JoinEndpoint(j *api.JoinRequest) (*api.JoinResponse, error) {
driver.logReq("JoinEndpoint", j, fmt.Sprintf("%s:%s to %s", j.NetworkID, j.EndpointID, j.SandboxKey))
network, err := driver.findNetworkInfo(j.NetworkID)
if err != nil {
return nil, driver.error("JoinEndpoint", "unable to find network info: %s", err)
}
name, peerName := vethPair(j.EndpointID)
if _, err := weavenet.CreateAndAttachVeth(name, peerName, weavenet.WeaveBridgeName, 0, nil); err != nil {
return nil, driver.error("JoinEndpoint", "%s", err)
@@ -107,7 +145,7 @@ func (driver *driver) JoinEndpoint(j *api.JoinRequest) (*api.JoinResponse, error
DstPrefix: weavenet.VethName,
},
}
if !driver.noMulticastRoute {
if network.hasMulticastRoute {
multicastRoute := api.StaticRoute{
Destination: "224.0.0.0/4",
RouteType: types.CONNECTED,
@@ -118,6 +156,44 @@ func (driver *driver) JoinEndpoint(j *api.JoinRequest) (*api.JoinResponse, error
return response, nil
}
func (driver *driver) findNetworkInfo(id string) (network, error) {
driver.Lock()
network, found := driver.networks[id]
driver.Unlock()
if found {
return network, nil
}
info, err := driver.docker.NetworkInfo(id)
if err != nil {
return network, err
}
return driver.setupNetworkInfo(id, info.Options)
}
func (driver *driver) setupNetworkInfo(id string, options map[string]string) (network, error) {
var network network
for key, value := range options {
switch key {
case MulticastOption:
if value == "" { // interpret "--opt works.weave.multicast" as "turn it on"
network.hasMulticastRoute = true
} else {
var err error
if network.hasMulticastRoute, err = strconv.ParseBool(value); err != nil {
return network, fmt.Errorf("unrecognized value %q for option %s", value, key)
}
}
default:
driver.warn("setupNetworkInfo", "unrecognized option: %s", key)
}
}
driver.Lock()
driver.networks[id] = network
driver.Unlock()
return network, nil
}
func (driver *driver) LeaveEndpoint(leave *api.LeaveRequest) error {
driver.logReq("LeaveEndpoint", leave, fmt.Sprintf("%s:%s", leave.NetworkID, leave.EndpointID))
+10 -7
View File
@@ -42,7 +42,7 @@ func main() {
flag.StringVar(&logLevel, "log-level", "info", "logging level (debug, info, warning, error)")
flag.StringVar(&address, "socket", "/run/docker/plugins/weave.sock", "socket on which to listen")
flag.StringVar(&meshAddress, "meshsocket", "/run/docker/plugins/weavemesh.sock", "socket on which to listen in mesh mode")
flag.BoolVar(&noMulticastRoute, "no-multicast-route", false, "do not add a multicast route to network endpoints")
flag.BoolVar(&noMulticastRoute, "no-multicast-route", false, "deprecated (this is now the default)")
flag.Parse()
@@ -73,18 +73,21 @@ func main() {
}
Log.Println("Weave plugin", version, "Command line options:", os.Args[1:])
if noMulticastRoute {
Log.Warning("--no-multicast-route option has been removed; multicast is off by default")
}
Log.Info(dockerClient.Info())
err = run(dockerClient, weave, address, meshAddress, noMulticastRoute)
err = run(dockerClient, weave, address, meshAddress)
if err != nil {
Log.Fatal(err)
}
}
func run(dockerClient *docker.Client, weave *weaveapi.Client, address, meshAddress string, noMulticastRoute bool) error {
func run(dockerClient *docker.Client, weave *weaveapi.Client, address, meshAddress string) error {
endChan := make(chan error, 1)
if address != "" {
globalListener, err := listenAndServe(dockerClient, weave, address, noMulticastRoute, endChan, "global", false)
globalListener, err := listenAndServe(dockerClient, weave, address, endChan, "global", false)
if err != nil {
return err
}
@@ -92,7 +95,7 @@ func run(dockerClient *docker.Client, weave *weaveapi.Client, address, meshAddre
defer globalListener.Close()
}
if meshAddress != "" {
meshListener, err := listenAndServe(dockerClient, weave, meshAddress, noMulticastRoute, endChan, "local", true)
meshListener, err := listenAndServe(dockerClient, weave, meshAddress, endChan, "local", true)
if err != nil {
return err
}
@@ -117,8 +120,8 @@ func run(dockerClient *docker.Client, weave *weaveapi.Client, address, meshAddre
}
}
func listenAndServe(dockerClient *docker.Client, weave *weaveapi.Client, address string, noMulticastRoute bool, endChan chan<- error, scope string, withIpam bool) (net.Listener, error) {
d, err := netplugin.New(dockerClient, weave, scope, noMulticastRoute)
func listenAndServe(dockerClient *docker.Client, weave *weaveapi.Client, address string, endChan chan<- error, scope string, withIpam bool) (net.Listener, error) {
d, err := netplugin.New(dockerClient, weave, scope)
if err != nil {
return nil, err
}
+4 -1
View File
@@ -4,7 +4,9 @@ package main
import (
"fmt"
"github.com/fsouza/go-dockerclient"
docker "github.com/fsouza/go-dockerclient"
"github.com/weaveworks/weave/plugin/net"
)
func createPluginNetwork(args []string) error {
@@ -23,6 +25,7 @@ func createPluginNetwork(args []string) error {
CheckDuplicate: true,
Driver: driverName,
IPAM: docker.IPAMOptions{Driver: driverName},
Options: map[string]interface{}{plugin.MulticastOption: "true"},
})
if err != docker.ErrNetworkAlreadyExists && err != nil {
// Despite appearances to the contrary, CreateNetwork does
+2 -7
View File
@@ -22,7 +22,8 @@ After you've launched Weave Net and peered your hosts, you can start containers
$ docker run --net=weave -ti ubuntu
on any of the hosts, and they can all communicate with each other.
on any of the hosts, and they can all communicate with each other
using any protocol, even multicast.
>**Warning!** It is inadvisable to attach containers to the Weave network using the Weave Docker Networking Plugin and Weave Docker API Proxy simultaneously. Such containers will end up with two Weave network interfaces and two IP addresses, which is rarely desirable. To ensure that the proxy is not being used, do not run `eval $(weave env)`, or `docker $(weave config) ...`.
@@ -82,12 +83,6 @@ The plugin configuration parameters are:
how much information to emit for debugging.
* `--no-restart` -- remove the default policy of `--restart=always`, if
you want to control start-up of the plugin yourself
* `--no-multicast-route` -- stops weave from adding a static IP route for
multicast traffic onto its interface
By default, multicast traffic is routed over the weave network.
To turn this off, e.g. you want to configure your own multicast
route, add the `--no-multicast-route` flag to `weave launch-plugin`.
**See Also**
+9
View File
@@ -26,6 +26,15 @@ store, but the first part of
>**Note:** In the case of multiple networks using the `weave` driver, all containers are on the same virtual network but Docker allocates their addresses on different subnets so they cannot talk to each other directly.
The plugin accepts the following options via `docker network create ... --opt`:
* `works.weave.multicast` -- tells weave to add a static IP
route for multicast traffic onto its interface.
>**Note:** If you connect a container to multiple Weave networks, at
most one of them can have the multicast route enabled. The `weave`
network created when the plugin is first launched has the multicast
option turned on, but for any networks you create it defaults to off.
**See Also**
+16 -3
View File
@@ -8,10 +8,13 @@ show_multicast_route_on() {
start_suite "--no-multicast-route operation"
# In case one is left around from a previous test
$SSH $HOST1 docker network rm testmcasttrue testmcastfalse >/dev/null 2>&1 || true
# Ensure containers run either way have no multicast route
weave_on $HOST1 launch-router
weave_on $HOST1 launch-proxy --no-multicast-route
weave_on $HOST1 launch-plugin --no-multicast-route
weave_on $HOST1 launch-plugin # plugin defaults to multicast off except for 'net=weave'
start_container $HOST1 --no-multicast-route --name c1
proxy_start_container $HOST1 --name c2
@@ -19,7 +22,16 @@ start_container_local_plugin $HOST1 --name=c3
assert "show_multicast_route_on $HOST1 c1"
assert "show_multicast_route_on $HOST1 c2"
assert "show_multicast_route_on $HOST1 c3"
assert "show_multicast_route_on $HOST1 c3" "224.0.0.0/4 dev ethwe0 "
# Now try via docker network options
# using ssh rather than docker -H because CircleCI docker client is older
$SSH $HOST1 docker network create --driver weavemesh --ipam-driver weavemesh --opt works.weave.multicast=false testmcastfalse
$SSH $HOST1 docker run --net=testmcastfalse --name c4 -di $SMALL_IMAGE /bin/sh
assert "show_multicast_route_on $HOST1 c4"
$SSH $HOST1 docker network create --driver weavemesh --ipam-driver weavemesh --opt works.weave.multicast testmcasttrue
$SSH $HOST1 docker run --net=testmcasttrue --name c5 -di $SMALL_IMAGE /bin/sh
assert "show_multicast_route_on $HOST1 c5" "224.0.0.0/4 dev ethwe0 "
# Ensure current proxy options are obeyed on container start
docker_on $HOST1 stop -t 1 c2
@@ -30,6 +42,7 @@ proxy docker_on $HOST1 start c2
assert "show_multicast_route_on $HOST1 c2" "224.0.0.0/4 dev ethwe "
docker_on $HOST1 rm -f c3
docker_on $HOST1 rm -f c3 c4 c5
$SSH $HOST1 docker network rm testmcasttrue testmcastfalse
end_suite