Skip to content

Add rate limiting feature to xapi#7114

Open
cplaursen wants to merge 10 commits into
xapi-project:feature/throttling2from
cplaursen:feature/throttling2
Open

Add rate limiting feature to xapi#7114
cplaursen wants to merge 10 commits into
xapi-project:feature/throttling2from
cplaursen:feature/throttling2

Conversation

@cplaursen

Copy link
Copy Markdown
Contributor

This commit implements the changes laid out in the rate_limit design document.
In particular, we add two datamodels:

  • Caller: tracks every client who has called into xapi
  • Rate_limit: allows admins to place usage limits on groups of callers

These changes include intercepting RPC calls as they arrive for logging and rate limiting purposes. The feature is currently behind a feature flag - to activate, write rate_limit=true into xapi.conf.

cplaursen added 5 commits June 3, 2026 15:19
The rate limit library is currently called xapi_rate_limit, which will clash
with the xapi file associated to the rate limit datamodel. Renaming to
rate_limit_lib.

Signed-off-by: Christian Pardillo Laursen <christian.pardillolaursen@citrix.com>
As per the rate_limit design, this commit adds two new datamodels to xapi:

- Caller: tracks usage statistics on clients calling into xapi. Clients are
  currently identified by their ip address and HTTP user agent
- Rate_limit: lets xapi admins apply rate limits to groups of callers. Rate
  limiters allow a fixed number of "tokens" (number correlated with call cost)
  to be used per second; if the token count is exceeded, the calls get throttled.

Signed-off-by: Christian Pardillo Laursen <christian.pardillolaursen@citrix.com>
Signed-off-by: Christian Pardillo Laursen <christian.pardillolaursen@citrix.com>
Signed-off-by: Christian Pardillo Laursen <christian.pardillolaursen@citrix.com>
Signed-off-by: Christian Pardillo Laursen <christian.pardillolaursen@citrix.com>
@cplaursen cplaursen force-pushed the feature/throttling2 branch from 001cf30 to 198af98 Compare June 3, 2026 14:30

@robhoes robhoes left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial feedback on the Caller definition.

(** Total order on patterns: fewer wildcards first, then lexicographic
by patterns. *)

val is_all_wildcard : pattern_key -> bool

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change and the addition of to_list are in the rename commit, but strictly speaking shouldn't be.

Comment thread ocaml/idl/datamodel_caller.ml Outdated
Comment thread ocaml/idl/datamodel_caller.ml Outdated
Comment thread ocaml/idl/datamodel_lifecycle.ml
Comment thread ocaml/idl/datamodel_caller.ml Outdated
Comment thread ocaml/idl/datamodel_caller.ml
Comment thread ocaml/idl/datamodel_caller.ml
Comment thread ocaml/idl/datamodel_caller.ml Outdated
Comment thread ocaml/idl/datamodel_caller.ml Outdated
Comment thread ocaml/idl/datamodel_rate_limit.ml Outdated
@cplaursen cplaursen force-pushed the feature/throttling2 branch from 8d31c94 to 4b9ca96 Compare June 4, 2026 10:46
cplaursen added 5 commits June 4, 2026 14:59
Signed-off-by: Christian Pardillo Laursen <christian.pardillolaursen@citrix.com>
Signed-off-by: Christian Pardillo Laursen <christian.pardillolaursen@citrix.com>
Signed-off-by: Christian Pardillo Laursen <christian.pardillolaursen@citrix.com>
Signed-off-by: Christian Pardillo Laursen <christian.pardillolaursen@citrix.com>
Signed-off-by: Christian Pardillo Laursen <christian.pardillolaursen@citrix.com>
@cplaursen cplaursen force-pushed the feature/throttling2 branch from 2e50449 to 5fdf69c Compare June 4, 2026 14:00
; flags= []
}
)
; ( "rate-limit-set-burst-size"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need this, because you have a set function in Records (alongside the get). This means that you get xe rate-limit-param-get and xe rate-limit-param-set automatically. Same for fill-rate.

Comment thread ocaml/xapi/context.ml

let get_origin ctx = string_of_origin ctx.origin

let is_internal_origin ctx = ctx.origin = Internal

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that Internal here just means that the call did not come in over the network. This does not include calls from other hosts in a pool.

@robhoes robhoes left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments, but overall I think this looks good.

Comment thread ocaml/xapi/xapi_caller.ml
Hashtbl.of_seq
(List.to_seq
[
("VDI.pool_migrate", 2500.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to store these in a file that is read on startup. That would make it possible to tweak the values and add other calls without having to recompile xapi.

Comment thread ocaml/xapi/xapi_caller.ml
)

let insert_entry ~caller_ref ~pattern_key ~rate_limit_ref =
let uuid = Uuidx.(to_string (make () : [`Caller] t)) in

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is a new uuid created here rather than using the one from the DB record?

Comment thread ocaml/xapi/xapi_caller.ml
maybe_autocreate ~task_create ~user_agent ~client_ip ~existing:matches ;
match bucket with
| Some rl ->
Rate_limit.submit_async rl ~callback amount

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the exception of this line, the function looks identical to submit_sync, so there seems to be scope for reducing duplication.

Comment thread ocaml/xapi/xapi_caller.ml
task_create (fun __context ->
try
let caller_ref =
create ~__context ~name_label:"" ~name_description:""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can do better than empty strings for name_label and name_description here? At the very least we could map the user_agent to a "friendly name", where the mapping can be stored in a file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants