// NeighList gets a list of IP-MAC mappings in the system (ARP table). // Equivalent to: `ip neighbor show`. // The list can be filtered by link and ip family. func NeighList(linkIndex, family int) ([]Neigh, error) { req := nl.NewNetlinkRequest(syscall.RTM_GETNEIGH, syscall.NLM_F_DUMP) msg := Ndmsg{ Family: uint8(family), Index: uint32(linkIndex), } req.AddData(&msg) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWNEIGH) if err != nil { return nil, err } var res []Neigh for _, m := range msgs { ndm := deserializeNdmsg(m) if linkIndex != 0 && int(ndm.Index) != linkIndex { // Ignore messages from other interfaces continue } neigh, err := NeighDeserialize(m) if err != nil { continue } res = append(res, *neigh) } return res, nil }
// XfrmPolicyAdd will add an xfrm policy to the system. // Equivalent to: `ip xfrm policy add $policy` func XfrmPolicyAdd(policy *XfrmPolicy) error { req := nl.NewNetlinkRequest(nl.XFRM_MSG_NEWPOLICY, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) msg := &nl.XfrmUserpolicyInfo{} selFromPolicy(&msg.Sel, policy) msg.Priority = uint32(policy.Priority) msg.Index = uint32(policy.Index) msg.Dir = uint8(policy.Dir) msg.Lft.SoftByteLimit = nl.XFRM_INF msg.Lft.HardByteLimit = nl.XFRM_INF msg.Lft.SoftPacketLimit = nl.XFRM_INF msg.Lft.HardPacketLimit = nl.XFRM_INF req.AddData(msg) tmplData := make([]byte, nl.SizeofXfrmUserTmpl*len(policy.Tmpls)) for i, tmpl := range policy.Tmpls { start := i * nl.SizeofXfrmUserTmpl userTmpl := nl.DeserializeXfrmUserTmpl(tmplData[start : start+nl.SizeofXfrmUserTmpl]) userTmpl.XfrmId.Daddr.FromIP(tmpl.Dst) userTmpl.Saddr.FromIP(tmpl.Src) userTmpl.XfrmId.Proto = uint8(tmpl.Proto) userTmpl.Mode = uint8(tmpl.Mode) userTmpl.Reqid = uint32(tmpl.Reqid) userTmpl.Aalgos = ^uint32(0) userTmpl.Ealgos = ^uint32(0) userTmpl.Calgos = ^uint32(0) } if len(tmplData) > 0 { tmpls := nl.NewRtAttr(nl.XFRMA_TMPL, tmplData) req.AddData(tmpls) } _, err := req.Execute(syscall.NETLINK_XFRM, 0) return err }
// LinkByIndex finds a link by index and returns a pointer to the object. func LinkByIndex(index int) (Link, error) { req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Index = int32(index) req.AddData(msg) return execGetLink(req) }
// XfrmPolicyDel will delete an xfrm policy from the system. Note that // the Tmpls are ignored when matching the policy to delete. // Equivalent to: `ip xfrm policy del $policy` func XfrmPolicyDel(policy *XfrmPolicy) error { req := nl.NewNetlinkRequest(nl.XFRM_MSG_DELPOLICY, syscall.NLM_F_ACK) msg := &nl.XfrmUserpolicyId{} selFromPolicy(&msg.Sel, policy) msg.Index = uint32(policy.Index) msg.Dir = uint8(policy.Dir) req.AddData(msg) _, err := req.Execute(syscall.NETLINK_XFRM, 0) return err }
// XfrmPolicyList gets a list of xfrm policies in the system. // Equivalent to: `ip xfrm policy show`. // The list can be filtered by ip family. func XfrmPolicyList(family int) ([]XfrmPolicy, error) { req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETPOLICY, syscall.NLM_F_DUMP) msg := nl.NewIfInfomsg(family) req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY) if err != nil { return nil, err } var res []XfrmPolicy for _, m := range msgs { msg := nl.DeserializeXfrmUserpolicyInfo(m) if family != FAMILY_ALL && family != int(msg.Sel.Family) { continue } var policy XfrmPolicy policy.Dst = msg.Sel.Daddr.ToIPNet(msg.Sel.PrefixlenD) policy.Src = msg.Sel.Saddr.ToIPNet(msg.Sel.PrefixlenS) policy.Priority = int(msg.Priority) policy.Index = int(msg.Index) policy.Dir = Dir(msg.Dir) attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return nil, err } for _, attr := range attrs { switch attr.Attr.Type { case nl.XFRMA_TMPL: max := len(attr.Value) for i := 0; i < max; i += nl.SizeofXfrmUserTmpl { var resTmpl XfrmPolicyTmpl tmpl := nl.DeserializeXfrmUserTmpl(attr.Value[i : i+nl.SizeofXfrmUserTmpl]) resTmpl.Dst = tmpl.XfrmId.Daddr.ToIP() resTmpl.Src = tmpl.Saddr.ToIP() resTmpl.Proto = Proto(tmpl.XfrmId.Proto) resTmpl.Mode = Mode(tmpl.Mode) resTmpl.Reqid = int(tmpl.Reqid) policy.Tmpls = append(policy.Tmpls, resTmpl) } } } res = append(res, policy) } return res, nil }
func LinkGetProtinfo(link Link) (Protinfo, error) { base := link.Attrs() ensureIndex(base) var pi Protinfo req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP) msg := nl.NewIfInfomsg(syscall.AF_BRIDGE) req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_ROUTE, 0) if err != nil { return pi, err } for _, m := range msgs { ans := nl.DeserializeIfInfomsg(m) if int(ans.Index) != base.Index { continue } attrs, err := nl.ParseRouteAttr(m[ans.Len():]) if err != nil { return pi, err } for _, attr := range attrs { if attr.Attr.Type != syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED { continue } infos, err := nl.ParseRouteAttr(attr.Value) if err != nil { return pi, err } var pi Protinfo for _, info := range infos { switch info.Attr.Type { case nl.IFLA_BRPORT_MODE: pi.Hairpin = byteToBool(info.Value[0]) case nl.IFLA_BRPORT_GUARD: pi.Guard = byteToBool(info.Value[0]) case nl.IFLA_BRPORT_FAST_LEAVE: pi.FastLeave = byteToBool(info.Value[0]) case nl.IFLA_BRPORT_PROTECT: pi.RootBlock = byteToBool(info.Value[0]) case nl.IFLA_BRPORT_LEARNING: pi.Learning = byteToBool(info.Value[0]) case nl.IFLA_BRPORT_UNICAST_FLOOD: pi.Flood = byteToBool(info.Value[0]) } } return pi, nil } } return pi, fmt.Errorf("Device with index %d not found", base.Index) }
// LinkDel deletes link device. Either Index or Name must be set in // the link object for it to be deleted. The other values are ignored. // Equivalent to: `ip link del $link` func LinkDel(link Link) error { base := link.Attrs() ensureIndex(base) req := nl.NewNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Index = int32(base.Index) req.AddData(msg) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) return err }
// LinkSetDown disables link device. // Equivalent to: `ip link set $link down` func LinkSetDown(link Link) error { base := link.Attrs() ensureIndex(base) req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Change = syscall.IFF_UP msg.Flags = 0 & ^syscall.IFF_UP msg.Index = int32(base.Index) req.AddData(msg) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) return err }
// LinkSetName sets the name of the link device. // Equivalent to: `ip link set $link name $name` func LinkSetName(link Link, name string) error { base := link.Attrs() ensureIndex(base) req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Index = int32(base.Index) req.AddData(msg) data := nl.NewRtAttr(syscall.IFLA_IFNAME, []byte(name)) req.AddData(data) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) return err }
// LinkSetHardwareAddr sets the hardware address of the link device. // Equivalent to: `ip link set $link address $hwaddr` func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error { base := link.Attrs() ensureIndex(base) req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Index = int32(base.Index) req.AddData(msg) data := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(hwaddr)) req.AddData(data) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) return err }
// FilterDel will delete a filter from the system. // Equivalent to: `tc filter del $filter` func FilterDel(filter Filter) error { req := nl.NewNetlinkRequest(syscall.RTM_DELTFILTER, syscall.NLM_F_ACK) base := filter.Attrs() msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, Ifindex: int32(base.LinkIndex), Handle: base.Handle, Parent: base.Parent, Info: MakeHandle(base.Priority, nl.Swap16(base.Protocol)), } req.AddData(msg) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) return err }
// LinkSetMTU sets the mtu of the link device. // Equivalent to: `ip link set $link mtu $mtu` func LinkSetMTU(link Link, mtu int) error { base := link.Attrs() ensureIndex(base) req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Index = int32(base.Index) req.AddData(msg) b := make([]byte, 4) native.PutUint32(b, uint32(mtu)) data := nl.NewRtAttr(syscall.IFLA_MTU, b) req.AddData(data) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) return err }
func setProtinfoAttr(link Link, mode bool, attr int) error { base := link.Attrs() ensureIndex(base) req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_BRIDGE) msg.Index = int32(base.Index) req.AddData(msg) br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil) nl.NewRtAttrChild(br, attr, boolToByte(mode)) req.AddData(br) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) if err != nil { return err } return nil }
// XfrmStateAdd will add an xfrm state to the system. // Equivalent to: `ip xfrm state add $state` func XfrmStateAdd(state *XfrmState) error { // A state with spi 0 can't be deleted so don't allow it to be set if state.Spi == 0 { return fmt.Errorf("Spi must be set when adding xfrm state.") } req := nl.NewNetlinkRequest(nl.XFRM_MSG_NEWSA, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) msg := &nl.XfrmUsersaInfo{} msg.Family = uint16(nl.GetIPFamily(state.Dst)) msg.Id.Daddr.FromIP(state.Dst) msg.Saddr.FromIP(state.Src) msg.Id.Proto = uint8(state.Proto) msg.Mode = uint8(state.Mode) msg.Id.Spi = nl.Swap32(uint32(state.Spi)) msg.Reqid = uint32(state.Reqid) msg.ReplayWindow = uint8(state.ReplayWindow) msg.Lft.SoftByteLimit = nl.XFRM_INF msg.Lft.HardByteLimit = nl.XFRM_INF msg.Lft.SoftPacketLimit = nl.XFRM_INF msg.Lft.HardPacketLimit = nl.XFRM_INF req.AddData(msg) if state.Auth != nil { out := nl.NewRtAttr(nl.XFRMA_ALG_AUTH_TRUNC, writeStateAlgoAuth(state.Auth)) req.AddData(out) } if state.Crypt != nil { out := nl.NewRtAttr(nl.XFRMA_ALG_CRYPT, writeStateAlgo(state.Crypt)) req.AddData(out) } if state.Encap != nil { encapData := make([]byte, nl.SizeofXfrmEncapTmpl) encap := nl.DeserializeXfrmEncapTmpl(encapData) encap.EncapType = uint16(state.Encap.Type) encap.EncapSport = nl.Swap16(uint16(state.Encap.SrcPort)) encap.EncapDport = nl.Swap16(uint16(state.Encap.DstPort)) encap.EncapOa.FromIP(state.Encap.OriginalAddress) out := nl.NewRtAttr(nl.XFRMA_ENCAP, encapData) req.AddData(out) } _, err := req.Execute(syscall.NETLINK_XFRM, 0) return err }
// XfrmStateDel will delete an xfrm state from the system. Note that // the Algos are ignored when matching the state to delete. // Equivalent to: `ip xfrm state del $state` func XfrmStateDel(state *XfrmState) error { req := nl.NewNetlinkRequest(nl.XFRM_MSG_DELSA, syscall.NLM_F_ACK) msg := &nl.XfrmUsersaId{} msg.Daddr.FromIP(state.Dst) msg.Family = uint16(nl.GetIPFamily(state.Dst)) msg.Proto = uint8(state.Proto) msg.Spi = nl.Swap32(uint32(state.Spi)) req.AddData(msg) saddr := nl.XfrmAddress{} saddr.FromIP(state.Src) srcdata := nl.NewRtAttr(nl.XFRMA_SRCADDR, saddr.Serialize()) req.AddData(srcdata) _, err := req.Execute(syscall.NETLINK_XFRM, 0) return err }
func classModify(cmd, flags int, class Class) error { req := nl.NewNetlinkRequest(cmd, flags|syscall.NLM_F_ACK) base := class.Attrs() msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, Ifindex: int32(base.LinkIndex), Handle: base.Handle, Parent: base.Parent, } req.AddData(msg) if cmd != syscall.RTM_DELTCLASS { if err := classPayload(req, class); err != nil { return err } } _, err := req.Execute(syscall.NETLINK_ROUTE, 0) return err }
func qdiscModify(cmd, flags int, qdisc Qdisc) error { req := nl.NewNetlinkRequest(cmd, flags|syscall.NLM_F_ACK) base := qdisc.Attrs() msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, Ifindex: int32(base.LinkIndex), Handle: base.Handle, Parent: base.Parent, } req.AddData(msg) // When deleting don't bother building the rest of the netlink payload if cmd != syscall.RTM_DELQDISC { if err := qdiscPayload(req, qdisc); err != nil { return err } } _, err := req.Execute(syscall.NETLINK_ROUTE, 0) return err }
// LinkByAlias finds a link by its alias and returns a pointer to the object. // If there are multiple links with the alias it returns the first one func LinkByAlias(alias string) (Link, error) { if lookupByDump { return linkByAliasDump(alias) } req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) req.AddData(msg) nameData := nl.NewRtAttr(syscall.IFLA_IFALIAS, nl.ZeroTerminated(alias)) req.AddData(nameData) link, err := execGetLink(req) if err == syscall.EINVAL { // older kernels don't support looking up via IFLA_IFALIAS // so fall back to dumping all links lookupByDump = true return linkByAliasDump(alias) } return link, err }
// LinkList gets a list of link devices. // Equivalent to: `ip link show` func LinkList() ([]Link, error) { // NOTE(vish): This duplicates functionality in net/iface_linux.go, but we need // to get the message ourselves to parse link type. req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWLINK) if err != nil { return nil, err } var res []Link for _, m := range msgs { link, err := linkDeserialize(m) if err != nil { return nil, err } res = append(res, link) } return res, nil }
// RouteGet gets a route to a specific destination from the host system. // Equivalent to: 'ip route get'. func RouteGet(destination net.IP) ([]Route, error) { req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST) family := nl.GetIPFamily(destination) var destinationData []byte var bitlen uint8 if family == FAMILY_V4 { destinationData = destination.To4() bitlen = 32 } else { destinationData = destination.To16() bitlen = 128 } msg := &nl.RtMsg{} msg.Family = uint8(family) msg.Dst_len = bitlen req.AddData(msg) rtaDst := nl.NewRtAttr(syscall.RTA_DST, destinationData) req.AddData(rtaDst) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE) if err != nil { return nil, err } var res []Route for _, m := range msgs { route, err := deserializeRoute(m) if err != nil { return nil, err } res = append(res, route) } return res, nil }
// NeighDel will delete an IP address from a link device. // Equivalent to: `ip addr del $addr dev $link` func NeighDel(neigh *Neigh) error { req := nl.NewNetlinkRequest(syscall.RTM_DELNEIGH, syscall.NLM_F_ACK) return neighHandle(neigh, req) }
// XfrmStateList gets a list of xfrm states in the system. // Equivalent to: `ip xfrm state show`. // The list can be filtered by ip family. func XfrmStateList(family int) ([]XfrmState, error) { req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP) msg := nl.NewIfInfomsg(family) req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA) if err != nil { return nil, err } var res []XfrmState for _, m := range msgs { msg := nl.DeserializeXfrmUsersaInfo(m) if family != FAMILY_ALL && family != int(msg.Family) { continue } var state XfrmState state.Dst = msg.Id.Daddr.ToIP() state.Src = msg.Saddr.ToIP() state.Proto = Proto(msg.Id.Proto) state.Mode = Mode(msg.Mode) state.Spi = int(nl.Swap32(msg.Id.Spi)) state.Reqid = int(msg.Reqid) state.ReplayWindow = int(msg.ReplayWindow) attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return nil, err } for _, attr := range attrs { switch attr.Attr.Type { case nl.XFRMA_ALG_AUTH, nl.XFRMA_ALG_CRYPT: var resAlgo *XfrmStateAlgo if attr.Attr.Type == nl.XFRMA_ALG_AUTH { if state.Auth == nil { state.Auth = new(XfrmStateAlgo) } resAlgo = state.Auth } else { state.Crypt = new(XfrmStateAlgo) resAlgo = state.Crypt } algo := nl.DeserializeXfrmAlgo(attr.Value[:]) (*resAlgo).Name = nl.BytesToString(algo.AlgName[:]) (*resAlgo).Key = algo.AlgKey case nl.XFRMA_ALG_AUTH_TRUNC: if state.Auth == nil { state.Auth = new(XfrmStateAlgo) } algo := nl.DeserializeXfrmAlgoAuth(attr.Value[:]) state.Auth.Name = nl.BytesToString(algo.AlgName[:]) state.Auth.Key = algo.AlgKey state.Auth.TruncateLen = int(algo.AlgTruncLen) case nl.XFRMA_ENCAP: encap := nl.DeserializeXfrmEncapTmpl(attr.Value[:]) state.Encap = new(XfrmStateEncap) state.Encap.Type = EncapType(encap.EncapType) state.Encap.SrcPort = int(nl.Swap16(encap.EncapSport)) state.Encap.DstPort = int(nl.Swap16(encap.EncapDport)) state.Encap.OriginalAddress = encap.EncapOa.ToIP() } } res = append(res, state) } return res, nil }
// LinkAdd adds a new link device. The type and features of the device // are taken fromt the parameters in the link object. // Equivalent to: `ip link add $link` func LinkAdd(link Link) error { // TODO: set mtu and hardware address // TODO: support extra data for macvlan base := link.Attrs() if base.Name == "" { return fmt.Errorf("LinkAttrs.Name cannot be empty!") } if tuntap, ok := link.(*Tuntap); ok { // TODO: support user // TODO: support group // TODO: support non- one_queue // TODO: support pi | vnet_hdr | multi_queue // TODO: support non- exclusive // TODO: support non- persistent if tuntap.Mode < syscall.IFF_TUN || tuntap.Mode > syscall.IFF_TAP { return fmt.Errorf("Tuntap.Mode %v unknown!", tuntap.Mode) } file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0) if err != nil { return err } defer file.Close() var req ifReq req.Flags |= syscall.IFF_ONE_QUEUE req.Flags |= syscall.IFF_TUN_EXCL copy(req.Name[:15], base.Name) req.Flags |= uint16(tuntap.Mode) _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), uintptr(syscall.TUNSETIFF), uintptr(unsafe.Pointer(&req))) if errno != 0 { return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed, errno %v", errno) } _, _, errno = syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), uintptr(syscall.TUNSETPERSIST), 1) if errno != 0 { return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno) } ensureIndex(base) // can't set master during create, so set it afterwards if base.MasterIndex != 0 { // TODO: verify MasterIndex is actually a bridge? return LinkSetMasterByIndex(link, base.MasterIndex) } return nil } req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) // TODO: make it shorter if base.Flags&FlagUp != 0 { msg.Change = syscall.IFF_UP msg.Flags = syscall.IFF_UP } if base.Flags&FlagBroadcast != 0 { msg.Change |= syscall.IFF_BROADCAST msg.Flags |= syscall.IFF_BROADCAST } if base.Flags&FlagLoopback != 0 { msg.Change |= syscall.IFF_LOOPBACK msg.Flags |= syscall.IFF_LOOPBACK } if base.Flags&FlagPointToPoint != 0 { msg.Change |= syscall.IFF_POINTOPOINT msg.Flags |= syscall.IFF_POINTOPOINT } if base.Flags&FlagMulticast != 0 { msg.Change |= syscall.IFF_MULTICAST msg.Flags |= syscall.IFF_MULTICAST } if base.Flags&FlagRunning != 0 { msg.Change |= syscall.IFF_RUNNING msg.Flags |= syscall.IFF_RUNNING } req.AddData(msg) if base.ParentIndex != 0 { b := make([]byte, 4) native.PutUint32(b, uint32(base.ParentIndex)) data := nl.NewRtAttr(syscall.IFLA_LINK, b) req.AddData(data) } else if link.Type() == "ipvlan" { return fmt.Errorf("Can't create ipvlan link without ParentIndex") } nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(base.Name)) req.AddData(nameData) if base.MTU > 0 { mtu := nl.NewRtAttr(syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU))) req.AddData(mtu) } if base.TxQLen >= 0 { qlen := nl.NewRtAttr(syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen))) req.AddData(qlen) } if base.Namespace != nil { var attr *nl.RtAttr switch base.Namespace.(type) { case NsPid: val := nl.Uint32Attr(uint32(base.Namespace.(NsPid))) attr = nl.NewRtAttr(syscall.IFLA_NET_NS_PID, val) case NsFd: val := nl.Uint32Attr(uint32(base.Namespace.(NsFd))) attr = nl.NewRtAttr(nl.IFLA_NET_NS_FD, val) } req.AddData(attr) } linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil) nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type())) if vlan, ok := link.(*Vlan); ok { b := make([]byte, 2) native.PutUint16(b, uint16(vlan.VlanId)) data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) nl.NewRtAttrChild(data, nl.IFLA_VLAN_ID, b) } else if veth, ok := link.(*Veth); ok { data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil) nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC) nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(veth.PeerName)) if base.TxQLen >= 0 { nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen))) } if base.MTU > 0 { nl.NewRtAttrChild(peer, syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU))) } } else if vxlan, ok := link.(*Vxlan); ok { addVxlanAttrs(vxlan, linkInfo) } else if bond, ok := link.(*Bond); ok { addBondAttrs(bond, linkInfo) } else if ipv, ok := link.(*IPVlan); ok { data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) nl.NewRtAttrChild(data, nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(ipv.Mode))) } else if macv, ok := link.(*Macvlan); ok { if macv.Mode != MACVLAN_MODE_DEFAULT { data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) nl.NewRtAttrChild(data, nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[macv.Mode])) } } else if gretap, ok := link.(*Gretap); ok { addGretapAttrs(gretap, linkInfo) } req.AddData(linkInfo) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) if err != nil { return err } ensureIndex(base) // can't set master during create, so set it afterwards if base.MasterIndex != 0 { // TODO: verify MasterIndex is actually a bridge? return LinkSetMasterByIndex(link, base.MasterIndex) } return nil }
// QdiscList gets a list of qdiscs in the system. // Equivalent to: `tc qdisc show`. // The list can be filtered by link. func QdiscList(link Link) ([]Qdisc, error) { req := nl.NewNetlinkRequest(syscall.RTM_GETQDISC, syscall.NLM_F_DUMP) index := int32(0) if link != nil { base := link.Attrs() ensureIndex(base) index = int32(base.Index) } msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, Ifindex: index, } req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWQDISC) if err != nil { return nil, err } var res []Qdisc for _, m := range msgs { msg := nl.DeserializeTcMsg(m) attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return nil, err } // skip qdiscs from other interfaces if link != nil && msg.Ifindex != index { continue } base := QdiscAttrs{ LinkIndex: int(msg.Ifindex), Handle: msg.Handle, Parent: msg.Parent, Refcnt: msg.Info, } var qdisc Qdisc qdiscType := "" for _, attr := range attrs { switch attr.Attr.Type { case nl.TCA_KIND: qdiscType = string(attr.Value[:len(attr.Value)-1]) switch qdiscType { case "pfifo_fast": qdisc = &PfifoFast{} case "prio": qdisc = &Prio{} case "tbf": qdisc = &Tbf{} case "ingress": qdisc = &Ingress{} case "htb": qdisc = &Htb{} case "netem": qdisc = &Netem{} default: qdisc = &GenericQdisc{QdiscType: qdiscType} } case nl.TCA_OPTIONS: switch qdiscType { case "pfifo_fast": // pfifo returns TcPrioMap directly without wrapping it in rtattr if err := parsePfifoFastData(qdisc, attr.Value); err != nil { return nil, err } case "prio": // prio returns TcPrioMap directly without wrapping it in rtattr if err := parsePrioData(qdisc, attr.Value); err != nil { return nil, err } case "tbf": data, err := nl.ParseRouteAttr(attr.Value) if err != nil { return nil, err } if err := parseTbfData(qdisc, data); err != nil { return nil, err } case "htb": data, err := nl.ParseRouteAttr(attr.Value) if err != nil { return nil, err } if err := parseHtbData(qdisc, data); err != nil { return nil, err } case "netem": if err := parseNetemData(qdisc, attr.Value); err != nil { return nil, err } // no options for ingress } } } *qdisc.Attrs() = base res = append(res, qdisc) } return res, nil }
// RuleList lists rules in the system. // Equivalent to: ip rule list func RuleList(family int) ([]Rule, error) { req := nl.NewNetlinkRequest(syscall.RTM_GETRULE, syscall.NLM_F_DUMP|syscall.NLM_F_REQUEST) msg := nl.NewIfInfomsg(family) req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWRULE) if err != nil { return nil, err } native := nl.NativeEndian() var res = make([]Rule, 0) for i := range msgs { msg := nl.DeserializeRtMsg(msgs[i]) attrs, err := nl.ParseRouteAttr(msgs[i][msg.Len():]) if err != nil { return nil, err } rule := NewRule() rule.RtMsg = msg for j := range attrs { switch attrs[j].Attr.Type { case syscall.RTA_TABLE: rule.Table = int(native.Uint32(attrs[j].Value[0:4])) case nl.FRA_SRC: rule.Src = &net.IPNet{ IP: attrs[j].Value, Mask: net.CIDRMask(int(msg.Src_len), 8*len(attrs[j].Value)), } case nl.FRA_DST: rule.Dst = &net.IPNet{ IP: attrs[j].Value, Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attrs[j].Value)), } case nl.FRA_FWMARK: rule.Mark = int(native.Uint32(attrs[j].Value[0:4])) case nl.FRA_FWMASK: rule.Mask = int(native.Uint32(attrs[j].Value[0:4])) case nl.FRA_TUN_ID: rule.TunID = uint(native.Uint64(attrs[j].Value[0:4])) case nl.FRA_IIFNAME: rule.IifName = string(attrs[j].Value[:len(attrs[j].Value)-1]) case nl.FRA_OIFNAME: rule.OifName = string(attrs[j].Value[:len(attrs[j].Value)-1]) case nl.FRA_SUPPRESS_PREFIXLEN: i := native.Uint32(attrs[j].Value[0:4]) if i != 0xffffffff { rule.SuppressPrefixlen = int(i) } case nl.FRA_SUPPRESS_IFGROUP: i := native.Uint32(attrs[j].Value[0:4]) if i != 0xffffffff { rule.SuppressIfgroup = int(i) } case nl.FRA_FLOW: rule.Flow = int(native.Uint32(attrs[j].Value[0:4])) case nl.FRA_GOTO: rule.Goto = int(native.Uint32(attrs[j].Value[0:4])) case nl.FRA_PRIORITY: rule.Priority = int(native.Uint32(attrs[j].Value[0:4])) } } res = append(res, *rule) } return res, nil }
// FilterAdd will add a filter to the system. // Equivalent to: `tc filter add $filter` func FilterAdd(filter Filter) error { native = nl.NativeEndian() req := nl.NewNetlinkRequest(syscall.RTM_NEWTFILTER, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) base := filter.Attrs() msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, Ifindex: int32(base.LinkIndex), Handle: base.Handle, Parent: base.Parent, Info: MakeHandle(base.Priority, nl.Swap16(base.Protocol)), } req.AddData(msg) req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(filter.Type()))) options := nl.NewRtAttr(nl.TCA_OPTIONS, nil) if u32, ok := filter.(*U32); ok { // match all sel := nl.TcU32Sel{ Nkeys: 1, Flags: nl.TC_U32_TERMINAL, } sel.Keys = append(sel.Keys, nl.TcU32Key{}) nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize()) actions := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil) table := nl.NewRtAttrChild(actions, nl.TCA_ACT_TAB, nil) nl.NewRtAttrChild(table, nl.TCA_KIND, nl.ZeroTerminated("mirred")) // redirect to other interface mir := nl.TcMirred{ Action: nl.TC_ACT_STOLEN, Eaction: nl.TCA_EGRESS_REDIR, Ifindex: uint32(u32.RedirIndex), } aopts := nl.NewRtAttrChild(table, nl.TCA_OPTIONS, nil) nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, mir.Serialize()) } else if fw, ok := filter.(*Fw); ok { if fw.Mask != 0 { b := make([]byte, 4) native.PutUint32(b, fw.Mask) nl.NewRtAttrChild(options, nl.TCA_FW_MASK, b) } if fw.InDev != "" { nl.NewRtAttrChild(options, nl.TCA_FW_INDEV, nl.ZeroTerminated(fw.InDev)) } if (fw.Police != nl.TcPolice{}) { police := nl.NewRtAttrChild(options, nl.TCA_FW_POLICE, nil) nl.NewRtAttrChild(police, nl.TCA_POLICE_TBF, fw.Police.Serialize()) if (fw.Police.Rate != nl.TcRateSpec{}) { payload := SerializeRtab(fw.Rtab) nl.NewRtAttrChild(police, nl.TCA_POLICE_RATE, payload) } if (fw.Police.PeakRate != nl.TcRateSpec{}) { payload := SerializeRtab(fw.Ptab) nl.NewRtAttrChild(police, nl.TCA_POLICE_PEAKRATE, payload) } } if fw.ClassId != 0 { b := make([]byte, 4) native.PutUint32(b, fw.ClassId) nl.NewRtAttrChild(options, nl.TCA_FW_CLASSID, b) } } req.AddData(options) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) return err }
// RuleDel deletes a rule from the system. // Equivalent to: ip rule del func RuleDel(rule *Rule) error { req := nl.NewNetlinkRequest(syscall.RTM_DELRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) return ruleHandle(rule, req) }
// FilterList gets a list of filters in the system. // Equivalent to: `tc filter show`. // Generally retunrs nothing if link and parent are not specified. func FilterList(link Link, parent uint32) ([]Filter, error) { req := nl.NewNetlinkRequest(syscall.RTM_GETTFILTER, syscall.NLM_F_DUMP) msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, Parent: parent, } if link != nil { base := link.Attrs() ensureIndex(base) msg.Ifindex = int32(base.Index) } req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWTFILTER) if err != nil { return nil, err } var res []Filter for _, m := range msgs { msg := nl.DeserializeTcMsg(m) attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return nil, err } base := FilterAttrs{ LinkIndex: int(msg.Ifindex), Handle: msg.Handle, Parent: msg.Parent, } base.Priority, base.Protocol = MajorMinor(msg.Info) base.Protocol = nl.Swap16(base.Protocol) var filter Filter filterType := "" detailed := false for _, attr := range attrs { switch attr.Attr.Type { case nl.TCA_KIND: filterType = string(attr.Value[:len(attr.Value)-1]) switch filterType { case "u32": filter = &U32{} case "fw": filter = &Fw{} default: filter = &GenericFilter{FilterType: filterType} } case nl.TCA_OPTIONS: switch filterType { case "u32": data, err := nl.ParseRouteAttr(attr.Value) if err != nil { return nil, err } detailed, err = parseU32Data(filter, data) if err != nil { return nil, err } case "fw": data, err := nl.ParseRouteAttr(attr.Value) if err != nil { return nil, err } detailed, err = parseFwData(filter, data) if err != nil { return nil, err } } } } // only return the detailed version of the filter if detailed { *filter.Attrs() = base res = append(res, filter) } } return res, nil }
func neighAdd(neigh *Neigh, mode int) error { req := nl.NewNetlinkRequest(syscall.RTM_NEWNEIGH, mode|syscall.NLM_F_ACK) return neighHandle(neigh, req) }
// ClassList gets a list of classes in the system. // Equivalent to: `tc class show`. // Generally returns nothing if link and parent are not specified. func ClassList(link Link, parent uint32) ([]Class, error) { req := nl.NewNetlinkRequest(syscall.RTM_GETTCLASS, syscall.NLM_F_DUMP) msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, Parent: parent, } if link != nil { base := link.Attrs() ensureIndex(base) msg.Ifindex = int32(base.Index) } req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWTCLASS) if err != nil { return nil, err } var res []Class for _, m := range msgs { msg := nl.DeserializeTcMsg(m) attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return nil, err } base := ClassAttrs{ LinkIndex: int(msg.Ifindex), Handle: msg.Handle, Parent: msg.Parent, } var class Class classType := "" for _, attr := range attrs { switch attr.Attr.Type { case nl.TCA_KIND: classType = string(attr.Value[:len(attr.Value)-1]) switch classType { case "htb": class = &HtbClass{} default: class = &GenericClass{ClassType: classType} } case nl.TCA_OPTIONS: switch classType { case "htb": data, err := nl.ParseRouteAttr(attr.Value) if err != nil { return nil, err } _, err = parseHtbClassData(class, data) if err != nil { return nil, err } } } } *class.Attrs() = base res = append(res, class) } return res, nil }