neigh_linux.go 3.8 KB

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