Making Ostinato’s variable fields more flexible
The Problem
Back in 2020, Javor wanted to test 2 million CGNAT scale using Ostinato but was running into a problem generating the flows he wanted.
The stream just generated sequentially flows one by one like this for example:
src-ip_1, src port 30001 -> dst-ip_1, port 1001
src-ip_2, src port 30002 -> dst-ip_2, port 1002
src-ip_3, src port 30003 -> dst-ip_3, port 1003But I don’t want this. I would like to achieve the following way of order and incrementation:
src_ip1, src port 30001 -> dst-ip_1, port 1001
src_ip1, src port 30002 -> dst-ip_1, port 1002
src_ip1, src port 30003 -> dst-ip_1, port 1003
src_ip1, src port 30004 -> dst-ip_1, port 1004
src_ip1, src port 30005 -> dst-ip_1, port 1005
……
So I would like the stream to generate the packets in order to start first from src-ip and incrementally passthrough over all src-ports range ( for example range of 5000 ports ) and then to go to the next src-ip then to next src-ip and so on….
Irrespective of how many variable fields you have in a Ostinato stream, each variable field increments with every packet - which was not what Javor wanted.
He wanted a counter behavior similar to nested loops.
I filed issue #302 on the Ostinato issue tracker to keep track of the feature request.
The Workaround(s)
For Javor’s use case I came up with a workaround to do what he wanted using the variable field mask and wrote a blog post about it.
But the variable field mask workaround had a limitation of being able to use only those counts which are power of 2 (read the blog post for details). In addition to this limitation, the solution is not very intuitive for users to understand and use.
Last week another customer Ashok had a similar requirement to test Linux conntrack with scaled sessions. However, Ashok’s scale was lower and he was ok with creating multiple Ostinato streams - one each for a pair of source and destination UDP ports while each Ostinato stream would vary IP addresses 4000 times. 20 streams of 4000 IP address each makes for 80K flows.
The Solution
I figured it was time to dust off this issue and look into what it takes to implement it properly. I worked it out an example on paper first -
Now that I knew what needed to be done, I did a quick and dirty test with a hard-coded value -
And it worked!
Yup, that one-line change was the essential core of what was required!
Next, I needed to replace that hard coded value with a user-specified parameter.
I spent a fair amount of time trying to come up with a suitable name for the new parameter. Struggling to come up with a name I liked, I asked ChatGPT to suggest some names.
I short listed a few and sent a message to a few friends to solicit human feedback!
Based on the feedback received and my own thoughts, I decided to finalize on calling the parameter skip
- I wasn’t entirely convinced of the name as it may lead to off-by-one confusion, but decided to go ahead with it.
Other code changes were just to add the skip
field to the UI and the Protobuf RPC.
In the end, it turned out to be actually a very small code change that need not have been on the issue tracker for 4 years!
Note to Self
I am more motivated to implement or fix something when there’s a related trigger - in this case the new customer wanting this same feature. In the future I will take advantage of this increased motivation to at least do a prototype/scoping of the feature right away.
Wrapping up
Finally, to wrap up the feature, I added a test to the variable fields test suite and updated the Ostinato User Guide.
Is there a feature you’d like added to Ostinato? Let me know in the comments!
Leave a Comment