Invert multicast option in plugin

Now it's off by default, and there is an option to enable the
multicast route per-network.
We turn it on for the `weave` network created when we start the plugin.
This commit is contained in:
Bryan Boreham committed 2016-06-02 12:52:30 +01:00
1 parent b1fa417381
commit a1c3cba363
5 files changed
+125 -23

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
+7
View File
@@ -26,6 +26,13 @@ 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.
**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