neigh_linux.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package osl
  2. import (
  3. "bytes"
  4. "fmt"
  5. "net"
  6. "github.com/Sirupsen/logrus"
  7. "github.com/vishvananda/netlink"
  8. )
  9. // NeighOption is a function option type to set interface options
  10. type NeighOption func(nh *neigh)
  11. type neigh struct {
  12. dstIP net.IP
  13. dstMac net.HardwareAddr
  14. linkName string
  15. linkDst string
  16. family int
  17. }
  18. func (n *networkNamespace) findNeighbor(dstIP net.IP, dstMac net.HardwareAddr) *neigh {
  19. n.Lock()
  20. defer n.Unlock()
  21. for _, nh := range n.neighbors {
  22. if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) {
  23. return nh
  24. }
  25. }
  26. return nil
  27. }
  28. func (n *networkNamespace) DeleteNeighbor(dstIP net.IP, dstMac net.HardwareAddr, osDelete bool) error {
  29. var (
  30. iface netlink.Link
  31. err error
  32. )
  33. nh := n.findNeighbor(dstIP, dstMac)
  34. if nh == nil {
  35. return fmt.Errorf("could not find the neighbor entry to delete")
  36. }
  37. if osDelete {
  38. n.Lock()
  39. nlh := n.nlHandle
  40. n.Unlock()
  41. if nh.linkDst != "" {
  42. iface, err = nlh.LinkByName(nh.linkDst)
  43. if err != nil {
  44. return fmt.Errorf("could not find interface with destination name %s: %v",
  45. nh.linkDst, err)
  46. }
  47. }
  48. nlnh := &netlink.Neigh{
  49. IP: dstIP,
  50. State: netlink.NUD_PERMANENT,
  51. Family: nh.family,
  52. }
  53. if nlnh.Family > 0 {
  54. nlnh.HardwareAddr = dstMac
  55. nlnh.Flags = netlink.NTF_SELF
  56. }
  57. if nh.linkDst != "" {
  58. nlnh.LinkIndex = iface.Attrs().Index
  59. }
  60. // If the kernel deletion fails for the neighbor entry still remote it
  61. // from the namespace cache. Otherwise if the neighbor moves back to the
  62. // same host again, kernel update can fail.
  63. if err := nlh.NeighDel(nlnh); err != nil {
  64. logrus.Warnf("Deleting neighbor IP %s, mac %s failed, %v", dstIP, dstMac, err)
  65. }
  66. }
  67. n.Lock()
  68. for i, nh := range n.neighbors {
  69. if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) {
  70. n.neighbors = append(n.neighbors[:i], n.neighbors[i+1:]...)
  71. break
  72. }
  73. }
  74. n.Unlock()
  75. logrus.Debugf("Neighbor entry deleted for IP %v, mac %v", dstIP, dstMac)
  76. return nil
  77. }
  78. func (n *networkNamespace) AddNeighbor(dstIP net.IP, dstMac net.HardwareAddr, force bool, options ...NeighOption) error {
  79. var (
  80. iface netlink.Link
  81. err error
  82. )
  83. // If the namespace already has the neighbor entry but the AddNeighbor is called
  84. // because of a miss notification (force flag) program the kernel anyway.
  85. nh := n.findNeighbor(dstIP, dstMac)
  86. if nh != nil {
  87. if !force {
  88. logrus.Warnf("Neighbor entry already present for IP %v, mac %v", dstIP, dstMac)
  89. return nil
  90. }
  91. logrus.Warnf("Force kernel update, Neighbor entry already present for IP %v, mac %v", dstIP, dstMac)
  92. }
  93. nh = &neigh{
  94. dstIP: dstIP,
  95. dstMac: dstMac,
  96. }
  97. nh.processNeighOptions(options...)
  98. if nh.linkName != "" {
  99. nh.linkDst = n.findDst(nh.linkName, false)
  100. if nh.linkDst == "" {
  101. return fmt.Errorf("could not find the interface with name %s", nh.linkName)
  102. }
  103. }
  104. n.Lock()
  105. nlh := n.nlHandle
  106. n.Unlock()
  107. if nh.linkDst != "" {
  108. iface, err = nlh.LinkByName(nh.linkDst)
  109. if err != nil {
  110. return fmt.Errorf("could not find interface with destination name %s: %v",
  111. nh.linkDst, err)
  112. }
  113. }
  114. nlnh := &netlink.Neigh{
  115. IP: dstIP,
  116. HardwareAddr: dstMac,
  117. State: netlink.NUD_PERMANENT,
  118. Family: nh.family,
  119. }
  120. if nlnh.Family > 0 {
  121. nlnh.Flags = netlink.NTF_SELF
  122. }
  123. if nh.linkDst != "" {
  124. nlnh.LinkIndex = iface.Attrs().Index
  125. }
  126. if err := nlh.NeighSet(nlnh); err != nil {
  127. return fmt.Errorf("could not add neighbor entry: %v", err)
  128. }
  129. n.Lock()
  130. n.neighbors = append(n.neighbors, nh)
  131. n.Unlock()
  132. logrus.Debugf("Neighbor entry added for IP %v, mac %v", dstIP, dstMac)
  133. return nil
  134. }