container_bridge.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. Copyright 2015 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package kubelet
  14. import (
  15. "bytes"
  16. "fmt"
  17. "net"
  18. "os"
  19. "os/exec"
  20. "regexp"
  21. "github.com/golang/glog"
  22. "k8s.io/kubernetes/pkg/util"
  23. "k8s.io/kubernetes/pkg/util/iptables"
  24. "k8s.io/kubernetes/pkg/util/procfs"
  25. "syscall"
  26. )
  27. var cidrRegexp = regexp.MustCompile(`inet ([0-9a-fA-F.:]*/[0-9]*)`)
  28. func createCBR0(wantCIDR *net.IPNet, babysitDaemons bool) error {
  29. // recreate cbr0 with wantCIDR
  30. if err := exec.Command("brctl", "addbr", "cbr0").Run(); err != nil {
  31. glog.Error(err)
  32. return err
  33. }
  34. if err := exec.Command("ip", "addr", "add", wantCIDR.String(), "dev", "cbr0").Run(); err != nil {
  35. glog.Error(err)
  36. return err
  37. }
  38. if err := exec.Command("ip", "link", "set", "dev", "cbr0", "mtu", "1460", "up").Run(); err != nil {
  39. glog.Error(err)
  40. return err
  41. }
  42. // Stop docker so that babysitter process can restart it again with proper configurations and
  43. // checkpoint file (https://github.com/docker/docker/issues/18283). It is safe to kill docker
  44. // process here since CIDR can be changed only once for a given node object, and node is marked
  45. // as NotReady until the docker daemon is restarted with the newly configured custom bridge.
  46. // TODO (dawnchen): Remove this once corrupted checkpoint issue is fixed.
  47. //
  48. // For now just log the error. The containerRuntime check will catch docker failures.
  49. // TODO (dawnchen) figure out what we should do for rkt here.
  50. if babysitDaemons {
  51. if err := procfs.PKill("docker", syscall.SIGKILL); err != nil {
  52. glog.Error(err)
  53. }
  54. } else if util.UsingSystemdInitSystem() {
  55. if err := exec.Command("systemctl", "restart", "docker").Run(); err != nil {
  56. glog.Error(err)
  57. }
  58. } else {
  59. if err := exec.Command("service", "docker", "restart").Run(); err != nil {
  60. glog.Error(err)
  61. }
  62. }
  63. glog.V(2).Info("Recreated cbr0 and restarted docker")
  64. return nil
  65. }
  66. func ensureCbr0(wantCIDR *net.IPNet, promiscuous, babysitDaemons bool) error {
  67. exists, err := cbr0Exists()
  68. if err != nil {
  69. return err
  70. }
  71. if !exists {
  72. glog.V(2).Infof("CBR0 doesn't exist, attempting to create it with range: %s", wantCIDR)
  73. return createCBR0(wantCIDR, babysitDaemons)
  74. }
  75. if !cbr0CidrCorrect(wantCIDR) {
  76. glog.V(2).Infof("Attempting to recreate cbr0 with address range: %s", wantCIDR)
  77. // delete cbr0
  78. if err := exec.Command("ip", "link", "set", "dev", "cbr0", "down").Run(); err != nil {
  79. glog.Error(err)
  80. return err
  81. }
  82. if err := exec.Command("brctl", "delbr", "cbr0").Run(); err != nil {
  83. glog.Error(err)
  84. return err
  85. }
  86. if err := createCBR0(wantCIDR, babysitDaemons); err != nil {
  87. glog.Error(err)
  88. return err
  89. }
  90. }
  91. // Put the container bridge into promiscuous mode to force it to accept hairpin packets.
  92. // TODO: Remove this once the kernel bug (#20096) is fixed.
  93. if promiscuous {
  94. // Checking if the bridge is in promiscuous mode is as expensive and more brittle than
  95. // simply setting the flag every time.
  96. if err := exec.Command("ip", "link", "set", "cbr0", "promisc", "on").Run(); err != nil {
  97. glog.Error(err)
  98. return err
  99. }
  100. }
  101. return nil
  102. }
  103. // Check if cbr0 network interface is configured or not, and take action
  104. // when the configuration is missing on the node, and propagate the rest
  105. // error to kubelet to handle.
  106. func cbr0Exists() (bool, error) {
  107. if _, err := os.Stat("/sys/class/net/cbr0"); err != nil {
  108. if os.IsNotExist(err) {
  109. return false, nil
  110. }
  111. return false, err
  112. }
  113. return true, nil
  114. }
  115. func cbr0CidrCorrect(wantCIDR *net.IPNet) bool {
  116. output, err := exec.Command("ip", "addr", "show", "cbr0").Output()
  117. if err != nil {
  118. return false
  119. }
  120. match := cidrRegexp.FindSubmatch(output)
  121. if len(match) < 2 {
  122. return false
  123. }
  124. cbr0IP, cbr0CIDR, err := net.ParseCIDR(string(match[1]))
  125. if err != nil {
  126. glog.Errorf("Couldn't parse CIDR: %q", match[1])
  127. return false
  128. }
  129. cbr0CIDR.IP = cbr0IP
  130. glog.V(5).Infof("Want cbr0 CIDR: %s, have cbr0 CIDR: %s", wantCIDR, cbr0CIDR)
  131. return wantCIDR.IP.Equal(cbr0IP) && bytes.Equal(wantCIDR.Mask, cbr0CIDR.Mask)
  132. }
  133. // nonMasqueradeCIDR is the CIDR for our internal IP range; traffic to IPs
  134. // outside this range will use IP masquerade.
  135. func ensureIPTablesMasqRule(client iptables.Interface, nonMasqueradeCIDR string) error {
  136. if _, err := client.EnsureRule(iptables.Append, iptables.TableNAT,
  137. iptables.ChainPostrouting,
  138. "-m", "comment", "--comment", "kubelet: SNAT outbound cluster traffic",
  139. "-m", "addrtype", "!", "--dst-type", "LOCAL",
  140. "!", "-d", nonMasqueradeCIDR,
  141. "-j", "MASQUERADE"); err != nil {
  142. return fmt.Errorf("Failed to ensure masquerading for %s chain %s: %v",
  143. iptables.TableNAT, iptables.ChainPostrouting, err)
  144. }
  145. return nil
  146. }