NAT with Linux

NAT with Linux

To share an internet connection may sometimes be very practical when working with embedded devices. The network may have restrictions/authentications that stops you from plug in your device into the network of the big company you are working for.

But what about creating your own network and use your computer as NAT (Network Address Translation)?
I was surprised how easy it is to set up your Linux host as a NAT, it is just a few command lines.

OK, here is the setup on Host:
– eth0 has ip address 192.168.1.50 and is connected to the company network
– eth1 has ip address 10.2.234.1 ans is connected to the target

Setup on Target:
– eth0 has ip address 10.2.234.100 ans is connected to host

First of all, we need to setup a default gateway on our target, do this as you allways do – with route.:

Target$ route add default gw 10.2.234.1 eth0

Next, we need to create a post-routing rule in the to the NAT table that masquerades all traffic to the eth0 interface.
iptables is your friend:

Host$ sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Thats it! Well, allmost. We just need to enable ip-forwarding.:

Host$ echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

High resolution timers

High resolution timers

Nearly all systems has some kind of Programmable Interrupt Timer (PIT) or High Precision Event Timer (HPET) that is programmed to periodically interrupt the operating system (if not configured with CONFIG_NO_HZl). The kernel performs several tasks in every of these ticks, such as timekeeping, calculate statistics for the currently running process, schedule a new process and so on.
The interrupt occurs at regular intervals – exactly HZ times per second. HZ is architecture specific and defined in asm-arch/param.h.

Jiffies is a central concept when talking about time management in the Linux kernel. A jiffy is simple the time between the ticks. More exactly 1/HZ seconds.
HZ has a typical value of 250 on IA-32/AMD64 architectures, and 100 on smaller systems such as ARM.

Most of the time management in the Linux-kernel is based on jiffies, even the timer_list (also known as low-resolution-timers).

High resolution timers (hrtimers) in the Linux kernel is timers that do not use a time specification based on jiffies, but employ nanosecond time stamps. In fact, the low resolution timers are implemented on top of the high-resolution mechanism, but that is another story.
Components of the hrtimer framework that are not universally applicable (not used by the low-resolution timers) is selected by CONFIG_HIGH_RES_TIMERS in the kernel configuration.

Setting up a timer

The usage of the hrtimers is really simple.

  1. Initialize a struct hrtimer with

    hrtimer_init(struct hrtimer *timer, clockid_t which_clock, enum hrtimer_mode mode);
    

timer is a pointer to the instance of the struct hrtimer.
clock is the clock to bind the timer to, often CLOCK_MONOTONIC or CLOCK_REALTIME.
mode specifies if the timer is working with absolute or relative time values. Two constants are available: HRTIMER_MODE_ABS and HRTIMER_MODE_REL.

Set a callback function with:

mytimer.function = my_callback;

Where my_callback is declared as:

enum hrtimer_restart my_callback(struct hrtimer *timer)

Start the timer with hrtimer_start:

struct ktime_t delay = ktime_set(5,0);
hrtimer_start(&mytimer, delay, CLOCK_MONOTONIC);

ktime_set initialize delay with 5 seconds and 0 nanoseconds.

Wait. The callback function will be called after 5s!

A full example

struct hrtimer mytimer;
ktime_t delay = ktime_set(5, 0);

enum hrtimer_restart my_callback(struct hrtimer *timer)
{
    printk("Hello from timer!n");
    return HRTIMER_NORESTART;
}

void ....()
{
    hrtimer_init(&mytimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
    mytimer.function = my_callback;

    hrtimer_start(&mytimer, delay, CLOCK_MONOTONIC);
}

Further reading

There is more functions related to the hrtimers. See incude/linux/hrtimer.h for a full list.
Other useful functions are:

int hrtimer_cancel(struct hrtimer *timer)
int hrtimer_try_to_cancel(struct hrtimer *timer)
int hrtimer_restart(struct hrtimer *timer)