From 38f78286c730c14208621a29ccd8298fd5f7ba13 Mon Sep 17 00:00:00 2001 From: David Wragg Date: Mon, 2 Nov 2015 15:53:16 +0000 Subject: [PATCH] Probe whether the kernel has ODP vxlan support It's possible to build that kernel with openvswitch, and vxlan, but without the vport_vxlan module that glues them together. And at least one distro has actually done this. --- prog/weaver/main.go | 9 ++++++--- router/odp.go | 43 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/prog/weaver/main.go b/prog/weaver/main.go index bf85b916..634bb46c 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -13,7 +13,6 @@ import ( "github.com/davecheney/profile" "github.com/docker/docker/pkg/mflag" "github.com/gorilla/mux" - "github.com/weaveworks/go-odp/odp" . "github.com/weaveworks/weave/common" "github.com/weaveworks/weave/common/docker" @@ -119,8 +118,12 @@ func main() { os.Exit(0) case createDatapath: - err := weave.CreateDatapath(datapathName) - if odp.IsKernelLacksODPError(err) { + err, odp_supported := weave.CreateDatapath(datapathName) + if !odp_supported { + if err != nil { + Log.Error(err) + } + // When the kernel lacks ODP support, exit // with a special status to distinguish it for // the weave script. diff --git a/router/odp.go b/router/odp.go index cea42dd5..d772d930 100644 --- a/router/odp.go +++ b/router/odp.go @@ -1,25 +1,58 @@ package router import ( + "fmt" + "net" + "syscall" + "github.com/weaveworks/go-odp/odp" ) // ODP admin functionality -func CreateDatapath(dpname string) error { +func CreateDatapath(dpname string) (err error, supported bool) { dpif, err := odp.NewDpif() if err != nil { - return err + if odp.IsKernelLacksODPError(err) { + return nil, false + } + + return err, true } defer dpif.Close() - _, err = dpif.CreateDatapath(dpname) + dp, err := dpif.CreateDatapath(dpname) if err != nil && !odp.IsDatapathNameAlreadyExistsError(err) { - return err + return err, true } - return nil + // Pick an ephemeral port number to use in probing for vxlan + // support. + udpconn, err := net.ListenUDP("udp4", nil) + if err != nil { + return err, true + } + + // we leave the UDP socket open, so creating a vxlan vport on + // the same port number should fail. But that's fine: It's + // still sufficient to probe for support. + portno := uint16(udpconn.LocalAddr().(*net.UDPAddr).Port) + vpid, err := dp.CreateVport(odp.NewVxlanVportSpec( + fmt.Sprintf("vxlan-%d", portno), portno)) + if nlerr, ok := err.(odp.NetlinkError); ok { + if syscall.Errno(nlerr) == syscall.EAFNOSUPPORT { + dp.Delete() + return fmt.Errorf("kernel does not have Open vSwitch VXLAN support"), false + } + } + + if err == nil { + dp.DeleteVport(vpid) + } + + udpconn.Close() + return nil, true } func DeleteDatapath(dpname string) error {