Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple Forward with Token Bucket NF #199

Merged
merged 16 commits into from
May 29, 2020
Merged

Conversation

rohit-mp
Copy link
Contributor

@rohit-mp rohit-mp commented Mar 27, 2020

This PR adds a new example - simple_fwd_tb

The NF uses the advanced rings mode and simulates a queue with a token bucket. It takes in depth and rate as additional parameters and forwards/drops the packets based on the those values.

Summary:

Usage:

This PR includes
Resolves issues
Breaking API changes
Internal API changes
Usability improvements
Bug fixes
New functionality 👍
New NF/onvm_mgr args
Changes to starting NFs
Dependency updates
Web stats updates

Merging notes:

  • Dependencies: None

TODO before merging :

  • PR is ready for review

Test Plan:

Trivial inputs have been tested.
The rate was increased while keeping depth constant to observe a increase in tx_pps upto a limit.
The depth was increased while keeping rate constant to observe a decrease in the number of dropped packets.
Any input on how to test the same thoroughly is appreciated.

Testing the rate

R=100
R=100

R=1000
R=1000

R=10000
R=10000

Testing the depth

D=1000
D=1000

D=10000
D=10000

D=100000
D=100000

Point to be noted is that the depth should be sufficiently high enough to enqueue atleast 32 packets at once onto the tx_ring for the NF stats to be updated properly. Related to #198

Review:

@twood02

Subscribers: << @-mention people who probably care about these changes >>
@Shashwatha-Mitra @NishanthSubramanian @archit-p @mohittahiliani

@onvm
Copy link

onvm commented Mar 27, 2020

In response to PR creation

CI Message

Your results will arrive shortly

Copy link

@onvm onvm left a comment

Choose a reason for hiding this comment

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

In response to PR creation

CI Message

Run successful see results:
✔️ PR submitted to develop branch
✔️ Linter passed

@twood02
Copy link
Member

twood02 commented Mar 27, 2020

@onvm test this please!

@onvm
Copy link

onvm commented Mar 27, 2020

@onvm test this please!

CI Message

Your results will arrive shortly

onvm
onvm previously approved these changes Mar 27, 2020
Copy link

@onvm onvm left a comment

Choose a reason for hiding this comment

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

@onvm test this please!

CI Message

Run successful see results:
✔️ PR submitted to develop branch
✔️ Pktgen performance check passed
✔️ Speed Test performance check passed
✔️ Linter passed

[Results from nimbnode23]

  • Median TX pps for Pktgen: 7705634
    Performance rating - 100.07% (compared to 7700000 average)

  • Median TX pps for Speed Tester: 42169402
    Performance rating - 100.40% (compared to 42000000 average)

@kkrama
Copy link

kkrama commented Mar 30, 2020 via email

@rohit-mp
Copy link
Contributor Author

rohit-mp commented Mar 30, 2020

I could think of 3 possible ways of implementing the token bucket:

  1. Dequeue pkt by pkt based on availability of tokens - This way, we wouldn't be able to apply a dynamic depth constraint and it would be fixed to the size of the ring. Also, we'd have to preemptively dequeue a pkt to know it's size if we treat a token to be equivalent to a byte instead of a pkt.
  2. Burst dequeue and process pkts based on availability of tokens - This way, we can apply depth constraints since we know how many pkts were in the queue (since we dequeue all available pkts). Although, the packets which would've been dropped as compared between this implementation and dequeuing one-by-one would be different.
  3. Maintain a separate queue apart from the ring to simulate a traditional token bucket - This method would involve launching threads, one for processing rx and the other for tx since it would be hard for a single thread to dequeue from rx_ring at a constant rate while generating tokens and enqueuing to tx_ring based on availability of tokens. And maintaining two threads comes with the cost of having locks on the queue which could lead to poor performance.

Considering the above points, I went ahead with the second approach as mentioned above. Does that look fine? Thanks and Regards.

@kkrama
Copy link

kkrama commented Mar 30, 2020 via email

@rohit-mp
Copy link
Contributor Author

Thanks for the feedback Sir. I could remove the tx burst by modifying my implementation but I'm not quite sure how the rx latency is increasing. Should I send an email to Sameer?

@rohit-mp
Copy link
Contributor Author

rohit-mp commented Apr 3, 2020

Thanks for the inputs. I've simplified the code to work with a batch size of 32. The excess packets are now stalled and not dropped if tokens are insufficient. Packets are dropped only when the ring becomes full.

@twood02
Copy link
Member

twood02 commented Apr 8, 2020

Thanks @rohit-mp . I think this is a good solution which should reduce burstiness caused by large dequeues/enqueues.

How have you been testing this?

@rohit-mp
Copy link
Contributor Author

rohit-mp commented Apr 8, 2020

I tested the rate by varying it to see a corresponding change in the packets processed per second. I'm not sure how to verify depth as that can be tested under bursty condition and speed-tester wasn't suitable for that.

Any input on how to test it thoroughly is appreciated.

@dennisafa
Copy link
Member

