route_linux.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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 iproute2
  15. import (
  16. "net"
  17. "github.com/vishvananda/netlink"
  18. "yunion.io/x/pkg/errors"
  19. )
  20. const (
  21. errBadIP = errors.Error("bad ip")
  22. )
  23. type RouteSpec = netlink.Route
  24. type Route struct {
  25. *Link
  26. }
  27. func NewRoute(ifname string) *Route {
  28. l := NewLink(ifname)
  29. route := &Route{
  30. Link: l,
  31. }
  32. return route
  33. }
  34. func (route *Route) link() (link netlink.Link, ok bool) {
  35. link = route.Link.link
  36. if link != nil {
  37. ok = true
  38. }
  39. return
  40. }
  41. func (route *Route) List4() ([]RouteSpec, error) {
  42. link, ok := route.link()
  43. if !ok {
  44. return nil, route.Err()
  45. }
  46. rs, err := netlink.RouteList(link, netlink.FAMILY_V4)
  47. if err != nil {
  48. route.addErr(err, "route list")
  49. return nil, route.Err()
  50. }
  51. for i := range rs {
  52. if rs[i].Dst == nil {
  53. // make the return value easier to work with
  54. rs[i].Dst = &net.IPNet{
  55. IP: net.IPv4zero,
  56. Mask: net.IPMask(net.IPv4zero),
  57. }
  58. }
  59. }
  60. return rs, nil
  61. }
  62. func (route *Route) List6() ([]RouteSpec, error) {
  63. link, ok := route.link()
  64. if !ok {
  65. return nil, route.Err()
  66. }
  67. rs, err := netlink.RouteList(link, netlink.FAMILY_V6)
  68. if err != nil {
  69. route.addErr(err, "route list")
  70. return nil, route.Err()
  71. }
  72. for i := range rs {
  73. if rs[i].Dst == nil {
  74. // make the return value easier to work with
  75. rs[i].Dst = &net.IPNet{
  76. IP: net.IPv6zero,
  77. Mask: net.IPMask(net.IPv6zero),
  78. }
  79. }
  80. }
  81. return rs, nil
  82. }
  83. func (route *Route) AddByIPNet(ipnet *net.IPNet, gw net.IP) *Route {
  84. r := RouteSpec{
  85. Dst: ipnet,
  86. }
  87. if len(gw) > 0 {
  88. r.Gw = gw
  89. }
  90. return route.AddByRouteSpec(r)
  91. }
  92. func (route *Route) AddByCidr(cidr string, gwStr string) *Route {
  93. dst, gw, err := route.parseCidr(cidr, gwStr)
  94. if err != nil {
  95. route.addErr2(err)
  96. return route
  97. }
  98. return route.AddByIPNet(dst, gw)
  99. }
  100. func (route *Route) AddByRouteSpec(r RouteSpec) *Route {
  101. link, ok := route.link()
  102. if !ok {
  103. return route
  104. }
  105. r.LinkIndex = link.Attrs().Index
  106. if err := netlink.RouteReplace(&r); err != nil {
  107. route.addErr(err, "RouteReplace %s", r.String())
  108. }
  109. return route
  110. }
  111. func (route *Route) parseCidr(cidr, gwStr string) (dst *net.IPNet, gw net.IP, err error) {
  112. if _, dst, err = net.ParseCIDR(cidr); err != nil {
  113. err = errors.Wrap(err, "parse cidr")
  114. return
  115. }
  116. if gwStr != "" {
  117. gw = net.ParseIP(gwStr)
  118. if len(gw) == 0 {
  119. err = errors.Wrapf(errBadIP, "gwStr: %s", gwStr)
  120. return
  121. }
  122. }
  123. return
  124. }
  125. func (route *Route) parse(netStr, maskStr, gwStr string) (ip net.IP, mask net.IPMask, gw net.IP, err error) {
  126. if ip = net.ParseIP(netStr); len(ip) == 0 {
  127. err = errors.Wrapf(errBadIP, "netStr %s", netStr)
  128. return
  129. }
  130. if maskIp := net.ParseIP(maskStr); len(maskIp) == 0 {
  131. err = errors.Wrapf(errBadIP, "maskStr %s", maskStr)
  132. return
  133. } else {
  134. if ip := maskIp.To4(); len(ip) > 0 {
  135. maskIp = ip
  136. }
  137. mask = net.IPMask(maskIp)
  138. ones, bits := mask.Size()
  139. if ones == 0 && bits == 0 {
  140. err = errors.Wrapf(errBadIP, "bad mask %s", maskStr)
  141. return
  142. }
  143. }
  144. if gwStr != "" {
  145. if gw = net.ParseIP(gwStr); len(gw) == 0 {
  146. err = errors.Wrapf(errBadIP, "gwStr %s", gwStr)
  147. return
  148. }
  149. }
  150. return
  151. }
  152. func (route *Route) Add(netStr, maskStr, gwStr string) *Route {
  153. var (
  154. ip net.IP
  155. mask net.IPMask
  156. gw net.IP
  157. )
  158. ip, mask, gw, err := route.parse(netStr, maskStr, gwStr)
  159. if err != nil {
  160. route.addErr2(err)
  161. }
  162. ipnet := &net.IPNet{
  163. IP: ip,
  164. Mask: mask,
  165. }
  166. return route.AddByIPNet(ipnet, gw)
  167. }
  168. func (route *Route) Del(netStr, maskStr string) *Route {
  169. ip, mask, _, err := route.parse(netStr, maskStr, "")
  170. if err != nil {
  171. route.addErr2(err)
  172. return route
  173. }
  174. ipnet := &net.IPNet{
  175. IP: ip,
  176. Mask: mask,
  177. }
  178. return route.DelByIPNet(ipnet)
  179. }
  180. func (route *Route) DelByCidr(cidr string) *Route {
  181. dst, _, err := route.parseCidr(cidr, "")
  182. if err != nil {
  183. route.addErr2(err)
  184. return route
  185. }
  186. return route.DelByIPNet(dst)
  187. }
  188. func (route *Route) DelByIPNet(ipnet *net.IPNet) *Route {
  189. link, ok := route.link()
  190. if !ok {
  191. return route
  192. }
  193. r := &netlink.Route{
  194. LinkIndex: link.Attrs().Index,
  195. Dst: ipnet,
  196. }
  197. if err := netlink.RouteDel(r); err != nil {
  198. route.addErr(err, "RouteDel %s", r)
  199. return route
  200. }
  201. return route
  202. }
  203. func RouteGetByDst(dstStr string) ([]RouteSpec, error) {
  204. dstIp := net.ParseIP(dstStr)
  205. routes, err := netlink.RouteGet(dstIp)
  206. return routes, err
  207. }