neigh_linux.go 4.4 KB

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