Changing adapter MTU with in Python

I’m writing a little p2p VPN app in python. A little bit ago I noticed that over the internet, the connection was stalling and it turned out that the packets I was sending were too big. Setting a lower MTU fixed the problem. As a quick fix, I need to make my app set the MTU automatically.

I could do this by calling ifconfig or ip with the subprocess module, but I wanted to do it w/out using an external program. After a few hours of toiling and googling, I was able to get it to work:

from fcntl import ioctl
import socket
import struct

SIOCGIFMTU = 0x8921
SIOCSIFMTU = 0x8922

s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
ioctl(s, SIOCGIFMTU, struct.pack('<16sH', 'eth0', 0))

mtu = 1280
ioctl(s, SIOCSIFMTU, struct.pack('<16sH', 'eth0', mtu)+'\x00'*14)

EDIT: The code I now use to change the MTU looks more like this (same definitions as above):

def get_mtu(self):
	'''Use socket ioctl call to get MTU size'''
	s = socket.socket(type=socket.SOCK_DGRAM)
	ifr = self.ifname + '\x00'*(32-len(self.ifname))
	try:
		ifs = ioctl(s, SIOCGIFMTU, ifr)
		mtu = struct.unpack('<H',ifs[16:18])[0]
	except Exception, s:
		logger.critical('socket ioctl call failed: {0}'.format(s))
		raise

	logger.debug('get_mtu: mtu of {0} = {1}'.format(self.ifname, mtu))
	self.mtu = mtu
	return mtu

 def set_mtu(self, mtu):
	'''Use socket ioctl call to set MTU size'''
	s = socket.socket(type=socket.SOCK_DGRAM)
	ifr = struct.pack('<16sH', self.ifname, mtu) + '\x00'*14
	try:
		ifs = ioctl(s, SIOCSIFMTU, ifr)
		self.mtu = struct.unpack('<H',ifs[16:18])[0]
	except Exception, s:
		logger.critical('socket ioctl call failed: {0}'.format(s))
		raise

	logger.debug('set_mtu: mtu of {0} = {1}'.format(self.ifname, self.mtu))

	return self.mtu
Advertisements

2 Responses to “Changing adapter MTU with in Python”

  1. akismet-dbb4037381989d877df1875598c08c50Miha Says:

    Hello,

    First thanks for sharing your experience, much appreciated!

    I have tried to use your code, and I have the following error:

    Traceback (most recent call last):
    File “./get_3MB.sh”, line 21, in
    ioctl(s, SIOCGIFMTU, struct.pack(‘<16sH’, ‘eth0’, 0))
    struct.error: bad char in struct format

    Do you have any suggestions on this?

    Thanks again.
    M.

  2. bj0z Says:

    Not sure what’s specifically causing that problem, your input structure may be too short. In any case, I’ve updated the post with the function that I currently use regularly.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: