1package netlink 2 3import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "io/ioutil" 8 "net" 9 "os" 10 "strconv" 11 "strings" 12 "syscall" 13 "unsafe" 14 15 "github.com/vishvananda/netlink/nl" 16 "github.com/vishvananda/netns" 17 "golang.org/x/sys/unix" 18) 19 20const ( 21 SizeofLinkStats32 = 0x5c 22 SizeofLinkStats64 = 0xb8 23) 24 25const ( 26 TUNTAP_MODE_TUN TuntapMode = unix.IFF_TUN 27 TUNTAP_MODE_TAP TuntapMode = unix.IFF_TAP 28 TUNTAP_DEFAULTS TuntapFlag = unix.IFF_TUN_EXCL | unix.IFF_ONE_QUEUE 29 TUNTAP_VNET_HDR TuntapFlag = unix.IFF_VNET_HDR 30 TUNTAP_TUN_EXCL TuntapFlag = unix.IFF_TUN_EXCL 31 TUNTAP_NO_PI TuntapFlag = unix.IFF_NO_PI 32 TUNTAP_ONE_QUEUE TuntapFlag = unix.IFF_ONE_QUEUE 33 TUNTAP_MULTI_QUEUE TuntapFlag = unix.IFF_MULTI_QUEUE 34 TUNTAP_MULTI_QUEUE_DEFAULTS TuntapFlag = TUNTAP_MULTI_QUEUE | TUNTAP_NO_PI 35) 36 37const ( 38 VF_LINK_STATE_AUTO uint32 = 0 39 VF_LINK_STATE_ENABLE uint32 = 1 40 VF_LINK_STATE_DISABLE uint32 = 2 41) 42 43var lookupByDump = false 44 45var macvlanModes = [...]uint32{ 46 0, 47 nl.MACVLAN_MODE_PRIVATE, 48 nl.MACVLAN_MODE_VEPA, 49 nl.MACVLAN_MODE_BRIDGE, 50 nl.MACVLAN_MODE_PASSTHRU, 51 nl.MACVLAN_MODE_SOURCE, 52} 53 54func ensureIndex(link *LinkAttrs) { 55 if link != nil && link.Index == 0 { 56 newlink, _ := LinkByName(link.Name) 57 if newlink != nil { 58 link.Index = newlink.Attrs().Index 59 } 60 } 61} 62 63func (h *Handle) ensureIndex(link *LinkAttrs) { 64 if link != nil && link.Index == 0 { 65 newlink, _ := h.LinkByName(link.Name) 66 if newlink != nil { 67 link.Index = newlink.Attrs().Index 68 } 69 } 70} 71 72func (h *Handle) LinkSetARPOff(link Link) error { 73 base := link.Attrs() 74 h.ensureIndex(base) 75 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 76 77 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 78 msg.Change |= unix.IFF_NOARP 79 msg.Flags |= unix.IFF_NOARP 80 msg.Index = int32(base.Index) 81 req.AddData(msg) 82 83 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 84 return err 85} 86 87func LinkSetARPOff(link Link) error { 88 return pkgHandle.LinkSetARPOff(link) 89} 90 91func (h *Handle) LinkSetARPOn(link Link) error { 92 base := link.Attrs() 93 h.ensureIndex(base) 94 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 95 96 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 97 msg.Change |= unix.IFF_NOARP 98 msg.Flags &= ^uint32(unix.IFF_NOARP) 99 msg.Index = int32(base.Index) 100 req.AddData(msg) 101 102 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 103 return err 104} 105 106func LinkSetARPOn(link Link) error { 107 return pkgHandle.LinkSetARPOn(link) 108} 109 110func (h *Handle) SetPromiscOn(link Link) error { 111 base := link.Attrs() 112 h.ensureIndex(base) 113 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 114 115 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 116 msg.Change = unix.IFF_PROMISC 117 msg.Flags = unix.IFF_PROMISC 118 msg.Index = int32(base.Index) 119 req.AddData(msg) 120 121 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 122 return err 123} 124 125// LinkSetAllmulticastOn enables the reception of all hardware multicast packets for the link device. 126// Equivalent to: `ip link set $link allmulticast on` 127func LinkSetAllmulticastOn(link Link) error { 128 return pkgHandle.LinkSetAllmulticastOn(link) 129} 130 131// LinkSetAllmulticastOn enables the reception of all hardware multicast packets for the link device. 132// Equivalent to: `ip link set $link allmulticast on` 133func (h *Handle) LinkSetAllmulticastOn(link Link) error { 134 base := link.Attrs() 135 h.ensureIndex(base) 136 req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK) 137 138 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 139 msg.Change = unix.IFF_ALLMULTI 140 msg.Flags = unix.IFF_ALLMULTI 141 142 msg.Index = int32(base.Index) 143 req.AddData(msg) 144 145 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 146 return err 147} 148 149// LinkSetAllmulticastOff disables the reception of all hardware multicast packets for the link device. 150// Equivalent to: `ip link set $link allmulticast off` 151func LinkSetAllmulticastOff(link Link) error { 152 return pkgHandle.LinkSetAllmulticastOff(link) 153} 154 155// LinkSetAllmulticastOff disables the reception of all hardware multicast packets for the link device. 156// Equivalent to: `ip link set $link allmulticast off` 157func (h *Handle) LinkSetAllmulticastOff(link Link) error { 158 base := link.Attrs() 159 h.ensureIndex(base) 160 req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK) 161 162 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 163 msg.Change = unix.IFF_ALLMULTI 164 msg.Index = int32(base.Index) 165 req.AddData(msg) 166 167 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 168 return err 169} 170 171func MacvlanMACAddrAdd(link Link, addr net.HardwareAddr) error { 172 return pkgHandle.MacvlanMACAddrAdd(link, addr) 173} 174 175func (h *Handle) MacvlanMACAddrAdd(link Link, addr net.HardwareAddr) error { 176 return h.macvlanMACAddrChange(link, []net.HardwareAddr{addr}, nl.MACVLAN_MACADDR_ADD) 177} 178 179func MacvlanMACAddrDel(link Link, addr net.HardwareAddr) error { 180 return pkgHandle.MacvlanMACAddrDel(link, addr) 181} 182 183func (h *Handle) MacvlanMACAddrDel(link Link, addr net.HardwareAddr) error { 184 return h.macvlanMACAddrChange(link, []net.HardwareAddr{addr}, nl.MACVLAN_MACADDR_DEL) 185} 186 187func MacvlanMACAddrFlush(link Link) error { 188 return pkgHandle.MacvlanMACAddrFlush(link) 189} 190 191func (h *Handle) MacvlanMACAddrFlush(link Link) error { 192 return h.macvlanMACAddrChange(link, nil, nl.MACVLAN_MACADDR_FLUSH) 193} 194 195func MacvlanMACAddrSet(link Link, addrs []net.HardwareAddr) error { 196 return pkgHandle.MacvlanMACAddrSet(link, addrs) 197} 198 199func (h *Handle) MacvlanMACAddrSet(link Link, addrs []net.HardwareAddr) error { 200 return h.macvlanMACAddrChange(link, addrs, nl.MACVLAN_MACADDR_SET) 201} 202 203func (h *Handle) macvlanMACAddrChange(link Link, addrs []net.HardwareAddr, mode uint32) error { 204 base := link.Attrs() 205 h.ensureIndex(base) 206 req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK) 207 208 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 209 msg.Index = int32(base.Index) 210 req.AddData(msg) 211 212 linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil) 213 linkInfo.AddRtAttr(nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type())) 214 inner := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 215 216 // IFLA_MACVLAN_MACADDR_MODE = mode 217 b := make([]byte, 4) 218 native.PutUint32(b, mode) 219 inner.AddRtAttr(nl.IFLA_MACVLAN_MACADDR_MODE, b) 220 221 // populate message with MAC addrs, if necessary 222 switch mode { 223 case nl.MACVLAN_MACADDR_ADD, nl.MACVLAN_MACADDR_DEL: 224 if len(addrs) == 1 { 225 inner.AddRtAttr(nl.IFLA_MACVLAN_MACADDR, []byte(addrs[0])) 226 } 227 case nl.MACVLAN_MACADDR_SET: 228 mad := inner.AddRtAttr(nl.IFLA_MACVLAN_MACADDR_DATA, nil) 229 for _, addr := range addrs { 230 mad.AddRtAttr(nl.IFLA_MACVLAN_MACADDR, []byte(addr)) 231 } 232 } 233 234 req.AddData(linkInfo) 235 236 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 237 return err 238} 239 240func BridgeSetMcastSnoop(link Link, on bool) error { 241 return pkgHandle.BridgeSetMcastSnoop(link, on) 242} 243 244func (h *Handle) BridgeSetMcastSnoop(link Link, on bool) error { 245 bridge := link.(*Bridge) 246 bridge.MulticastSnooping = &on 247 return h.linkModify(bridge, unix.NLM_F_ACK) 248} 249 250func SetPromiscOn(link Link) error { 251 return pkgHandle.SetPromiscOn(link) 252} 253 254func (h *Handle) SetPromiscOff(link Link) error { 255 base := link.Attrs() 256 h.ensureIndex(base) 257 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 258 259 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 260 msg.Change = unix.IFF_PROMISC 261 msg.Index = int32(base.Index) 262 req.AddData(msg) 263 264 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 265 return err 266} 267 268func SetPromiscOff(link Link) error { 269 return pkgHandle.SetPromiscOff(link) 270} 271 272// LinkSetUp enables the link device. 273// Equivalent to: `ip link set $link up` 274func LinkSetUp(link Link) error { 275 return pkgHandle.LinkSetUp(link) 276} 277 278// LinkSetUp enables the link device. 279// Equivalent to: `ip link set $link up` 280func (h *Handle) LinkSetUp(link Link) error { 281 base := link.Attrs() 282 h.ensureIndex(base) 283 req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK) 284 285 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 286 msg.Change = unix.IFF_UP 287 msg.Flags = unix.IFF_UP 288 msg.Index = int32(base.Index) 289 req.AddData(msg) 290 291 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 292 return err 293} 294 295// LinkSetDown disables link device. 296// Equivalent to: `ip link set $link down` 297func LinkSetDown(link Link) error { 298 return pkgHandle.LinkSetDown(link) 299} 300 301// LinkSetDown disables link device. 302// Equivalent to: `ip link set $link down` 303func (h *Handle) LinkSetDown(link Link) error { 304 base := link.Attrs() 305 h.ensureIndex(base) 306 req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK) 307 308 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 309 msg.Change = unix.IFF_UP 310 msg.Index = int32(base.Index) 311 req.AddData(msg) 312 313 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 314 return err 315} 316 317// LinkSetMTU sets the mtu of the link device. 318// Equivalent to: `ip link set $link mtu $mtu` 319func LinkSetMTU(link Link, mtu int) error { 320 return pkgHandle.LinkSetMTU(link, mtu) 321} 322 323// LinkSetMTU sets the mtu of the link device. 324// Equivalent to: `ip link set $link mtu $mtu` 325func (h *Handle) LinkSetMTU(link Link, mtu int) error { 326 base := link.Attrs() 327 h.ensureIndex(base) 328 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 329 330 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 331 msg.Index = int32(base.Index) 332 req.AddData(msg) 333 334 b := make([]byte, 4) 335 native.PutUint32(b, uint32(mtu)) 336 337 data := nl.NewRtAttr(unix.IFLA_MTU, b) 338 req.AddData(data) 339 340 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 341 return err 342} 343 344// LinkSetName sets the name of the link device. 345// Equivalent to: `ip link set $link name $name` 346func LinkSetName(link Link, name string) error { 347 return pkgHandle.LinkSetName(link, name) 348} 349 350// LinkSetName sets the name of the link device. 351// Equivalent to: `ip link set $link name $name` 352func (h *Handle) LinkSetName(link Link, name string) error { 353 base := link.Attrs() 354 h.ensureIndex(base) 355 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 356 357 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 358 msg.Index = int32(base.Index) 359 req.AddData(msg) 360 361 data := nl.NewRtAttr(unix.IFLA_IFNAME, []byte(name)) 362 req.AddData(data) 363 364 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 365 return err 366} 367 368// LinkSetAlias sets the alias of the link device. 369// Equivalent to: `ip link set dev $link alias $name` 370func LinkSetAlias(link Link, name string) error { 371 return pkgHandle.LinkSetAlias(link, name) 372} 373 374// LinkSetAlias sets the alias of the link device. 375// Equivalent to: `ip link set dev $link alias $name` 376func (h *Handle) LinkSetAlias(link Link, name string) error { 377 base := link.Attrs() 378 h.ensureIndex(base) 379 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 380 381 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 382 msg.Index = int32(base.Index) 383 req.AddData(msg) 384 385 data := nl.NewRtAttr(unix.IFLA_IFALIAS, []byte(name)) 386 req.AddData(data) 387 388 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 389 return err 390} 391 392// LinkSetHardwareAddr sets the hardware address of the link device. 393// Equivalent to: `ip link set $link address $hwaddr` 394func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error { 395 return pkgHandle.LinkSetHardwareAddr(link, hwaddr) 396} 397 398// LinkSetHardwareAddr sets the hardware address of the link device. 399// Equivalent to: `ip link set $link address $hwaddr` 400func (h *Handle) LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error { 401 base := link.Attrs() 402 h.ensureIndex(base) 403 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 404 405 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 406 msg.Index = int32(base.Index) 407 req.AddData(msg) 408 409 data := nl.NewRtAttr(unix.IFLA_ADDRESS, []byte(hwaddr)) 410 req.AddData(data) 411 412 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 413 return err 414} 415 416// LinkSetVfHardwareAddr sets the hardware address of a vf for the link. 417// Equivalent to: `ip link set $link vf $vf mac $hwaddr` 418func LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error { 419 return pkgHandle.LinkSetVfHardwareAddr(link, vf, hwaddr) 420} 421 422// LinkSetVfHardwareAddr sets the hardware address of a vf for the link. 423// Equivalent to: `ip link set $link vf $vf mac $hwaddr` 424func (h *Handle) LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error { 425 base := link.Attrs() 426 h.ensureIndex(base) 427 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 428 429 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 430 msg.Index = int32(base.Index) 431 req.AddData(msg) 432 433 data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) 434 info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) 435 vfmsg := nl.VfMac{ 436 Vf: uint32(vf), 437 } 438 copy(vfmsg.Mac[:], []byte(hwaddr)) 439 info.AddRtAttr(nl.IFLA_VF_MAC, vfmsg.Serialize()) 440 req.AddData(data) 441 442 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 443 return err 444} 445 446// LinkSetVfVlan sets the vlan of a vf for the link. 447// Equivalent to: `ip link set $link vf $vf vlan $vlan` 448func LinkSetVfVlan(link Link, vf, vlan int) error { 449 return pkgHandle.LinkSetVfVlan(link, vf, vlan) 450} 451 452// LinkSetVfVlan sets the vlan of a vf for the link. 453// Equivalent to: `ip link set $link vf $vf vlan $vlan` 454func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error { 455 base := link.Attrs() 456 h.ensureIndex(base) 457 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 458 459 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 460 msg.Index = int32(base.Index) 461 req.AddData(msg) 462 463 data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) 464 info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) 465 vfmsg := nl.VfVlan{ 466 Vf: uint32(vf), 467 Vlan: uint32(vlan), 468 } 469 info.AddRtAttr(nl.IFLA_VF_VLAN, vfmsg.Serialize()) 470 req.AddData(data) 471 472 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 473 return err 474} 475 476// LinkSetVfVlanQos sets the vlan and qos priority of a vf for the link. 477// Equivalent to: `ip link set $link vf $vf vlan $vlan qos $qos` 478func LinkSetVfVlanQos(link Link, vf, vlan, qos int) error { 479 return pkgHandle.LinkSetVfVlanQos(link, vf, vlan, qos) 480} 481 482// LinkSetVfVlanQos sets the vlan and qos priority of a vf for the link. 483// Equivalent to: `ip link set $link vf $vf vlan $vlan qos $qos` 484func (h *Handle) LinkSetVfVlanQos(link Link, vf, vlan, qos int) error { 485 base := link.Attrs() 486 h.ensureIndex(base) 487 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 488 489 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 490 msg.Index = int32(base.Index) 491 req.AddData(msg) 492 493 data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) 494 info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil) 495 vfmsg := nl.VfVlan{ 496 Vf: uint32(vf), 497 Vlan: uint32(vlan), 498 Qos: uint32(qos), 499 } 500 nl.NewRtAttrChild(info, nl.IFLA_VF_VLAN, vfmsg.Serialize()) 501 req.AddData(data) 502 503 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 504 return err 505} 506 507// LinkSetVfTxRate sets the tx rate of a vf for the link. 508// Equivalent to: `ip link set $link vf $vf rate $rate` 509func LinkSetVfTxRate(link Link, vf, rate int) error { 510 return pkgHandle.LinkSetVfTxRate(link, vf, rate) 511} 512 513// LinkSetVfTxRate sets the tx rate of a vf for the link. 514// Equivalent to: `ip link set $link vf $vf rate $rate` 515func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error { 516 base := link.Attrs() 517 h.ensureIndex(base) 518 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 519 520 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 521 msg.Index = int32(base.Index) 522 req.AddData(msg) 523 524 data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) 525 info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) 526 vfmsg := nl.VfTxRate{ 527 Vf: uint32(vf), 528 Rate: uint32(rate), 529 } 530 info.AddRtAttr(nl.IFLA_VF_TX_RATE, vfmsg.Serialize()) 531 req.AddData(data) 532 533 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 534 return err 535} 536 537// LinkSetVfRate sets the min and max tx rate of a vf for the link. 538// Equivalent to: `ip link set $link vf $vf min_tx_rate $min_rate max_tx_rate $max_rate` 539func LinkSetVfRate(link Link, vf, minRate, maxRate int) error { 540 return pkgHandle.LinkSetVfRate(link, vf, minRate, maxRate) 541} 542 543// LinkSetVfRate sets the min and max tx rate of a vf for the link. 544// Equivalent to: `ip link set $link vf $vf min_tx_rate $min_rate max_tx_rate $max_rate` 545func (h *Handle) LinkSetVfRate(link Link, vf, minRate, maxRate int) error { 546 base := link.Attrs() 547 h.ensureIndex(base) 548 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 549 550 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 551 msg.Index = int32(base.Index) 552 req.AddData(msg) 553 554 data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) 555 info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) 556 vfmsg := nl.VfRate{ 557 Vf: uint32(vf), 558 MinTxRate: uint32(minRate), 559 MaxTxRate: uint32(maxRate), 560 } 561 info.AddRtAttr(nl.IFLA_VF_RATE, vfmsg.Serialize()) 562 req.AddData(data) 563 564 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 565 return err 566} 567 568// LinkSetVfState enables/disables virtual link state on a vf. 569// Equivalent to: `ip link set $link vf $vf state $state` 570func LinkSetVfState(link Link, vf int, state uint32) error { 571 return pkgHandle.LinkSetVfState(link, vf, state) 572} 573 574// LinkSetVfState enables/disables virtual link state on a vf. 575// Equivalent to: `ip link set $link vf $vf state $state` 576func (h *Handle) LinkSetVfState(link Link, vf int, state uint32) error { 577 base := link.Attrs() 578 h.ensureIndex(base) 579 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 580 581 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 582 msg.Index = int32(base.Index) 583 req.AddData(msg) 584 585 data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) 586 info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) 587 vfmsg := nl.VfLinkState{ 588 Vf: uint32(vf), 589 LinkState: state, 590 } 591 info.AddRtAttr(nl.IFLA_VF_LINK_STATE, vfmsg.Serialize()) 592 req.AddData(data) 593 594 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 595 return err 596} 597 598// LinkSetVfSpoofchk enables/disables spoof check on a vf for the link. 599// Equivalent to: `ip link set $link vf $vf spoofchk $check` 600func LinkSetVfSpoofchk(link Link, vf int, check bool) error { 601 return pkgHandle.LinkSetVfSpoofchk(link, vf, check) 602} 603 604// LinkSetVfSpoofchk enables/disables spoof check on a vf for the link. 605// Equivalent to: `ip link set $link vf $vf spoofchk $check` 606func (h *Handle) LinkSetVfSpoofchk(link Link, vf int, check bool) error { 607 var setting uint32 608 base := link.Attrs() 609 h.ensureIndex(base) 610 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 611 612 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 613 msg.Index = int32(base.Index) 614 req.AddData(msg) 615 616 data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) 617 info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) 618 if check { 619 setting = 1 620 } 621 vfmsg := nl.VfSpoofchk{ 622 Vf: uint32(vf), 623 Setting: setting, 624 } 625 info.AddRtAttr(nl.IFLA_VF_SPOOFCHK, vfmsg.Serialize()) 626 req.AddData(data) 627 628 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 629 return err 630} 631 632// LinkSetVfTrust enables/disables trust state on a vf for the link. 633// Equivalent to: `ip link set $link vf $vf trust $state` 634func LinkSetVfTrust(link Link, vf int, state bool) error { 635 return pkgHandle.LinkSetVfTrust(link, vf, state) 636} 637 638// LinkSetVfTrust enables/disables trust state on a vf for the link. 639// Equivalent to: `ip link set $link vf $vf trust $state` 640func (h *Handle) LinkSetVfTrust(link Link, vf int, state bool) error { 641 var setting uint32 642 base := link.Attrs() 643 h.ensureIndex(base) 644 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 645 646 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 647 msg.Index = int32(base.Index) 648 req.AddData(msg) 649 650 data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) 651 info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) 652 if state { 653 setting = 1 654 } 655 vfmsg := nl.VfTrust{ 656 Vf: uint32(vf), 657 Setting: setting, 658 } 659 info.AddRtAttr(nl.IFLA_VF_TRUST, vfmsg.Serialize()) 660 req.AddData(data) 661 662 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 663 return err 664} 665 666// LinkSetVfNodeGUID sets the node GUID of a vf for the link. 667// Equivalent to: `ip link set dev $link vf $vf node_guid $nodeguid` 668func LinkSetVfNodeGUID(link Link, vf int, nodeguid net.HardwareAddr) error { 669 return pkgHandle.LinkSetVfGUID(link, vf, nodeguid, nl.IFLA_VF_IB_NODE_GUID) 670} 671 672// LinkSetVfPortGUID sets the port GUID of a vf for the link. 673// Equivalent to: `ip link set dev $link vf $vf port_guid $portguid` 674func LinkSetVfPortGUID(link Link, vf int, portguid net.HardwareAddr) error { 675 return pkgHandle.LinkSetVfGUID(link, vf, portguid, nl.IFLA_VF_IB_PORT_GUID) 676} 677 678// LinkSetVfGUID sets the node or port GUID of a vf for the link. 679func (h *Handle) LinkSetVfGUID(link Link, vf int, vfGuid net.HardwareAddr, guidType int) error { 680 var err error 681 var guid uint64 682 683 buf := bytes.NewBuffer(vfGuid) 684 err = binary.Read(buf, binary.BigEndian, &guid) 685 if err != nil { 686 return err 687 } 688 689 base := link.Attrs() 690 h.ensureIndex(base) 691 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 692 693 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 694 msg.Index = int32(base.Index) 695 req.AddData(msg) 696 697 data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) 698 info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) 699 vfmsg := nl.VfGUID{ 700 Vf: uint32(vf), 701 GUID: guid, 702 } 703 info.AddRtAttr(guidType, vfmsg.Serialize()) 704 req.AddData(data) 705 706 _, err = req.Execute(unix.NETLINK_ROUTE, 0) 707 return err 708} 709 710// LinkSetMaster sets the master of the link device. 711// Equivalent to: `ip link set $link master $master` 712func LinkSetMaster(link Link, master Link) error { 713 return pkgHandle.LinkSetMaster(link, master) 714} 715 716// LinkSetMaster sets the master of the link device. 717// Equivalent to: `ip link set $link master $master` 718func (h *Handle) LinkSetMaster(link Link, master Link) error { 719 index := 0 720 if master != nil { 721 masterBase := master.Attrs() 722 h.ensureIndex(masterBase) 723 index = masterBase.Index 724 } 725 if index <= 0 { 726 return fmt.Errorf("Device does not exist") 727 } 728 return h.LinkSetMasterByIndex(link, index) 729} 730 731// LinkSetNoMaster removes the master of the link device. 732// Equivalent to: `ip link set $link nomaster` 733func LinkSetNoMaster(link Link) error { 734 return pkgHandle.LinkSetNoMaster(link) 735} 736 737// LinkSetNoMaster removes the master of the link device. 738// Equivalent to: `ip link set $link nomaster` 739func (h *Handle) LinkSetNoMaster(link Link) error { 740 return h.LinkSetMasterByIndex(link, 0) 741} 742 743// LinkSetMasterByIndex sets the master of the link device. 744// Equivalent to: `ip link set $link master $master` 745func LinkSetMasterByIndex(link Link, masterIndex int) error { 746 return pkgHandle.LinkSetMasterByIndex(link, masterIndex) 747} 748 749// LinkSetMasterByIndex sets the master of the link device. 750// Equivalent to: `ip link set $link master $master` 751func (h *Handle) LinkSetMasterByIndex(link Link, masterIndex int) error { 752 base := link.Attrs() 753 h.ensureIndex(base) 754 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 755 756 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 757 msg.Index = int32(base.Index) 758 req.AddData(msg) 759 760 b := make([]byte, 4) 761 native.PutUint32(b, uint32(masterIndex)) 762 763 data := nl.NewRtAttr(unix.IFLA_MASTER, b) 764 req.AddData(data) 765 766 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 767 return err 768} 769 770// LinkSetNsPid puts the device into a new network namespace. The 771// pid must be a pid of a running process. 772// Equivalent to: `ip link set $link netns $pid` 773func LinkSetNsPid(link Link, nspid int) error { 774 return pkgHandle.LinkSetNsPid(link, nspid) 775} 776 777// LinkSetNsPid puts the device into a new network namespace. The 778// pid must be a pid of a running process. 779// Equivalent to: `ip link set $link netns $pid` 780func (h *Handle) LinkSetNsPid(link Link, nspid int) error { 781 base := link.Attrs() 782 h.ensureIndex(base) 783 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 784 785 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 786 msg.Index = int32(base.Index) 787 req.AddData(msg) 788 789 b := make([]byte, 4) 790 native.PutUint32(b, uint32(nspid)) 791 792 data := nl.NewRtAttr(unix.IFLA_NET_NS_PID, b) 793 req.AddData(data) 794 795 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 796 return err 797} 798 799// LinkSetNsFd puts the device into a new network namespace. The 800// fd must be an open file descriptor to a network namespace. 801// Similar to: `ip link set $link netns $ns` 802func LinkSetNsFd(link Link, fd int) error { 803 return pkgHandle.LinkSetNsFd(link, fd) 804} 805 806// LinkSetNsFd puts the device into a new network namespace. The 807// fd must be an open file descriptor to a network namespace. 808// Similar to: `ip link set $link netns $ns` 809func (h *Handle) LinkSetNsFd(link Link, fd int) error { 810 base := link.Attrs() 811 h.ensureIndex(base) 812 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 813 814 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 815 msg.Index = int32(base.Index) 816 req.AddData(msg) 817 818 b := make([]byte, 4) 819 native.PutUint32(b, uint32(fd)) 820 821 data := nl.NewRtAttr(unix.IFLA_NET_NS_FD, b) 822 req.AddData(data) 823 824 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 825 return err 826} 827 828// LinkSetXdpFd adds a bpf function to the driver. The fd must be a bpf 829// program loaded with bpf(type=BPF_PROG_TYPE_XDP) 830func LinkSetXdpFd(link Link, fd int) error { 831 return LinkSetXdpFdWithFlags(link, fd, 0) 832} 833 834// LinkSetXdpFdWithFlags adds a bpf function to the driver with the given 835// options. The fd must be a bpf program loaded with bpf(type=BPF_PROG_TYPE_XDP) 836func LinkSetXdpFdWithFlags(link Link, fd, flags int) error { 837 base := link.Attrs() 838 ensureIndex(base) 839 req := nl.NewNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 840 841 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 842 msg.Index = int32(base.Index) 843 req.AddData(msg) 844 845 addXdpAttrs(&LinkXdp{Fd: fd, Flags: uint32(flags)}, req) 846 847 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 848 return err 849} 850 851func boolAttr(val bool) []byte { 852 var v uint8 853 if val { 854 v = 1 855 } 856 return nl.Uint8Attr(v) 857} 858 859type vxlanPortRange struct { 860 Lo, Hi uint16 861} 862 863func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) { 864 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 865 866 if vxlan.FlowBased { 867 vxlan.VxlanId = 0 868 } 869 870 data.AddRtAttr(nl.IFLA_VXLAN_ID, nl.Uint32Attr(uint32(vxlan.VxlanId))) 871 872 if vxlan.VtepDevIndex != 0 { 873 data.AddRtAttr(nl.IFLA_VXLAN_LINK, nl.Uint32Attr(uint32(vxlan.VtepDevIndex))) 874 } 875 if vxlan.SrcAddr != nil { 876 ip := vxlan.SrcAddr.To4() 877 if ip != nil { 878 data.AddRtAttr(nl.IFLA_VXLAN_LOCAL, []byte(ip)) 879 } else { 880 ip = vxlan.SrcAddr.To16() 881 if ip != nil { 882 data.AddRtAttr(nl.IFLA_VXLAN_LOCAL6, []byte(ip)) 883 } 884 } 885 } 886 if vxlan.Group != nil { 887 group := vxlan.Group.To4() 888 if group != nil { 889 data.AddRtAttr(nl.IFLA_VXLAN_GROUP, []byte(group)) 890 } else { 891 group = vxlan.Group.To16() 892 if group != nil { 893 data.AddRtAttr(nl.IFLA_VXLAN_GROUP6, []byte(group)) 894 } 895 } 896 } 897 898 data.AddRtAttr(nl.IFLA_VXLAN_TTL, nl.Uint8Attr(uint8(vxlan.TTL))) 899 data.AddRtAttr(nl.IFLA_VXLAN_TOS, nl.Uint8Attr(uint8(vxlan.TOS))) 900 data.AddRtAttr(nl.IFLA_VXLAN_LEARNING, boolAttr(vxlan.Learning)) 901 data.AddRtAttr(nl.IFLA_VXLAN_PROXY, boolAttr(vxlan.Proxy)) 902 data.AddRtAttr(nl.IFLA_VXLAN_RSC, boolAttr(vxlan.RSC)) 903 data.AddRtAttr(nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss)) 904 data.AddRtAttr(nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss)) 905 data.AddRtAttr(nl.IFLA_VXLAN_UDP_ZERO_CSUM6_TX, boolAttr(vxlan.UDP6ZeroCSumTx)) 906 data.AddRtAttr(nl.IFLA_VXLAN_UDP_ZERO_CSUM6_RX, boolAttr(vxlan.UDP6ZeroCSumRx)) 907 908 if vxlan.UDPCSum { 909 data.AddRtAttr(nl.IFLA_VXLAN_UDP_CSUM, boolAttr(vxlan.UDPCSum)) 910 } 911 if vxlan.GBP { 912 data.AddRtAttr(nl.IFLA_VXLAN_GBP, []byte{}) 913 } 914 if vxlan.FlowBased { 915 data.AddRtAttr(nl.IFLA_VXLAN_FLOWBASED, boolAttr(vxlan.FlowBased)) 916 } 917 if vxlan.NoAge { 918 data.AddRtAttr(nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0)) 919 } else if vxlan.Age > 0 { 920 data.AddRtAttr(nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(uint32(vxlan.Age))) 921 } 922 if vxlan.Limit > 0 { 923 data.AddRtAttr(nl.IFLA_VXLAN_LIMIT, nl.Uint32Attr(uint32(vxlan.Limit))) 924 } 925 if vxlan.Port > 0 { 926 data.AddRtAttr(nl.IFLA_VXLAN_PORT, htons(uint16(vxlan.Port))) 927 } 928 if vxlan.PortLow > 0 || vxlan.PortHigh > 0 { 929 pr := vxlanPortRange{uint16(vxlan.PortLow), uint16(vxlan.PortHigh)} 930 931 buf := new(bytes.Buffer) 932 binary.Write(buf, binary.BigEndian, &pr) 933 934 data.AddRtAttr(nl.IFLA_VXLAN_PORT_RANGE, buf.Bytes()) 935 } 936} 937 938func addBondAttrs(bond *Bond, linkInfo *nl.RtAttr) { 939 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 940 if bond.Mode >= 0 { 941 data.AddRtAttr(nl.IFLA_BOND_MODE, nl.Uint8Attr(uint8(bond.Mode))) 942 } 943 if bond.ActiveSlave >= 0 { 944 data.AddRtAttr(nl.IFLA_BOND_ACTIVE_SLAVE, nl.Uint32Attr(uint32(bond.ActiveSlave))) 945 } 946 if bond.Miimon >= 0 { 947 data.AddRtAttr(nl.IFLA_BOND_MIIMON, nl.Uint32Attr(uint32(bond.Miimon))) 948 } 949 if bond.UpDelay >= 0 { 950 data.AddRtAttr(nl.IFLA_BOND_UPDELAY, nl.Uint32Attr(uint32(bond.UpDelay))) 951 } 952 if bond.DownDelay >= 0 { 953 data.AddRtAttr(nl.IFLA_BOND_DOWNDELAY, nl.Uint32Attr(uint32(bond.DownDelay))) 954 } 955 if bond.UseCarrier >= 0 { 956 data.AddRtAttr(nl.IFLA_BOND_USE_CARRIER, nl.Uint8Attr(uint8(bond.UseCarrier))) 957 } 958 if bond.ArpInterval >= 0 { 959 data.AddRtAttr(nl.IFLA_BOND_ARP_INTERVAL, nl.Uint32Attr(uint32(bond.ArpInterval))) 960 } 961 if bond.ArpIpTargets != nil { 962 msg := data.AddRtAttr(nl.IFLA_BOND_ARP_IP_TARGET, nil) 963 for i := range bond.ArpIpTargets { 964 ip := bond.ArpIpTargets[i].To4() 965 if ip != nil { 966 msg.AddRtAttr(i, []byte(ip)) 967 continue 968 } 969 ip = bond.ArpIpTargets[i].To16() 970 if ip != nil { 971 msg.AddRtAttr(i, []byte(ip)) 972 } 973 } 974 } 975 if bond.ArpValidate >= 0 { 976 data.AddRtAttr(nl.IFLA_BOND_ARP_VALIDATE, nl.Uint32Attr(uint32(bond.ArpValidate))) 977 } 978 if bond.ArpAllTargets >= 0 { 979 data.AddRtAttr(nl.IFLA_BOND_ARP_ALL_TARGETS, nl.Uint32Attr(uint32(bond.ArpAllTargets))) 980 } 981 if bond.Primary >= 0 { 982 data.AddRtAttr(nl.IFLA_BOND_PRIMARY, nl.Uint32Attr(uint32(bond.Primary))) 983 } 984 if bond.PrimaryReselect >= 0 { 985 data.AddRtAttr(nl.IFLA_BOND_PRIMARY_RESELECT, nl.Uint8Attr(uint8(bond.PrimaryReselect))) 986 } 987 if bond.FailOverMac >= 0 { 988 data.AddRtAttr(nl.IFLA_BOND_FAIL_OVER_MAC, nl.Uint8Attr(uint8(bond.FailOverMac))) 989 } 990 if bond.XmitHashPolicy >= 0 { 991 data.AddRtAttr(nl.IFLA_BOND_XMIT_HASH_POLICY, nl.Uint8Attr(uint8(bond.XmitHashPolicy))) 992 } 993 if bond.ResendIgmp >= 0 { 994 data.AddRtAttr(nl.IFLA_BOND_RESEND_IGMP, nl.Uint32Attr(uint32(bond.ResendIgmp))) 995 } 996 if bond.NumPeerNotif >= 0 { 997 data.AddRtAttr(nl.IFLA_BOND_NUM_PEER_NOTIF, nl.Uint8Attr(uint8(bond.NumPeerNotif))) 998 } 999 if bond.AllSlavesActive >= 0 { 1000 data.AddRtAttr(nl.IFLA_BOND_ALL_SLAVES_ACTIVE, nl.Uint8Attr(uint8(bond.AllSlavesActive))) 1001 } 1002 if bond.MinLinks >= 0 { 1003 data.AddRtAttr(nl.IFLA_BOND_MIN_LINKS, nl.Uint32Attr(uint32(bond.MinLinks))) 1004 } 1005 if bond.LpInterval >= 0 { 1006 data.AddRtAttr(nl.IFLA_BOND_LP_INTERVAL, nl.Uint32Attr(uint32(bond.LpInterval))) 1007 } 1008 if bond.PackersPerSlave >= 0 { 1009 data.AddRtAttr(nl.IFLA_BOND_PACKETS_PER_SLAVE, nl.Uint32Attr(uint32(bond.PackersPerSlave))) 1010 } 1011 if bond.LacpRate >= 0 { 1012 data.AddRtAttr(nl.IFLA_BOND_AD_LACP_RATE, nl.Uint8Attr(uint8(bond.LacpRate))) 1013 } 1014 if bond.AdSelect >= 0 { 1015 data.AddRtAttr(nl.IFLA_BOND_AD_SELECT, nl.Uint8Attr(uint8(bond.AdSelect))) 1016 } 1017 if bond.AdActorSysPrio >= 0 { 1018 data.AddRtAttr(nl.IFLA_BOND_AD_ACTOR_SYS_PRIO, nl.Uint16Attr(uint16(bond.AdActorSysPrio))) 1019 } 1020 if bond.AdUserPortKey >= 0 { 1021 data.AddRtAttr(nl.IFLA_BOND_AD_USER_PORT_KEY, nl.Uint16Attr(uint16(bond.AdUserPortKey))) 1022 } 1023 if bond.AdActorSystem != nil { 1024 data.AddRtAttr(nl.IFLA_BOND_AD_ACTOR_SYSTEM, []byte(bond.AdActorSystem)) 1025 } 1026 if bond.TlbDynamicLb >= 0 { 1027 data.AddRtAttr(nl.IFLA_BOND_TLB_DYNAMIC_LB, nl.Uint8Attr(uint8(bond.TlbDynamicLb))) 1028 } 1029} 1030 1031func cleanupFds(fds []*os.File) { 1032 for _, f := range fds { 1033 f.Close() 1034 } 1035} 1036 1037// LinkAdd adds a new link device. The type and features of the device 1038// are taken from the parameters in the link object. 1039// Equivalent to: `ip link add $link` 1040func LinkAdd(link Link) error { 1041 return pkgHandle.LinkAdd(link) 1042} 1043 1044// LinkAdd adds a new link device. The type and features of the device 1045// are taken from the parameters in the link object. 1046// Equivalent to: `ip link add $link` 1047func (h *Handle) LinkAdd(link Link) error { 1048 return h.linkModify(link, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK) 1049} 1050 1051func (h *Handle) linkModify(link Link, flags int) error { 1052 // TODO: support extra data for macvlan 1053 base := link.Attrs() 1054 1055 // if tuntap, then the name can be empty, OS will provide a name 1056 tuntap, isTuntap := link.(*Tuntap) 1057 1058 if base.Name == "" && !isTuntap { 1059 return fmt.Errorf("LinkAttrs.Name cannot be empty") 1060 } 1061 1062 if isTuntap { 1063 // TODO: support user 1064 // TODO: support group 1065 if tuntap.Mode < unix.IFF_TUN || tuntap.Mode > unix.IFF_TAP { 1066 return fmt.Errorf("Tuntap.Mode %v unknown", tuntap.Mode) 1067 } 1068 1069 queues := tuntap.Queues 1070 1071 var fds []*os.File 1072 var req ifReq 1073 copy(req.Name[:15], base.Name) 1074 1075 req.Flags = uint16(tuntap.Flags) 1076 1077 if queues == 0 { //Legacy compatibility 1078 queues = 1 1079 if tuntap.Flags == 0 { 1080 req.Flags = uint16(TUNTAP_DEFAULTS) 1081 } 1082 } else { 1083 // For best peformance set Flags to TUNTAP_MULTI_QUEUE_DEFAULTS | TUNTAP_VNET_HDR 1084 // when a) KVM has support for this ABI and 1085 // b) the value of the flag is queryable using the TUNGETIFF ioctl 1086 if tuntap.Flags == 0 { 1087 req.Flags = uint16(TUNTAP_MULTI_QUEUE_DEFAULTS) 1088 } 1089 } 1090 1091 req.Flags |= uint16(tuntap.Mode) 1092 1093 for i := 0; i < queues; i++ { 1094 localReq := req 1095 file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0) 1096 if err != nil { 1097 cleanupFds(fds) 1098 return err 1099 } 1100 1101 fds = append(fds, file) 1102 _, _, errno := unix.Syscall(unix.SYS_IOCTL, file.Fd(), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&localReq))) 1103 if errno != 0 { 1104 cleanupFds(fds) 1105 return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed [%d], errno %v", i, errno) 1106 } 1107 // 1) we only care for the name of the first tap in the multi queue set 1108 // 2) if the original name was empty, the localReq has now the actual name 1109 // 1110 // In addition: 1111 // This ensures that the link name is always identical to what the kernel returns. 1112 // Not only in case of an empty name, but also when using name templates. 1113 // e.g. when the provided name is "tap%d", the kernel replaces %d with the next available number. 1114 if i == 0 { 1115 link.Attrs().Name = strings.Trim(string(localReq.Name[:]), "\x00") 1116 } 1117 } 1118 1119 // only persist interface if NonPersist is NOT set 1120 if !tuntap.NonPersist { 1121 _, _, errno := unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 1) 1122 if errno != 0 { 1123 cleanupFds(fds) 1124 return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno) 1125 } 1126 } 1127 1128 h.ensureIndex(base) 1129 1130 // can't set master during create, so set it afterwards 1131 if base.MasterIndex != 0 { 1132 // TODO: verify MasterIndex is actually a bridge? 1133 err := h.LinkSetMasterByIndex(link, base.MasterIndex) 1134 if err != nil { 1135 // un-persist (e.g. allow the interface to be removed) the tuntap 1136 // should not hurt if not set prior, condition might be not needed 1137 if !tuntap.NonPersist { 1138 _, _, _ = unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 0) 1139 } 1140 cleanupFds(fds) 1141 return err 1142 } 1143 } 1144 1145 if tuntap.Queues == 0 { 1146 cleanupFds(fds) 1147 } else { 1148 tuntap.Fds = fds 1149 } 1150 1151 return nil 1152 } 1153 1154 req := h.newNetlinkRequest(unix.RTM_NEWLINK, flags) 1155 1156 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 1157 // TODO: make it shorter 1158 if base.Flags&net.FlagUp != 0 { 1159 msg.Change = unix.IFF_UP 1160 msg.Flags = unix.IFF_UP 1161 } 1162 if base.Flags&net.FlagBroadcast != 0 { 1163 msg.Change |= unix.IFF_BROADCAST 1164 msg.Flags |= unix.IFF_BROADCAST 1165 } 1166 if base.Flags&net.FlagLoopback != 0 { 1167 msg.Change |= unix.IFF_LOOPBACK 1168 msg.Flags |= unix.IFF_LOOPBACK 1169 } 1170 if base.Flags&net.FlagPointToPoint != 0 { 1171 msg.Change |= unix.IFF_POINTOPOINT 1172 msg.Flags |= unix.IFF_POINTOPOINT 1173 } 1174 if base.Flags&net.FlagMulticast != 0 { 1175 msg.Change |= unix.IFF_MULTICAST 1176 msg.Flags |= unix.IFF_MULTICAST 1177 } 1178 if base.Index != 0 { 1179 msg.Index = int32(base.Index) 1180 } 1181 1182 req.AddData(msg) 1183 1184 if base.ParentIndex != 0 { 1185 b := make([]byte, 4) 1186 native.PutUint32(b, uint32(base.ParentIndex)) 1187 data := nl.NewRtAttr(unix.IFLA_LINK, b) 1188 req.AddData(data) 1189 } else if link.Type() == "ipvlan" || link.Type() == "ipoib" { 1190 return fmt.Errorf("Can't create %s link without ParentIndex", link.Type()) 1191 } 1192 1193 nameData := nl.NewRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(base.Name)) 1194 req.AddData(nameData) 1195 1196 if base.MTU > 0 { 1197 mtu := nl.NewRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU))) 1198 req.AddData(mtu) 1199 } 1200 1201 if base.TxQLen >= 0 { 1202 qlen := nl.NewRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen))) 1203 req.AddData(qlen) 1204 } 1205 1206 if base.HardwareAddr != nil { 1207 hwaddr := nl.NewRtAttr(unix.IFLA_ADDRESS, []byte(base.HardwareAddr)) 1208 req.AddData(hwaddr) 1209 } 1210 1211 if base.NumTxQueues > 0 { 1212 txqueues := nl.NewRtAttr(unix.IFLA_NUM_TX_QUEUES, nl.Uint32Attr(uint32(base.NumTxQueues))) 1213 req.AddData(txqueues) 1214 } 1215 1216 if base.NumRxQueues > 0 { 1217 rxqueues := nl.NewRtAttr(unix.IFLA_NUM_RX_QUEUES, nl.Uint32Attr(uint32(base.NumRxQueues))) 1218 req.AddData(rxqueues) 1219 } 1220 1221 if base.GSOMaxSegs > 0 { 1222 gsoAttr := nl.NewRtAttr(unix.IFLA_GSO_MAX_SEGS, nl.Uint32Attr(base.GSOMaxSegs)) 1223 req.AddData(gsoAttr) 1224 } 1225 1226 if base.GSOMaxSize > 0 { 1227 gsoAttr := nl.NewRtAttr(unix.IFLA_GSO_MAX_SIZE, nl.Uint32Attr(base.GSOMaxSize)) 1228 req.AddData(gsoAttr) 1229 } 1230 1231 if base.Group > 0 { 1232 groupAttr := nl.NewRtAttr(unix.IFLA_GROUP, nl.Uint32Attr(base.Group)) 1233 req.AddData(groupAttr) 1234 } 1235 1236 if base.Namespace != nil { 1237 var attr *nl.RtAttr 1238 switch ns := base.Namespace.(type) { 1239 case NsPid: 1240 val := nl.Uint32Attr(uint32(ns)) 1241 attr = nl.NewRtAttr(unix.IFLA_NET_NS_PID, val) 1242 case NsFd: 1243 val := nl.Uint32Attr(uint32(ns)) 1244 attr = nl.NewRtAttr(unix.IFLA_NET_NS_FD, val) 1245 } 1246 1247 req.AddData(attr) 1248 } 1249 1250 if base.Xdp != nil { 1251 addXdpAttrs(base.Xdp, req) 1252 } 1253 1254 linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil) 1255 linkInfo.AddRtAttr(nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type())) 1256 1257 switch link := link.(type) { 1258 case *Vlan: 1259 b := make([]byte, 2) 1260 native.PutUint16(b, uint16(link.VlanId)) 1261 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 1262 data.AddRtAttr(nl.IFLA_VLAN_ID, b) 1263 1264 if link.VlanProtocol != VLAN_PROTOCOL_UNKNOWN { 1265 data.AddRtAttr(nl.IFLA_VLAN_PROTOCOL, htons(uint16(link.VlanProtocol))) 1266 } 1267 case *Veth: 1268 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 1269 peer := data.AddRtAttr(nl.VETH_INFO_PEER, nil) 1270 nl.NewIfInfomsgChild(peer, unix.AF_UNSPEC) 1271 peer.AddRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName)) 1272 if base.TxQLen >= 0 { 1273 peer.AddRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen))) 1274 } 1275 if base.MTU > 0 { 1276 peer.AddRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU))) 1277 } 1278 if link.PeerHardwareAddr != nil { 1279 peer.AddRtAttr(unix.IFLA_ADDRESS, []byte(link.PeerHardwareAddr)) 1280 } 1281 case *Vxlan: 1282 addVxlanAttrs(link, linkInfo) 1283 case *Bond: 1284 addBondAttrs(link, linkInfo) 1285 case *IPVlan: 1286 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 1287 data.AddRtAttr(nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(link.Mode))) 1288 data.AddRtAttr(nl.IFLA_IPVLAN_FLAG, nl.Uint16Attr(uint16(link.Flag))) 1289 case *Macvlan: 1290 if link.Mode != MACVLAN_MODE_DEFAULT { 1291 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 1292 data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode])) 1293 } 1294 case *Macvtap: 1295 if link.Mode != MACVLAN_MODE_DEFAULT { 1296 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 1297 data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode])) 1298 } 1299 case *Gretap: 1300 addGretapAttrs(link, linkInfo) 1301 case *Iptun: 1302 addIptunAttrs(link, linkInfo) 1303 case *Ip6tnl: 1304 addIp6tnlAttrs(link, linkInfo) 1305 case *Sittun: 1306 addSittunAttrs(link, linkInfo) 1307 case *Gretun: 1308 addGretunAttrs(link, linkInfo) 1309 case *Vti: 1310 addVtiAttrs(link, linkInfo) 1311 case *Vrf: 1312 addVrfAttrs(link, linkInfo) 1313 case *Bridge: 1314 addBridgeAttrs(link, linkInfo) 1315 case *GTP: 1316 addGTPAttrs(link, linkInfo) 1317 case *Xfrmi: 1318 addXfrmiAttrs(link, linkInfo) 1319 case *IPoIB: 1320 addIPoIBAttrs(link, linkInfo) 1321 } 1322 1323 req.AddData(linkInfo) 1324 1325 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 1326 if err != nil { 1327 return err 1328 } 1329 1330 h.ensureIndex(base) 1331 1332 // can't set master during create, so set it afterwards 1333 if base.MasterIndex != 0 { 1334 // TODO: verify MasterIndex is actually a bridge? 1335 return h.LinkSetMasterByIndex(link, base.MasterIndex) 1336 } 1337 return nil 1338} 1339 1340// LinkDel deletes link device. Either Index or Name must be set in 1341// the link object for it to be deleted. The other values are ignored. 1342// Equivalent to: `ip link del $link` 1343func LinkDel(link Link) error { 1344 return pkgHandle.LinkDel(link) 1345} 1346 1347// LinkDel deletes link device. Either Index or Name must be set in 1348// the link object for it to be deleted. The other values are ignored. 1349// Equivalent to: `ip link del $link` 1350func (h *Handle) LinkDel(link Link) error { 1351 base := link.Attrs() 1352 1353 h.ensureIndex(base) 1354 1355 req := h.newNetlinkRequest(unix.RTM_DELLINK, unix.NLM_F_ACK) 1356 1357 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 1358 msg.Index = int32(base.Index) 1359 req.AddData(msg) 1360 1361 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 1362 return err 1363} 1364 1365func (h *Handle) linkByNameDump(name string) (Link, error) { 1366 links, err := h.LinkList() 1367 if err != nil { 1368 return nil, err 1369 } 1370 1371 for _, link := range links { 1372 if link.Attrs().Name == name { 1373 return link, nil 1374 } 1375 } 1376 return nil, LinkNotFoundError{fmt.Errorf("Link %s not found", name)} 1377} 1378 1379func (h *Handle) linkByAliasDump(alias string) (Link, error) { 1380 links, err := h.LinkList() 1381 if err != nil { 1382 return nil, err 1383 } 1384 1385 for _, link := range links { 1386 if link.Attrs().Alias == alias { 1387 return link, nil 1388 } 1389 } 1390 return nil, LinkNotFoundError{fmt.Errorf("Link alias %s not found", alias)} 1391} 1392 1393// LinkByName finds a link by name and returns a pointer to the object. 1394func LinkByName(name string) (Link, error) { 1395 return pkgHandle.LinkByName(name) 1396} 1397 1398// LinkByName finds a link by name and returns a pointer to the object. 1399func (h *Handle) LinkByName(name string) (Link, error) { 1400 if h.lookupByDump { 1401 return h.linkByNameDump(name) 1402 } 1403 1404 req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_ACK) 1405 1406 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 1407 req.AddData(msg) 1408 1409 attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF)) 1410 req.AddData(attr) 1411 1412 nameData := nl.NewRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(name)) 1413 req.AddData(nameData) 1414 1415 link, err := execGetLink(req) 1416 if err == unix.EINVAL { 1417 // older kernels don't support looking up via IFLA_IFNAME 1418 // so fall back to dumping all links 1419 h.lookupByDump = true 1420 return h.linkByNameDump(name) 1421 } 1422 1423 return link, err 1424} 1425 1426// LinkByAlias finds a link by its alias and returns a pointer to the object. 1427// If there are multiple links with the alias it returns the first one 1428func LinkByAlias(alias string) (Link, error) { 1429 return pkgHandle.LinkByAlias(alias) 1430} 1431 1432// LinkByAlias finds a link by its alias and returns a pointer to the object. 1433// If there are multiple links with the alias it returns the first one 1434func (h *Handle) LinkByAlias(alias string) (Link, error) { 1435 if h.lookupByDump { 1436 return h.linkByAliasDump(alias) 1437 } 1438 1439 req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_ACK) 1440 1441 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 1442 req.AddData(msg) 1443 1444 attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF)) 1445 req.AddData(attr) 1446 1447 nameData := nl.NewRtAttr(unix.IFLA_IFALIAS, nl.ZeroTerminated(alias)) 1448 req.AddData(nameData) 1449 1450 link, err := execGetLink(req) 1451 if err == unix.EINVAL { 1452 // older kernels don't support looking up via IFLA_IFALIAS 1453 // so fall back to dumping all links 1454 h.lookupByDump = true 1455 return h.linkByAliasDump(alias) 1456 } 1457 1458 return link, err 1459} 1460 1461// LinkByIndex finds a link by index and returns a pointer to the object. 1462func LinkByIndex(index int) (Link, error) { 1463 return pkgHandle.LinkByIndex(index) 1464} 1465 1466// LinkByIndex finds a link by index and returns a pointer to the object. 1467func (h *Handle) LinkByIndex(index int) (Link, error) { 1468 req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_ACK) 1469 1470 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 1471 msg.Index = int32(index) 1472 req.AddData(msg) 1473 attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF)) 1474 req.AddData(attr) 1475 1476 return execGetLink(req) 1477} 1478 1479func execGetLink(req *nl.NetlinkRequest) (Link, error) { 1480 msgs, err := req.Execute(unix.NETLINK_ROUTE, 0) 1481 if err != nil { 1482 if errno, ok := err.(syscall.Errno); ok { 1483 if errno == unix.ENODEV { 1484 return nil, LinkNotFoundError{fmt.Errorf("Link not found")} 1485 } 1486 } 1487 return nil, err 1488 } 1489 1490 switch { 1491 case len(msgs) == 0: 1492 return nil, LinkNotFoundError{fmt.Errorf("Link not found")} 1493 1494 case len(msgs) == 1: 1495 return LinkDeserialize(nil, msgs[0]) 1496 1497 default: 1498 return nil, fmt.Errorf("More than one link found") 1499 } 1500} 1501 1502// linkDeserialize deserializes a raw message received from netlink into 1503// a link object. 1504func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { 1505 msg := nl.DeserializeIfInfomsg(m) 1506 1507 attrs, err := nl.ParseRouteAttr(m[msg.Len():]) 1508 if err != nil { 1509 return nil, err 1510 } 1511 1512 base := LinkAttrs{Index: int(msg.Index), RawFlags: msg.Flags, Flags: linkFlags(msg.Flags), EncapType: msg.EncapType()} 1513 if msg.Flags&unix.IFF_PROMISC != 0 { 1514 base.Promisc = 1 1515 } 1516 var ( 1517 link Link 1518 stats32 *LinkStatistics32 1519 stats64 *LinkStatistics64 1520 linkType string 1521 linkSlave LinkSlave 1522 slaveType string 1523 ) 1524 for _, attr := range attrs { 1525 switch attr.Attr.Type { 1526 case unix.IFLA_LINKINFO: 1527 infos, err := nl.ParseRouteAttr(attr.Value) 1528 if err != nil { 1529 return nil, err 1530 } 1531 for _, info := range infos { 1532 switch info.Attr.Type { 1533 case nl.IFLA_INFO_KIND: 1534 linkType = string(info.Value[:len(info.Value)-1]) 1535 switch linkType { 1536 case "dummy": 1537 link = &Dummy{} 1538 case "ifb": 1539 link = &Ifb{} 1540 case "bridge": 1541 link = &Bridge{} 1542 case "vlan": 1543 link = &Vlan{} 1544 case "veth": 1545 link = &Veth{} 1546 case "vxlan": 1547 link = &Vxlan{} 1548 case "bond": 1549 link = &Bond{} 1550 case "ipvlan": 1551 link = &IPVlan{} 1552 case "macvlan": 1553 link = &Macvlan{} 1554 case "macvtap": 1555 link = &Macvtap{} 1556 case "gretap": 1557 link = &Gretap{} 1558 case "ip6gretap": 1559 link = &Gretap{} 1560 case "ipip": 1561 link = &Iptun{} 1562 case "ip6tnl": 1563 link = &Ip6tnl{} 1564 case "sit": 1565 link = &Sittun{} 1566 case "gre": 1567 link = &Gretun{} 1568 case "ip6gre": 1569 link = &Gretun{} 1570 case "vti", "vti6": 1571 link = &Vti{} 1572 case "vrf": 1573 link = &Vrf{} 1574 case "gtp": 1575 link = >P{} 1576 case "xfrm": 1577 link = &Xfrmi{} 1578 case "tun": 1579 link = &Tuntap{} 1580 case "ipoib": 1581 link = &IPoIB{} 1582 default: 1583 link = &GenericLink{LinkType: linkType} 1584 } 1585 case nl.IFLA_INFO_DATA: 1586 data, err := nl.ParseRouteAttr(info.Value) 1587 if err != nil { 1588 return nil, err 1589 } 1590 switch linkType { 1591 case "vlan": 1592 parseVlanData(link, data) 1593 case "vxlan": 1594 parseVxlanData(link, data) 1595 case "bond": 1596 parseBondData(link, data) 1597 case "ipvlan": 1598 parseIPVlanData(link, data) 1599 case "macvlan": 1600 parseMacvlanData(link, data) 1601 case "macvtap": 1602 parseMacvtapData(link, data) 1603 case "gretap": 1604 parseGretapData(link, data) 1605 case "ip6gretap": 1606 parseGretapData(link, data) 1607 case "ipip": 1608 parseIptunData(link, data) 1609 case "ip6tnl": 1610 parseIp6tnlData(link, data) 1611 case "sit": 1612 parseSittunData(link, data) 1613 case "gre": 1614 parseGretunData(link, data) 1615 case "ip6gre": 1616 parseGretunData(link, data) 1617 case "vti", "vti6": 1618 parseVtiData(link, data) 1619 case "vrf": 1620 parseVrfData(link, data) 1621 case "bridge": 1622 parseBridgeData(link, data) 1623 case "gtp": 1624 parseGTPData(link, data) 1625 case "xfrm": 1626 parseXfrmiData(link, data) 1627 case "tun": 1628 parseTuntapData(link, data) 1629 case "ipoib": 1630 parseIPoIBData(link, data) 1631 } 1632 case nl.IFLA_INFO_SLAVE_KIND: 1633 slaveType = string(info.Value[:len(info.Value)-1]) 1634 switch slaveType { 1635 case "bond": 1636 linkSlave = &BondSlave{} 1637 } 1638 case nl.IFLA_INFO_SLAVE_DATA: 1639 switch slaveType { 1640 case "bond": 1641 data, err := nl.ParseRouteAttr(info.Value) 1642 if err != nil { 1643 return nil, err 1644 } 1645 parseBondSlaveData(linkSlave, data) 1646 } 1647 } 1648 } 1649 case unix.IFLA_ADDRESS: 1650 var nonzero bool 1651 for _, b := range attr.Value { 1652 if b != 0 { 1653 nonzero = true 1654 } 1655 } 1656 if nonzero { 1657 base.HardwareAddr = attr.Value[:] 1658 } 1659 case unix.IFLA_IFNAME: 1660 base.Name = string(attr.Value[:len(attr.Value)-1]) 1661 case unix.IFLA_MTU: 1662 base.MTU = int(native.Uint32(attr.Value[0:4])) 1663 case unix.IFLA_LINK: 1664 base.ParentIndex = int(native.Uint32(attr.Value[0:4])) 1665 case unix.IFLA_MASTER: 1666 base.MasterIndex = int(native.Uint32(attr.Value[0:4])) 1667 case unix.IFLA_TXQLEN: 1668 base.TxQLen = int(native.Uint32(attr.Value[0:4])) 1669 case unix.IFLA_IFALIAS: 1670 base.Alias = string(attr.Value[:len(attr.Value)-1]) 1671 case unix.IFLA_STATS: 1672 stats32 = new(LinkStatistics32) 1673 if err := binary.Read(bytes.NewBuffer(attr.Value[:]), nl.NativeEndian(), stats32); err != nil { 1674 return nil, err 1675 } 1676 case unix.IFLA_STATS64: 1677 stats64 = new(LinkStatistics64) 1678 if err := binary.Read(bytes.NewBuffer(attr.Value[:]), nl.NativeEndian(), stats64); err != nil { 1679 return nil, err 1680 } 1681 case unix.IFLA_XDP: 1682 xdp, err := parseLinkXdp(attr.Value[:]) 1683 if err != nil { 1684 return nil, err 1685 } 1686 base.Xdp = xdp 1687 case unix.IFLA_PROTINFO | unix.NLA_F_NESTED: 1688 if hdr != nil && hdr.Type == unix.RTM_NEWLINK && 1689 msg.Family == unix.AF_BRIDGE { 1690 attrs, err := nl.ParseRouteAttr(attr.Value[:]) 1691 if err != nil { 1692 return nil, err 1693 } 1694 protinfo := parseProtinfo(attrs) 1695 base.Protinfo = &protinfo 1696 } 1697 case unix.IFLA_OPERSTATE: 1698 base.OperState = LinkOperState(uint8(attr.Value[0])) 1699 case unix.IFLA_LINK_NETNSID: 1700 base.NetNsID = int(native.Uint32(attr.Value[0:4])) 1701 case unix.IFLA_GSO_MAX_SIZE: 1702 base.GSOMaxSize = native.Uint32(attr.Value[0:4]) 1703 case unix.IFLA_GSO_MAX_SEGS: 1704 base.GSOMaxSegs = native.Uint32(attr.Value[0:4]) 1705 case unix.IFLA_VFINFO_LIST: 1706 data, err := nl.ParseRouteAttr(attr.Value) 1707 if err != nil { 1708 return nil, err 1709 } 1710 vfs, err := parseVfInfoList(data) 1711 if err != nil { 1712 return nil, err 1713 } 1714 base.Vfs = vfs 1715 case unix.IFLA_NUM_TX_QUEUES: 1716 base.NumTxQueues = int(native.Uint32(attr.Value[0:4])) 1717 case unix.IFLA_NUM_RX_QUEUES: 1718 base.NumRxQueues = int(native.Uint32(attr.Value[0:4])) 1719 case unix.IFLA_GROUP: 1720 base.Group = native.Uint32(attr.Value[0:4]) 1721 } 1722 } 1723 1724 if stats64 != nil { 1725 base.Statistics = (*LinkStatistics)(stats64) 1726 } else if stats32 != nil { 1727 base.Statistics = (*LinkStatistics)(stats32.to64()) 1728 } 1729 1730 // Links that don't have IFLA_INFO_KIND are hardware devices 1731 if link == nil { 1732 link = &Device{} 1733 } 1734 *link.Attrs() = base 1735 link.Attrs().Slave = linkSlave 1736 1737 // If the tuntap attributes are not updated by netlink due to 1738 // an older driver, use sysfs 1739 if link != nil && linkType == "tun" { 1740 tuntap := link.(*Tuntap) 1741 1742 if tuntap.Mode == 0 { 1743 ifname := tuntap.Attrs().Name 1744 if flags, err := readSysPropAsInt64(ifname, "tun_flags"); err == nil { 1745 1746 if flags&unix.IFF_TUN != 0 { 1747 tuntap.Mode = unix.IFF_TUN 1748 } else if flags&unix.IFF_TAP != 0 { 1749 tuntap.Mode = unix.IFF_TAP 1750 } 1751 1752 tuntap.NonPersist = false 1753 if flags&unix.IFF_PERSIST == 0 { 1754 tuntap.NonPersist = true 1755 } 1756 } 1757 1758 // The sysfs interface for owner/group returns -1 for root user, instead of returning 0. 1759 // So explicitly check for negative value, before assigning the owner uid/gid. 1760 if owner, err := readSysPropAsInt64(ifname, "owner"); err == nil && owner > 0 { 1761 tuntap.Owner = uint32(owner) 1762 } 1763 1764 if group, err := readSysPropAsInt64(ifname, "group"); err == nil && group > 0 { 1765 tuntap.Group = uint32(group) 1766 } 1767 } 1768 } 1769 1770 return link, nil 1771} 1772 1773func readSysPropAsInt64(ifname, prop string) (int64, error) { 1774 fname := fmt.Sprintf("/sys/class/net/%s/%s", ifname, prop) 1775 contents, err := ioutil.ReadFile(fname) 1776 if err != nil { 1777 return 0, err 1778 } 1779 1780 num, err := strconv.ParseInt(strings.TrimSpace(string(contents)), 0, 64) 1781 if err == nil { 1782 return num, nil 1783 } 1784 1785 return 0, err 1786} 1787 1788// LinkList gets a list of link devices. 1789// Equivalent to: `ip link show` 1790func LinkList() ([]Link, error) { 1791 return pkgHandle.LinkList() 1792} 1793 1794// LinkList gets a list of link devices. 1795// Equivalent to: `ip link show` 1796func (h *Handle) LinkList() ([]Link, error) { 1797 // NOTE(vish): This duplicates functionality in net/iface_linux.go, but we need 1798 // to get the message ourselves to parse link type. 1799 req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP) 1800 1801 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 1802 req.AddData(msg) 1803 attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF)) 1804 req.AddData(attr) 1805 1806 msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK) 1807 if err != nil { 1808 return nil, err 1809 } 1810 1811 var res []Link 1812 for _, m := range msgs { 1813 link, err := LinkDeserialize(nil, m) 1814 if err != nil { 1815 return nil, err 1816 } 1817 res = append(res, link) 1818 } 1819 1820 return res, nil 1821} 1822 1823// LinkUpdate is used to pass information back from LinkSubscribe() 1824type LinkUpdate struct { 1825 nl.IfInfomsg 1826 Header unix.NlMsghdr 1827 Link 1828} 1829 1830// LinkSubscribe takes a chan down which notifications will be sent 1831// when links change. Close the 'done' chan to stop subscription. 1832func LinkSubscribe(ch chan<- LinkUpdate, done <-chan struct{}) error { 1833 return linkSubscribeAt(netns.None(), netns.None(), ch, done, nil, false) 1834} 1835 1836// LinkSubscribeAt works like LinkSubscribe plus it allows the caller 1837// to choose the network namespace in which to subscribe (ns). 1838func LinkSubscribeAt(ns netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}) error { 1839 return linkSubscribeAt(ns, netns.None(), ch, done, nil, false) 1840} 1841 1842// LinkSubscribeOptions contains a set of options to use with 1843// LinkSubscribeWithOptions. 1844type LinkSubscribeOptions struct { 1845 Namespace *netns.NsHandle 1846 ErrorCallback func(error) 1847 ListExisting bool 1848} 1849 1850// LinkSubscribeWithOptions work like LinkSubscribe but enable to 1851// provide additional options to modify the behavior. Currently, the 1852// namespace can be provided as well as an error callback. 1853func LinkSubscribeWithOptions(ch chan<- LinkUpdate, done <-chan struct{}, options LinkSubscribeOptions) error { 1854 if options.Namespace == nil { 1855 none := netns.None() 1856 options.Namespace = &none 1857 } 1858 return linkSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting) 1859} 1860 1861func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error { 1862 s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_LINK) 1863 if err != nil { 1864 return err 1865 } 1866 if done != nil { 1867 go func() { 1868 <-done 1869 s.Close() 1870 }() 1871 } 1872 if listExisting { 1873 req := pkgHandle.newNetlinkRequest(unix.RTM_GETLINK, 1874 unix.NLM_F_DUMP) 1875 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 1876 req.AddData(msg) 1877 if err := s.Send(req); err != nil { 1878 return err 1879 } 1880 } 1881 go func() { 1882 defer close(ch) 1883 for { 1884 msgs, from, err := s.Receive() 1885 if err != nil { 1886 if cberr != nil { 1887 cberr(err) 1888 } 1889 return 1890 } 1891 if from.Pid != nl.PidKernel { 1892 if cberr != nil { 1893 cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)) 1894 } 1895 continue 1896 } 1897 for _, m := range msgs { 1898 if m.Header.Type == unix.NLMSG_DONE { 1899 continue 1900 } 1901 if m.Header.Type == unix.NLMSG_ERROR { 1902 native := nl.NativeEndian() 1903 error := int32(native.Uint32(m.Data[0:4])) 1904 if error == 0 { 1905 continue 1906 } 1907 if cberr != nil { 1908 cberr(syscall.Errno(-error)) 1909 } 1910 return 1911 } 1912 ifmsg := nl.DeserializeIfInfomsg(m.Data) 1913 header := unix.NlMsghdr(m.Header) 1914 link, err := LinkDeserialize(&header, m.Data) 1915 if err != nil { 1916 if cberr != nil { 1917 cberr(err) 1918 } 1919 return 1920 } 1921 ch <- LinkUpdate{IfInfomsg: *ifmsg, Header: header, Link: link} 1922 } 1923 } 1924 }() 1925 1926 return nil 1927} 1928 1929func LinkSetHairpin(link Link, mode bool) error { 1930 return pkgHandle.LinkSetHairpin(link, mode) 1931} 1932 1933func (h *Handle) LinkSetHairpin(link Link, mode bool) error { 1934 return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_MODE) 1935} 1936 1937func LinkSetGuard(link Link, mode bool) error { 1938 return pkgHandle.LinkSetGuard(link, mode) 1939} 1940 1941func (h *Handle) LinkSetGuard(link Link, mode bool) error { 1942 return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_GUARD) 1943} 1944 1945func LinkSetFastLeave(link Link, mode bool) error { 1946 return pkgHandle.LinkSetFastLeave(link, mode) 1947} 1948 1949func (h *Handle) LinkSetFastLeave(link Link, mode bool) error { 1950 return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_FAST_LEAVE) 1951} 1952 1953func LinkSetLearning(link Link, mode bool) error { 1954 return pkgHandle.LinkSetLearning(link, mode) 1955} 1956 1957func (h *Handle) LinkSetLearning(link Link, mode bool) error { 1958 return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING) 1959} 1960 1961func LinkSetRootBlock(link Link, mode bool) error { 1962 return pkgHandle.LinkSetRootBlock(link, mode) 1963} 1964 1965func (h *Handle) LinkSetRootBlock(link Link, mode bool) error { 1966 return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROTECT) 1967} 1968 1969func LinkSetFlood(link Link, mode bool) error { 1970 return pkgHandle.LinkSetFlood(link, mode) 1971} 1972 1973func (h *Handle) LinkSetFlood(link Link, mode bool) error { 1974 return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD) 1975} 1976 1977func LinkSetBrProxyArp(link Link, mode bool) error { 1978 return pkgHandle.LinkSetBrProxyArp(link, mode) 1979} 1980 1981func (h *Handle) LinkSetBrProxyArp(link Link, mode bool) error { 1982 return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROXYARP) 1983} 1984 1985func LinkSetBrProxyArpWiFi(link Link, mode bool) error { 1986 return pkgHandle.LinkSetBrProxyArpWiFi(link, mode) 1987} 1988 1989func (h *Handle) LinkSetBrProxyArpWiFi(link Link, mode bool) error { 1990 return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROXYARP_WIFI) 1991} 1992 1993func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error { 1994 base := link.Attrs() 1995 h.ensureIndex(base) 1996 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 1997 1998 msg := nl.NewIfInfomsg(unix.AF_BRIDGE) 1999 msg.Index = int32(base.Index) 2000 req.AddData(msg) 2001 2002 br := nl.NewRtAttr(unix.IFLA_PROTINFO|unix.NLA_F_NESTED, nil) 2003 br.AddRtAttr(attr, boolToByte(mode)) 2004 req.AddData(br) 2005 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 2006 if err != nil { 2007 return err 2008 } 2009 return nil 2010} 2011 2012// LinkSetTxQLen sets the transaction queue length for the link. 2013// Equivalent to: `ip link set $link txqlen $qlen` 2014func LinkSetTxQLen(link Link, qlen int) error { 2015 return pkgHandle.LinkSetTxQLen(link, qlen) 2016} 2017 2018// LinkSetTxQLen sets the transaction queue length for the link. 2019// Equivalent to: `ip link set $link txqlen $qlen` 2020func (h *Handle) LinkSetTxQLen(link Link, qlen int) error { 2021 base := link.Attrs() 2022 h.ensureIndex(base) 2023 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 2024 2025 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 2026 msg.Index = int32(base.Index) 2027 req.AddData(msg) 2028 2029 b := make([]byte, 4) 2030 native.PutUint32(b, uint32(qlen)) 2031 2032 data := nl.NewRtAttr(unix.IFLA_TXQLEN, b) 2033 req.AddData(data) 2034 2035 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 2036 return err 2037} 2038 2039// LinkSetGroup sets the link group id which can be used to perform mass actions 2040// with iproute2 as well use it as a reference in nft filters. 2041// Equivalent to: `ip link set $link group $id` 2042func LinkSetGroup(link Link, group int) error { 2043 return pkgHandle.LinkSetGroup(link, group) 2044} 2045 2046// LinkSetGroup sets the link group id which can be used to perform mass actions 2047// with iproute2 as well use it as a reference in nft filters. 2048// Equivalent to: `ip link set $link group $id` 2049func (h *Handle) LinkSetGroup(link Link, group int) error { 2050 base := link.Attrs() 2051 h.ensureIndex(base) 2052 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 2053 2054 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 2055 msg.Index = int32(base.Index) 2056 req.AddData(msg) 2057 2058 b := make([]byte, 4) 2059 native.PutUint32(b, uint32(group)) 2060 2061 data := nl.NewRtAttr(unix.IFLA_GROUP, b) 2062 req.AddData(data) 2063 2064 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 2065 return err 2066} 2067 2068func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) { 2069 vlan := link.(*Vlan) 2070 for _, datum := range data { 2071 switch datum.Attr.Type { 2072 case nl.IFLA_VLAN_ID: 2073 vlan.VlanId = int(native.Uint16(datum.Value[0:2])) 2074 case nl.IFLA_VLAN_PROTOCOL: 2075 vlan.VlanProtocol = VlanProtocol(int(ntohs(datum.Value[0:2]))) 2076 } 2077 } 2078} 2079 2080func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) { 2081 vxlan := link.(*Vxlan) 2082 for _, datum := range data { 2083 switch datum.Attr.Type { 2084 case nl.IFLA_VXLAN_ID: 2085 vxlan.VxlanId = int(native.Uint32(datum.Value[0:4])) 2086 case nl.IFLA_VXLAN_LINK: 2087 vxlan.VtepDevIndex = int(native.Uint32(datum.Value[0:4])) 2088 case nl.IFLA_VXLAN_LOCAL: 2089 vxlan.SrcAddr = net.IP(datum.Value[0:4]) 2090 case nl.IFLA_VXLAN_LOCAL6: 2091 vxlan.SrcAddr = net.IP(datum.Value[0:16]) 2092 case nl.IFLA_VXLAN_GROUP: 2093 vxlan.Group = net.IP(datum.Value[0:4]) 2094 case nl.IFLA_VXLAN_GROUP6: 2095 vxlan.Group = net.IP(datum.Value[0:16]) 2096 case nl.IFLA_VXLAN_TTL: 2097 vxlan.TTL = int(datum.Value[0]) 2098 case nl.IFLA_VXLAN_TOS: 2099 vxlan.TOS = int(datum.Value[0]) 2100 case nl.IFLA_VXLAN_LEARNING: 2101 vxlan.Learning = int8(datum.Value[0]) != 0 2102 case nl.IFLA_VXLAN_PROXY: 2103 vxlan.Proxy = int8(datum.Value[0]) != 0 2104 case nl.IFLA_VXLAN_RSC: 2105 vxlan.RSC = int8(datum.Value[0]) != 0 2106 case nl.IFLA_VXLAN_L2MISS: 2107 vxlan.L2miss = int8(datum.Value[0]) != 0 2108 case nl.IFLA_VXLAN_L3MISS: 2109 vxlan.L3miss = int8(datum.Value[0]) != 0 2110 case nl.IFLA_VXLAN_UDP_CSUM: 2111 vxlan.UDPCSum = int8(datum.Value[0]) != 0 2112 case nl.IFLA_VXLAN_UDP_ZERO_CSUM6_TX: 2113 vxlan.UDP6ZeroCSumTx = int8(datum.Value[0]) != 0 2114 case nl.IFLA_VXLAN_UDP_ZERO_CSUM6_RX: 2115 vxlan.UDP6ZeroCSumRx = int8(datum.Value[0]) != 0 2116 case nl.IFLA_VXLAN_GBP: 2117 vxlan.GBP = true 2118 case nl.IFLA_VXLAN_FLOWBASED: 2119 vxlan.FlowBased = int8(datum.Value[0]) != 0 2120 case nl.IFLA_VXLAN_AGEING: 2121 vxlan.Age = int(native.Uint32(datum.Value[0:4])) 2122 vxlan.NoAge = vxlan.Age == 0 2123 case nl.IFLA_VXLAN_LIMIT: 2124 vxlan.Limit = int(native.Uint32(datum.Value[0:4])) 2125 case nl.IFLA_VXLAN_PORT: 2126 vxlan.Port = int(ntohs(datum.Value[0:2])) 2127 case nl.IFLA_VXLAN_PORT_RANGE: 2128 buf := bytes.NewBuffer(datum.Value[0:4]) 2129 var pr vxlanPortRange 2130 if binary.Read(buf, binary.BigEndian, &pr) != nil { 2131 vxlan.PortLow = int(pr.Lo) 2132 vxlan.PortHigh = int(pr.Hi) 2133 } 2134 } 2135 } 2136} 2137 2138func parseBondData(link Link, data []syscall.NetlinkRouteAttr) { 2139 bond := link.(*Bond) 2140 for i := range data { 2141 switch data[i].Attr.Type { 2142 case nl.IFLA_BOND_MODE: 2143 bond.Mode = BondMode(data[i].Value[0]) 2144 case nl.IFLA_BOND_ACTIVE_SLAVE: 2145 bond.ActiveSlave = int(native.Uint32(data[i].Value[0:4])) 2146 case nl.IFLA_BOND_MIIMON: 2147 bond.Miimon = int(native.Uint32(data[i].Value[0:4])) 2148 case nl.IFLA_BOND_UPDELAY: 2149 bond.UpDelay = int(native.Uint32(data[i].Value[0:4])) 2150 case nl.IFLA_BOND_DOWNDELAY: 2151 bond.DownDelay = int(native.Uint32(data[i].Value[0:4])) 2152 case nl.IFLA_BOND_USE_CARRIER: 2153 bond.UseCarrier = int(data[i].Value[0]) 2154 case nl.IFLA_BOND_ARP_INTERVAL: 2155 bond.ArpInterval = int(native.Uint32(data[i].Value[0:4])) 2156 case nl.IFLA_BOND_ARP_IP_TARGET: 2157 bond.ArpIpTargets = parseBondArpIpTargets(data[i].Value) 2158 case nl.IFLA_BOND_ARP_VALIDATE: 2159 bond.ArpValidate = BondArpValidate(native.Uint32(data[i].Value[0:4])) 2160 case nl.IFLA_BOND_ARP_ALL_TARGETS: 2161 bond.ArpAllTargets = BondArpAllTargets(native.Uint32(data[i].Value[0:4])) 2162 case nl.IFLA_BOND_PRIMARY: 2163 bond.Primary = int(native.Uint32(data[i].Value[0:4])) 2164 case nl.IFLA_BOND_PRIMARY_RESELECT: 2165 bond.PrimaryReselect = BondPrimaryReselect(data[i].Value[0]) 2166 case nl.IFLA_BOND_FAIL_OVER_MAC: 2167 bond.FailOverMac = BondFailOverMac(data[i].Value[0]) 2168 case nl.IFLA_BOND_XMIT_HASH_POLICY: 2169 bond.XmitHashPolicy = BondXmitHashPolicy(data[i].Value[0]) 2170 case nl.IFLA_BOND_RESEND_IGMP: 2171 bond.ResendIgmp = int(native.Uint32(data[i].Value[0:4])) 2172 case nl.IFLA_BOND_NUM_PEER_NOTIF: 2173 bond.NumPeerNotif = int(data[i].Value[0]) 2174 case nl.IFLA_BOND_ALL_SLAVES_ACTIVE: 2175 bond.AllSlavesActive = int(data[i].Value[0]) 2176 case nl.IFLA_BOND_MIN_LINKS: 2177 bond.MinLinks = int(native.Uint32(data[i].Value[0:4])) 2178 case nl.IFLA_BOND_LP_INTERVAL: 2179 bond.LpInterval = int(native.Uint32(data[i].Value[0:4])) 2180 case nl.IFLA_BOND_PACKETS_PER_SLAVE: 2181 bond.PackersPerSlave = int(native.Uint32(data[i].Value[0:4])) 2182 case nl.IFLA_BOND_AD_LACP_RATE: 2183 bond.LacpRate = BondLacpRate(data[i].Value[0]) 2184 case nl.IFLA_BOND_AD_SELECT: 2185 bond.AdSelect = BondAdSelect(data[i].Value[0]) 2186 case nl.IFLA_BOND_AD_INFO: 2187 // TODO: implement 2188 case nl.IFLA_BOND_AD_ACTOR_SYS_PRIO: 2189 bond.AdActorSysPrio = int(native.Uint16(data[i].Value[0:2])) 2190 case nl.IFLA_BOND_AD_USER_PORT_KEY: 2191 bond.AdUserPortKey = int(native.Uint16(data[i].Value[0:2])) 2192 case nl.IFLA_BOND_AD_ACTOR_SYSTEM: 2193 bond.AdActorSystem = net.HardwareAddr(data[i].Value[0:6]) 2194 case nl.IFLA_BOND_TLB_DYNAMIC_LB: 2195 bond.TlbDynamicLb = int(data[i].Value[0]) 2196 } 2197 } 2198} 2199 2200func parseBondArpIpTargets(value []byte) []net.IP { 2201 data, err := nl.ParseRouteAttr(value) 2202 if err != nil { 2203 return nil 2204 } 2205 2206 targets := []net.IP{} 2207 for i := range data { 2208 target := net.IP(data[i].Value) 2209 if ip := target.To4(); ip != nil { 2210 targets = append(targets, ip) 2211 continue 2212 } 2213 if ip := target.To16(); ip != nil { 2214 targets = append(targets, ip) 2215 } 2216 } 2217 2218 return targets 2219} 2220 2221func addBondSlaveAttrs(bondSlave *BondSlave, linkInfo *nl.RtAttr) { 2222 data := linkInfo.AddRtAttr(nl.IFLA_INFO_SLAVE_DATA, nil) 2223 2224 data.AddRtAttr(nl.IFLA_BOND_SLAVE_STATE, nl.Uint8Attr(uint8(bondSlave.State))) 2225 data.AddRtAttr(nl.IFLA_BOND_SLAVE_MII_STATUS, nl.Uint8Attr(uint8(bondSlave.MiiStatus))) 2226 data.AddRtAttr(nl.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT, nl.Uint32Attr(bondSlave.LinkFailureCount)) 2227 data.AddRtAttr(nl.IFLA_BOND_SLAVE_QUEUE_ID, nl.Uint16Attr(bondSlave.QueueId)) 2228 data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, nl.Uint16Attr(bondSlave.AggregatorId)) 2229 data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, nl.Uint8Attr(bondSlave.AdActorOperPortState)) 2230 data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, nl.Uint16Attr(bondSlave.AdPartnerOperPortState)) 2231 2232 if mac := bondSlave.PermHardwareAddr; mac != nil { 2233 data.AddRtAttr(nl.IFLA_BOND_SLAVE_PERM_HWADDR, []byte(mac)) 2234 } 2235} 2236 2237func parseBondSlaveData(slave LinkSlave, data []syscall.NetlinkRouteAttr) { 2238 bondSlave := slave.(*BondSlave) 2239 for i := range data { 2240 switch data[i].Attr.Type { 2241 case nl.IFLA_BOND_SLAVE_STATE: 2242 bondSlave.State = BondSlaveState(data[i].Value[0]) 2243 case nl.IFLA_BOND_SLAVE_MII_STATUS: 2244 bondSlave.MiiStatus = BondSlaveMiiStatus(data[i].Value[0]) 2245 case nl.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT: 2246 bondSlave.LinkFailureCount = native.Uint32(data[i].Value[0:4]) 2247 case nl.IFLA_BOND_SLAVE_PERM_HWADDR: 2248 bondSlave.PermHardwareAddr = net.HardwareAddr(data[i].Value[0:6]) 2249 case nl.IFLA_BOND_SLAVE_QUEUE_ID: 2250 bondSlave.QueueId = native.Uint16(data[i].Value[0:2]) 2251 case nl.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID: 2252 bondSlave.AggregatorId = native.Uint16(data[i].Value[0:2]) 2253 case nl.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE: 2254 bondSlave.AdActorOperPortState = uint8(data[i].Value[0]) 2255 case nl.IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE: 2256 bondSlave.AdPartnerOperPortState = native.Uint16(data[i].Value[0:2]) 2257 } 2258 } 2259} 2260 2261func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) { 2262 ipv := link.(*IPVlan) 2263 for _, datum := range data { 2264 switch datum.Attr.Type { 2265 case nl.IFLA_IPVLAN_MODE: 2266 ipv.Mode = IPVlanMode(native.Uint32(datum.Value[0:4])) 2267 case nl.IFLA_IPVLAN_FLAG: 2268 ipv.Flag = IPVlanFlag(native.Uint32(datum.Value[0:4])) 2269 } 2270 } 2271} 2272 2273func parseMacvtapData(link Link, data []syscall.NetlinkRouteAttr) { 2274 macv := link.(*Macvtap) 2275 parseMacvlanData(&macv.Macvlan, data) 2276} 2277 2278func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) { 2279 macv := link.(*Macvlan) 2280 for _, datum := range data { 2281 switch datum.Attr.Type { 2282 case nl.IFLA_MACVLAN_MODE: 2283 switch native.Uint32(datum.Value[0:4]) { 2284 case nl.MACVLAN_MODE_PRIVATE: 2285 macv.Mode = MACVLAN_MODE_PRIVATE 2286 case nl.MACVLAN_MODE_VEPA: 2287 macv.Mode = MACVLAN_MODE_VEPA 2288 case nl.MACVLAN_MODE_BRIDGE: 2289 macv.Mode = MACVLAN_MODE_BRIDGE 2290 case nl.MACVLAN_MODE_PASSTHRU: 2291 macv.Mode = MACVLAN_MODE_PASSTHRU 2292 case nl.MACVLAN_MODE_SOURCE: 2293 macv.Mode = MACVLAN_MODE_SOURCE 2294 } 2295 case nl.IFLA_MACVLAN_MACADDR_COUNT: 2296 macv.MACAddrs = make([]net.HardwareAddr, 0, int(native.Uint32(datum.Value[0:4]))) 2297 case nl.IFLA_MACVLAN_MACADDR_DATA: 2298 macs, err := nl.ParseRouteAttr(datum.Value[:]) 2299 if err != nil { 2300 panic(fmt.Sprintf("failed to ParseRouteAttr for IFLA_MACVLAN_MACADDR_DATA: %v", err)) 2301 } 2302 for _, macDatum := range macs { 2303 macv.MACAddrs = append(macv.MACAddrs, net.HardwareAddr(macDatum.Value[0:6])) 2304 } 2305 } 2306 } 2307} 2308 2309// copied from pkg/net_linux.go 2310func linkFlags(rawFlags uint32) net.Flags { 2311 var f net.Flags 2312 if rawFlags&unix.IFF_UP != 0 { 2313 f |= net.FlagUp 2314 } 2315 if rawFlags&unix.IFF_BROADCAST != 0 { 2316 f |= net.FlagBroadcast 2317 } 2318 if rawFlags&unix.IFF_LOOPBACK != 0 { 2319 f |= net.FlagLoopback 2320 } 2321 if rawFlags&unix.IFF_POINTOPOINT != 0 { 2322 f |= net.FlagPointToPoint 2323 } 2324 if rawFlags&unix.IFF_MULTICAST != 0 { 2325 f |= net.FlagMulticast 2326 } 2327 return f 2328} 2329 2330func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) { 2331 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 2332 2333 if gretap.FlowBased { 2334 // In flow based mode, no other attributes need to be configured 2335 data.AddRtAttr(nl.IFLA_GRE_COLLECT_METADATA, boolAttr(gretap.FlowBased)) 2336 return 2337 } 2338 2339 if ip := gretap.Local; ip != nil { 2340 if ip.To4() != nil { 2341 ip = ip.To4() 2342 } 2343 data.AddRtAttr(nl.IFLA_GRE_LOCAL, []byte(ip)) 2344 } 2345 2346 if ip := gretap.Remote; ip != nil { 2347 if ip.To4() != nil { 2348 ip = ip.To4() 2349 } 2350 data.AddRtAttr(nl.IFLA_GRE_REMOTE, []byte(ip)) 2351 } 2352 2353 if gretap.IKey != 0 { 2354 data.AddRtAttr(nl.IFLA_GRE_IKEY, htonl(gretap.IKey)) 2355 gretap.IFlags |= uint16(nl.GRE_KEY) 2356 } 2357 2358 if gretap.OKey != 0 { 2359 data.AddRtAttr(nl.IFLA_GRE_OKEY, htonl(gretap.OKey)) 2360 gretap.OFlags |= uint16(nl.GRE_KEY) 2361 } 2362 2363 data.AddRtAttr(nl.IFLA_GRE_IFLAGS, htons(gretap.IFlags)) 2364 data.AddRtAttr(nl.IFLA_GRE_OFLAGS, htons(gretap.OFlags)) 2365 2366 if gretap.Link != 0 { 2367 data.AddRtAttr(nl.IFLA_GRE_LINK, nl.Uint32Attr(gretap.Link)) 2368 } 2369 2370 data.AddRtAttr(nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gretap.PMtuDisc)) 2371 data.AddRtAttr(nl.IFLA_GRE_TTL, nl.Uint8Attr(gretap.Ttl)) 2372 data.AddRtAttr(nl.IFLA_GRE_TOS, nl.Uint8Attr(gretap.Tos)) 2373 data.AddRtAttr(nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gretap.EncapType)) 2374 data.AddRtAttr(nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gretap.EncapFlags)) 2375 data.AddRtAttr(nl.IFLA_GRE_ENCAP_SPORT, htons(gretap.EncapSport)) 2376 data.AddRtAttr(nl.IFLA_GRE_ENCAP_DPORT, htons(gretap.EncapDport)) 2377} 2378 2379func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) { 2380 gre := link.(*Gretap) 2381 for _, datum := range data { 2382 switch datum.Attr.Type { 2383 case nl.IFLA_GRE_OKEY: 2384 gre.IKey = ntohl(datum.Value[0:4]) 2385 case nl.IFLA_GRE_IKEY: 2386 gre.OKey = ntohl(datum.Value[0:4]) 2387 case nl.IFLA_GRE_LOCAL: 2388 gre.Local = net.IP(datum.Value) 2389 case nl.IFLA_GRE_REMOTE: 2390 gre.Remote = net.IP(datum.Value) 2391 case nl.IFLA_GRE_ENCAP_SPORT: 2392 gre.EncapSport = ntohs(datum.Value[0:2]) 2393 case nl.IFLA_GRE_ENCAP_DPORT: 2394 gre.EncapDport = ntohs(datum.Value[0:2]) 2395 case nl.IFLA_GRE_IFLAGS: 2396 gre.IFlags = ntohs(datum.Value[0:2]) 2397 case nl.IFLA_GRE_OFLAGS: 2398 gre.OFlags = ntohs(datum.Value[0:2]) 2399 case nl.IFLA_GRE_TTL: 2400 gre.Ttl = uint8(datum.Value[0]) 2401 case nl.IFLA_GRE_TOS: 2402 gre.Tos = uint8(datum.Value[0]) 2403 case nl.IFLA_GRE_PMTUDISC: 2404 gre.PMtuDisc = uint8(datum.Value[0]) 2405 case nl.IFLA_GRE_ENCAP_TYPE: 2406 gre.EncapType = native.Uint16(datum.Value[0:2]) 2407 case nl.IFLA_GRE_ENCAP_FLAGS: 2408 gre.EncapFlags = native.Uint16(datum.Value[0:2]) 2409 case nl.IFLA_GRE_COLLECT_METADATA: 2410 gre.FlowBased = true 2411 } 2412 } 2413} 2414 2415func addGretunAttrs(gre *Gretun, linkInfo *nl.RtAttr) { 2416 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 2417 2418 if ip := gre.Local; ip != nil { 2419 if ip.To4() != nil { 2420 ip = ip.To4() 2421 } 2422 data.AddRtAttr(nl.IFLA_GRE_LOCAL, []byte(ip)) 2423 } 2424 2425 if ip := gre.Remote; ip != nil { 2426 if ip.To4() != nil { 2427 ip = ip.To4() 2428 } 2429 data.AddRtAttr(nl.IFLA_GRE_REMOTE, []byte(ip)) 2430 } 2431 2432 if gre.IKey != 0 { 2433 data.AddRtAttr(nl.IFLA_GRE_IKEY, htonl(gre.IKey)) 2434 gre.IFlags |= uint16(nl.GRE_KEY) 2435 } 2436 2437 if gre.OKey != 0 { 2438 data.AddRtAttr(nl.IFLA_GRE_OKEY, htonl(gre.OKey)) 2439 gre.OFlags |= uint16(nl.GRE_KEY) 2440 } 2441 2442 data.AddRtAttr(nl.IFLA_GRE_IFLAGS, htons(gre.IFlags)) 2443 data.AddRtAttr(nl.IFLA_GRE_OFLAGS, htons(gre.OFlags)) 2444 2445 if gre.Link != 0 { 2446 data.AddRtAttr(nl.IFLA_GRE_LINK, nl.Uint32Attr(gre.Link)) 2447 } 2448 2449 data.AddRtAttr(nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gre.PMtuDisc)) 2450 data.AddRtAttr(nl.IFLA_GRE_TTL, nl.Uint8Attr(gre.Ttl)) 2451 data.AddRtAttr(nl.IFLA_GRE_TOS, nl.Uint8Attr(gre.Tos)) 2452 data.AddRtAttr(nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gre.EncapType)) 2453 data.AddRtAttr(nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gre.EncapFlags)) 2454 data.AddRtAttr(nl.IFLA_GRE_ENCAP_SPORT, htons(gre.EncapSport)) 2455 data.AddRtAttr(nl.IFLA_GRE_ENCAP_DPORT, htons(gre.EncapDport)) 2456} 2457 2458func parseGretunData(link Link, data []syscall.NetlinkRouteAttr) { 2459 gre := link.(*Gretun) 2460 for _, datum := range data { 2461 switch datum.Attr.Type { 2462 case nl.IFLA_GRE_IKEY: 2463 gre.IKey = ntohl(datum.Value[0:4]) 2464 case nl.IFLA_GRE_OKEY: 2465 gre.OKey = ntohl(datum.Value[0:4]) 2466 case nl.IFLA_GRE_LOCAL: 2467 gre.Local = net.IP(datum.Value) 2468 case nl.IFLA_GRE_REMOTE: 2469 gre.Remote = net.IP(datum.Value) 2470 case nl.IFLA_GRE_IFLAGS: 2471 gre.IFlags = ntohs(datum.Value[0:2]) 2472 case nl.IFLA_GRE_OFLAGS: 2473 gre.OFlags = ntohs(datum.Value[0:2]) 2474 case nl.IFLA_GRE_TTL: 2475 gre.Ttl = uint8(datum.Value[0]) 2476 case nl.IFLA_GRE_TOS: 2477 gre.Tos = uint8(datum.Value[0]) 2478 case nl.IFLA_GRE_PMTUDISC: 2479 gre.PMtuDisc = uint8(datum.Value[0]) 2480 case nl.IFLA_GRE_ENCAP_TYPE: 2481 gre.EncapType = native.Uint16(datum.Value[0:2]) 2482 case nl.IFLA_GRE_ENCAP_FLAGS: 2483 gre.EncapFlags = native.Uint16(datum.Value[0:2]) 2484 case nl.IFLA_GRE_ENCAP_SPORT: 2485 gre.EncapSport = ntohs(datum.Value[0:2]) 2486 case nl.IFLA_GRE_ENCAP_DPORT: 2487 gre.EncapDport = ntohs(datum.Value[0:2]) 2488 } 2489 } 2490} 2491 2492func addXdpAttrs(xdp *LinkXdp, req *nl.NetlinkRequest) { 2493 attrs := nl.NewRtAttr(unix.IFLA_XDP|unix.NLA_F_NESTED, nil) 2494 b := make([]byte, 4) 2495 native.PutUint32(b, uint32(xdp.Fd)) 2496 attrs.AddRtAttr(nl.IFLA_XDP_FD, b) 2497 if xdp.Flags != 0 { 2498 b := make([]byte, 4) 2499 native.PutUint32(b, xdp.Flags) 2500 attrs.AddRtAttr(nl.IFLA_XDP_FLAGS, b) 2501 } 2502 req.AddData(attrs) 2503} 2504 2505func parseLinkXdp(data []byte) (*LinkXdp, error) { 2506 attrs, err := nl.ParseRouteAttr(data) 2507 if err != nil { 2508 return nil, err 2509 } 2510 xdp := &LinkXdp{} 2511 for _, attr := range attrs { 2512 switch attr.Attr.Type { 2513 case nl.IFLA_XDP_FD: 2514 xdp.Fd = int(native.Uint32(attr.Value[0:4])) 2515 case nl.IFLA_XDP_ATTACHED: 2516 xdp.Attached = attr.Value[0] != 0 2517 case nl.IFLA_XDP_FLAGS: 2518 xdp.Flags = native.Uint32(attr.Value[0:4]) 2519 case nl.IFLA_XDP_PROG_ID: 2520 xdp.ProgId = native.Uint32(attr.Value[0:4]) 2521 } 2522 } 2523 return xdp, nil 2524} 2525 2526func addIptunAttrs(iptun *Iptun, linkInfo *nl.RtAttr) { 2527 if iptun.FlowBased { 2528 // In flow based mode, no other attributes need to be configured 2529 linkInfo.AddRtAttr(nl.IFLA_IPTUN_COLLECT_METADATA, boolAttr(iptun.FlowBased)) 2530 return 2531 } 2532 2533 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 2534 2535 ip := iptun.Local.To4() 2536 if ip != nil { 2537 data.AddRtAttr(nl.IFLA_IPTUN_LOCAL, []byte(ip)) 2538 } 2539 2540 ip = iptun.Remote.To4() 2541 if ip != nil { 2542 data.AddRtAttr(nl.IFLA_IPTUN_REMOTE, []byte(ip)) 2543 } 2544 2545 if iptun.Link != 0 { 2546 data.AddRtAttr(nl.IFLA_IPTUN_LINK, nl.Uint32Attr(iptun.Link)) 2547 } 2548 data.AddRtAttr(nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(iptun.PMtuDisc)) 2549 data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(iptun.Ttl)) 2550 data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(iptun.Tos)) 2551 data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(iptun.EncapType)) 2552 data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(iptun.EncapFlags)) 2553 data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_SPORT, htons(iptun.EncapSport)) 2554 data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_DPORT, htons(iptun.EncapDport)) 2555} 2556 2557func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) { 2558 iptun := link.(*Iptun) 2559 for _, datum := range data { 2560 switch datum.Attr.Type { 2561 case nl.IFLA_IPTUN_LOCAL: 2562 iptun.Local = net.IP(datum.Value[0:4]) 2563 case nl.IFLA_IPTUN_REMOTE: 2564 iptun.Remote = net.IP(datum.Value[0:4]) 2565 case nl.IFLA_IPTUN_TTL: 2566 iptun.Ttl = uint8(datum.Value[0]) 2567 case nl.IFLA_IPTUN_TOS: 2568 iptun.Tos = uint8(datum.Value[0]) 2569 case nl.IFLA_IPTUN_PMTUDISC: 2570 iptun.PMtuDisc = uint8(datum.Value[0]) 2571 case nl.IFLA_IPTUN_ENCAP_SPORT: 2572 iptun.EncapSport = ntohs(datum.Value[0:2]) 2573 case nl.IFLA_IPTUN_ENCAP_DPORT: 2574 iptun.EncapDport = ntohs(datum.Value[0:2]) 2575 case nl.IFLA_IPTUN_ENCAP_TYPE: 2576 iptun.EncapType = native.Uint16(datum.Value[0:2]) 2577 case nl.IFLA_IPTUN_ENCAP_FLAGS: 2578 iptun.EncapFlags = native.Uint16(datum.Value[0:2]) 2579 case nl.IFLA_IPTUN_COLLECT_METADATA: 2580 iptun.FlowBased = int8(datum.Value[0]) != 0 2581 } 2582 } 2583} 2584 2585func addIp6tnlAttrs(ip6tnl *Ip6tnl, linkInfo *nl.RtAttr) { 2586 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 2587 2588 if ip6tnl.Link != 0 { 2589 data.AddRtAttr(nl.IFLA_IPTUN_LINK, nl.Uint32Attr(ip6tnl.Link)) 2590 } 2591 2592 ip := ip6tnl.Local.To16() 2593 if ip != nil { 2594 data.AddRtAttr(nl.IFLA_IPTUN_LOCAL, []byte(ip)) 2595 } 2596 2597 ip = ip6tnl.Remote.To16() 2598 if ip != nil { 2599 data.AddRtAttr(nl.IFLA_IPTUN_REMOTE, []byte(ip)) 2600 } 2601 2602 data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(ip6tnl.Ttl)) 2603 data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(ip6tnl.Tos)) 2604 data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_LIMIT, nl.Uint8Attr(ip6tnl.EncapLimit)) 2605 data.AddRtAttr(nl.IFLA_IPTUN_FLAGS, nl.Uint32Attr(ip6tnl.Flags)) 2606 data.AddRtAttr(nl.IFLA_IPTUN_PROTO, nl.Uint8Attr(ip6tnl.Proto)) 2607 data.AddRtAttr(nl.IFLA_IPTUN_FLOWINFO, nl.Uint32Attr(ip6tnl.FlowInfo)) 2608} 2609 2610func parseIp6tnlData(link Link, data []syscall.NetlinkRouteAttr) { 2611 ip6tnl := link.(*Ip6tnl) 2612 for _, datum := range data { 2613 switch datum.Attr.Type { 2614 case nl.IFLA_IPTUN_LOCAL: 2615 ip6tnl.Local = net.IP(datum.Value[:16]) 2616 case nl.IFLA_IPTUN_REMOTE: 2617 ip6tnl.Remote = net.IP(datum.Value[:16]) 2618 case nl.IFLA_IPTUN_TTL: 2619 ip6tnl.Ttl = uint8(datum.Value[0]) 2620 case nl.IFLA_IPTUN_TOS: 2621 ip6tnl.Tos = uint8(datum.Value[0]) 2622 case nl.IFLA_IPTUN_ENCAP_LIMIT: 2623 ip6tnl.EncapLimit = uint8(datum.Value[0]) 2624 case nl.IFLA_IPTUN_FLAGS: 2625 ip6tnl.Flags = native.Uint32(datum.Value[:4]) 2626 case nl.IFLA_IPTUN_PROTO: 2627 ip6tnl.Proto = uint8(datum.Value[0]) 2628 case nl.IFLA_IPTUN_FLOWINFO: 2629 ip6tnl.FlowInfo = native.Uint32(datum.Value[:4]) 2630 } 2631 } 2632} 2633 2634func addSittunAttrs(sittun *Sittun, linkInfo *nl.RtAttr) { 2635 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 2636 2637 if sittun.Link != 0 { 2638 data.AddRtAttr(nl.IFLA_IPTUN_LINK, nl.Uint32Attr(sittun.Link)) 2639 } 2640 2641 ip := sittun.Local.To4() 2642 if ip != nil { 2643 data.AddRtAttr(nl.IFLA_IPTUN_LOCAL, []byte(ip)) 2644 } 2645 2646 ip = sittun.Remote.To4() 2647 if ip != nil { 2648 data.AddRtAttr(nl.IFLA_IPTUN_REMOTE, []byte(ip)) 2649 } 2650 2651 if sittun.Ttl > 0 { 2652 // Would otherwise fail on 3.10 kernel 2653 data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(sittun.Ttl)) 2654 } 2655 2656 data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(sittun.Tos)) 2657 data.AddRtAttr(nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(sittun.PMtuDisc)) 2658 data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(sittun.EncapType)) 2659 data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(sittun.EncapFlags)) 2660 data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_SPORT, htons(sittun.EncapSport)) 2661 data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_DPORT, htons(sittun.EncapDport)) 2662} 2663 2664func parseSittunData(link Link, data []syscall.NetlinkRouteAttr) { 2665 sittun := link.(*Sittun) 2666 for _, datum := range data { 2667 switch datum.Attr.Type { 2668 case nl.IFLA_IPTUN_LOCAL: 2669 sittun.Local = net.IP(datum.Value[0:4]) 2670 case nl.IFLA_IPTUN_REMOTE: 2671 sittun.Remote = net.IP(datum.Value[0:4]) 2672 case nl.IFLA_IPTUN_TTL: 2673 sittun.Ttl = uint8(datum.Value[0]) 2674 case nl.IFLA_IPTUN_TOS: 2675 sittun.Tos = uint8(datum.Value[0]) 2676 case nl.IFLA_IPTUN_PMTUDISC: 2677 sittun.PMtuDisc = uint8(datum.Value[0]) 2678 case nl.IFLA_IPTUN_ENCAP_TYPE: 2679 sittun.EncapType = native.Uint16(datum.Value[0:2]) 2680 case nl.IFLA_IPTUN_ENCAP_FLAGS: 2681 sittun.EncapFlags = native.Uint16(datum.Value[0:2]) 2682 case nl.IFLA_IPTUN_ENCAP_SPORT: 2683 sittun.EncapSport = ntohs(datum.Value[0:2]) 2684 case nl.IFLA_IPTUN_ENCAP_DPORT: 2685 sittun.EncapDport = ntohs(datum.Value[0:2]) 2686 } 2687 } 2688} 2689 2690func addVtiAttrs(vti *Vti, linkInfo *nl.RtAttr) { 2691 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 2692 2693 family := FAMILY_V4 2694 if vti.Local.To4() == nil { 2695 family = FAMILY_V6 2696 } 2697 2698 var ip net.IP 2699 2700 if family == FAMILY_V4 { 2701 ip = vti.Local.To4() 2702 } else { 2703 ip = vti.Local 2704 } 2705 if ip != nil { 2706 data.AddRtAttr(nl.IFLA_VTI_LOCAL, []byte(ip)) 2707 } 2708 2709 if family == FAMILY_V4 { 2710 ip = vti.Remote.To4() 2711 } else { 2712 ip = vti.Remote 2713 } 2714 if ip != nil { 2715 data.AddRtAttr(nl.IFLA_VTI_REMOTE, []byte(ip)) 2716 } 2717 2718 if vti.Link != 0 { 2719 data.AddRtAttr(nl.IFLA_VTI_LINK, nl.Uint32Attr(vti.Link)) 2720 } 2721 2722 data.AddRtAttr(nl.IFLA_VTI_IKEY, htonl(vti.IKey)) 2723 data.AddRtAttr(nl.IFLA_VTI_OKEY, htonl(vti.OKey)) 2724} 2725 2726func parseVtiData(link Link, data []syscall.NetlinkRouteAttr) { 2727 vti := link.(*Vti) 2728 for _, datum := range data { 2729 switch datum.Attr.Type { 2730 case nl.IFLA_VTI_LOCAL: 2731 vti.Local = net.IP(datum.Value) 2732 case nl.IFLA_VTI_REMOTE: 2733 vti.Remote = net.IP(datum.Value) 2734 case nl.IFLA_VTI_IKEY: 2735 vti.IKey = ntohl(datum.Value[0:4]) 2736 case nl.IFLA_VTI_OKEY: 2737 vti.OKey = ntohl(datum.Value[0:4]) 2738 } 2739 } 2740} 2741 2742func addVrfAttrs(vrf *Vrf, linkInfo *nl.RtAttr) { 2743 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 2744 b := make([]byte, 4) 2745 native.PutUint32(b, uint32(vrf.Table)) 2746 data.AddRtAttr(nl.IFLA_VRF_TABLE, b) 2747} 2748 2749func parseVrfData(link Link, data []syscall.NetlinkRouteAttr) { 2750 vrf := link.(*Vrf) 2751 for _, datum := range data { 2752 switch datum.Attr.Type { 2753 case nl.IFLA_VRF_TABLE: 2754 vrf.Table = native.Uint32(datum.Value[0:4]) 2755 } 2756 } 2757} 2758 2759func addBridgeAttrs(bridge *Bridge, linkInfo *nl.RtAttr) { 2760 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 2761 if bridge.MulticastSnooping != nil { 2762 data.AddRtAttr(nl.IFLA_BR_MCAST_SNOOPING, boolToByte(*bridge.MulticastSnooping)) 2763 } 2764 if bridge.HelloTime != nil { 2765 data.AddRtAttr(nl.IFLA_BR_HELLO_TIME, nl.Uint32Attr(*bridge.HelloTime)) 2766 } 2767 if bridge.VlanFiltering != nil { 2768 data.AddRtAttr(nl.IFLA_BR_VLAN_FILTERING, boolToByte(*bridge.VlanFiltering)) 2769 } 2770} 2771 2772func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) { 2773 br := bridge.(*Bridge) 2774 for _, datum := range data { 2775 switch datum.Attr.Type { 2776 case nl.IFLA_BR_HELLO_TIME: 2777 helloTime := native.Uint32(datum.Value[0:4]) 2778 br.HelloTime = &helloTime 2779 case nl.IFLA_BR_MCAST_SNOOPING: 2780 mcastSnooping := datum.Value[0] == 1 2781 br.MulticastSnooping = &mcastSnooping 2782 case nl.IFLA_BR_VLAN_FILTERING: 2783 vlanFiltering := datum.Value[0] == 1 2784 br.VlanFiltering = &vlanFiltering 2785 } 2786 } 2787} 2788 2789func addGTPAttrs(gtp *GTP, linkInfo *nl.RtAttr) { 2790 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 2791 data.AddRtAttr(nl.IFLA_GTP_FD0, nl.Uint32Attr(uint32(gtp.FD0))) 2792 data.AddRtAttr(nl.IFLA_GTP_FD1, nl.Uint32Attr(uint32(gtp.FD1))) 2793 data.AddRtAttr(nl.IFLA_GTP_PDP_HASHSIZE, nl.Uint32Attr(131072)) 2794 if gtp.Role != nl.GTP_ROLE_GGSN { 2795 data.AddRtAttr(nl.IFLA_GTP_ROLE, nl.Uint32Attr(uint32(gtp.Role))) 2796 } 2797} 2798 2799func parseGTPData(link Link, data []syscall.NetlinkRouteAttr) { 2800 gtp := link.(*GTP) 2801 for _, datum := range data { 2802 switch datum.Attr.Type { 2803 case nl.IFLA_GTP_FD0: 2804 gtp.FD0 = int(native.Uint32(datum.Value)) 2805 case nl.IFLA_GTP_FD1: 2806 gtp.FD1 = int(native.Uint32(datum.Value)) 2807 case nl.IFLA_GTP_PDP_HASHSIZE: 2808 gtp.PDPHashsize = int(native.Uint32(datum.Value)) 2809 case nl.IFLA_GTP_ROLE: 2810 gtp.Role = int(native.Uint32(datum.Value)) 2811 } 2812 } 2813} 2814 2815func parseVfInfoList(data []syscall.NetlinkRouteAttr) ([]VfInfo, error) { 2816 var vfs []VfInfo 2817 2818 for i, element := range data { 2819 if element.Attr.Type != nl.IFLA_VF_INFO { 2820 return nil, fmt.Errorf("Incorrect element type in vf info list: %d", element.Attr.Type) 2821 } 2822 vfAttrs, err := nl.ParseRouteAttr(element.Value) 2823 if err != nil { 2824 return nil, err 2825 } 2826 vfs = append(vfs, parseVfInfo(vfAttrs, i)) 2827 } 2828 return vfs, nil 2829} 2830 2831func parseVfInfo(data []syscall.NetlinkRouteAttr, id int) VfInfo { 2832 vf := VfInfo{ID: id} 2833 for _, element := range data { 2834 switch element.Attr.Type { 2835 case nl.IFLA_VF_MAC: 2836 mac := nl.DeserializeVfMac(element.Value[:]) 2837 vf.Mac = mac.Mac[:6] 2838 case nl.IFLA_VF_VLAN: 2839 vl := nl.DeserializeVfVlan(element.Value[:]) 2840 vf.Vlan = int(vl.Vlan) 2841 vf.Qos = int(vl.Qos) 2842 case nl.IFLA_VF_TX_RATE: 2843 txr := nl.DeserializeVfTxRate(element.Value[:]) 2844 vf.TxRate = int(txr.Rate) 2845 case nl.IFLA_VF_SPOOFCHK: 2846 sp := nl.DeserializeVfSpoofchk(element.Value[:]) 2847 vf.Spoofchk = sp.Setting != 0 2848 case nl.IFLA_VF_LINK_STATE: 2849 ls := nl.DeserializeVfLinkState(element.Value[:]) 2850 vf.LinkState = ls.LinkState 2851 case nl.IFLA_VF_RATE: 2852 vfr := nl.DeserializeVfRate(element.Value[:]) 2853 vf.MaxTxRate = vfr.MaxTxRate 2854 vf.MinTxRate = vfr.MinTxRate 2855 } 2856 } 2857 return vf 2858} 2859 2860func addXfrmiAttrs(xfrmi *Xfrmi, linkInfo *nl.RtAttr) { 2861 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 2862 data.AddRtAttr(nl.IFLA_XFRM_LINK, nl.Uint32Attr(uint32(xfrmi.ParentIndex))) 2863 data.AddRtAttr(nl.IFLA_XFRM_IF_ID, nl.Uint32Attr(xfrmi.Ifid)) 2864 2865} 2866 2867func parseXfrmiData(link Link, data []syscall.NetlinkRouteAttr) { 2868 xfrmi := link.(*Xfrmi) 2869 for _, datum := range data { 2870 switch datum.Attr.Type { 2871 case nl.IFLA_XFRM_LINK: 2872 xfrmi.ParentIndex = int(native.Uint32(datum.Value)) 2873 case nl.IFLA_XFRM_IF_ID: 2874 xfrmi.Ifid = native.Uint32(datum.Value) 2875 } 2876 } 2877} 2878 2879// LinkSetBondSlave add slave to bond link via ioctl interface. 2880func LinkSetBondSlave(link Link, master *Bond) error { 2881 fd, err := getSocketUDP() 2882 if err != nil { 2883 return err 2884 } 2885 defer syscall.Close(fd) 2886 2887 ifreq := newIocltSlaveReq(link.Attrs().Name, master.Attrs().Name) 2888 2889 _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), unix.SIOCBONDENSLAVE, uintptr(unsafe.Pointer(ifreq))) 2890 if errno != 0 { 2891 return fmt.Errorf("Failed to enslave %q to %q, errno=%v", link.Attrs().Name, master.Attrs().Name, errno) 2892 } 2893 return nil 2894} 2895 2896// LinkSetBondSlaveQueueId modify bond slave queue-id. 2897func (h *Handle) LinkSetBondSlaveQueueId(link Link, queueId uint16) error { 2898 base := link.Attrs() 2899 h.ensureIndex(base) 2900 req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) 2901 2902 msg := nl.NewIfInfomsg(unix.AF_UNSPEC) 2903 msg.Index = int32(base.Index) 2904 req.AddData(msg) 2905 2906 linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil) 2907 data := linkInfo.AddRtAttr(nl.IFLA_INFO_SLAVE_DATA, nil) 2908 data.AddRtAttr(nl.IFLA_BOND_SLAVE_QUEUE_ID, nl.Uint16Attr(queueId)) 2909 2910 req.AddData(linkInfo) 2911 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 2912 return err 2913} 2914 2915// LinkSetBondSlaveQueueId modify bond slave queue-id. 2916func LinkSetBondSlaveQueueId(link Link, queueId uint16) error { 2917 return pkgHandle.LinkSetBondSlaveQueueId(link, queueId) 2918} 2919 2920func vethStatsSerialize(stats ethtoolStats) ([]byte, error) { 2921 statsSize := int(unsafe.Sizeof(stats)) + int(stats.nStats)*int(unsafe.Sizeof(uint64(0))) 2922 b := make([]byte, 0, statsSize) 2923 buf := bytes.NewBuffer(b) 2924 err := binary.Write(buf, nl.NativeEndian(), stats) 2925 return buf.Bytes()[:statsSize], err 2926} 2927 2928type vethEthtoolStats struct { 2929 Cmd uint32 2930 NStats uint32 2931 Peer uint64 2932 // Newer kernels have XDP stats in here, but we only care 2933 // to extract the peer ifindex here. 2934} 2935 2936func vethStatsDeserialize(b []byte) (vethEthtoolStats, error) { 2937 var stats = vethEthtoolStats{} 2938 err := binary.Read(bytes.NewReader(b), nl.NativeEndian(), &stats) 2939 return stats, err 2940} 2941 2942// VethPeerIndex get veth peer index. 2943func VethPeerIndex(link *Veth) (int, error) { 2944 fd, err := getSocketUDP() 2945 if err != nil { 2946 return -1, err 2947 } 2948 defer syscall.Close(fd) 2949 2950 ifreq, sSet := newIocltStringSetReq(link.Name) 2951 _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq))) 2952 if errno != 0 { 2953 return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno) 2954 } 2955 2956 stats := ethtoolStats{ 2957 cmd: ETHTOOL_GSTATS, 2958 nStats: sSet.data[0], 2959 } 2960 2961 buffer, err := vethStatsSerialize(stats) 2962 if err != nil { 2963 return -1, err 2964 } 2965 2966 ifreq.Data = uintptr(unsafe.Pointer(&buffer[0])) 2967 _, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq))) 2968 if errno != 0 { 2969 return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno) 2970 } 2971 2972 vstats, err := vethStatsDeserialize(buffer) 2973 if err != nil { 2974 return -1, err 2975 } 2976 2977 return int(vstats.Peer), nil 2978} 2979 2980func parseTuntapData(link Link, data []syscall.NetlinkRouteAttr) { 2981 tuntap := link.(*Tuntap) 2982 for _, datum := range data { 2983 switch datum.Attr.Type { 2984 case nl.IFLA_TUN_OWNER: 2985 tuntap.Owner = native.Uint32(datum.Value) 2986 case nl.IFLA_TUN_GROUP: 2987 tuntap.Group = native.Uint32(datum.Value) 2988 case nl.IFLA_TUN_TYPE: 2989 tuntap.Mode = TuntapMode(uint8(datum.Value[0])) 2990 case nl.IFLA_TUN_PERSIST: 2991 tuntap.NonPersist = false 2992 if uint8(datum.Value[0]) == 0 { 2993 tuntap.NonPersist = true 2994 } 2995 } 2996 } 2997} 2998 2999func parseIPoIBData(link Link, data []syscall.NetlinkRouteAttr) { 3000 ipoib := link.(*IPoIB) 3001 for _, datum := range data { 3002 switch datum.Attr.Type { 3003 case nl.IFLA_IPOIB_PKEY: 3004 ipoib.Pkey = uint16(native.Uint16(datum.Value)) 3005 case nl.IFLA_IPOIB_MODE: 3006 ipoib.Mode = IPoIBMode(native.Uint16(datum.Value)) 3007 case nl.IFLA_IPOIB_UMCAST: 3008 ipoib.Umcast = uint16(native.Uint16(datum.Value)) 3009 } 3010 } 3011} 3012 3013func addIPoIBAttrs(ipoib *IPoIB, linkInfo *nl.RtAttr) { 3014 data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) 3015 data.AddRtAttr(nl.IFLA_IPOIB_PKEY, nl.Uint16Attr(uint16(ipoib.Pkey))) 3016 data.AddRtAttr(nl.IFLA_IPOIB_MODE, nl.Uint16Attr(uint16(ipoib.Mode))) 3017 data.AddRtAttr(nl.IFLA_IPOIB_UMCAST, nl.Uint16Attr(uint16(ipoib.Umcast))) 3018} 3019