I tested the rate by varying it to see a corresponding change in the packets processed per second. I'm not sure how to verify depth as that can be tested under bursty condition and speed-tester wasn't suitable for that.

Any input on how to test it thoroughly is appreciated.

You may try testing depth out by hooking up pktgen on a client node and sending it traffic from there, check out our Wiki page to see how to set it up. I think that pktgen lets you attach a script, you can try simulating bursty behavior through that.

@kevindweb
Copy link
Contributor

Just like @dennisafa said, write a little Lua code that Pktgen will process and send. If you update pktgen Lua script you can create these kinds of advanced tests to pump packets through the network.

@twood02 twood02 added this to the ONVM 20.05 milestone Apr 9, 2020
@dennisafa dennisafa mentioned this pull request Apr 10, 2020
3 tasks
@rohit-mp
Copy link
Contributor Author

rohit-mp commented May 3, 2020

Hello team, I recently realized that we don't actually need advanced rings mode to simulate the token bucket. But I think this is still a good basic example showing the usage.
Would you prefer that I use default rings mode instead? Or would it be good to provide both modes as options as done in scaling NF?

@kkrama
Copy link

kkrama commented May 3, 2020 via email

@rohit-mp
Copy link
Contributor Author

rohit-mp commented May 3, 2020

Thank you for the suggestion. Yes, default ring mode is sufficient. But @twood02 mentioned that this would be a good example for helping people learn how to use the advanced rings interface (in the comments above on this PR).

@dennisafa
Copy link
Member

Thank you for the suggestion. Yes, default ring mode is sufficient. But @twood02 mentioned that this would be a good example for helping people learn how to use the advanced rings interface (in the comments above on this PR).

In my opinion I think that it would be best to use the default mode unless necessary. Adv. rings mode should just be used when we need full control over the RX/TX rings.

@twood02
Copy link
Member

twood02 commented May 3, 2020

Yes, I still think this is quite useful as an example of the advanced rings mode. I suggest we finalize this Pull Request and merge it with just the advanced rings mode. Later we can make a second version based on the normal packet handler function, which I'd prefer to keep as a separate directory so it is easier to see the differences in the two approaches. If @rohit-mp wants to add the standard packet handler version, that'd be great. Otherwise one of our students can do it this summer.

@rohit-mp
Copy link
Contributor Author

rohit-mp commented May 4, 2020

Thanks, let me know if anything is needed to help in finalizing the PR.

I'd be happy to add the default ring mode as well soon.

@catherinemeadows
Copy link
Contributor

Tested Rate

Tested rate by increasing rate parameter and keeping depth consistent and saw the expected increase in tx_pps.

R=100, D=100
test1

R=1000, D=100
test2

R=10000, D=100
test3

R=20000, D=100
test7

@rohit-mp
Copy link
Contributor Author

rohit-mp commented May 8, 2020

This is the output of the C Linter which failed:

examples/simple_fwd_tb/forward_tb.c:57:  Include the directory when naming .h files  [build/include] [3]
examples/simple_fwd_tb/forward_tb.c:58:  Include the directory when naming .h files  [build/include] [3]
examples/simple_fwd_tb/forward_tb.c:90:  Odd number of spaces at line-start.  Are you using a 4/8-space indent?  [whitespace/indent] [3]
examples/simple_fwd_tb/forward_tb.c:182:  Odd number of spaces at line-start.  Are you using a 4/8-space indent?  [whitespace/indent] [3]
examples/simple_fwd_tb/forward_tb.c:191:  Odd number of spaces at line-start.  Are you using a 4/8-space indent?  [whitespace/indent] [3]

The first two lines would be an issue with every example in the repo. Should I fix that here?
The next three lines are due to the indentation done by an extension for vs code which I personally think looks neater. Should I change that as well to make it conform to the start of the line everywhere? The same code didn't raise the error during the CI checks before.

@bdevierno1
Copy link
Contributor

This is the output of the C Linter which failed:

examples/simple_fwd_tb/forward_tb.c:57:  Include the directory when naming .h files  [build/include] [3]
examples/simple_fwd_tb/forward_tb.c:58:  Include the directory when naming .h files  [build/include] [3]
examples/simple_fwd_tb/forward_tb.c:90:  Odd number of spaces at line-start.  Are you using a 4/8-space indent?  [whitespace/indent] [3]
examples/simple_fwd_tb/forward_tb.c:182:  Odd number of spaces at line-start.  Are you using a 4/8-space indent?  [whitespace/indent] [3]
examples/simple_fwd_tb/forward_tb.c:191:  Odd number of spaces at line-start.  Are you using a 4/8-space indent?  [whitespace/indent] [3]

The first two lines would be an issue with every example in the repo. Should I fix that here?
The next three lines are due to the indentation done by an extension for vs code which I personally think looks neater. Should I change that as well to make it conform to the start of the line everywhere? The same code didn't raise the error during the CI checks before.

Hi @rohit-mp . Thanks for your comment. The reason is because we recently introduced a new linter using Github actions. The new linter updated the verbosity level --the amount of information returned by the linter-- which is why the lint failed. I felt this would provide more useful feedback to the user. However, you raised some important points and I will speak to the rest of the team and get back to you.

