github.com/cilium/cilium@v1.16.2/pkg/datapath/tables/device.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package tables
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"net"
    10  	"net/netip"
    11  	"slices"
    12  	"strings"
    13  
    14  	"github.com/cilium/statedb"
    15  	"github.com/cilium/statedb/index"
    16  )
    17  
    18  var (
    19  	DeviceIDIndex = statedb.Index[*Device, int]{
    20  		Name: "id",
    21  		FromObject: func(d *Device) index.KeySet {
    22  			return index.NewKeySet(index.Int(d.Index))
    23  		},
    24  		FromKey: index.Int,
    25  		Unique:  true,
    26  	}
    27  
    28  	DeviceNameIndex = statedb.Index[*Device, string]{
    29  		Name: "name",
    30  		FromObject: func(d *Device) index.KeySet {
    31  			return index.NewKeySet(index.String(d.Name))
    32  		},
    33  		FromKey: index.String,
    34  	}
    35  
    36  	DeviceSelectedIndex = statedb.Index[*Device, bool]{
    37  		Name: "selected",
    38  		FromObject: func(d *Device) index.KeySet {
    39  			return index.NewKeySet(index.Bool(d.Selected))
    40  		},
    41  		FromKey: index.Bool,
    42  	}
    43  )
    44  
    45  func NewDeviceTable() (statedb.RWTable[*Device], error) {
    46  	return statedb.NewTable(
    47  		"devices",
    48  		DeviceIDIndex,
    49  		DeviceNameIndex,
    50  		DeviceSelectedIndex,
    51  	)
    52  }
    53  
    54  // HardwareAddr is the physical address for a network device.
    55  // Defined here instead of using net.HardwareAddr for proper
    56  // JSON marshalling.
    57  type HardwareAddr []byte
    58  
    59  func (a HardwareAddr) String() string {
    60  	return net.HardwareAddr([]byte(a)).String()
    61  }
    62  
    63  func (a HardwareAddr) MarshalJSON() ([]byte, error) {
    64  	return []byte("\"" + a.String() + "\""), nil
    65  }
    66  
    67  func (a *HardwareAddr) UnmarshalJSON(bs []byte) error {
    68  	bs = bytes.Trim(bs, "\"")
    69  	if len(bs) == 0 {
    70  		return nil
    71  	}
    72  	hw, err := net.ParseMAC(string(bs))
    73  	if err != nil {
    74  		return err
    75  	}
    76  	*a = []byte(hw)
    77  	return nil
    78  }
    79  
    80  // Device is a local network device along with addresses associated with it.
    81  //
    82  // The devices that are selected are the external facing native devices that
    83  // Cilium will use with features such as load-balancing, host firewall and routing.
    84  // For the selection logic applied see 'pkg/datapath/linux/devices_controller.go'.
    85  type Device struct {
    86  	Index        int             // positive integer that starts at one, zero is never used
    87  	MTU          int             // maximum transmission unit
    88  	Name         string          // e.g., "en0", "lo0", "eth0.100"
    89  	HardwareAddr HardwareAddr    // IEEE MAC-48, EUI-48 and EUI-64 form
    90  	Flags        net.Flags       // e.g. net.FlagUp, net.eFlagLoopback, net.FlagMulticast
    91  	Addrs        []DeviceAddress // Addresses assigned to the device
    92  	RawFlags     uint32          // Raw interface flags
    93  	Type         string          // Device type, e.g. "veth" etc.
    94  	MasterIndex  int             // Index of the master device (e.g. bridge or bonding device)
    95  
    96  	Selected          bool   // True if this is an external facing device
    97  	NotSelectedReason string // Reason why this device was not selected
    98  }
    99  
   100  func (d *Device) DeepCopy() *Device {
   101  	copy := *d
   102  	copy.Addrs = slices.Clone(d.Addrs)
   103  	return &copy
   104  }
   105  
   106  func (d *Device) HasIP(ip net.IP) bool {
   107  	for _, addr := range d.Addrs {
   108  		if addr.AsIP().Equal(ip) {
   109  			return true
   110  		}
   111  	}
   112  	return false
   113  }
   114  
   115  func (*Device) TableHeader() []string {
   116  	return []string{
   117  		"Name",
   118  		"Index",
   119  		"Selected",
   120  		"Type",
   121  		"MTU",
   122  		"HWAddr",
   123  		"Flags",
   124  		"Addresses",
   125  	}
   126  }
   127  
   128  func (d *Device) TableRow() []string {
   129  	addrs := []string{}
   130  	for _, addr := range d.Addrs {
   131  		addrs = append(addrs, addr.Addr.String())
   132  	}
   133  	return []string{
   134  		d.Name,
   135  		fmt.Sprintf("%d", d.Index),
   136  		fmt.Sprintf("%v", d.Selected),
   137  		d.Type,
   138  		fmt.Sprintf("%d", d.MTU),
   139  		d.HardwareAddr.String(),
   140  		d.Flags.String(),
   141  		strings.Join(addrs, ", "),
   142  	}
   143  }
   144  
   145  type DeviceAddress struct {
   146  	Addr      netip.Addr
   147  	Secondary bool
   148  	Scope     RouteScope // Address scope, e.g. RT_SCOPE_LINK, RT_SCOPE_HOST etc.
   149  }
   150  
   151  func (d *DeviceAddress) AsIP() net.IP {
   152  	return d.Addr.AsSlice()
   153  }
   154  
   155  func (d *DeviceAddress) String() string {
   156  	return fmt.Sprintf("%s (secondary=%v, scope=%d)", d.Addr, d.Secondary, d.Scope)
   157  }
   158  
   159  // SelectedDevices returns the external facing network devices to use for
   160  // load-balancing, host firewall and routing.
   161  //
   162  // The invalidated channel is closed when devices have changed and
   163  // should be requeried with a new transaction.
   164  func SelectedDevices(tbl statedb.Table[*Device], txn statedb.ReadTxn) ([]*Device, <-chan struct{}) {
   165  	iter, invalidated := tbl.ListWatch(txn, DeviceSelectedIndex.Query(true))
   166  	return statedb.Collect(iter), invalidated
   167  }
   168  
   169  // DeviceNames extracts the device names from a slice of devices.
   170  func DeviceNames(devs []*Device) (names []string) {
   171  	names = make([]string, len(devs))
   172  	for i := range devs {
   173  		names[i] = devs[i].Name
   174  	}
   175  	return
   176  }