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  }