Copy link
Contributor

@catherinemeadows catherinemeadows left a comment

Choose a reason for hiding this comment

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

In order to fix a bug for the case where the token bucket is larger than the packet size, on line 210 of forward_tb.c, you should have a condition:

 if (pkt->pkt_len > tb_tokens) {
                tb_tokens -= pkt->pkt_len;
 } else {
                tb_tokens = 0;
 }

Also, in your README.md, when describing the -R flag, 'Mbps' should be changed to 'MBps' to specify Megabytes rather than Megabits.

@rohit-mp
Copy link
Contributor Author

rohit-mp commented May 14, 2020

In order to fix a bug for the case where the token bucket is larger than the packet size, on line 210 of forward_tb.c, you should have a condition:

 if (pkt->pkt_len > tb_tokens) {
                tb_tokens -= pkt->pkt_len;
 } else {
                tb_tokens = 0;
 }

Token Bucket being larger than the pkt size is the only valid case here. If size of Token Bucket is less than the pkt size, we would never be able to process any pkts. I think you meant you say tokens instead. These lines make sure that tokens are more than pkt size before reaching line 210:
https://github.com/rohit-mp/openNetVM/blob/108f9ed196399a133de9620fcb47b19ddc1a26c3/examples/simple_fwd_tb/forward_tb.c#L187-L191
Also, I think you meant to use > in the if condition instead of <. In that case, the if condition wouldn't be required as just tb_tokens -= pkt->pkt_len would take care of the situation.

Also, in your README.md, when describing the -R flag, 'Mbps' should be changed to 'MBps' to specify Megabytes rather than Megabits.

Good catch. Will fix that in the usage as well.

@twood02
Copy link
Member

twood02 commented May 17, 2020

@rohit-mp I think you are correct that your if statement up top helps prevent it in the normal case, but since tb_tokens is initialized to a large number, the bug can still arise as @catherinemeadows and @bdevierno1 point out.

To test this, run speed tester with -s 1024 (for 1024 byte packets) and your code with a depth of 1000. There will be no rate limiting because of the unsigned issue. @catherinemeadows‘s fix works, but maybe adjusting the default value will be simpler and trigger your existing check.

Your PR mentions depth should be set carefully, but I think that should be more explicit. At least print an obvious warning if depth is less than say 10,000.

@rohit-mp
Copy link
Contributor Author

Ah nice catch! Thanks for that. I missed out the value of depth being less than pkt_len.

But @catherinemeadows fix would resolve the issue only partially (I'm assuming we've to interchange the if and else part in that) since we'd still be processing the pkt without sufficient tokens.

I will add a warning for when depth is set to less than 10,000. But along with that warning, should I drop pkts that arrive with a size of more than the depth? It seems like the better option to me since technically, that packet should never be processed and all the pkts arriving behind it would be stalled forever.

@twood02
Copy link
Member

twood02 commented May 22, 2020

@rohit-mp if you have a chance to add the warning and fix soon that'd be great (sorry to bug you with all these little things, your contribution is greatly appreciated!). If you won't have time to make them soon, then we can push the edits ourselves. We'd like to merge this for our May release.

@rohit-mp
Copy link
Contributor Author

@rohit-mp if you have a chance to add the warning and fix soon that'd be great (sorry to bug you with all these little things, your contribution is greatly appreciated!). If you won't have time to make them soon, then we can push the edits ourselves. We'd like to merge this for our May release.

Not an issue at all. The careful reviews are highly appreciated. I was waiting for confirmation on what to do when a pkt with length greater than depth arrives (as asked in my last message).

@twood02
Copy link
Member

twood02 commented May 22, 2020

oops, sorry missed your question at the end.

should I drop pkts that arrive with a size of more than the depth? It seems like the better option to me since technically, that packet should never be processed and all the pkts arriving behind it would be stalled forever.

Yes, I agree that dropping packets that are larger than the depth is fine. I don't think this would be used much in practice (depth should always be much bigger), but I suppose this would be a way to apply a filter to remove large packets which might be useful in some cases.

@twood02 twood02 added the NeedsReleaseNote Needs updated release note info label May 22, 2020
@rohit-mp
Copy link
Contributor Author

I've added a warning for when depth is less than 10,000 and an unlikely check in the packet handler for when pkt length is more than depth. Let me know if any changes are required

@twood02 twood02 added ready-for-gatekeeper 🚪 PRs that have been approved and are ready for a final review/merge and removed NeedsReleaseNote Needs updated release note info labels May 28, 2020
Copy link
Member

@dennisafa dennisafa left a comment

Choose a reason for hiding this comment

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

Great work!

@dennisafa dennisafa merged commit ec2b2fa into sdnfv:develop May 29, 2020
@rohit-mp rohit-mp deleted the token_bucket_nf branch June 10, 2020 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new NF 🛰️ ready-for-gatekeeper 🚪 PRs that have been approved and are ready for a final review/merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants