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

Fwmtu mis-measures some MTUs. #1490

Open
mfeit-internet2 opened this issue Dec 5, 2024 · 2 comments
Open

Fwmtu mis-measures some MTUs. #1490

mfeit-internet2 opened this issue Dec 5, 2024 · 2 comments
Assignees
Labels

Comments

@mfeit-internet2
Copy link
Member

@bltierney Noticed that the I2 perfSONAR hosts are showing MTUs of 1500. I checked the interfaces; they were reconfigured incorrectly to 1500 during a recent re-provisioning.

Sometimes he's able to get it to show 9000, which we suspect may be that the socket.error exception being caught after the call to sock.send() may be too simplistic and is returning a MTU value for something that doesn't make it all the way there.

Investigate this and make corrections to make it work properly.

@bltierney
Copy link
Contributor

bltierney commented Dec 5, 2024

I did some more research on this, and it looks like you have to use ICMP packets to find receive host issues. IP packets only tell you about router config issues.

Here is some sample code that uses ICMP and seems to address the problem:

import socket
import struct
import time

def checksum(data):
    """Calculate ICMP checksum."""
    if len(data) % 2:
        data += b'\x00'
    s = sum(struct.unpack("!%dH" % (len(data) // 2), data))
    s = (s >> 16) + (s & 0xFFFF)
    s += s >> 16
    return ~s & 0xFFFF

def icmp_echo_test(host, packet_size):
    """Send ICMP echo request with a specified packet size."""
    try:
        # Create a raw socket for ICMP
        sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
        sock.settimeout(1)

        # ICMP Header: Type (8), Code (0), Checksum (0 initially), ID, Sequence
        icmp_header = struct.pack("!BBHHH", 8, 0, 0, 12345, 1)
        payload = b'a' * packet_size
        checksum_value = checksum(icmp_header + payload)
        icmp_header = struct.pack("!BBHHH", 8, 0, checksum_value, 12345, 1)

        # Send the ICMP packet
        sock.sendto(icmp_header + payload, (host, 0))
        start_time = time.time()

        # Wait for a response
        try:
            sock.recv(1024)
            return time.time() - start_time
        except socket.timeout:
            return None
    except PermissionError:
        print("Run the script with administrative privileges.")
        return None
    finally:
        sock.close()

def find_path_mtu(host):
    """Perform MTU discovery using adaptive probing."""
    # Start with common MTU sizes
    common_mtu = [1500, 9000, 1492, 576]
    for mtu in common_mtu:
        print(f"Testing MTU: {mtu} bytes...")
        response_time = icmp_echo_test(host, mtu - 28)  # Subtract headers

        if response_time is not None:
            print(f"MTU {mtu} works!")
            # Perform binary search above this MTU to refine
            return refine_mtu(host, mtu, 9000)

    print(f"No common MTU worked. Falling back to binary search.")
    return refine_mtu(host, 576, 1500)

def refine_mtu(host, min_mtu, max_mtu):
    """Refine MTU using binary search."""
    while min_mtu <= max_mtu:
        current_mtu = (min_mtu + max_mtu) // 2
        print(f"Refining MTU: Testing {current_mtu} bytes...")
        response_time = icmp_echo_test(host, current_mtu - 28)

        if response_time is not None:
            min_mtu = current_mtu + 1
        else:
            max_mtu = current_mtu - 1

    print(f"Final Path MTU to {host} is {max_mtu} bytes.")
    return max_mtu
###############

# Replace 'example.com' with your target host
find_path_mtu("example.com")

@mfeit-internet2
Copy link
Member Author

NB: The above code was generated with ChatGPT and will have to be clean-roomed to be license-compatible with perfSONAR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Ready
Development

No branches or pull requests

2 participants