|
@@ -1,23 +1,26 @@
|
|
package main
|
|
package main
|
|
|
|
|
|
import (
|
|
import (
|
|
|
|
+ "encoding/json"
|
|
"flag"
|
|
"flag"
|
|
"fmt"
|
|
"fmt"
|
|
"net"
|
|
"net"
|
|
"os"
|
|
"os"
|
|
|
|
+ "os/signal"
|
|
"path"
|
|
"path"
|
|
|
|
+ "strings"
|
|
|
|
+ "syscall"
|
|
"time"
|
|
"time"
|
|
|
|
|
|
"github.com/coreos/rudder/Godeps/_workspace/src/github.com/coreos/go-systemd/daemon"
|
|
"github.com/coreos/rudder/Godeps/_workspace/src/github.com/coreos/go-systemd/daemon"
|
|
log "github.com/coreos/rudder/Godeps/_workspace/src/github.com/golang/glog"
|
|
log "github.com/coreos/rudder/Godeps/_workspace/src/github.com/golang/glog"
|
|
|
|
|
|
|
|
+ "github.com/coreos/rudder/backend"
|
|
"github.com/coreos/rudder/pkg/ip"
|
|
"github.com/coreos/rudder/pkg/ip"
|
|
|
|
+ "github.com/coreos/rudder/pkg/task"
|
|
"github.com/coreos/rudder/subnet"
|
|
"github.com/coreos/rudder/subnet"
|
|
- "github.com/coreos/rudder/udp"
|
|
|
|
-)
|
|
|
|
-
|
|
|
|
-const (
|
|
|
|
- defaultPort = 8285
|
|
|
|
|
|
+ "github.com/coreos/rudder/backend/alloc"
|
|
|
|
+ "github.com/coreos/rudder/backend/udp"
|
|
)
|
|
)
|
|
|
|
|
|
type CmdLineOpts struct {
|
|
type CmdLineOpts struct {
|
|
@@ -26,7 +29,6 @@ type CmdLineOpts struct {
|
|
help bool
|
|
help bool
|
|
version bool
|
|
version bool
|
|
ipMasq bool
|
|
ipMasq bool
|
|
- port int
|
|
|
|
subnetFile string
|
|
subnetFile string
|
|
iface string
|
|
iface string
|
|
}
|
|
}
|
|
@@ -36,7 +38,6 @@ var opts CmdLineOpts
|
|
func init() {
|
|
func init() {
|
|
flag.StringVar(&opts.etcdEndpoint, "etcd-endpoint", "http://127.0.0.1:4001", "etcd endpoint")
|
|
flag.StringVar(&opts.etcdEndpoint, "etcd-endpoint", "http://127.0.0.1:4001", "etcd endpoint")
|
|
flag.StringVar(&opts.etcdPrefix, "etcd-prefix", "/coreos.com/network", "etcd prefix")
|
|
flag.StringVar(&opts.etcdPrefix, "etcd-prefix", "/coreos.com/network", "etcd prefix")
|
|
- flag.IntVar(&opts.port, "port", defaultPort, "port to use for inter-node communications")
|
|
|
|
flag.StringVar(&opts.subnetFile, "subnet-file", "/run/rudder/subnet.env", "filename where env variables (subnet and MTU values) will be written to")
|
|
flag.StringVar(&opts.subnetFile, "subnet-file", "/run/rudder/subnet.env", "filename where env variables (subnet and MTU values) will be written to")
|
|
flag.StringVar(&opts.iface, "iface", "", "interface to use (IP or name) for inter-host communication")
|
|
flag.StringVar(&opts.iface, "iface", "", "interface to use (IP or name) for inter-host communication")
|
|
flag.BoolVar(&opts.ipMasq, "ip-masq", false, "setup IP masquerade rule for traffic destined outside of overlay network")
|
|
flag.BoolVar(&opts.ipMasq, "ip-masq", false, "setup IP masquerade rule for traffic destined outside of overlay network")
|
|
@@ -44,10 +45,10 @@ func init() {
|
|
flag.BoolVar(&opts.version, "version", false, "print version and exit")
|
|
flag.BoolVar(&opts.version, "version", false, "print version and exit")
|
|
}
|
|
}
|
|
|
|
|
|
-func writeSubnet(sn ip.IP4Net, mtu int) error {
|
|
|
|
|
|
+func writeSubnetFile(sn *backend.SubnetDef) error {
|
|
// Write out the first usable IP by incrementing
|
|
// Write out the first usable IP by incrementing
|
|
// sn.IP by one
|
|
// sn.IP by one
|
|
- sn.IP += 1
|
|
|
|
|
|
+ sn.Net.IP += 1
|
|
|
|
|
|
dir, _ := path.Split(opts.subnetFile)
|
|
dir, _ := path.Split(opts.subnetFile)
|
|
os.MkdirAll(dir, 0755)
|
|
os.MkdirAll(dir, 0755)
|
|
@@ -58,49 +59,47 @@ func writeSubnet(sn ip.IP4Net, mtu int) error {
|
|
}
|
|
}
|
|
defer f.Close()
|
|
defer f.Close()
|
|
|
|
|
|
- fmt.Fprintf(f, "RUDDER_SUBNET=%s\n", sn)
|
|
|
|
- fmt.Fprintf(f, "RUDDER_MTU=%d\n", mtu)
|
|
|
|
|
|
+ if _, err = fmt.Fprintf(f, "RUDDER_SUBNET=%s\n", sn.Net); err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ if _, err = fmt.Fprintf(f, "RUDDER_MTU=%d\n", sn.MTU); err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
-func lookupIface() (*net.Interface, net.IP) {
|
|
|
|
|
|
+func lookupIface() (*net.Interface, net.IP, error) {
|
|
var iface *net.Interface
|
|
var iface *net.Interface
|
|
- var tep net.IP
|
|
|
|
|
|
+ var ipaddr net.IP
|
|
var err error
|
|
var err error
|
|
|
|
|
|
if len(opts.iface) > 0 {
|
|
if len(opts.iface) > 0 {
|
|
- if tep = net.ParseIP(opts.iface); tep != nil {
|
|
|
|
- iface, err = ip.GetInterfaceByIP(tep)
|
|
|
|
|
|
+ if ipaddr = net.ParseIP(opts.iface); ipaddr != nil {
|
|
|
|
+ iface, err = ip.GetInterfaceByIP(ipaddr)
|
|
if err != nil {
|
|
if err != nil {
|
|
- log.Errorf("Error looking up interface %s: %s", opts.iface, err)
|
|
|
|
- return nil, nil
|
|
|
|
|
|
+ return nil, nil, fmt.Errorf("Error looking up interface %s: %s", opts.iface, err)
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
iface, err = net.InterfaceByName(opts.iface)
|
|
iface, err = net.InterfaceByName(opts.iface)
|
|
if err != nil {
|
|
if err != nil {
|
|
- log.Errorf("Error looking up interface %s: %s", opts.iface, err)
|
|
|
|
- return nil, nil
|
|
|
|
|
|
+ return nil, nil, fmt.Errorf("Error looking up interface %s: %s", opts.iface, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
log.Info("Determining IP address of default interface")
|
|
log.Info("Determining IP address of default interface")
|
|
- for {
|
|
|
|
- if iface, err = ip.GetDefaultGatewayIface(); err == nil {
|
|
|
|
- break
|
|
|
|
- }
|
|
|
|
- log.Error("Failed to get default interface: ", err)
|
|
|
|
- time.Sleep(time.Second)
|
|
|
|
|
|
+ if iface, err = ip.GetDefaultGatewayIface(); err != nil {
|
|
|
|
+ return nil, nil, fmt.Errorf("Failed to get default interface: %s", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if tep == nil {
|
|
|
|
- tep, err = ip.GetIfaceIP4Addr(iface)
|
|
|
|
|
|
+ if ipaddr == nil {
|
|
|
|
+ ipaddr, err = ip.GetIfaceIP4Addr(iface)
|
|
if err != nil {
|
|
if err != nil {
|
|
- log.Error("Failed to find IPv4 address for interface ", iface.Name)
|
|
|
|
|
|
+ return nil, nil, fmt.Errorf("Failed to find IPv4 address for interface %s", iface.Name)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- return iface, tep
|
|
|
|
|
|
+ return iface, ipaddr, nil
|
|
}
|
|
}
|
|
|
|
|
|
func makeSubnetManager() *subnet.SubnetManager {
|
|
func makeSubnetManager() *subnet.SubnetManager {
|
|
@@ -115,6 +114,68 @@ func makeSubnetManager() *subnet.SubnetManager {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func newBackend() (backend.Backend, error) {
|
|
|
|
+ sm := makeSubnetManager()
|
|
|
|
+ config := sm.GetConfig()
|
|
|
|
+
|
|
|
|
+ var bt struct {
|
|
|
|
+ Type string
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if len(config.Backend) == 0 {
|
|
|
|
+ bt.Type = "udp"
|
|
|
|
+ } else {
|
|
|
|
+ if err := json.Unmarshal(config.Backend, &bt); err != nil {
|
|
|
|
+ return nil, fmt.Errorf("Error decoding Backend property of config: %v", err)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ switch strings.ToLower(bt.Type) {
|
|
|
|
+ case "udp":
|
|
|
|
+ return udp.New(sm, config.Backend), nil
|
|
|
|
+ case "alloc":
|
|
|
|
+ return alloc.New(sm), nil
|
|
|
|
+ default:
|
|
|
|
+ return nil, fmt.Errorf("'%v': unknown backend type", bt.Type)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func run(be backend.Backend, exit chan int) {
|
|
|
|
+ var err error
|
|
|
|
+ defer func() {
|
|
|
|
+ if err == nil || err == task.ErrCanceled {
|
|
|
|
+ exit <- 0
|
|
|
|
+ } else {
|
|
|
|
+ log.Error(err)
|
|
|
|
+ exit <- 1
|
|
|
|
+ }
|
|
|
|
+ }()
|
|
|
|
+
|
|
|
|
+ iface, ipaddr, err := lookupIface()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if iface.MTU == 0 {
|
|
|
|
+ err = fmt.Errorf("Failed to determine MTU for %s interface", ipaddr)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ log.Infof("Using %s as external interface", ipaddr)
|
|
|
|
+
|
|
|
|
+ sn, err := be.Init(iface, ipaddr, opts.ipMasq)
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Error("Could not init %v backend: %v", be.Name(), err)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ writeSubnetFile(sn)
|
|
|
|
+ daemon.SdNotify("READY=1")
|
|
|
|
+
|
|
|
|
+ log.Infof("%s mode initialized", be.Name())
|
|
|
|
+ be.Run()
|
|
|
|
+}
|
|
|
|
+
|
|
func main() {
|
|
func main() {
|
|
// glog will log to tmp files by default. override so all entries
|
|
// glog will log to tmp files by default. override so all entries
|
|
// can flow into journald (if running under systemd)
|
|
// can flow into journald (if running under systemd)
|
|
@@ -134,17 +195,32 @@ func main() {
|
|
os.Exit(0)
|
|
os.Exit(0)
|
|
}
|
|
}
|
|
|
|
|
|
- iface, tep := lookupIface()
|
|
|
|
- if iface == nil || tep == nil {
|
|
|
|
- return
|
|
|
|
|
|
+ be, err := newBackend()
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Info(err)
|
|
|
|
+ os.Exit(1)
|
|
}
|
|
}
|
|
|
|
|
|
- log.Infof("Using %s to tunnel", tep)
|
|
|
|
|
|
+ // Register for SIGINT and SIGTERM and wait for one of them to arrive
|
|
|
|
+ log.Info("Installing signal handlers")
|
|
|
|
+ sigs := make(chan os.Signal, 1)
|
|
|
|
+ signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)
|
|
|
|
|
|
- sm := makeSubnetManager()
|
|
|
|
|
|
+ exit := make(chan int)
|
|
|
|
+ go run(be, exit)
|
|
|
|
|
|
- udp.Run(sm, iface, tep, opts.port, opts.ipMasq, func(sn ip.IP4Net, mtu int) {
|
|
|
|
- writeSubnet(sn, mtu)
|
|
|
|
- daemon.SdNotify("READY=1")
|
|
|
|
- })
|
|
|
|
|
|
+ for {
|
|
|
|
+ select {
|
|
|
|
+ case <-sigs:
|
|
|
|
+ // unregister to get default OS nuke behaviour in case we don't exit cleanly
|
|
|
|
+ signal.Stop(sigs)
|
|
|
|
+
|
|
|
|
+ log.Info("Exiting...")
|
|
|
|
+ be.Stop()
|
|
|
|
+
|
|
|
|
+ case code := <-exit:
|
|
|
|
+ log.Infof("%s mode exited", be.Name())
|
|
|
|
+ os.Exit(code)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|