neigh_linux.go 4.3 KB

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