четверг, 3 апреля 2008 г.

О туннелях в linux

Те, кто все-таки читал Linux Advanced Routing and Traffic Control HOWTO знают, что с помощью ip tunnel add можно создать ipip, gre или sit туннель. Но вчера случайно возник вопрос:
dpmmsrv:/home/stasikos# ip tun add gre0 local 192.168.20.250
ioctl: No buffer space available

Но:
dpmmsrv:/home/stasikos# ip tun sh
gre0: gre/ip remote any local any ttl inherit nopmtudisc

Да и вообще странно, что его нельзя удалить:

dpmmsrv:/home/stasikos# ip tun del gre0
ioctl: Operation not permitted


То же самое можно заметить, если вы создали ipip-туннель с именем tunl0, или sit-туннель с именем sit0.

Да, можно гуглить по этой ошибке. Скорее всего ответ вы найдете только в этой статье, если будете искать ответ на вопрос "как удалить tunl0".

Вот, ответ - по крайней мере до 2.6.22 (выше не проверял) - удалять туннели с именами tunl0, gre0, sit0 не удается.

Если почитать документацию к iproute2, можно заметить, что эти туннели называются "base devices". Это специальные устройства, у которых remote и local адреса устанавливаются в "any", и это конечный пункт для туннелированных пакетов, если они не попадают в критерии другого туннеля.
Туннель с другим именем с remote any local any создать нельзя. Нет, система не ругается, но туннель просто не создаст:
dpmmsrv:/home/stasikos# ip tun add gre1   
dpmmsrv:/home/stasikos# ip tun sh gre1
ioctl: No such device

Но если указать хотя-бы один адрес - ради бога, вот он:
dpmmsrv:/home/stasikos# ip tun add gre1 local 192.168.20.250
dpmmsrv:/home/stasikos# ip tun sh gre1
gre1: gre/ip remote any local 192.168.20.250 ttl inherit

Да, и такой туннель легко удаляется:
dpmmsrv:/home/stasikos# ip tun del gre1
dpmmsrv:/home/stasikos# ip tun sh gre1
ioctl: No such device


Полный ответ на этот вопрос есть в исходных кодах модулей ядра, которые и включают поддержку туннелирования. Откроем, например, net/ipv4/ip_gre.c.
В нем есть вот такие вот строки:
/* Fallback tunnel: no source, no destination, no key, no options */
static int ipgre_fb_tunnel_init(struct net_device *dev);

Вот это вот и есть gre0 устройство, которое создается при инициализации модуля:
(в __init)

ipgre_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0",
ipgre_tunnel_setup);

Причем в функциях конфигурирования и удаления туннелей мы заметим особые случаи попыток удаления и перенастройки этого fallback tunnel, которые и вызывают появление ошибки ioctl:Operation is not permitted:

case SIOCDELTUNNEL:
err = -EPERM;
if (!capable(CAP_NET_ADMIN))
goto done;

if (dev == ipgre_fb_tunnel_dev) {
err = -EFAULT;
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p
)))
goto done;
err = -ENOENT;
if ((t = ipgre_tunnel_locate(&p, 0)) == NULL)
goto done;
err = -EPERM;
if (t == ipgre_fb_tunnel_dev->priv)
goto done;
dev = t->dev;
}
err = unregister_netdevice(dev);
break;


Как раз где-то тут оно и намеренно выдает эту ошибку.

P.S. Ничего страшного в том что туннель останется, нет.


Комментариев нет:

Отправить комментарий