Created
October 22, 2025 18:15
-
-
Save carlos-jenkins/64e2d6bcc19e036e5eecc3fda60828af to your computer and use it in GitHub Desktop.
Linux kernel bonding driver hash algorithm Python equivalent for xmit_hash_policy=layer3+4 unfragmented TCP/UDP and IPv4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import socket | |
| import struct | |
| def _ipv4_to_u32(ip_str: str) -> int: | |
| # network-order (big-endian) to host int | |
| return struct.unpack("!I", socket.inet_aton(ip_str))[0] | |
| def bond_layer3_4_hash_tcp( | |
| src_ip: str, | |
| dst_ip: str, | |
| src_port: int, | |
| dst_port: int, | |
| slave_count: int | |
| ) -> int: | |
| """ | |
| Predict the slave index for Linux bonding xmit_hash_policy=layer3+4 for | |
| unfragmented TCP. | |
| :param str src_ip: Source IPv4 address, e.g. "192.168.1.10" | |
| :param str dst_ip: Destination IPv4 address, e.g. "10.0.0.5" | |
| :param int src_port: TCP source port (0..65535) | |
| :param int dst_port: TCP destination port (0..65535) | |
| :param int slave_count: Number of slaves (>0) | |
| :return: Slave index in [0, slave_count-1] | |
| :rtype: int | |
| """ | |
| if not (0 <= src_port <= 0xFFFF and 0 <= dst_port <= 0xFFFF): | |
| raise ValueError("Ports must be 0..65535") | |
| if slave_count <= 0: | |
| raise ValueError("slave_count must be > 0") | |
| sip = _ipv4_to_u32(src_ip) | |
| dip = _ipv4_to_u32(dst_ip) | |
| # Start with ports "as in the header". | |
| # A common interpretation is to pack them as 16|16 bits: | |
| h = ((src_port & 0xFFFF) << 16) | (dst_port & 0xFFFF) | |
| # Then XOR in the IPs (L3) | |
| h ^= sip ^ dip | |
| # Fold/mix as per docs | |
| h ^= (h >> 16) | |
| h ^= (h >> 8) | |
| # Bonding special-case for LAYER34: discard lowest bit | |
| h >>= 1 | |
| # Reduce to slave index | |
| return h % slave_count | |
| # Example usage | |
| ip_src = '192.168.1.10' | |
| ip_dst = '10.0.0.5' | |
| slave_count = 2 | |
| port_dst = 80 | |
| # Show distribution of source ports to slave indices | |
| distribution = [0] * slave_count | |
| for port_src in range(1, 65536): | |
| slave_index = bond_layer3_4_hash_tcp( | |
| ip_src, | |
| ip_dst, | |
| port_src, | |
| port_dst, | |
| slave_count, | |
| ) | |
| distribution[slave_index] += 1 | |
| print(f'Distribution of source ports to {slave_count} slaves:') | |
| for idx, count in enumerate(distribution): | |
| print(f' Slave {idx}: {count} ports') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment