Skip to content

Support nested prefixes in the LcTrie class#2614

Merged
alyssawilk merged 5 commits intoenvoyproxy:masterfrom
brian-pane:nested-prefix
Feb 20, 2018
Merged

Support nested prefixes in the LcTrie class#2614
alyssawilk merged 5 commits intoenvoyproxy:masterfrom
brian-pane:nested-prefix

Conversation

@brian-pane
Copy link
Contributor

@brian-pane brian-pane commented Feb 15, 2018

Description:
Support nested prefixes such as 127.0.0.0/24 and 127.0.0.1/32 in the LcTrie class. An address comparison against an LcTrie will now return the union of all matching prefixes' tags.

Risk Level: Low

Testing: Updated unit tests included

Docs Changes: N/A

Release Notes: N/A

Partially Fixes: #1001

Signed-off-by: Brian Pane bpane@pinterest.com

Signed-off-by: Brian Pane <bpane@pinterest.com>
@htuch
Copy link
Member

htuch commented Feb 15, 2018

Please merge master to pick up #2613, this should fix CI TSAN.

Signed-off-by: Brian Pane <bpane@pinterest.com>
@dnoe dnoe requested a review from ccaraman February 15, 2018 14:59
@dnoe
Copy link
Contributor

dnoe commented Feb 15, 2018

I think this will be much easier to review if it doesn't contain the changes from #2612 . Can you make a pass over that PR to review it, and we'll get it merged? @ccaraman can separately review your changes here.

Copy link
Contributor

@ccaraman ccaraman left a comment

Choose a reason for hiding this comment

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

Thank you for implementing this! Looks good, just a few comments/questions.

// prefix, the lookup will scan the nested prefixes to see if any of them match,
// too. This situation is rare, so to save memory in the common case the
// nested_prefixes field is a pointer to a vector rather than an inline vector.
std::shared_ptr<std::vector<IpPrefix>> nested_prefixes_;
Copy link
Contributor

Choose a reason for hiding this comment

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

is this meant to be a unique_ptr? addNestedPrefix is calling make_unique

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching that. It started out as unique_ptr but then I found that the existing code assumed copyability of the containing struct. So I changed to shared_ptr, but I forgot to change addNestedPrefix. I’ll fix that today.

IpType bitmask = ip_prefixes_[address].ip_ ^ ip_address;
if (extractBits<IpType, address_size>(0, ip_prefixes_[address].length_, bitmask) == 0) {
return ip_prefixes_[address].tag_;
// The prefix table entry ip_prefixes_[address] contains either a single prefix or
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a todo assigned to me to look into if having a better way to handle /0 is ideal.

Copy link
Contributor Author

@brian-pane brian-pane Feb 16, 2018

Choose a reason for hiding this comment

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

Ok, added! With this PR, the code is relatively clean, because the /0 special case is encapsulated in the extractBits function, but the drawback is that the extra conditional in that function will make the common case (prefixes of nonzero length) a bit slower. I'll defer to you on whether to optimize for code simplicity or runtime speed.

Signed-off-by: Brian Pane <bpane@pinterest.com>
@dnoe
Copy link
Contributor

dnoe commented Feb 16, 2018

@alyssawilk for senior maintainer review

Copy link
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

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

Mind doing a merge now that #2612 has landed, and I'll take a look this afternoon?? I think you'll need to update the tests per the latest push there.

Signed-off-by: Brian Pane <bpane@pinterest.com>
@@ -155,15 +133,36 @@ class LcTrie {
extractBits<IpType, address_size>(0, length_, other.ip_)));
Copy link
Contributor

Choose a reason for hiding this comment

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

migrate over to using contains()?


if (tag_data[i - 1] != tag_data[i]) {
if (ip_prefixes_[ip_prefixes_.size() - 1].isPrefix(tag_data[i])) {
ip_prefixes_[ip_prefixes_.size() - 1].addNestedPrefix(tag_data[i]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, question time, if we're trying to build a trie, isn't this actually building a vector of maybe vectors? I'd expect from the class name if we had nested prefixes those could have their own nested prefix rather than being bundled together at depth 1. Is this just infrequent enough we do it the inefficient way and if so, mind commenting it up?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, it is building a vector of nested prefixes. From talking to @mattklein123, nested prefixes aren't that common and linearly traversing a sorted vector in these cases should be good enough for now. If we do notice there being an issue, we can always swap this to have tries for the nested prefix cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll add a TODO comment about how more general-purpose usage will require using sub-tries for the nested prefix cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another solution, I think, would be to change the construction of the base LC Trie to allow nested prefixes. As far as I can tell, the data structure should be able to handle nested prefixes in a single trie; it's just the trie construction algorithm from the original paper that doesn't support nesting. For now, though, I just added the TODO comment.

… `contains`

Signed-off-by: Brian Pane <bpane@pinterest.com>
// too. This situation is rare, so to save memory in the common case the
// nested_prefixes field is a pointer to a vector rather than an inline vector.
// TODO(brian-pane) switch to a trie of nested prefixes, to ensure sublinear-time
// searching even in situations where there are a lot of nested prefixes.
Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW if we think nested prefixes are rare I'm totally fine just commenting "this is a vector rather than a trie of nested prefixes because it's rare and not worth optimizing for" but a TODO is fine if you think we'll fix eventually :-)

Copy link
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

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

Looks good, thanks!
One final request - mind removing the stale note?

Notes: This PR includes the changes from @ccaraman's PR #2612.

@alyssawilk
Copy link
Contributor

Actually I can go ahead and do that. Mergable! :-)

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.

5 participants