manager.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. // Copyright 2015 flannel authors
  2. // Copyright 2015 Red Hat, Inc.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. package network
  16. import (
  17. "flag"
  18. "fmt"
  19. "net"
  20. "os"
  21. "path/filepath"
  22. "strings"
  23. "sync"
  24. "github.com/coreos/flannel/Godeps/_workspace/src/github.com/coreos/go-systemd/daemon"
  25. log "github.com/coreos/flannel/Godeps/_workspace/src/github.com/golang/glog"
  26. "github.com/coreos/flannel/Godeps/_workspace/src/golang.org/x/net/context"
  27. "github.com/coreos/flannel/backend"
  28. "github.com/coreos/flannel/pkg/ip"
  29. "github.com/coreos/flannel/subnet"
  30. )
  31. type CmdLineOpts struct {
  32. publicIP string
  33. ipMasq bool
  34. subnetFile string
  35. subnetDir string
  36. iface string
  37. networks string
  38. watchNetworks bool
  39. }
  40. var opts CmdLineOpts
  41. func init() {
  42. flag.StringVar(&opts.publicIP, "public-ip", "", "IP accessible by other nodes for inter-host communication")
  43. flag.StringVar(&opts.subnetFile, "subnet-file", "/run/flannel/subnet.env", "filename where env variables (subnet, MTU, ... ) will be written to")
  44. flag.StringVar(&opts.subnetDir, "subnet-dir", "/run/flannel/networks", "directory where files with env variables (subnet, MTU, ...) will be written to")
  45. flag.StringVar(&opts.iface, "iface", "", "interface to use (IP or name) for inter-host communication")
  46. flag.StringVar(&opts.networks, "networks", "", "run in multi-network mode and service the specified networks")
  47. flag.BoolVar(&opts.watchNetworks, "watch-networks", false, "run in multi-network mode and watch for networks from 'networks' or all networks")
  48. flag.BoolVar(&opts.ipMasq, "ip-masq", false, "setup IP masquerade rule for traffic destined outside of overlay network")
  49. }
  50. type Manager struct {
  51. ctx context.Context
  52. sm subnet.Manager
  53. allowedNetworks map[string]bool
  54. networks map[string]*Network
  55. watch bool
  56. ipMasq bool
  57. extIface *net.Interface
  58. iaddr net.IP
  59. eaddr net.IP
  60. }
  61. func (m *Manager) isNetAllowed(name string) bool {
  62. // If allowedNetworks is empty all networks are allowed
  63. if len(m.allowedNetworks) > 0 {
  64. _, ok := m.allowedNetworks[name]
  65. return ok
  66. }
  67. return true
  68. }
  69. func (m *Manager) isMultiNetwork() bool {
  70. return len(m.allowedNetworks) > 0 || m.watch
  71. }
  72. func NewNetworkManager(ctx context.Context, sm subnet.Manager) (*Manager, error) {
  73. iface, iaddr, err := lookupExtIface(opts.iface)
  74. if err != nil {
  75. return nil, err
  76. }
  77. if iface.MTU == 0 {
  78. return nil, fmt.Errorf("Failed to determine MTU for %s interface", iaddr)
  79. }
  80. var eaddr net.IP
  81. if len(opts.publicIP) > 0 {
  82. eaddr = net.ParseIP(opts.publicIP)
  83. if eaddr == nil {
  84. return nil, fmt.Errorf("Invalid public IP address", opts.publicIP)
  85. }
  86. }
  87. if eaddr == nil {
  88. eaddr = iaddr
  89. }
  90. log.Infof("Using %s as external interface", iaddr)
  91. log.Infof("Using %s as external endpoint", eaddr)
  92. manager := &Manager{
  93. ctx: ctx,
  94. sm: sm,
  95. allowedNetworks: make(map[string]bool),
  96. networks: make(map[string]*Network),
  97. watch: opts.watchNetworks,
  98. ipMasq: opts.ipMasq,
  99. extIface: iface,
  100. iaddr: iaddr,
  101. eaddr: eaddr,
  102. }
  103. for _, name := range strings.Split(opts.networks, ",") {
  104. if name != "" {
  105. manager.allowedNetworks[name] = true
  106. }
  107. }
  108. if manager.isMultiNetwork() {
  109. // Get list of existing networks
  110. result, err := manager.sm.WatchNetworks(ctx, nil)
  111. if err != nil {
  112. return nil, err
  113. }
  114. for _, n := range result.Snapshot {
  115. if manager.isNetAllowed(n) {
  116. manager.networks[n] = NewNetwork(ctx, sm, n, manager.ipMasq)
  117. }
  118. }
  119. } else {
  120. manager.networks[""] = NewNetwork(ctx, sm, "", manager.ipMasq)
  121. }
  122. return manager, nil
  123. }
  124. func lookupExtIface(ifname string) (*net.Interface, net.IP, error) {
  125. var iface *net.Interface
  126. var iaddr net.IP
  127. var err error
  128. if len(ifname) > 0 {
  129. if iaddr = net.ParseIP(ifname); iaddr != nil {
  130. iface, err = ip.GetInterfaceByIP(iaddr)
  131. if err != nil {
  132. return nil, nil, fmt.Errorf("Error looking up interface %s: %s", ifname, err)
  133. }
  134. } else {
  135. iface, err = net.InterfaceByName(ifname)
  136. if err != nil {
  137. return nil, nil, fmt.Errorf("Error looking up interface %s: %s", ifname, err)
  138. }
  139. }
  140. } else {
  141. log.Info("Determining IP address of default interface")
  142. if iface, err = ip.GetDefaultGatewayIface(); err != nil {
  143. return nil, nil, fmt.Errorf("Failed to get default interface: %s", err)
  144. }
  145. }
  146. if iaddr == nil {
  147. iaddr, err = ip.GetIfaceIP4Addr(iface)
  148. if err != nil {
  149. return nil, nil, fmt.Errorf("Failed to find IPv4 address for interface %s", iface.Name)
  150. }
  151. }
  152. return iface, iaddr, nil
  153. }
  154. func writeSubnetFile(path string, nw ip.IP4Net, ipMasq bool, sd *backend.SubnetDef) error {
  155. dir, name := filepath.Split(path)
  156. os.MkdirAll(dir, 0755)
  157. tempFile := filepath.Join(dir, "."+name)
  158. f, err := os.Create(tempFile)
  159. if err != nil {
  160. return err
  161. }
  162. // Write out the first usable IP by incrementing
  163. // sn.IP by one
  164. sn := sd.Lease.Subnet
  165. sn.IP += 1
  166. fmt.Fprintf(f, "FLANNEL_NETWORK=%s\n", nw)
  167. fmt.Fprintf(f, "FLANNEL_SUBNET=%s\n", sn)
  168. fmt.Fprintf(f, "FLANNEL_MTU=%d\n", sd.MTU)
  169. _, err = fmt.Fprintf(f, "FLANNEL_IPMASQ=%v\n", ipMasq)
  170. f.Close()
  171. if err != nil {
  172. return err
  173. }
  174. // rename(2) the temporary file to the desired location so that it becomes
  175. // atomically visible with the contents
  176. return os.Rename(tempFile, path)
  177. }
  178. func (m *Manager) RunNetwork(net *Network) {
  179. sn := net.Init(m.extIface, m.iaddr, m.eaddr)
  180. if sn != nil {
  181. if m.isMultiNetwork() {
  182. path := filepath.Join(opts.subnetDir, net.Name) + ".env"
  183. if err := writeSubnetFile(path, net.Config.Network, m.ipMasq, sn); err != nil {
  184. log.Warningf("%v failed to write subnet file: %s", net.Name, err)
  185. return
  186. }
  187. } else {
  188. if err := writeSubnetFile(opts.subnetFile, net.Config.Network, m.ipMasq, sn); err != nil {
  189. log.Warningf("%v failed to write subnet file: %s", net.Name, err)
  190. return
  191. }
  192. daemon.SdNotify("READY=1")
  193. }
  194. log.Infof("Running network %v", net.Name)
  195. net.Run()
  196. log.Infof("%v exited", net.Name)
  197. }
  198. }
  199. func (m *Manager) watchNetworks() {
  200. wg := sync.WaitGroup{}
  201. events := make(chan []subnet.Event)
  202. wg.Add(1)
  203. go func() {
  204. subnet.WatchNetworks(m.ctx, m.sm, events)
  205. wg.Done()
  206. }()
  207. // skip over the initial snapshot
  208. <-events
  209. for {
  210. select {
  211. case <-m.ctx.Done():
  212. break
  213. case evtBatch := <-events:
  214. for _, e := range evtBatch {
  215. netname := e.Network
  216. if !m.isNetAllowed(netname) {
  217. continue
  218. }
  219. switch e.Type {
  220. case subnet.EventAdded:
  221. if _, ok := m.networks[netname]; ok {
  222. continue
  223. }
  224. net := NewNetwork(m.ctx, m.sm, netname, m.ipMasq)
  225. m.networks[netname] = net
  226. wg.Add(1)
  227. go func() {
  228. m.RunNetwork(net)
  229. wg.Done()
  230. }()
  231. case subnet.EventRemoved:
  232. net, ok := m.networks[netname]
  233. if !ok {
  234. log.Warningf("Network %v unknown; ignoring EventRemoved", netname)
  235. continue
  236. }
  237. net.Cancel()
  238. delete(m.networks, netname)
  239. }
  240. }
  241. }
  242. }
  243. wg.Wait()
  244. }
  245. func (m *Manager) Run() {
  246. wg := sync.WaitGroup{}
  247. // Run existing networks
  248. for _, net := range m.networks {
  249. wg.Add(1)
  250. go func(n *Network) {
  251. m.RunNetwork(n)
  252. wg.Done()
  253. }(net)
  254. }
  255. if opts.watchNetworks {
  256. wg.Add(1)
  257. go func() {
  258. m.watchNetworks()
  259. wg.Done()
  260. }()
  261. } else {
  262. <-m.ctx.Done()
  263. }
  264. wg.Wait()
  265. }