ovs.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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 hostbridge
  15. import (
  16. "fmt"
  17. "strings"
  18. "time"
  19. "yunion.io/x/log"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/utils"
  22. "yunion.io/x/onecloud/pkg/apis/compute"
  23. "yunion.io/x/onecloud/pkg/hostman/guestman/desc"
  24. "yunion.io/x/onecloud/pkg/hostman/options"
  25. "yunion.io/x/onecloud/pkg/hostman/system_service"
  26. "yunion.io/x/onecloud/pkg/util/bwutils"
  27. "yunion.io/x/onecloud/pkg/util/procutils"
  28. )
  29. type SOVSBridgeDriver struct {
  30. SBaseBridgeDriver
  31. }
  32. func (o *SOVSBridgeDriver) CleanupConfig() {
  33. //ovsutils.CleanAllHiddenPorts()
  34. // if enableopenflowcontroller ...
  35. }
  36. func (o *SOVSBridgeDriver) Exists() (bool, error) {
  37. data, err := procutils.NewCommand("ovs-vsctl", "list-br").Output()
  38. if err != nil {
  39. return false, errors.Wrapf(err, "failed list br: %s", data)
  40. }
  41. for _, d := range strings.Split(string(data), "\n") {
  42. if strings.TrimSpace(d) == o.bridge.String() {
  43. return true, nil
  44. }
  45. }
  46. return false, nil
  47. }
  48. func (o *SOVSBridgeDriver) Interfaces() ([]string, error) {
  49. data, err := procutils.NewCommand("ovs-vsctl", "list-ifaces", o.bridge.String()).Output()
  50. if err != nil {
  51. return nil, errors.Wrapf(err, "failed list ifaces: %s", data)
  52. }
  53. var infs = make([]string, 0)
  54. for _, d := range strings.Split(string(data), "\n") {
  55. if len(strings.TrimSpace(d)) > 0 {
  56. infs = append(infs, strings.TrimSpace(d))
  57. }
  58. }
  59. return infs, nil
  60. }
  61. func (o *SOVSBridgeDriver) SetupInterface() error {
  62. infs, err := o.Interfaces()
  63. if err != nil {
  64. return err
  65. }
  66. if o.inter != nil && !utils.IsInStringArray(o.inter.String(), infs) {
  67. output, err := procutils.NewCommand("ovs-vsctl", "--", "--may-exist",
  68. "add-port", o.bridge.String(), o.inter.String()).Output()
  69. if err != nil {
  70. return fmt.Errorf("Failed to add interface: %s, %s", err, output)
  71. }
  72. }
  73. return nil
  74. }
  75. func (o *SOVSBridgeDriver) SetupBridgeDev() error {
  76. exist, err := o.Exists()
  77. if err != nil {
  78. return err
  79. }
  80. if !exist {
  81. output, err := procutils.NewCommand("ovs-vsctl", "--", "--may-exist", "add-br", o.bridge.String()).Output()
  82. if err != nil {
  83. return errors.Wrapf(err, "ovs-vsctl add br %s failed: %s", o.bridge.String(), output)
  84. }
  85. return nil
  86. }
  87. return nil
  88. }
  89. func (d *SOVSBridgeDriver) PersistentConfig() error {
  90. if d.inter == nil {
  91. return nil
  92. }
  93. args := []string{
  94. "ovs-vsctl", "set", "Bridge", d.bridge.String(),
  95. "other-config:hwaddr=" + d.inter.GetMac(),
  96. }
  97. output, err := procutils.NewCommand(args[0], args[1:]...).Output()
  98. if err != nil {
  99. return fmt.Errorf("Ovs bridge set mac address failed %s %s", output, err)
  100. }
  101. args = []string{
  102. "ovs-vsctl", "set", "Interface", d.bridge.String(),
  103. fmt.Sprintf("mtu_request=%d", d.inter.Mtu),
  104. }
  105. output, err = procutils.NewCommand(args[0], args[1:]...).Output()
  106. if err != nil {
  107. return fmt.Errorf("Ovs bridge set MTU failed %s %s", output, err)
  108. }
  109. return nil
  110. }
  111. func (o *SOVSBridgeDriver) GenerateIfdownScripts(scriptPath string, nic *desc.SGuestNetwork, isVolatileHost bool) error {
  112. return o.generateIfdownScripts(o, scriptPath, nic, isVolatileHost)
  113. }
  114. func (o *SOVSBridgeDriver) GenerateIfupScripts(scriptPath string, nic *desc.SGuestNetwork, isVolatileHost bool) error {
  115. return o.generateIfupScripts(o, scriptPath, nic, isVolatileHost)
  116. }
  117. func (o *SOVSBridgeDriver) OnVolatileGuestResume(nic *desc.SGuestNetwork) error {
  118. cmd := []string{"ovs-vsctl", "set", "Interface", nic.Ifname,
  119. fmt.Sprintf("external_ids:iface-id=iface-%s-%s", nic.NetId, nic.Ifname),
  120. }
  121. output, err := procutils.NewRemoteCommandAsFarAsPossible(cmd[0], cmd[1:]...).Output()
  122. if err != nil {
  123. log.Errorf("failed exec %v: %s %s", cmd, err, output)
  124. return errors.Wrapf(err, "set interface external_ids failed: %s", output)
  125. }
  126. return nil
  127. }
  128. func (o *SOVSBridgeDriver) getUpScripts(nic *desc.SGuestNetwork, isVolatileHost bool) (string, error) {
  129. var (
  130. bridge = o.bridge.String()
  131. ifname = nic.Ifname
  132. ip = nic.Ip
  133. mac = nic.Mac
  134. netId = nic.NetId
  135. vlan = nic.Vlan
  136. vpcProvider = nic.Vpc.Provider
  137. )
  138. if vpcProvider == compute.VPC_PROVIDER_OVN {
  139. bridge = options.HostOptions.OvnIntegrationBridge
  140. }
  141. s := "#!/bin/bash\n\n"
  142. s += fmt.Sprintf("SWITCH='%s'\n", bridge)
  143. s += fmt.Sprintf("IF='%s'\n", ifname)
  144. s += fmt.Sprintf("IP='%s'\n", ip)
  145. s += fmt.Sprintf("MAC='%s'\n", mac)
  146. s += fmt.Sprintf("VLAN_ID=%d\n", vlan)
  147. s += fmt.Sprintf("NET_ID=%s\n", netId)
  148. limit, burst, err := bwutils.GetOvsBwValues(nic.Bw, nic.Ip)
  149. if err != nil {
  150. return "", err
  151. }
  152. s += fmt.Sprintf("LIMIT=%d\n", limit)
  153. s += fmt.Sprintf("BURST=%d\n", burst)
  154. bwDownload, err := bwutils.GetDownloadBwValue(nic.Bw, nic.Ip, nic.Ifname, options.HostOptions.BwDownloadBandwidth)
  155. if err != nil {
  156. return "", err
  157. }
  158. s += fmt.Sprintf("LIMIT_DOWNLOAD='%dmbit'\n", bwDownload)
  159. if options.HostOptions.TunnelPaddingBytes > 0 {
  160. s += fmt.Sprintf("ip link set dev $IF mtu %d\n",
  161. 1500+options.HostOptions.TunnelPaddingBytes)
  162. }
  163. s += "ip address flush dev $IF\n"
  164. s += "ip link set dev $IF up\n"
  165. s += "ovs-vsctl list-ifaces $SWITCH | grep -w $IF > /dev/null 2>&1\n"
  166. s += "if [ $? -eq '0' ]; then\n"
  167. s += " ovs-vsctl del-port $SWITCH $IF\n"
  168. s += "fi\n"
  169. s += "if [ \"$VLAN_ID\" -ne \"1\" ]; then\n"
  170. s += " TAG=\"tag=$VLAN_ID\"\n"
  171. s += "fi\n"
  172. s += "ovs-vsctl add-port $SWITCH $IF $TAG\n"
  173. if vpcProvider == compute.VPC_PROVIDER_OVN && !isVolatileHost {
  174. s += "ovs-vsctl set Interface $IF external_ids:iface-id=iface-$NET_ID-$IF\n"
  175. }
  176. s += "PORT=$(ovs-ofctl show $SWITCH | grep -w $IF)\n"
  177. s += "PORT=$(echo $PORT | awk 'BEGIN{FS=\"(\"}{print $1}')\n"
  178. s += "OFCTL=$(ovs-vsctl get-controller $SWITCH)\n"
  179. if nic.Driver != compute.NETWORK_DRIVER_VFIO {
  180. s += "if [ -z \"$OFCTL\" ]; then\n"
  181. s += " ovs-vsctl set Interface $IF ingress_policing_rate=$LIMIT\n"
  182. s += " ovs-vsctl set Interface $IF ingress_policing_burst=$BURST\n"
  183. s += "fi\n"
  184. if vpcProvider != compute.VPC_PROVIDER_OVN && len(options.HostOptions.SRIOVNics) > 0 {
  185. s += fmt.Sprintf("bridge fdb add %s dev %s\n", nic.Mac, o.inter.String())
  186. }
  187. }
  188. s += "if [ $LIMIT_DOWNLOAD != \"0mbit\" ]; then\n"
  189. s += " tc qdisc del dev $IF root 2>/dev/null\n"
  190. s += " tc qdisc add dev $IF root handle 1: htb default 10\n"
  191. s += " tc class add dev $IF parent 1: classid 1:1 htb " +
  192. "rate $LIMIT_DOWNLOAD ceil $LIMIT_DOWNLOAD\n"
  193. s += " tc class add dev $IF parent 1:1 classid 1:10 htb " +
  194. "rate $LIMIT_DOWNLOAD ceil $LIMIT_DOWNLOAD\n"
  195. s += "fi\n"
  196. return s, nil
  197. }
  198. func (o *SOVSBridgeDriver) getDownScripts(nic *desc.SGuestNetwork, isVolatileHost bool) (string, error) {
  199. var (
  200. bridge = o.bridge.String()
  201. ifname = nic.Ifname
  202. ip = nic.Ip
  203. mac = nic.Mac
  204. vlan = nic.Vlan
  205. )
  206. s := "#!/bin/bash\n\n"
  207. s += fmt.Sprintf("SWITCH='%s'\n", bridge)
  208. s += fmt.Sprintf("IF='%s'\n", ifname)
  209. s += fmt.Sprintf("IP='%s'\n", ip)
  210. s += fmt.Sprintf("MAC='%s'\n", mac)
  211. s += fmt.Sprintf("VLAN_ID=%d\n", vlan)
  212. s += "PORT=$(ovs-ofctl show $SWITCH | grep -w $IF)\n"
  213. s += "if [ $? -ne '0' ]; then\n"
  214. s += " exit 0\n"
  215. s += "fi\n"
  216. s += "OFCTL=$(ovs-vsctl get-controller $SWITCH)\n"
  217. s += "PORT=$(echo $PORT | awk 'BEGIN{FS=\"(\"}{print $1}')\n"
  218. s += "ip link set dev $IF down\n"
  219. s += "ovs-vsctl -- --if-exists del-port $SWITCH $IF\n"
  220. if nic.Driver != compute.NETWORK_DRIVER_VFIO {
  221. if nic.Vpc.Provider != compute.VPC_PROVIDER_OVN && len(options.HostOptions.SRIOVNics) > 0 {
  222. s += fmt.Sprintf("bridge fdb del %s dev %s\n", nic.Mac, o.inter.String())
  223. }
  224. }
  225. return s, nil
  226. }
  227. type SRule struct {
  228. priority int
  229. cond string
  230. actions string
  231. }
  232. func (o *SOVSBridgeDriver) RegisterHostlocalServer(mac, ip string) error {
  233. return nil
  234. }
  235. func (o *SOVSBridgeDriver) ovsSetParams(params map[string]map[string]string) {
  236. for tbl, tblval := range params {
  237. for k, v := range tblval {
  238. procutils.NewCommand("ovs-vsctl", "set", tbl, o.bridge.String(),
  239. fmt.Sprintf("%s=%s", k, v)).Run()
  240. }
  241. }
  242. }
  243. func (o *SOVSBridgeDriver) WarmupConfig() error {
  244. // if options.OvsSflowBridges ...
  245. if options.HostOptions.EnableOpenflowController {
  246. // ...
  247. } else {
  248. params := map[string]map[string]string{
  249. "bridge": {
  250. "stp_enable": "false",
  251. "fail_mode": "standalone",
  252. "other-config:flow-eviction-threshold": "2500",
  253. },
  254. }
  255. o.ovsSetParams(params)
  256. }
  257. return nil
  258. }
  259. func OVSPrepare() error {
  260. ovs := system_service.GetService("openvswitch")
  261. if !ovs.IsInstalled() || !ovs.IsActive() {
  262. // no openvswitch service found, first try load openvswitch kernel modules, then try ovs-vsctl command, if success, return nil
  263. if !utils.IsInStringArray("openvswitch", options.HostOptions.SkipCheckKernelMods) {
  264. err := procutils.NewRemoteCommandAsFarAsPossible("modprobe", "openvswitch").Run()
  265. if err != nil {
  266. return errors.Wrap(err, "Failed to load openvswitch kernel modules")
  267. }
  268. }
  269. // wait for the ovs-vswitchd to start
  270. startProbe := time.Now()
  271. const waitSeconds = 60 * 2 // wait ovs-vswitch running for 2 minutes
  272. for time.Since(startProbe) < time.Duration(waitSeconds)*time.Second {
  273. err := procutils.NewCommand("ovs-vsctl", "show").Run()
  274. if err != nil {
  275. time.Sleep(2 * time.Second)
  276. } else {
  277. return nil
  278. }
  279. }
  280. // ovs service start timeout
  281. if !ovs.IsInstalled() {
  282. // ovs service not installed, return error
  283. return fmt.Errorf("service openvswitch not installed and wait ovs service timeout, please check ovs service status")
  284. }
  285. // ovs service installed but not running, continue to start the service
  286. }
  287. if ovs.IsEnabled() {
  288. err := ovs.Disable()
  289. if err != nil {
  290. log.Errorf("Disabling openvswitch service failed: %v", err)
  291. }
  292. }
  293. if !ovs.IsActive() {
  294. return ovs.Start(false)
  295. }
  296. return nil
  297. }
  298. func cleanOvsBridge() {
  299. //ovsutils.CleanAllHiddenPorts()
  300. }
  301. func NewOVSBridgeDriver(bridge, inter, ip string, maskLen int, ip6 string, mask6Len int) (*SOVSBridgeDriver, error) {
  302. base, err := NewBaseBridgeDriver(bridge, inter, ip, maskLen, ip6, mask6Len)
  303. if err != nil {
  304. return nil, err
  305. }
  306. ovsDrv := &SOVSBridgeDriver{*base}
  307. ovsDrv.drv = ovsDrv
  308. return ovsDrv, nil
  309. }
  310. func NewOVSBridgeDriverByName(bridge string) (*SOVSBridgeDriver, error) {
  311. return NewOVSBridgeDriver(bridge, "", "", 0, "", 0)
  312. }