github.com/cilium/cilium@v1.16.2/pkg/datapath/linux/probes/managed_neighbors.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package probes 5 6 import ( 7 "errors" 8 "fmt" 9 "net" 10 "sync" 11 12 "github.com/vishvananda/netlink" 13 14 "github.com/cilium/cilium/pkg/netns" 15 ) 16 17 var ( 18 managedNeighborOnce sync.Once 19 managedNeighborResult error 20 ) 21 22 // HaveManagedNeighbors returns nil if the host supports managed neighbor entries (NTF_EXT_MANAGED). 23 // On unexpected probe results this function will terminate with log.Fatal(). 24 func HaveManagedNeighbors() error { 25 managedNeighborOnce.Do(func() { 26 ns, err := netns.New() 27 if err != nil { 28 managedNeighborResult = fmt.Errorf("create netns: %w", err) 29 return 30 } 31 defer ns.Close() 32 33 // In order to call haveManagedNeighbors safely, it has to be started 34 // in a standalone netns 35 managedNeighborResult = ns.Do(func() error { 36 return haveManagedNeighbors() 37 }) 38 39 // if we encounter a different error than ErrNotSupported, terminate the agent. 40 if managedNeighborResult != nil && !errors.Is(managedNeighborResult, ErrNotSupported) { 41 log.WithError(managedNeighborResult).Fatal("failed to probe managed neighbor support") 42 } 43 }) 44 45 return managedNeighborResult 46 } 47 48 func haveManagedNeighbors() (outer error) { 49 // Use a veth device instead of a dummy to avoid the kernel having to modprobe 50 // the dummy kmod, which could potentially be compiled out. veth is currently 51 // a hard dependency for Cilium, so safe to assume the module is available if 52 // not already loaded. 53 veth := &netlink.Veth{ 54 LinkAttrs: netlink.LinkAttrs{Name: "veth0"}, 55 PeerName: "veth1", 56 } 57 58 if err := netlink.LinkAdd(veth); err != nil { 59 return fmt.Errorf("failed to add dummy veth: %w", err) 60 } 61 62 neigh := netlink.Neigh{ 63 LinkIndex: veth.Index, 64 IP: net.IPv4(0, 0, 0, 1), 65 Flags: NTF_EXT_LEARNED, 66 FlagsExt: NTF_EXT_MANAGED, 67 } 68 69 if err := netlink.NeighAdd(&neigh); err != nil { 70 return fmt.Errorf("failed to add neighbor: %w", err) 71 } 72 73 nl, err := netlink.NeighList(veth.Index, 0) 74 if err != nil { 75 return fmt.Errorf("failed to list neighbors: %w", err) 76 } 77 78 for _, n := range nl { 79 if !n.IP.Equal(neigh.IP) { 80 continue 81 } 82 if n.Flags != NTF_EXT_LEARNED { 83 continue 84 } 85 if n.FlagsExt != NTF_EXT_MANAGED { 86 continue 87 } 88 89 return nil 90 } 91 92 return ErrNotSupported 93 }