go.ligato.io/vpp-agent/v3@v3.5.0/plugins/linux/ifplugin/linuxcalls/link_linuxcalls.go (about)

     1  //  Copyright (c) 2018 Cisco and/or its affiliates.
     2  //
     3  //  Licensed under the Apache License, Version 2.0 (the "License");
     4  //  you may not use this file except in compliance with the License.
     5  //  You may obtain a copy of the License at:
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  //  Unless required by applicable law or agreed to in writing, software
    10  //  distributed under the License is distributed on an "AS IS" BASIS,
    11  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //  See the License for the specific language governing permissions and
    13  //  limitations under the License.
    14  
    15  //go:build !windows && !darwin
    16  
    17  package linuxcalls
    18  
    19  import (
    20  	"net"
    21  
    22  	"github.com/pkg/errors"
    23  	"github.com/vishvananda/netlink"
    24  	"github.com/vishvananda/netns"
    25  )
    26  
    27  // GetLinkByName calls netlink API to get Link type from interface name
    28  func (h *NetLinkHandler) GetLinkByName(ifName string) (netlink.Link, error) {
    29  	link, err := h.LinkByName(ifName)
    30  	if err != nil {
    31  		return nil, errors.Wrapf(err, "LinkByName %q", ifName)
    32  	}
    33  	return link, nil
    34  }
    35  
    36  // GetLinkByIndex calls netlink API to get Link type from interface index
    37  func (h *NetLinkHandler) GetLinkByIndex(ifIdx int) (netlink.Link, error) {
    38  	link, err := h.LinkByIndex(ifIdx)
    39  	if err != nil {
    40  		return nil, errors.Wrapf(err, "LinkByIndex %q", ifIdx)
    41  	}
    42  	return link, nil
    43  }
    44  
    45  // GetLinkList calls netlink API to get all Links in namespace
    46  func (h *NetLinkHandler) GetLinkList() ([]netlink.Link, error) {
    47  	return h.LinkList()
    48  }
    49  
    50  // SetLinkNamespace puts link into a network namespace.
    51  func (h *NetLinkHandler) SetLinkNamespace(link netlink.Link, ns netns.NsHandle) (err error) {
    52  	if err := h.LinkSetNsFd(link, int(ns)); err != nil {
    53  		return errors.Wrapf(err, "LinkSetNsFd %v", ns)
    54  	}
    55  	return nil
    56  }
    57  
    58  // LinkSubscribe takes a channel to which notifications will be sent
    59  // when links change. Close the 'done' chan to stop subscription.
    60  func (h *NetLinkHandler) LinkSubscribe(ch chan<- netlink.LinkUpdate, done <-chan struct{}) error {
    61  	return netlink.LinkSubscribeAt(h.nsHandle, ch, done)
    62  }
    63  
    64  // AddrSubscribe takes a channel to which notifications will be sent
    65  // when addresses change. Close the 'done' chan to stop subscription.
    66  func (h *NetLinkHandler) AddrSubscribe(ch chan<- netlink.AddrUpdate, done <-chan struct{}) error {
    67  	return netlink.AddrSubscribeAt(h.nsHandle, ch, done)
    68  }
    69  
    70  // GetInterfaceType returns the type (string representation) of a given interface.
    71  func (h *NetLinkHandler) GetInterfaceType(ifName string) (string, error) {
    72  	link, err := h.GetLinkByName(ifName)
    73  	if err != nil {
    74  		return "", err
    75  	}
    76  	return link.Type(), nil
    77  }
    78  
    79  // InterfaceExists checks if interface with a given name exists.
    80  func (h *NetLinkHandler) InterfaceExists(ifName string) (bool, error) {
    81  	_, err := h.GetLinkByName(ifName)
    82  	if err == nil {
    83  		return true, nil
    84  	}
    85  	if _, notFound := err.(netlink.LinkNotFoundError); notFound {
    86  		return false, nil
    87  	}
    88  	return false, err
    89  }
    90  
    91  // IsInterfaceUp checks if the interface is UP.
    92  func (h *NetLinkHandler) IsInterfaceUp(ifName string) (bool, error) {
    93  	link, err := h.LinkByName(ifName)
    94  	if err != nil {
    95  		return false, errors.Wrapf(err, "LinkByName %s", ifName)
    96  	}
    97  	return isLinkUp(link), nil
    98  }
    99  
   100  // DeleteInterface removes the given interface.
   101  func (h *NetLinkHandler) DeleteInterface(ifName string) error {
   102  	link, err := h.GetLinkByName(ifName)
   103  	if err != nil {
   104  		return err
   105  	}
   106  	if err := h.LinkDel(link); err != nil {
   107  		return errors.Wrapf(err, "LinkDel %s", link)
   108  	}
   109  	return nil
   110  }
   111  
   112  // RenameInterface changes the name of the interface <ifName> to <newName>.
   113  func (h *NetLinkHandler) RenameInterface(ifName string, newName string) error {
   114  	link, err := h.GetLinkByName(ifName)
   115  	if err != nil {
   116  		return err
   117  	}
   118  	var wasUp bool
   119  	if isLinkUp(link) {
   120  		wasUp = true
   121  		if err = h.LinkSetDown(link); err != nil {
   122  			return errors.Wrapf(err, "LinkSetDown %v", link)
   123  		}
   124  	}
   125  	if err = h.LinkSetName(link, newName); err != nil {
   126  		return errors.Wrapf(err, "LinkSetName %s", newName)
   127  	}
   128  	if wasUp {
   129  		if err = h.LinkSetUp(link); err != nil {
   130  			return errors.Wrapf(err, "LinkSetUp %v", link)
   131  		}
   132  	}
   133  	return nil
   134  }
   135  
   136  // SetInterfaceAlias sets the alias of the given interface.
   137  // Equivalent to: `ip link set dev $ifName alias $alias`
   138  func (h *NetLinkHandler) SetInterfaceAlias(ifName, alias string) error {
   139  	link, err := h.GetLinkByName(ifName)
   140  	if err != nil {
   141  		return err
   142  	}
   143  	if err := h.LinkSetAlias(link, alias); err != nil {
   144  		return errors.Wrapf(err, "LinkSetAlias %s", alias)
   145  	}
   146  	return nil
   147  }
   148  
   149  // SetInterfaceDown calls Netlink API LinkSetDown.
   150  func (h *NetLinkHandler) SetInterfaceDown(ifName string) error {
   151  	link, err := h.GetLinkByName(ifName)
   152  	if err != nil {
   153  		return err
   154  	}
   155  	if err := h.LinkSetDown(link); err != nil {
   156  		return errors.Wrapf(err, "LinkSetDown %v", link)
   157  	}
   158  	return nil
   159  }
   160  
   161  // SetInterfaceUp calls Netlink API LinkSetUp.
   162  func (h *NetLinkHandler) SetInterfaceUp(ifName string) error {
   163  	link, err := h.GetLinkByName(ifName)
   164  	if err != nil {
   165  		return err
   166  	}
   167  	if err := h.LinkSetUp(link); err != nil {
   168  		return errors.Wrapf(err, "LinkSetUp %v", link)
   169  	}
   170  	return nil
   171  }
   172  
   173  // GetAddressList calls AddrList netlink API
   174  func (h *NetLinkHandler) GetAddressList(ifName string) ([]netlink.Addr, error) {
   175  	link, err := h.GetLinkByName(ifName)
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  	return h.AddrList(link, netlink.FAMILY_ALL)
   180  }
   181  
   182  // AddInterfaceIP calls AddrAdd Netlink API.
   183  func (h *NetLinkHandler) AddInterfaceIP(ifName string, ip *net.IPNet) error {
   184  	link, err := h.GetLinkByName(ifName)
   185  	if err != nil {
   186  		return err
   187  	}
   188  	addr := &netlink.Addr{IPNet: ip}
   189  	if err := h.AddrAdd(link, addr); err != nil {
   190  		return errors.Wrapf(err, "AddrAdd %v", addr)
   191  	}
   192  	return nil
   193  }
   194  
   195  // DelInterfaceIP calls AddrDel Netlink API.
   196  func (h *NetLinkHandler) DelInterfaceIP(ifName string, ip *net.IPNet) error {
   197  	link, err := h.GetLinkByName(ifName)
   198  	if err != nil {
   199  		return err
   200  	}
   201  	addr := &netlink.Addr{IPNet: ip}
   202  	if err := h.AddrDel(link, addr); err != nil {
   203  		return errors.Wrapf(err, "AddrDel %v", addr)
   204  	}
   205  	return nil
   206  }
   207  
   208  // SetInterfaceMTU calls LinkSetMTU Netlink API.
   209  func (h *NetLinkHandler) SetInterfaceMTU(ifName string, mtu int) error {
   210  	link, err := h.GetLinkByName(ifName)
   211  	if err != nil {
   212  		return err
   213  	}
   214  	if err := h.LinkSetMTU(link, mtu); err != nil {
   215  		return errors.Wrapf(err, "LinkSetMTU %v", mtu)
   216  	}
   217  	return nil
   218  }
   219  
   220  // SetInterfaceMac calls LinkSetHardwareAddr netlink API.
   221  func (h *NetLinkHandler) SetInterfaceMac(ifName string, macAddress string) error {
   222  	link, err := h.GetLinkByName(ifName)
   223  	if err != nil {
   224  		return err
   225  	}
   226  	hwAddr, err := net.ParseMAC(macAddress)
   227  	if err != nil {
   228  		return err
   229  	}
   230  	if err := h.LinkSetHardwareAddr(link, hwAddr); err != nil {
   231  		return errors.Wrapf(err, "LinkSetHardwareAddr %v", hwAddr)
   232  	}
   233  	return nil
   234  }
   235  
   236  // AddVethInterfacePair calls LinkAdd Netlink API for the Netlink.Veth interface type.
   237  func (h *NetLinkHandler) AddVethInterfacePair(ifName, peerIfName string) error {
   238  	link := &netlink.Veth{
   239  		LinkAttrs: newLinkAttrs(ifName),
   240  		PeerName:  peerIfName,
   241  	}
   242  	if err := h.LinkAdd(link); err != nil {
   243  		return errors.Wrapf(err, "LinkAdd %v", link)
   244  	}
   245  	return nil
   246  }
   247  
   248  // AddDummyInterface configures dummy interface (effectively additional loopback).
   249  func (h *NetLinkHandler) AddDummyInterface(ifName string) error {
   250  	link := &netlink.Dummy{
   251  		LinkAttrs: newLinkAttrs(ifName),
   252  	}
   253  	if err := h.LinkAdd(link); err != nil {
   254  		return errors.Wrapf(err, "LinkAdd (dummy-ifName=%s)", ifName)
   255  	}
   256  	return nil
   257  }
   258  
   259  // AddVRFDevice configures new VRF network device.
   260  func (h *NetLinkHandler) AddVRFDevice(vrfDevName string, routingTable uint32) error {
   261  	link := &netlink.Vrf{
   262  		LinkAttrs: newLinkAttrs(vrfDevName),
   263  		Table:     routingTable,
   264  	}
   265  	if err := h.LinkAdd(link); err != nil {
   266  		return errors.Wrapf(err, "LinkAdd (vrf=%s, rt=%d)",
   267  			vrfDevName, routingTable)
   268  	}
   269  	return nil
   270  }
   271  
   272  // PutInterfaceIntoVRF assigns Linux interface into a given VRF.
   273  func (h *NetLinkHandler) PutInterfaceIntoVRF(ifName, vrfDevName string) error {
   274  	ifLink, err := h.GetLinkByName(ifName)
   275  	if err != nil {
   276  		return err
   277  	}
   278  	vrfLink, err := h.GetLinkByName(vrfDevName)
   279  	if err != nil {
   280  		return err
   281  	}
   282  	if err := h.LinkSetMasterByIndex(ifLink, vrfLink.Attrs().Index); err != nil {
   283  		return errors.Wrapf(err, "LinkSetMasterByIndex (interface=%s, vrf=%s, vrf-index=%d)",
   284  			ifName, vrfDevName, vrfLink.Attrs().Index)
   285  	}
   286  	return nil
   287  }
   288  
   289  // RemoveInterfaceFromVRF un-assigns Linux interface from a given VRF.
   290  func (h *NetLinkHandler) RemoveInterfaceFromVRF(ifName, vrfDevName string) error {
   291  	ifLink, err := h.GetLinkByName(ifName)
   292  	if err != nil {
   293  		return err
   294  	}
   295  	if err := h.LinkSetNoMaster(ifLink); err != nil {
   296  		return errors.Wrapf(err, "LinkSetNoMaster (interface=%s, vrf=%s)",
   297  			ifName, vrfDevName)
   298  	}
   299  	return nil
   300  }
   301  
   302  func isLinkUp(link netlink.Link) bool {
   303  	return (link.Attrs().Flags & net.FlagUp) == net.FlagUp
   304  }
   305  
   306  func newLinkAttrs(name string) netlink.LinkAttrs {
   307  	attrs := netlink.NewLinkAttrs()
   308  	attrs.Name = name
   309  	return attrs
   310  }