...

Source file src/k8s.io/kubernetes/pkg/proxy/ipvs/netlink_linux.go

Documentation: k8s.io/kubernetes/pkg/proxy/ipvs

     1  //go:build linux
     2  // +build linux
     3  
     4  /*
     5  Copyright 2017 The Kubernetes Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  package ipvs
    21  
    22  import (
    23  	"fmt"
    24  	"net"
    25  
    26  	"k8s.io/apimachinery/pkg/util/sets"
    27  	"k8s.io/klog/v2"
    28  	proxyutil "k8s.io/kubernetes/pkg/proxy/util"
    29  	netutils "k8s.io/utils/net"
    30  
    31  	"github.com/vishvananda/netlink"
    32  	"golang.org/x/sys/unix"
    33  )
    34  
    35  type netlinkHandle struct {
    36  	netlink.Handle
    37  	isIPv6 bool
    38  }
    39  
    40  // NewNetLinkHandle will create a new NetLinkHandle
    41  func NewNetLinkHandle(isIPv6 bool) NetLinkHandle {
    42  	return &netlinkHandle{netlink.Handle{}, isIPv6}
    43  }
    44  
    45  // EnsureAddressBind checks if address is bound to the interface and, if not, binds it. If the address is already bound, return true.
    46  func (h *netlinkHandle) EnsureAddressBind(address, devName string) (exist bool, err error) {
    47  	dev, err := h.LinkByName(devName)
    48  	if err != nil {
    49  		return false, fmt.Errorf("error get interface: %s, err: %v", devName, err)
    50  	}
    51  	addr := netutils.ParseIPSloppy(address)
    52  	if addr == nil {
    53  		return false, fmt.Errorf("error parse ip address: %s", address)
    54  	}
    55  	if err := h.AddrAdd(dev, &netlink.Addr{IPNet: netlink.NewIPNet(addr)}); err != nil {
    56  		// "EEXIST" will be returned if the address is already bound to device
    57  		if err == unix.EEXIST {
    58  			return true, nil
    59  		}
    60  		return false, fmt.Errorf("error bind address: %s to interface: %s, err: %v", address, devName, err)
    61  	}
    62  	return false, nil
    63  }
    64  
    65  // UnbindAddress makes sure IP address is unbound from the network interface.
    66  func (h *netlinkHandle) UnbindAddress(address, devName string) error {
    67  	dev, err := h.LinkByName(devName)
    68  	if err != nil {
    69  		return fmt.Errorf("error get interface: %s, err: %v", devName, err)
    70  	}
    71  	addr := netutils.ParseIPSloppy(address)
    72  	if addr == nil {
    73  		return fmt.Errorf("error parse ip address: %s", address)
    74  	}
    75  	if err := h.AddrDel(dev, &netlink.Addr{IPNet: netlink.NewIPNet(addr)}); err != nil {
    76  		if err != unix.ENXIO {
    77  			return fmt.Errorf("error unbind address: %s from interface: %s, err: %v", address, devName, err)
    78  		}
    79  	}
    80  	return nil
    81  }
    82  
    83  // EnsureDummyDevice is part of interface
    84  func (h *netlinkHandle) EnsureDummyDevice(devName string) (bool, error) {
    85  	_, err := h.LinkByName(devName)
    86  	if err == nil {
    87  		// found dummy device
    88  		return true, nil
    89  	}
    90  	dummy := &netlink.Dummy{
    91  		LinkAttrs: netlink.LinkAttrs{Name: devName},
    92  	}
    93  	return false, h.LinkAdd(dummy)
    94  }
    95  
    96  // DeleteDummyDevice is part of interface.
    97  func (h *netlinkHandle) DeleteDummyDevice(devName string) error {
    98  	link, err := h.LinkByName(devName)
    99  	if err != nil {
   100  		_, ok := err.(netlink.LinkNotFoundError)
   101  		if ok {
   102  			return nil
   103  		}
   104  		return fmt.Errorf("error deleting a non-exist dummy device: %s, %v", devName, err)
   105  	}
   106  	dummy, ok := link.(*netlink.Dummy)
   107  	if !ok {
   108  		return fmt.Errorf("expect dummy device, got device type: %s", link.Type())
   109  	}
   110  	return h.LinkDel(dummy)
   111  }
   112  
   113  // ListBindAddress will list all IP addresses which are bound in a given interface
   114  func (h *netlinkHandle) ListBindAddress(devName string) ([]string, error) {
   115  	dev, err := h.LinkByName(devName)
   116  	if err != nil {
   117  		return nil, fmt.Errorf("error get interface: %s, err: %v", devName, err)
   118  	}
   119  	addrs, err := h.AddrList(dev, 0)
   120  	if err != nil {
   121  		return nil, fmt.Errorf("error list bound address of interface: %s, err: %v", devName, err)
   122  	}
   123  	var ips []string
   124  	for _, addr := range addrs {
   125  		ips = append(ips, addr.IP.String())
   126  	}
   127  	return ips, nil
   128  }
   129  
   130  // GetAllLocalAddresses return all local addresses on the node.
   131  // Only the addresses of the current family are returned.
   132  // IPv6 link-local and loopback addresses are excluded.
   133  func (h *netlinkHandle) GetAllLocalAddresses() (sets.Set[string], error) {
   134  	addr, err := net.InterfaceAddrs()
   135  	if err != nil {
   136  		return nil, fmt.Errorf("Could not get addresses: %v", err)
   137  	}
   138  	return proxyutil.AddressSet(h.isValidForSet, addr), nil
   139  }
   140  
   141  // GetLocalAddresses return all local addresses for an interface.
   142  // Only the addresses of the current family are returned.
   143  // IPv6 link-local and loopback addresses are excluded.
   144  func (h *netlinkHandle) GetLocalAddresses(dev string) (sets.Set[string], error) {
   145  	ifi, err := net.InterfaceByName(dev)
   146  	if err != nil {
   147  		return nil, fmt.Errorf("Could not get interface %s: %v", dev, err)
   148  	}
   149  	addr, err := ifi.Addrs()
   150  	if err != nil {
   151  		return nil, fmt.Errorf("Can't get addresses from %s: %v", ifi.Name, err)
   152  	}
   153  	return proxyutil.AddressSet(h.isValidForSet, addr), nil
   154  }
   155  
   156  func (h *netlinkHandle) isValidForSet(ip net.IP) bool {
   157  	if h.isIPv6 != netutils.IsIPv6(ip) {
   158  		return false
   159  	}
   160  	if h.isIPv6 && ip.IsLinkLocalUnicast() {
   161  		return false
   162  	}
   163  	if ip.IsLoopback() {
   164  		return false
   165  	}
   166  	return true
   167  }
   168  
   169  // GetAllLocalAddressesExcept return all local addresses on the node,
   170  // except from the passed dev.  This is not the same as to take the
   171  // diff between GetAllLocalAddresses and GetLocalAddresses since an
   172  // address can be assigned to many interfaces. This problem raised
   173  // https://github.com/kubernetes/kubernetes/issues/114815
   174  func (h *netlinkHandle) GetAllLocalAddressesExcept(dev string) (sets.Set[string], error) {
   175  	ifaces, err := net.Interfaces()
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  	var addr []net.Addr
   180  	for _, iface := range ifaces {
   181  		if iface.Name == dev {
   182  			continue
   183  		}
   184  		ifadr, err := iface.Addrs()
   185  		if err != nil {
   186  			// This may happen if the interface was deleted. Ignore
   187  			// but log the error.
   188  			klog.ErrorS(err, "Reading addresses", "interface", iface.Name)
   189  			continue
   190  		}
   191  		addr = append(addr, ifadr...)
   192  	}
   193  	return proxyutil.AddressSet(h.isValidForSet, addr), nil
   194  }
   195  

View as plain text