netlink/qdisc_linux.go

195 lines
5.0 KiB
Go
Raw Normal View History

2015-08-18 10:16:54 +00:00
package netlink
import (
"fmt"
"syscall"
"github.com/vishvananda/netlink/nl"
)
// // QdiscAdd will add a qdisc to the system.
// // Equivalent to: `tc qdisc add $qdisc`
// func QdiscAdd(qdisc *Qdisc) error {
// req := nl.NewNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
// return qdiscHandle(qdisc, req, nl.NewRtMsg())
// }
//
// // QdiscAdd will delete a qdisc from the system.
// // Equivalent to: `tc qdisc del $qdisc`
// func QdiscDel(qdisc *Qdisc) error {
// req := nl.NewNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK)
// return qdiscHandle(qdisc, req, nl.NewRtDelMsg())
// }
//
// func qdiscHandle(qdisc *Qdisc, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
// if (qdisc.Dst == nil || qdisc.Dst.IP == nil) && qdisc.Src == nil && qdisc.Gw == nil {
// return fmt.Errorf("one of Dst.IP, Src, or Gw must not be nil")
// }
//
// msg.Scope = uint8(qdisc.Scope)
// family := -1
// var rtAttrs []*nl.RtAttr
//
// if qdisc.Dst != nil && qdisc.Dst.IP != nil {
// dstLen, _ := qdisc.Dst.Mask.Size()
// msg.Dst_len = uint8(dstLen)
// dstFamily := nl.GetIPFamily(qdisc.Dst.IP)
// family = dstFamily
// var dstData []byte
// if dstFamily == FAMILY_V4 {
// dstData = qdisc.Dst.IP.To4()
// } else {
// dstData = qdisc.Dst.IP.To16()
// }
// rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData))
// }
//
// if qdisc.Src != nil {
// srcFamily := nl.GetIPFamily(qdisc.Src)
// if family != -1 && family != srcFamily {
// return fmt.Errorf("source and destination ip are not the same IP family")
// }
// family = srcFamily
// var srcData []byte
// if srcFamily == FAMILY_V4 {
// srcData = qdisc.Src.To4()
// } else {
// srcData = qdisc.Src.To16()
// }
// // The commonly used src ip for qdiscs is actually PREFSRC
// rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PREFSRC, srcData))
// }
//
// if qdisc.Gw != nil {
// gwFamily := nl.GetIPFamily(qdisc.Gw)
// if family != -1 && family != gwFamily {
// return fmt.Errorf("gateway, source, and destination ip are not the same IP family")
// }
// family = gwFamily
// var gwData []byte
// if gwFamily == FAMILY_V4 {
// gwData = qdisc.Gw.To4()
// } else {
// gwData = qdisc.Gw.To16()
// }
// rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData))
// }
//
// msg.Family = uint8(family)
//
// req.AddData(msg)
// for _, attr := range rtAttrs {
// req.AddData(attr)
// }
//
// var (
// b = make([]byte, 4)
// native = nl.NativeEndian()
// )
// native.PutUint32(b, uint32(qdisc.LinkIndex))
//
// req.AddData(nl.NewRtAttr(syscall.RTA_OIF, b))
//
// _, err := req.Execute(syscall.NETLINK_ROUTE, 0)
// return err
// }
// 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)
msg := &nl.TcMsg{
Family: nl.FAMILY_ALL,
}
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_NEWQDISC)
if err != nil {
return nil, err
}
//native := nl.NativeEndian()
var res []Qdisc
for _, m := range msgs {
msg := nl.DeserializeTcMsg(m)
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
if err != nil {
return nil, err
}
base := QdiscAttrs{
LinkIndex: int(msg.Ifindex),
Handle: msg.Handle,
Parent: msg.Parent,
}
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":
fmt.Printf("found pfifo_fast\n")
qdisc = &PfifoFast{}
case "tbf":
fmt.Printf("found tbf\n")
qdisc = &TokenBucketFilter{}
default:
fmt.Printf("found generic\n")
qdisc = &GenericQdisc{QdiscType: qdiscType}
}
case nl.TCA_OPTIONS:
fmt.Printf("in options\n")
fmt.Printf("Value %v\n", attr.Value)
switch qdiscType {
case "pfifo_fast":
// pfifo returns TcPrioMap directly without wrapping it in rtattr
fmt.Printf("parsing pfifo_fast\n")
if err := parsePfifoFastData(qdisc, attr.Value); err != nil {
return nil, err
}
case "tbf":
data, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return nil, err
}
if err := parseTokenBucketFilterData(qdisc, data); err != nil {
return nil, err
}
}
}
}
*qdisc.Attrs() = base
res = append(res, qdisc)
}
return res, nil
}
func parsePfifoFastData(qdisc Qdisc, value []byte) error {
pfifo := qdisc.(*PfifoFast)
tcmap := nl.DeserializeTcPrioMap(value)
pfifo.PriorityMap = tcmap.Priomap
pfifo.Bands = uint8(tcmap.Bands)
return nil
}
func parseTokenBucketFilterData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
tbf := qdisc.(*TokenBucketFilter)
for _, datum := range data {
switch datum.Attr.Type {
case nl.TCA_TBF_UNSPEC:
tbf.Type()
}
}
return nil
}