[GH-ISSUE #25] Support traffic caps #16

Closed
opened 2026-03-04 14:52:24 +03:00 by kerem · 7 comments
Owner

Originally created by @f00b4r0 on GitHub (May 10, 2025).
Original GitHub issue: https://github.com/f00b4r0/uspot/issues/25

Originally assigned to: @f00b4r0 on GitHub.

Once traffic accounting is implemented (see #9), uspot should support RADIUS-driven per-user data caps through the following attributes

• ChilliSpot-Max-Total-Octets
• ChilliSpot-Max-Total-Gigawords

Originally created by @f00b4r0 on GitHub (May 10, 2025). Original GitHub issue: https://github.com/f00b4r0/uspot/issues/25 Originally assigned to: @f00b4r0 on GitHub. Once traffic accounting is implemented (see #9), uspot should support RADIUS-driven per-user data caps through the following attributes • ChilliSpot-Max-Total-Octets • ChilliSpot-Max-Total-Gigawords
kerem 2026-03-04 14:52:24 +03:00
Author
Owner

@PWJW commented on GitHub (Jun 15, 2025):

Is it possible to support the three attributes, so that we can set a limit for download/upload or both?

ChilliSpot-Max-Total-Octets
ChilliSpot-Max-Input-Octets
ChilliSpot-Max-Output-Octets

Thanks!

<!-- gh-comment-id:2973804309 --> @PWJW commented on GitHub (Jun 15, 2025): Is it possible to support the three attributes, so that we can set a limit for download/upload or both? ChilliSpot-Max-Total-Octets ChilliSpot-Max-Input-Octets ChilliSpot-Max-Output-Octets Thanks!
Author
Owner

@f00b4r0 commented on GitHub (Jun 15, 2025):

Is it possible to support the three attributes, so that we can set a limit for download/upload or both?

ChilliSpot-Max-Total-Octets
ChilliSpot-Max-Input-Octets
ChilliSpot-Max-Output-Octets

Yes, + related 'Gigawords' attributes ;)

<!-- gh-comment-id:2973814659 --> @f00b4r0 commented on GitHub (Jun 15, 2025): > Is it possible to support the three attributes, so that we can set a limit for download/upload or both? > > ChilliSpot-Max-Total-Octets > ChilliSpot-Max-Input-Octets > ChilliSpot-Max-Output-Octets Yes, + related 'Gigawords' attributes ;)
Author
Owner

@f00b4r0 commented on GitHub (Jun 17, 2025):

Pushed new (untested) code to the ebpf branch, feedback welcome.

Any combination of the Chillispot-Max-* attributes should work.

<!-- gh-comment-id:2980189688 --> @f00b4r0 commented on GitHub (Jun 17, 2025): Pushed new (untested) code to the ebpf branch, feedback welcome. Any combination of the Chillispot-Max-* attributes should work.
Author
Owner

@PWJW commented on GitHub (Jun 17, 2025):

Great, I will test today 👍

<!-- gh-comment-id:2980193185 --> @PWJW commented on GitHub (Jun 17, 2025): Great, I will test today 👍
Author
Owner

@PWJW commented on GitHub (Jun 20, 2025):

I have some feedback on the traffic limiting:

It is working, but only when I comment out the following 4 lines of code in uspot.uc, i.e.:


function client_quotalimit(uspot, mac) {
        let client = uspots[uspot].clients[mac];
        let device = uspots[uspot].settings.device;
        let counters = +uspots[uspot].settings.device;

//      if (!(counters && client.radius?.reply))
//              return;

        let reply = client.radius.reply;

        // check known attributes
        let maxup = (reply?.['ChilliSpot-Max-Input-Octets'] + (reply?.['ChilliSpot-Max-Input-Gigawords'] << 32)) || 0;
        let maxdown = (reply?.['ChilliSpot-Max-Output-Octets'] + (reply?.['ChilliSpot-Max-Output-Gigawords'] << 32)) || 0;
        let maxtotal = (reply?.['ChilliSpot-Max-Total-Octets'] + (reply?.['ChilliSpot-Max-Total-Gigawords'] << 32)) || 0;

//      if (!(+maxdown || +maxup || +maxtotal))
//              return;

        let tx = (!!maxup || !!maxtotal), rx = (!!maxdown || !!maxtotal);
        if (!length(uacct.client_get(device, mac)))     // don't overide enabled tx/rx counters if radius accounting is on
                uacct.client_add(device, mac, tx, rx);

        debug(uspot, mac + " enabling quota limits: " + (tx ? "tx " : "") + (rx ? "rx" : ""));

        client.maxdown = maxdown;
        client.maxup = maxup;
        client.maxtotal = maxtotal;
}`

I see two potential issues:

  1. let counters seems to be returning 0, even though it's set in the config file, and uspot clients correctly shows the counters, and radius interim accounting with input/output octets is present.
  2. The if (!(+maxdown || +maxup || +maxtotal)) looks like be checking if ANY of these attributes are not present. But it shouldn't do, as normally, you either set just a download cap, upload cap or total cap. i.e. not all 3 attributes are sent in the Access-Accept, it could be one or two.

With these lines commented out as per above, the client limit is set, and enforced. It kicks me off correctly.

Also, the debug log doesn't seem to print the quota limit values it to the log:

Fri Jun 20 11:17:54 2025 daemon.debug uspot: hotspot 92:2c:96:76:40:70 creating client
Fri Jun 20 11:17:54 2025 daemon.info uspot: hotspot 92:2c:96:76:40:70 adding client
Fri Jun 20 11:17:54 2025 daemon.debug uspot: hotspot 92:2c:96:76:40:70 acct start
Fri Jun 20 11:17:54 2025 daemon.debug uspot: hotspot 92:2c:96:76:40:70 enabling quota limits: tx rx

should tx rx be the actual values set or just that label?

Thanks!

<!-- gh-comment-id:2991130666 --> @PWJW commented on GitHub (Jun 20, 2025): I have some feedback on the traffic limiting: It is working, but only when I comment out the following 4 lines of code in uspot.uc, i.e.: ``` function client_quotalimit(uspot, mac) { let client = uspots[uspot].clients[mac]; let device = uspots[uspot].settings.device; let counters = +uspots[uspot].settings.device; // if (!(counters && client.radius?.reply)) // return; let reply = client.radius.reply; // check known attributes let maxup = (reply?.['ChilliSpot-Max-Input-Octets'] + (reply?.['ChilliSpot-Max-Input-Gigawords'] << 32)) || 0; let maxdown = (reply?.['ChilliSpot-Max-Output-Octets'] + (reply?.['ChilliSpot-Max-Output-Gigawords'] << 32)) || 0; let maxtotal = (reply?.['ChilliSpot-Max-Total-Octets'] + (reply?.['ChilliSpot-Max-Total-Gigawords'] << 32)) || 0; // if (!(+maxdown || +maxup || +maxtotal)) // return; let tx = (!!maxup || !!maxtotal), rx = (!!maxdown || !!maxtotal); if (!length(uacct.client_get(device, mac))) // don't overide enabled tx/rx counters if radius accounting is on uacct.client_add(device, mac, tx, rx); debug(uspot, mac + " enabling quota limits: " + (tx ? "tx " : "") + (rx ? "rx" : "")); client.maxdown = maxdown; client.maxup = maxup; client.maxtotal = maxtotal; }` ``` I see two potential issues: 1. `let counters` seems to be returning 0, even though it's set in the config file, and `uspot clients` correctly shows the counters, and radius interim accounting with input/output octets is present. 2. The `if (!(+maxdown || +maxup || +maxtotal))` looks like be checking if ANY of these attributes are not present. But it shouldn't do, as normally, you either set just a download cap, upload cap or total cap. i.e. not all 3 attributes are sent in the Access-Accept, it could be one or two. With these lines commented out as per above, the client limit is set, and enforced. It kicks me off correctly. Also, the debug log doesn't seem to print the quota limit values it to the log: ``` Fri Jun 20 11:17:54 2025 daemon.debug uspot: hotspot 92:2c:96:76:40:70 creating client Fri Jun 20 11:17:54 2025 daemon.info uspot: hotspot 92:2c:96:76:40:70 adding client Fri Jun 20 11:17:54 2025 daemon.debug uspot: hotspot 92:2c:96:76:40:70 acct start Fri Jun 20 11:17:54 2025 daemon.debug uspot: hotspot 92:2c:96:76:40:70 enabling quota limits: tx rx ``` should `tx rx` be the actual values set or just that label? Thanks!
Author
Owner

@f00b4r0 commented on GitHub (Jun 20, 2025):

I have some feedback on the traffic limiting:

Thanks for testing. Please send further comments to PR #28 for easier tracking (since these comments relate directly to the PR)

It is working, but only when I comment out the following 4 lines of code in uspot.uc, i.e.:


function client_quotalimit(uspot, mac) {
        let client = uspots[uspot].clients[mac];
        let device = uspots[uspot].settings.device;
        let counters = +uspots[uspot].settings.device;

//      if (!(counters && client.radius?.reply))
//              return;

That's because of a typo in the assignment above (counters = device, obviously wrong). I just fixed that.

        let reply = client.radius.reply;

        // check known attributes
        let maxup = (reply?.['ChilliSpot-Max-Input-Octets'] + (reply?.['ChilliSpot-Max-Input-Gigawords'] << 32)) || 0;
        let maxdown = (reply?.['ChilliSpot-Max-Output-Octets'] + (reply?.['ChilliSpot-Max-Output-Gigawords'] << 32)) || 0;
        let maxtotal = (reply?.['ChilliSpot-Max-Total-Octets'] + (reply?.['ChilliSpot-Max-Total-Gigawords'] << 32)) || 0;

//      if (!(+maxdown || +maxup || +maxtotal))
//              return;

This however makes no sense to me, can you test again with the last update?

I see two potential issues:

  1. let counters seems to be returning 0, even though it's set in the config file, and uspot clients correctly shows the counters, and radius interim accounting with input/output octets is present.

Fixed

  1. The if (!(+maxdown || +maxup || +maxtotal)) looks like be checking if ANY of these attributes are not present.

No, it checks if all are not present: 'not(A or B or C)' is equivalent to '(not(A) and not(B) and not(C))'

i.e. it checks if ALL are missing and is the same as if (!+maxdown && !+maxup && !+maxtotal)

Also, the debug log doesn't seem to print the quota limit values it to the log:

Fri Jun 20 11:17:54 2025 daemon.debug uspot: hotspot 92:2c:96:76:40:70 creating client
Fri Jun 20 11:17:54 2025 daemon.info uspot: hotspot 92:2c:96:76:40:70 adding client
Fri Jun 20 11:17:54 2025 daemon.debug uspot: hotspot 92:2c:96:76:40:70 acct start
Fri Jun 20 11:17:54 2025 daemon.debug uspot: hotspot 92:2c:96:76:40:70 enabling quota limits: tx rx

should tx rx be the actual values set or just that label?

it's just the label: it says the limits are enforced for both tx and rx. I reworded the debug output to make that clearer.

<!-- gh-comment-id:2991195267 --> @f00b4r0 commented on GitHub (Jun 20, 2025): > I have some feedback on the traffic limiting: Thanks for testing. Please send further comments to PR #28 for easier tracking (since these comments relate directly to the PR) > It is working, but only when I comment out the following 4 lines of code in uspot.uc, i.e.: > > ``` > > function client_quotalimit(uspot, mac) { > let client = uspots[uspot].clients[mac]; > let device = uspots[uspot].settings.device; > let counters = +uspots[uspot].settings.device; > > // if (!(counters && client.radius?.reply)) > // return; > ``` That's because of a typo in the assignment above (counters = device, obviously wrong). I just fixed that. >``` > let reply = client.radius.reply; > > // check known attributes > let maxup = (reply?.['ChilliSpot-Max-Input-Octets'] + (reply?.['ChilliSpot-Max-Input-Gigawords'] << 32)) || 0; > let maxdown = (reply?.['ChilliSpot-Max-Output-Octets'] + (reply?.['ChilliSpot-Max-Output-Gigawords'] << 32)) || 0; > let maxtotal = (reply?.['ChilliSpot-Max-Total-Octets'] + (reply?.['ChilliSpot-Max-Total-Gigawords'] << 32)) || 0; > > // if (!(+maxdown || +maxup || +maxtotal)) > // return; > ``` This however makes no sense to me, can you test again with the last update? > I see two potential issues: > > 1. `let counters` seems to be returning 0, even though it's set in the config file, and `uspot clients` correctly shows the counters, and radius interim accounting with input/output octets is present. Fixed > 2. The `if (!(+maxdown || +maxup || +maxtotal))` looks like be checking if ANY of these attributes are not present. No, it checks if all are not present: 'not(A or B or C)' [is equivalent](https://en.wikipedia.org/wiki/De_Morgan%27s_laws) to '(not(A) and not(B) and not(C))' i.e. it checks if ALL are missing and is the same as `if (!+maxdown && !+maxup && !+maxtotal)` > Also, the debug log doesn't seem to print the quota limit values it to the log: > > ``` > Fri Jun 20 11:17:54 2025 daemon.debug uspot: hotspot 92:2c:96:76:40:70 creating client > Fri Jun 20 11:17:54 2025 daemon.info uspot: hotspot 92:2c:96:76:40:70 adding client > Fri Jun 20 11:17:54 2025 daemon.debug uspot: hotspot 92:2c:96:76:40:70 acct start > Fri Jun 20 11:17:54 2025 daemon.debug uspot: hotspot 92:2c:96:76:40:70 enabling quota limits: tx rx > ``` > > should `tx rx` be the actual values set or just that label? it's just the label: it says the limits are enforced for both tx and rx. I reworded the debug output to make that clearer.
Author
Owner

@PWJW commented on GitHub (Jun 20, 2025):

Oh, also, can we add some extra info to uspot clients to show any rx/tx limits active (if present), i.e.:

hotspot:
{
        "92:2c:96:76:40:70": {
                "status": "Authenticated",
                "time": 854,
                "idle": 0,
                "lost": 0,
                "ip4addr": "10.1.0.236",
                "ip6addr": "",
                "sessionid": "8e56d172b06dc413",
                "username": null,
                "client_ip": "10.1.0.236",
                "duration": 854,
                "packets_in": 346582,
                "bytes_in": 394094010,
                "packets_out": 437987,
                "bytes_out": 1096191174,
                "seconds_remaining": 13546,
                "quota_tx_remaining": 1234560, // new
                "quota_rx_remaining": 1234560, // new
                "quota_total_remaining": 1234560 // new
        }
}
<!-- gh-comment-id:2991199223 --> @PWJW commented on GitHub (Jun 20, 2025): Oh, also, can we add some extra info to `uspot clients` to show any rx/tx limits active (if present), i.e.: ``` hotspot: { "92:2c:96:76:40:70": { "status": "Authenticated", "time": 854, "idle": 0, "lost": 0, "ip4addr": "10.1.0.236", "ip6addr": "", "sessionid": "8e56d172b06dc413", "username": null, "client_ip": "10.1.0.236", "duration": 854, "packets_in": 346582, "bytes_in": 394094010, "packets_out": 437987, "bytes_out": 1096191174, "seconds_remaining": 13546, "quota_tx_remaining": 1234560, // new "quota_rx_remaining": 1234560, // new "quota_total_remaining": 1234560 // new } } ```
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/uspot#16
No description provided.