neigh_linux.go 4.4 KB

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