neigh_linux.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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 *Namespace) 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. // DeleteNeighbor deletes neighbor entry from the sandbox.
  37. func (n *Namespace) 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. log.G(context.TODO()).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. log.G(context.TODO()).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. log.G(context.TODO()).Debugf("Neighbor entry deleted for IP %v, mac %v osDelete:%t", dstIP, dstMac, osDelete)
  100. return nil
  101. }
  102. // AddNeighbor adds a neighbor entry into the sandbox.
  103. func (n *Namespace) AddNeighbor(dstIP net.IP, dstMac net.HardwareAddr, force bool, options ...NeighOption) error {
  104. var (
  105. iface netlink.Link
  106. err error
  107. neighborAlreadyPresent bool
  108. )
  109. // If the namespace already has the neighbor entry but the AddNeighbor is called
  110. // because of a miss notification (force flag) program the kernel anyway.
  111. nh := n.findNeighbor(dstIP, dstMac)
  112. if nh != nil {
  113. neighborAlreadyPresent = true
  114. log.G(context.TODO()).Warnf("Neighbor entry already present for IP %v, mac %v neighbor:%+v forceUpdate:%t", dstIP, dstMac, nh, force)
  115. if !force {
  116. return NeighborSearchError{dstIP, dstMac, true}
  117. }
  118. }
  119. nh = &neigh{
  120. dstIP: dstIP,
  121. dstMac: dstMac,
  122. }
  123. nh.processNeighOptions(options...)
  124. if nh.linkName != "" {
  125. nh.linkDst = n.findDst(nh.linkName, false)
  126. if nh.linkDst == "" {
  127. return fmt.Errorf("could not find the interface with name %s", nh.linkName)
  128. }
  129. }
  130. n.Lock()
  131. nlh := n.nlHandle
  132. n.Unlock()
  133. if nh.linkDst != "" {
  134. iface, err = nlh.LinkByName(nh.linkDst)
  135. if err != nil {
  136. return fmt.Errorf("could not find interface with destination name %s: %v", nh.linkDst, err)
  137. }
  138. }
  139. nlnh := &netlink.Neigh{
  140. IP: dstIP,
  141. HardwareAddr: dstMac,
  142. State: netlink.NUD_PERMANENT,
  143. Family: nh.family,
  144. }
  145. if nlnh.Family > 0 {
  146. nlnh.Flags = netlink.NTF_SELF
  147. }
  148. if nh.linkDst != "" {
  149. nlnh.LinkIndex = iface.Attrs().Index
  150. }
  151. if err := nlh.NeighSet(nlnh); err != nil {
  152. return fmt.Errorf("could not add neighbor entry:%+v error:%v", nlnh, err)
  153. }
  154. if neighborAlreadyPresent {
  155. return nil
  156. }
  157. n.Lock()
  158. n.neighbors = append(n.neighbors, nh)
  159. n.Unlock()
  160. log.G(context.TODO()).Debugf("Neighbor entry added for IP:%v, mac:%v on ifc:%s", dstIP, dstMac, nh.linkName)
  161. return nil
  162. }