neigh_linux.go 4.4 KB

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