finalize_network.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright 2019 Yunion
  2. //
  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. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package hostinfo
  15. import (
  16. "context"
  17. "fmt"
  18. "yunion.io/x/jsonutils"
  19. "yunion.io/x/log"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/util/netutils"
  22. computeapis "yunion.io/x/onecloud/pkg/apis/compute"
  23. "yunion.io/x/onecloud/pkg/hostman/hostutils"
  24. "yunion.io/x/onecloud/pkg/hostman/options"
  25. computemodules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
  26. computeoptions "yunion.io/x/onecloud/pkg/mcclient/options/compute"
  27. "yunion.io/x/onecloud/pkg/util/fileutils2"
  28. "yunion.io/x/onecloud/pkg/util/iproute2"
  29. "yunion.io/x/onecloud/pkg/util/netutils2"
  30. "yunion.io/x/onecloud/pkg/util/procutils"
  31. )
  32. func (h *SHostInfo) findExternalInterfaces() []string {
  33. interfaces := make([]string, 0)
  34. for i := 0; i < len(h.Nics); i++ {
  35. if !h.Nics[i].IsHostLocal() && len(h.Nics[i].Ip) > 0 {
  36. interfaces = append(interfaces, h.Nics[i].Bridge)
  37. }
  38. }
  39. if len(options.HostOptions.ListenInterface) > 0 {
  40. interfaces = append(interfaces, options.HostOptions.ListenInterface)
  41. }
  42. return interfaces
  43. }
  44. func (h *SHostInfo) finalizeNetworkSetup(ctx context.Context) error {
  45. for i := 0; i < len(h.Nics); i++ {
  46. if err := h.Nics[i].SetupDhcpRelay(); err != nil {
  47. return errors.Wrapf(err, "SetupDhcpRelay %s", h.Nics[i])
  48. }
  49. }
  50. extInterfaces := h.findExternalInterfaces()
  51. for i := 0; i < len(h.Nics); i++ {
  52. if err := h.Nics[i].setupHostLocalNetworks(ctx, extInterfaces); err != nil {
  53. return errors.Wrapf(err, "SetupHostLocalNetworks %s", h.Nics[i])
  54. }
  55. }
  56. return nil
  57. }
  58. func (n *SNIC) String() string {
  59. return fmt.Sprintf("%s/%s/%s", n.Inter, n.Bridge, n.Ip)
  60. }
  61. func (n *SNIC) setupHostLocalNetworks(ctx context.Context, extInterfaces []string) error {
  62. nets, err := n.fetchHostLocalNetworks(ctx)
  63. if err != nil {
  64. return errors.Wrap(err, "fetchHostLocalNetworks")
  65. }
  66. hostLocalNics := make([]computeapis.NetworkDetails, 0)
  67. for i := range nets {
  68. net := nets[i]
  69. if len(net.GuestGateway) == 0 {
  70. continue
  71. }
  72. err := n.setupHostLocalNet(ctx, net, extInterfaces)
  73. if err != nil {
  74. return errors.Wrapf(err, "setupHostLocalNet of %s", jsonutils.Marshal(net))
  75. }
  76. hostLocalNics = append(hostLocalNics, nets[i])
  77. }
  78. // save hostLocalNics
  79. fn := options.HostOptions.HostLocalNetconfPath(n.Bridge)
  80. fileutils2.FilePutContents(fn, jsonutils.Marshal(hostLocalNics).PrettyString(), false)
  81. return nil
  82. }
  83. func (n *SNIC) setupHostLocalNet(ctx context.Context, netInfo computeapis.NetworkDetails, extInterfaces []string) error {
  84. // setup gateway ip
  85. if err := n.setupSlaveIp(ctx, netInfo.GuestGateway, netInfo.GuestIpMask, extInterfaces); err != nil {
  86. return errors.Wrapf(err, "setupSlaveIp %s %s", n, netInfo.GuestGateway)
  87. }
  88. return nil
  89. }
  90. func (n *SNIC) setupSlaveIp(ctx context.Context, gatewayIp string, maskLen byte, extInterfaces []string) error {
  91. bridgeIf := netutils2.NewNetInterface(n.Bridge)
  92. slaveAddrs := bridgeIf.GetSlaveAddresses()
  93. var curGatewayIp string
  94. var curMaskLen int
  95. isMaskUpdate := false
  96. for i := range slaveAddrs {
  97. addr := slaveAddrs[i]
  98. curGatewayIp = addr.Addr
  99. curMaskLen = addr.MaskLen
  100. if curGatewayIp == gatewayIp {
  101. if curMaskLen == int(maskLen) {
  102. // already configured, skip
  103. return nil
  104. } else {
  105. isMaskUpdate = true
  106. break
  107. }
  108. }
  109. }
  110. if err := n.BridgeDev.SetupSlaveAddresses([]netutils2.SNicAddress{
  111. {Addr: gatewayIp, MaskLen: int(maskLen)},
  112. }); err != nil {
  113. return errors.Wrap(err, "SetupSlaveAddresses")
  114. }
  115. if err := n.setupMasqueradeRule(ctx, gatewayIp, maskLen, extInterfaces); err != nil {
  116. return errors.Wrap(err, "setupMasqueradeRule")
  117. }
  118. if isMaskUpdate {
  119. brName := n.BridgeDev.Bridge()
  120. logPrefix := fmt.Sprintf("%s slave address %s mask is update from %d to %d", brName, gatewayIp, curMaskLen, maskLen)
  121. addr := fmt.Sprintf("%s/%d", gatewayIp, curMaskLen)
  122. log.Infof("%s: delete addr %s", logPrefix, addr)
  123. if err := iproute2.NewAddress(n.BridgeDev.Bridge(), addr).Del().Err(); err != nil {
  124. log.Warningf("%s: delete addr %s: %v", logPrefix, addr, err)
  125. }
  126. curMaskLenInt := curMaskLen
  127. if err := n.deleteMasqueradeRule(ctx, gatewayIp, byte(curMaskLenInt), extInterfaces); err != nil {
  128. log.Warningf("%s: delete iptables masqueradeRule: %v", logPrefix, err)
  129. }
  130. }
  131. return nil
  132. }
  133. type IptablesAction int
  134. const (
  135. IPTABLES_ACTION_APPEND IptablesAction = iota
  136. IPTABLES_ACTION_DELETE
  137. )
  138. func (n *SNIC) doMasqueradeRule(ctx context.Context, ipStr string, maskLen byte, action IptablesAction, bridge string) error {
  139. gwip, err := netutils.NewIPV4Addr(ipStr)
  140. if err != nil {
  141. return errors.Wrapf(err, "NewIPV4Addr %s", ipStr)
  142. }
  143. netip := gwip.NetAddr(int8(maskLen))
  144. maskip := netutils.Masklen2Mask(int8(maskLen))
  145. var actionOpt string
  146. var actionInfo string
  147. switch action {
  148. case IPTABLES_ACTION_APPEND:
  149. actionOpt = "-A"
  150. actionInfo = "append"
  151. case IPTABLES_ACTION_DELETE:
  152. actionOpt = "-D"
  153. actionInfo = "delete"
  154. default:
  155. return errors.Errorf("unknown action %d", action)
  156. }
  157. cmd := procutils.NewCommand("iptables", "-t", "nat", actionOpt, "POSTROUTING", "-s",
  158. fmt.Sprintf("%s/%s", netip.String(), maskip.String()), "-o", bridge, "-j", "MASQUERADE")
  159. if err := cmd.Run(); err != nil {
  160. return errors.Wrapf(err, "%s masquerade rule", actionInfo)
  161. }
  162. return nil
  163. }
  164. func (n *SNIC) setupMasqueradeRule(ctx context.Context, ipStr string, maskLen byte, extInterfaces []string) error {
  165. if n.IsHostLocal() {
  166. for _, inf := range extInterfaces {
  167. if err := n.doMasqueradeRule(ctx, ipStr, maskLen, IPTABLES_ACTION_APPEND, inf); err != nil {
  168. return errors.Wrapf(err, "setupMasqueradeRule %s %d %s", ipStr, maskLen, inf)
  169. }
  170. }
  171. return nil
  172. } else {
  173. return n.doMasqueradeRule(ctx, ipStr, maskLen, IPTABLES_ACTION_APPEND, n.Bridge)
  174. }
  175. }
  176. func (n *SNIC) deleteMasqueradeRule(ctx context.Context, ipStr string, maskLen byte, extInterfaces []string) error {
  177. if n.IsHostLocal() {
  178. for _, inf := range extInterfaces {
  179. if err := n.doMasqueradeRule(ctx, ipStr, maskLen, IPTABLES_ACTION_DELETE, inf); err != nil {
  180. return errors.Wrapf(err, "deleteMasqueradeRule %s %d %s", ipStr, maskLen, inf)
  181. }
  182. }
  183. return nil
  184. } else {
  185. return n.doMasqueradeRule(ctx, ipStr, maskLen, IPTABLES_ACTION_DELETE, n.Bridge)
  186. }
  187. }
  188. func (n *SNIC) fetchHostLocalNetworks(ctx context.Context) ([]computeapis.NetworkDetails, error) {
  189. return fetchHostLocalNetworksByWireId(ctx, n.WireId)
  190. }
  191. func fetchHostLocalNetworksByWireId(ctx context.Context, wireId string) ([]computeapis.NetworkDetails, error) {
  192. s := hostutils.GetComputeSession(ctx)
  193. params := computeoptions.NetworkListOptions{}
  194. params.ServerType = "hostlocal"
  195. limit := 50
  196. params.Limit = &limit
  197. params.Scope = "system"
  198. total := -1
  199. nets := make([]computeapis.NetworkDetails, 0)
  200. for total < 0 || len(nets) < total {
  201. offset := len(nets)
  202. params.Offset = &offset
  203. results, err := computemodules.Networks.ListInContext(s, jsonutils.Marshal(params), &computemodules.Wires, wireId)
  204. if err != nil {
  205. return nil, errors.Wrap(err, "Networks.List")
  206. }
  207. total = results.Total
  208. for i := range results.Data {
  209. netDetails := computeapis.NetworkDetails{}
  210. err := results.Data[i].Unmarshal(&netDetails)
  211. if err != nil {
  212. return nil, errors.Wrap(err, "Unmarshal")
  213. }
  214. nets = append(nets, netDetails)
  215. }
  216. }
  217. return nets, nil
  218. }