florianl/go-tc

how to configure u32 classid

Opened this issue · 1 comments

Describe the issue

I created an HTB type qdisc, established two different classes with different speed configurations, and set up two different filters to match different traffic types, binding them to the corresponding classes. However, they did not take effect.

Expected behavior

tc qdisc add dev wg0 root handle 1: htb default 2
tc class add dev wg0 parent 1: classid 1:2 htb rate 5Mbit ceil 10Mbit
tc class add dev wg0 parent 1: classid 1:3 htb rate 1000Mbit ceil 10Mbit
tc filter add dev wg0 parent 1: protocol ip prio 1 u32 match ip dst 13.0.0.3/32 flowid 1:2
tc filter add dev wg0 parent 1: protocol ip prio 1 u32 match ip dst 13.0.0.4/32 flowid 1:3

Minimal code example to reproduce the issue

func setupUserLimit(tcnl *tc.Tc, ifindex int, classId uint32, userLimit UserLimit, parentQdisc uint32) error {
    class := tc.Object{
        Msg: tc.Msg{
            Family:  unix.AF_UNSPEC,
            Ifindex: uint32(ifindex),
            Handle:  core.BuildHandle(0, uint32(classId)), 
            Parent:  parentQdisc,                          

        },
        Attribute: tc.Attribute{
            Kind: "htb",
            Htb: &tc.Htb{
                // Rate64: &userLimit.Rate,
                // Ceil64: &userLimit.Burst,
                Parms: &tc.HtbOpt{
                    Rate: tc.RateSpec{CellLog: 0x3, Linklayer: 0x1, Overhead: 0x0, CellAlign: 0xffff, Mpu: 0x0, Rate: 0x98968},
                    Ceil: tc.RateSpec{CellLog: 0x3, Linklayer: 0x1, Overhead: 0x0, CellAlign: 0xffff, Mpu: 0x0, Rate: 0x1312d0},
                },
            },
        },
    }

  
    if err := tcnl.Class().Add(&class); err != nil {
        return fmt.Errorf("could not add class for %s: %v", userLimit.IPAddress, err)
    }

    htbClassid := core.BuildHandle(1, uint32(classId))

    filter := tc.Object{
        Msg: tc.Msg{
            Family:  syscall.AF_UNSPEC,
            Ifindex: uint32(ifindex),
            Handle:  core.BuildHandle(0, uint32(classId)), // 过滤器 ID
            Parent:  parentQdisc,                          // 过滤器的父级(与类一致)
            //Info:    core.BuildHandle(0, uint32(class.Msg.Handle)),
            Info: 0xa0300, //pref and proto is here
        },
        Attribute: tc.Attribute{
            Kind: "u32",
            U32: &tc.U32{
                ClassID: &htbClassid,
                Sel: &tc.U32Sel{
                    NKeys: 1,
                    Keys: []tc.U32Key{
                        {
                            Mask: 0xFFFFFFFF,
                            Val:  ipToUint32(userLimit.IPAddress), // 将 IP 地址转换为 uint32
                            Off:  16,                              // 匹配目标IP 地址
                        },
                    },
                },
            },
        },
    }

    if err := tcnl.Filter().Add(&filter); err != nil {
        return fmt.Errorf("could not add filter for %s: %v", userLimit.IPAddress, err)
    }

    return nil
}
go.mod

Environment

Provide some information about the system with the issue.

3.10.0-1160.45.1.el7.x86_64

Hi 👋
Sorry, to catch up just now.
Could you please provide a full reproducer for the issue you run into? How do you set up the qdisc parent and which values from this do you pass on in which way to setupUserLimit()? To setup Htb as class the fields Ctab and Rtab are essential and commented out in your example.
Can the isue be reproduced on a more recent Linux kernel version, that is at least listed on kernel.org?

For further investigation, it would also help to know which version of this package you use in your code.