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 }