Patricia(3)

🌸 Patricia(3) 🌸

Net::Patricia β€” the Patricia Trie perl module for fast IP address lookups. Yes bestie, this is a User Contributed Perl Documentation page (that's the Patricia(3) bit up top) and it's genuinely iconic, so let's get into it πŸ’…


✨ NAME ✨

Net::Patricia β€” Patricia Trie perl module for fast IP address lookups πŸ¦‹


πŸŽ€ SYNOPSIS πŸŽ€

  use Net::Patricia;

  my $pt = Net::Patricia->new;

  my $user_data;
  $pt->add_string('127.0.0.0/8', \$user_data);
  $pt->match_string('127.0.0.1');
  $pt->match_exact_string('127.0.0.0');
  $pt->match_integer(2130706433); # 127.0.0.1
  $pt->match_exact_integer(2130706432, 8); # 127.0.0.0
  $pt->remove_string('127.0.0.0/8');
  $pt->climb(sub { print "climbing at node $_[0]\n" });

  undef $pt; # automatically destroys the Patricia Trie

  # IPv6 support:
  $pt = Net::Patricia->new(AF_INET6);
  $pt->add_string('2001:db8::/32');
  $pt->add_string('2001:db8:0:dead::/64');
  $pt->add_string('2001:db8:0:beef::/64');
  $pt->climb(sub { print "climbing at node $_[0]\n" });
  print $pt->match_string('2001:db8:0:dead::1'), "\n";

  # IPv4-mapped IPv6 addresses:
  $pt->add_string('::ffff:0:0/96');
  for my $cidr (qw( 192.0.2.0/24 192.0.2.0/25 192.0.2.128/25 )) {
    my($ip, $len) = split(m|/|, $cidr);
    $pt->add_string("::ffff:$ip/" .
            (96+(defined($len)? $len : 32)), $cidr);
  }
  $pt->climb(sub { print "climbing at node $_[0]\n" });
  print $pt->match_string("::ffff:" . "192.0.2.129"), "\n";

🌈 DESCRIPTION 🌈

Okay so this module uses a Patricia Trie data structure to quickly do IP address prefix matching for stuff like IP subnet, network, or routing table lookups. Fast fast. πŸ’¨

The data structure is a radix tree with a radix of two, which is why you'll sometimes see patricia implementations also called "radix". Ngl the naming lore here is a whole thing:

  • "Trie" comes from the word "retrieval", but it's pronounced like "try" β€” yes, the spelling is lying to you, it's giving chaos πŸ™ˆ
  • "Patricia" stands for "Practical Algorithm to Retrieve Information Coded as Alphanumeric", and it was first suggested for routing table lookups by Van Jacobsen

Patricia Trie performance characteristics are well-known because it's been used for routing table lookups inside the BSD kernel since the 4.3 Reno release. She's been booked and busy for decades, no cap. πŸ‘‘

The BSD radix code is thoroughly described in "TCP/IP Illustrated, Volume 2" by Wright and Stevens, and also in the paper "A Tree-Based Packet Routing Table for Berkeley Unix" by Keith Sklower. Read up, bestie πŸ“š


πŸ’… METHODS πŸ’…

πŸ’– new β€” create a new Net::Patricia object πŸ’–

  $pt = Net::Patricia->new;

This is the class' constructor, and it returns a Net::Patricia object when it works, or undef on failure 😭. It takes an optional argument β€” either AF_INET or AF_INET6, and it defaults to the former β€” and it builds a tree whose keys are address and mask values of that type.

The Net::Patricia object gets destroyed automatically once nothing references it anymore. She cleans up after herself, queen. ✨


πŸ¦‹ add_string πŸ¦‹

  $pt->add_string(key_string[,user_data]);

The first argument, key_string, is a network or subnet specification in canonical form β€” like "10.0.0.0/8" β€” where the number after the slash is how many bits are in the netmask. If you don't specify a mask width, the longest possible mask is assumed, so that's 32 bits for AF_INET addresses.

The second argument, user_data, is optional. If you pass it, it should be a SCALAR value (which may totally be a perl reference) holding the user data that gets stored in the Patricia Trie node. Later on, the match methods below will hand this value back to you to say "yep, found it" βœ…. Remember: perl references and objects are represented as SCALAR values, so your user data can be a whole complicated data object. Sky's the limit fr fr.

If you don't pass a second argument, then key_string itself gets stored as the user data, and it'll be what the match functions return too.

On success, this method returns the user_data you passed in as the second argument β€” or key_string if you gave no user data. On failure it returns undef. πŸ˜”


πŸ“ match_string πŸ“

  $pt->match_string(key_string);

This method searches the Patricia Trie to find a matching node, following normal subnetting rules for the address and mask you specified.

The key_string argument is a network or subnet spec in canonical form, e.g. "10.0.0.0/8", where the number after the slash is the number of bits in the netmask. No mask width given? Then the longest mask is assumed β€” 32 bits for AF_INET addresses.

If a matching node turns up in the Patricia Trie, this method returns that node's user data. If not, it returns undef. πŸ’€


🧚 match_exact_string 🧚

  $pt->match_exact_string(key_string);

This one searches the Patricia Trie for a matching node too, and its semantics are exactly the same as what's described for match_string, except that the key has to match a node exactly. Like, it's not enough that the address and mask you specified merely falls within the subnet of some particular node. Exact only. Periodt. πŸ’…


πŸ‘‘ match_integer πŸ‘‘

  $pt->match_integer(integer[,mask_bits]);

This method searches the Patricia Trie to find a matching node, per the normal subnetting rules for the address and mask specified. Semantics are similar to match_string, except the key is given as an integer (i.e. a SCALAR) β€” the kind perl's unpack gives you for values converted using the "N" (network-ordered long). Heads up: this argument is not a packed network-ordered long, okay? Important distinction, don't get it twisted πŸ™…

To be completely clear, the integer argument should be a value of the sort this code produces:

  use Socket;
  $integer = unpack("N", inet_aton("10.0.0.0"));

⭐ match_exact_integer ⭐

  $pt->match_exact_integer(integer[,mask_bits]);

Searches the Patricia Trie for a matching node. Its semantics are exactly the same as match_integer, except the key must match a node exactly. So again β€” it is not sufficient that the address and mask specified merely falls within the subnet of a particular node. Exact match or nothing. πŸ”₯


πŸ’œ remove_string πŸ’œ

  $pt->remove_string(key_string);

This method removes the node that exactly matches the address and mask you specified from the Patricia Trie.

If the matching node is found, it gets removed, and this method returns the node's user data. On failure it returns undef. Goodbye bestie πŸ‘‹πŸ˜­


🌸 climb 🌸

  $pt->climb([CODEREF]);

This method climbs the Patricia Trie, visiting every node as it goes. It does a non-recursive, "preorder" traversal.

The CODEREF argument is optional. It's a perl code reference used to specify a user-defined subroutine that gets called when visiting each node. The node's user data gets passed as the sole argument to that subroutine.

This method returns the number of nodes successfully visited while climbing the Trie. So without a CODEREF argument, it's basically just counting the nodes in the Patricia Trie. Cute, right? πŸ₯°

Note: currently the return value from your CODEREF subroutine is ignored. In the future the climb method may return the number of times your subroutine returned non-zero, since it's called once per node. So if you're currently relying on the climb return value to accurately report a count of the number of nodes in the Patricia Trie, it would be prudent to have your subroutine return a non-zero value. πŸ‘€

This method is called climb() rather than walk() because climbing trees (and therefore tries) is a more popular pass-time than walking them. That's just the truth, iykyk 🌳


🌈 climb_inorder 🌈

  $pt->climb_inorder([CODEREF]);

This method climbs the Patricia Trie, visiting each node in order as it does so. That is, it performs an "inorder" traversal.

The CODEREF argument is optional. It's a perl code reference used to specify a user-defined subroutine that gets called when visiting each node. The node's user data gets passed as the sole argument to that subroutine.

This method returns the number of nodes successfully visited while climbing the Trie. Which means, without a CODEREF argument, it simply counts the number of nodes in the Patricia Trie. Same energy as before πŸ’«

Note: currently the return value from your CODEREF subroutine is ignored. In the future the climb method may return the number of times your subroutine returned non-zero, as it is called once per node. So if you're currently relying on the climb return value to accurately report a count of the number of nodes in the Patricia Trie, it would be prudent to have your subroutine return a non-zero value. ⚠️

This method is called climb() rather than walk() because climbing trees (and therfore tries) is a more popular pass-time than walking them. Yes, we're saying it again. It's a good bit. πŸ§—β™€οΈ


πŸŽ€ Serialization πŸŽ€

Net::Patricia trees, unlike a lot of classes with XS-level data, can be frozen and thawed using Storable. Slay, she's portable πŸ’–


πŸ’€ BUGS πŸ’€

When you pass a CODEREF argument to the climb method, the return value from your CODEREF subroutine is currently ignored. In the future the climb method may return the number of times your subroutine returned non-zero, as it is called once per node. So if you're currently relying on the climb return value to accurately report a count of the number of nodes in the Patricia Trie, it would be prudent to have your subroutine return a non-zero value. That's the bug note, and yes it's said like three times on this page β€” the module really wants you to know πŸ™ˆ


🫢 ACKNOWLEDGEMENTS 🫢

Thanks to all who have contributed patches and reported bugs:

  • Alexander Bluhm
  • Neil Bowers
  • Richard Bross
  • Joelle Maslak
  • Petr PΓ­saΕ™
  • Andreas VΓΆgele

Legends, every single one of them πŸ‘‘


🌟 AUTHOR 🌟

  • Dave Plonka <plonka@doit.wisc.edu>
  • Philip Prindeville <philipp@redfish-solutions.com>
  • Anton Berezin <tobez@tobez.org>

Copyright (C) 2000-2005 Dave Plonka. Copyright (C) 2009 Dave Plonka & Philip Prindeville. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This product includes software developed by the University of Michigan, Merit Network, Inc., and their contributors. See the copyright file in the patricialib sub-directory of the distribution for details.

patricialib, the C library used by this perl extension, is an extracted version of MRT's patricia code from radix.[ch], which was worked on by Masaki Hirabaru and Craig Labovitz. For more info on MRT see:

   https://github.com/deepfield/MRT

The MRT patricia code owes some heritage to GateD's radix code, which in turn owes something to the BSD kernel. It's a whole family tree, literally πŸ’…

🌈 SEE ALSO πŸ’«

ok bestie, go touch some other manuals too, it's called ✨enrichment✨:

  • perl(1) β€” the mothership 🫢
  • Socket β€” for when you're doing the whole network-address thing
  • Net::Netmask β€” netmask slay
  • Text::Trie β€” trie energy, text edition
  • Tree::Trie β€” trie energy, tree edition 🌳

Real talk about the competition tho πŸ‘€

Tree::Radix and Net::RoutingTable are modules by Daniel Hagerty <hag@linnaean.org>, and the way they're written entirely in perl, unlike this module πŸ’…. No C, no XS, just pure vibes and perl code.

At the time of this writing, they are works-in-progress β€” like, not done-done yet β€” but they may be available at:

https://www.linnaean.org/~hag/

and that's the whole page bestie, we ate and left no crumbs πŸ“βœ¨

πŸ’– this was Patricia(3) from perl v5.42.0, dated 2026-01-17 β€” go forth and route, my main character πŸ‘‘πŸŒˆ

πŸ“¦ where this page comes from