neigh_linux.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. package netlink
  2. import (
  3. "fmt"
  4. "net"
  5. "syscall"
  6. "unsafe"
  7. "github.com/vishvananda/netlink/nl"
  8. "github.com/vishvananda/netns"
  9. "golang.org/x/sys/unix"
  10. )
  11. const (
  12. NDA_UNSPEC = iota
  13. NDA_DST
  14. NDA_LLADDR
  15. NDA_CACHEINFO
  16. NDA_PROBES
  17. NDA_VLAN
  18. NDA_PORT
  19. NDA_VNI
  20. NDA_IFINDEX
  21. NDA_MASTER
  22. NDA_LINK_NETNSID
  23. NDA_SRC_VNI
  24. NDA_PROTOCOL
  25. NDA_NH_ID
  26. NDA_FDB_EXT_ATTRS
  27. NDA_FLAGS_EXT
  28. NDA_MAX = NDA_FLAGS_EXT
  29. )
  30. // Neighbor Cache Entry States.
  31. const (
  32. NUD_NONE = 0x00
  33. NUD_INCOMPLETE = 0x01
  34. NUD_REACHABLE = 0x02
  35. NUD_STALE = 0x04
  36. NUD_DELAY = 0x08
  37. NUD_PROBE = 0x10
  38. NUD_FAILED = 0x20
  39. NUD_NOARP = 0x40
  40. NUD_PERMANENT = 0x80
  41. )
  42. // Neighbor Flags
  43. const (
  44. NTF_USE = 0x01
  45. NTF_SELF = 0x02
  46. NTF_MASTER = 0x04
  47. NTF_PROXY = 0x08
  48. NTF_EXT_LEARNED = 0x10
  49. NTF_OFFLOADED = 0x20
  50. NTF_STICKY = 0x40
  51. NTF_ROUTER = 0x80
  52. )
  53. // Extended Neighbor Flags
  54. const (
  55. NTF_EXT_MANAGED = 0x00000001
  56. )
  57. // Ndmsg is for adding, removing or receiving information about a neighbor table entry
  58. type Ndmsg struct {
  59. Family uint8
  60. Index uint32
  61. State uint16
  62. Flags uint8
  63. Type uint8
  64. }
  65. func deserializeNdmsg(b []byte) *Ndmsg {
  66. var dummy Ndmsg
  67. return (*Ndmsg)(unsafe.Pointer(&b[0:unsafe.Sizeof(dummy)][0]))
  68. }
  69. func (msg *Ndmsg) Serialize() []byte {
  70. return (*(*[unsafe.Sizeof(*msg)]byte)(unsafe.Pointer(msg)))[:]
  71. }
  72. func (msg *Ndmsg) Len() int {
  73. return int(unsafe.Sizeof(*msg))
  74. }
  75. // NeighAdd will add an IP to MAC mapping to the ARP table
  76. // Equivalent to: `ip neigh add ....`
  77. func NeighAdd(neigh *Neigh) error {
  78. return pkgHandle.NeighAdd(neigh)
  79. }
  80. // NeighAdd will add an IP to MAC mapping to the ARP table
  81. // Equivalent to: `ip neigh add ....`
  82. func (h *Handle) NeighAdd(neigh *Neigh) error {
  83. return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_EXCL)
  84. }
  85. // NeighSet will add or replace an IP to MAC mapping to the ARP table
  86. // Equivalent to: `ip neigh replace....`
  87. func NeighSet(neigh *Neigh) error {
  88. return pkgHandle.NeighSet(neigh)
  89. }
  90. // NeighSet will add or replace an IP to MAC mapping to the ARP table
  91. // Equivalent to: `ip neigh replace....`
  92. func (h *Handle) NeighSet(neigh *Neigh) error {
  93. return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_REPLACE)
  94. }
  95. // NeighAppend will append an entry to FDB
  96. // Equivalent to: `bridge fdb append...`
  97. func NeighAppend(neigh *Neigh) error {
  98. return pkgHandle.NeighAppend(neigh)
  99. }
  100. // NeighAppend will append an entry to FDB
  101. // Equivalent to: `bridge fdb append...`
  102. func (h *Handle) NeighAppend(neigh *Neigh) error {
  103. return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_APPEND)
  104. }
  105. // NeighAppend will append an entry to FDB
  106. // Equivalent to: `bridge fdb append...`
  107. func neighAdd(neigh *Neigh, mode int) error {
  108. return pkgHandle.neighAdd(neigh, mode)
  109. }
  110. // NeighAppend will append an entry to FDB
  111. // Equivalent to: `bridge fdb append...`
  112. func (h *Handle) neighAdd(neigh *Neigh, mode int) error {
  113. req := h.newNetlinkRequest(unix.RTM_NEWNEIGH, mode|unix.NLM_F_ACK)
  114. return neighHandle(neigh, req)
  115. }
  116. // NeighDel will delete an IP address from a link device.
  117. // Equivalent to: `ip addr del $addr dev $link`
  118. func NeighDel(neigh *Neigh) error {
  119. return pkgHandle.NeighDel(neigh)
  120. }
  121. // NeighDel will delete an IP address from a link device.
  122. // Equivalent to: `ip addr del $addr dev $link`
  123. func (h *Handle) NeighDel(neigh *Neigh) error {
  124. req := h.newNetlinkRequest(unix.RTM_DELNEIGH, unix.NLM_F_ACK)
  125. return neighHandle(neigh, req)
  126. }
  127. func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
  128. var family int
  129. if neigh.Family > 0 {
  130. family = neigh.Family
  131. } else {
  132. family = nl.GetIPFamily(neigh.IP)
  133. }
  134. msg := Ndmsg{
  135. Family: uint8(family),
  136. Index: uint32(neigh.LinkIndex),
  137. State: uint16(neigh.State),
  138. Type: uint8(neigh.Type),
  139. Flags: uint8(neigh.Flags),
  140. }
  141. req.AddData(&msg)
  142. ipData := neigh.IP.To4()
  143. if ipData == nil {
  144. ipData = neigh.IP.To16()
  145. }
  146. dstData := nl.NewRtAttr(NDA_DST, ipData)
  147. req.AddData(dstData)
  148. if neigh.LLIPAddr != nil {
  149. llIPData := nl.NewRtAttr(NDA_LLADDR, neigh.LLIPAddr.To4())
  150. req.AddData(llIPData)
  151. } else if neigh.HardwareAddr != nil {
  152. hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr))
  153. req.AddData(hwData)
  154. }
  155. if neigh.FlagsExt != 0 {
  156. flagsExtData := nl.NewRtAttr(NDA_FLAGS_EXT, nl.Uint32Attr(uint32(neigh.FlagsExt)))
  157. req.AddData(flagsExtData)
  158. }
  159. if neigh.Vlan != 0 {
  160. vlanData := nl.NewRtAttr(NDA_VLAN, nl.Uint16Attr(uint16(neigh.Vlan)))
  161. req.AddData(vlanData)
  162. }
  163. if neigh.VNI != 0 {
  164. vniData := nl.NewRtAttr(NDA_VNI, nl.Uint32Attr(uint32(neigh.VNI)))
  165. req.AddData(vniData)
  166. }
  167. if neigh.MasterIndex != 0 {
  168. masterData := nl.NewRtAttr(NDA_MASTER, nl.Uint32Attr(uint32(neigh.MasterIndex)))
  169. req.AddData(masterData)
  170. }
  171. _, err := req.Execute(unix.NETLINK_ROUTE, 0)
  172. return err
  173. }
  174. // NeighList returns a list of IP-MAC mappings in the system (ARP table).
  175. // Equivalent to: `ip neighbor show`.
  176. // The list can be filtered by link and ip family.
  177. func NeighList(linkIndex, family int) ([]Neigh, error) {
  178. return pkgHandle.NeighList(linkIndex, family)
  179. }
  180. // NeighProxyList returns a list of neighbor proxies in the system.
  181. // Equivalent to: `ip neighbor show proxy`.
  182. // The list can be filtered by link and ip family.
  183. func NeighProxyList(linkIndex, family int) ([]Neigh, error) {
  184. return pkgHandle.NeighProxyList(linkIndex, family)
  185. }
  186. // NeighList returns a list of IP-MAC mappings in the system (ARP table).
  187. // Equivalent to: `ip neighbor show`.
  188. // The list can be filtered by link and ip family.
  189. func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
  190. return h.NeighListExecute(Ndmsg{
  191. Family: uint8(family),
  192. Index: uint32(linkIndex),
  193. })
  194. }
  195. // NeighProxyList returns a list of neighbor proxies in the system.
  196. // Equivalent to: `ip neighbor show proxy`.
  197. // The list can be filtered by link, ip family.
  198. func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
  199. return h.NeighListExecute(Ndmsg{
  200. Family: uint8(family),
  201. Index: uint32(linkIndex),
  202. Flags: NTF_PROXY,
  203. })
  204. }
  205. // NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
  206. func NeighListExecute(msg Ndmsg) ([]Neigh, error) {
  207. return pkgHandle.NeighListExecute(msg)
  208. }
  209. // NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
  210. func (h *Handle) NeighListExecute(msg Ndmsg) ([]Neigh, error) {
  211. req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
  212. req.AddData(&msg)
  213. msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
  214. if err != nil {
  215. return nil, err
  216. }
  217. var res []Neigh
  218. for _, m := range msgs {
  219. ndm := deserializeNdmsg(m)
  220. if msg.Index != 0 && ndm.Index != msg.Index {
  221. // Ignore messages from other interfaces
  222. continue
  223. }
  224. if msg.Family != 0 && ndm.Family != msg.Family {
  225. continue
  226. }
  227. if msg.State != 0 && ndm.State != msg.State {
  228. continue
  229. }
  230. if msg.Type != 0 && ndm.Type != msg.Type {
  231. continue
  232. }
  233. if msg.Flags != 0 && ndm.Flags != msg.Flags {
  234. continue
  235. }
  236. neigh, err := NeighDeserialize(m)
  237. if err != nil {
  238. continue
  239. }
  240. res = append(res, *neigh)
  241. }
  242. return res, nil
  243. }
  244. func NeighDeserialize(m []byte) (*Neigh, error) {
  245. msg := deserializeNdmsg(m)
  246. neigh := Neigh{
  247. LinkIndex: int(msg.Index),
  248. Family: int(msg.Family),
  249. State: int(msg.State),
  250. Type: int(msg.Type),
  251. Flags: int(msg.Flags),
  252. }
  253. attrs, err := nl.ParseRouteAttr(m[msg.Len():])
  254. if err != nil {
  255. return nil, err
  256. }
  257. for _, attr := range attrs {
  258. switch attr.Attr.Type {
  259. case NDA_DST:
  260. neigh.IP = net.IP(attr.Value)
  261. case NDA_LLADDR:
  262. // BUG: Is this a bug in the netlink library?
  263. // #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
  264. // #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
  265. attrLen := attr.Attr.Len - unix.SizeofRtAttr
  266. if attrLen == 4 {
  267. neigh.LLIPAddr = net.IP(attr.Value)
  268. } else if attrLen == 16 {
  269. // Can be IPv6 or FireWire HWAddr
  270. link, err := LinkByIndex(neigh.LinkIndex)
  271. if err == nil && link.Attrs().EncapType == "tunnel6" {
  272. neigh.IP = net.IP(attr.Value)
  273. } else {
  274. neigh.HardwareAddr = net.HardwareAddr(attr.Value)
  275. }
  276. } else {
  277. neigh.HardwareAddr = net.HardwareAddr(attr.Value)
  278. }
  279. case NDA_FLAGS_EXT:
  280. neigh.FlagsExt = int(native.Uint32(attr.Value[0:4]))
  281. case NDA_VLAN:
  282. neigh.Vlan = int(native.Uint16(attr.Value[0:2]))
  283. case NDA_VNI:
  284. neigh.VNI = int(native.Uint32(attr.Value[0:4]))
  285. case NDA_MASTER:
  286. neigh.MasterIndex = int(native.Uint32(attr.Value[0:4]))
  287. }
  288. }
  289. return &neigh, nil
  290. }
  291. // NeighSubscribe takes a chan down which notifications will be sent
  292. // when neighbors are added or deleted. Close the 'done' chan to stop subscription.
  293. func NeighSubscribe(ch chan<- NeighUpdate, done <-chan struct{}) error {
  294. return neighSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
  295. }
  296. // NeighSubscribeAt works like NeighSubscribe plus it allows the caller
  297. // to choose the network namespace in which to subscribe (ns).
  298. func NeighSubscribeAt(ns netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}) error {
  299. return neighSubscribeAt(ns, netns.None(), ch, done, nil, false)
  300. }
  301. // NeighSubscribeOptions contains a set of options to use with
  302. // NeighSubscribeWithOptions.
  303. type NeighSubscribeOptions struct {
  304. Namespace *netns.NsHandle
  305. ErrorCallback func(error)
  306. ListExisting bool
  307. }
  308. // NeighSubscribeWithOptions work like NeighSubscribe but enable to
  309. // provide additional options to modify the behavior. Currently, the
  310. // namespace can be provided as well as an error callback.
  311. func NeighSubscribeWithOptions(ch chan<- NeighUpdate, done <-chan struct{}, options NeighSubscribeOptions) error {
  312. if options.Namespace == nil {
  313. none := netns.None()
  314. options.Namespace = &none
  315. }
  316. return neighSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
  317. }
  318. func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
  319. s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_NEIGH)
  320. makeRequest := func(family int) error {
  321. req := pkgHandle.newNetlinkRequest(unix.RTM_GETNEIGH,
  322. unix.NLM_F_DUMP)
  323. infmsg := nl.NewIfInfomsg(family)
  324. req.AddData(infmsg)
  325. if err := s.Send(req); err != nil {
  326. return err
  327. }
  328. return nil
  329. }
  330. if err != nil {
  331. return err
  332. }
  333. if done != nil {
  334. go func() {
  335. <-done
  336. s.Close()
  337. }()
  338. }
  339. if listExisting {
  340. if err := makeRequest(unix.AF_UNSPEC); err != nil {
  341. return err
  342. }
  343. // We have to wait for NLMSG_DONE before making AF_BRIDGE request
  344. }
  345. go func() {
  346. defer close(ch)
  347. for {
  348. msgs, from, err := s.Receive()
  349. if err != nil {
  350. if cberr != nil {
  351. cberr(err)
  352. }
  353. return
  354. }
  355. if from.Pid != nl.PidKernel {
  356. if cberr != nil {
  357. cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
  358. }
  359. continue
  360. }
  361. for _, m := range msgs {
  362. if m.Header.Type == unix.NLMSG_DONE {
  363. if listExisting {
  364. // This will be called after handling AF_UNSPEC
  365. // list request, we have to wait for NLMSG_DONE
  366. // before making another request
  367. if err := makeRequest(unix.AF_BRIDGE); err != nil {
  368. if cberr != nil {
  369. cberr(err)
  370. }
  371. return
  372. }
  373. listExisting = false
  374. }
  375. continue
  376. }
  377. if m.Header.Type == unix.NLMSG_ERROR {
  378. error := int32(native.Uint32(m.Data[0:4]))
  379. if error == 0 {
  380. continue
  381. }
  382. if cberr != nil {
  383. cberr(syscall.Errno(-error))
  384. }
  385. return
  386. }
  387. neigh, err := NeighDeserialize(m.Data)
  388. if err != nil {
  389. if cberr != nil {
  390. cberr(err)
  391. }
  392. return
  393. }
  394. ch <- NeighUpdate{Type: m.Header.Type, Neigh: *neigh}
  395. }
  396. }
  397. }()
  398. return nil
  399. }