In summary:
- Looping over prefixes in a tree.
- Calling
tree.delete(prefix-X) for each prefix.
- There should be no problem here, we should just delete each prefix and eventually have an empty tree.
- Under the right conditions,
tree.delete(prefix-A) also deletes prefix-B.
- When the loop gets to prefix-B, the
tree.delete(prefix-B) call fails and raises an exception because we tried to delete a non-existing prefix (even though we haven't called delete on this prefix yet!).
- Prefixes are being silently deleted from the tree meaning trees are missing data if you deleted "some" prefixes and expect some others to remain (I found the bug after loading the global BGP table into a tree, 1.4M routes, and tried to delete about 7k prefixes).
This should not happen because tree.delete() deletes an exact match, and it doesn't delete any parent or child nodes/prefixes of the deleted prefix, so tree.delete(prefix-A) should never also delete prefix-B.
To reproduce this we seem to need two things:
- A large data set
- A data set with mixed IPv4 and IPv6 entries
- Import functions from another file (not have everything in-lined in a single file).
Here is a repro with a reliable reproduction of the bug: https://github.com/jwbensley/Radix-Bug
I you read the README, in-lining the load_tree_from_json function from data_loader.py into reproduce.py causes the issue to go away.
In summary:
tree.delete(prefix-X)for each prefix.tree.delete(prefix-A)also deletes prefix-B.tree.delete(prefix-B)call fails and raises an exception because we tried to delete a non-existing prefix (even though we haven't called delete on this prefix yet!).This should not happen because
tree.delete()deletes an exact match, and it doesn't delete any parent or child nodes/prefixes of the deleted prefix, sotree.delete(prefix-A)should never also delete prefix-B.To reproduce this we seem to need two things:
Here is a repro with a reliable reproduction of the bug: https://github.com/jwbensley/Radix-Bug
I you read the README, in-lining the
load_tree_from_jsonfunction fromdata_loader.pyintoreproduce.pycauses the issue to go away.