простой виртуальный сетевой интерфейс

Вопросы программного кода и архитектуры Linux

Модератор: Olej

bose
Писатель
Сообщения: 107
Зарегистрирован: 23 фев 2012, 14:41
Откуда: Киев
Контактная информация:

Re: простой виртуальный сетевой интерфейс

Непрочитанное сообщение bose » 09 апр 2012, 13:16

Olej писал(а): Возможно раньше там было описание массивом
Так и есть - http://lxr.free-electrons.com/source/in ... .6.28#L637
Начиная с 2.6.31 - там указатель

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: простой виртуальный сетевой интерфейс

Непрочитанное сообщение Olej » 09 апр 2012, 13:57

bose писал(а):
Olej писал(а): Возможно раньше там было описание массивом
Так и есть - http://lxr.free-electrons.com/source/in ... .6.28#L637
Начиная с 2.6.31 - там указатель
... и код примера модуля поплыл :-?

Ну, с этой особенностью разобрались.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: простой виртуальный сетевой интерфейс

Непрочитанное сообщение Olej » 09 апр 2012, 14:03

Olej писал(а):Ну, с этой особенностью разобрались.
... а также с различными вариантами размещения структуры статистики сетевого интерфейса, о чём говорилось viewtopic.php?f=18&t=1624&start=30#p3587.

Архив на этом этапе с 3-мя вариантами использования статистики прилагается.
virt.tgz
(5.13 КБ) 490 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: простой виртуальный сетевой интерфейс

Непрочитанное сообщение Olej » 09 апр 2012, 14:16

Olej писал(а):
Olej писал(а):Ну, с этой особенностью разобрались.
... а также с различными вариантами
Но тут есть ещё над чем поработать...
Новый виртуальный интерфейс замещает тот физический, на котором он установлен:
- вот был физический интерфейс:

Код: Выделить всё

[olej@fedora16vm virt.2]$ ip addr show dev p7p1
3: p7p1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:9e:02:02 brd ff:ff:ff:ff:ff:ff
    inet 192.168.56.101/24 brd 192.168.56.255 scope global p7p1
    inet6 fe80::a00:27ff:fe9e:202/64 scope link 
       valid_lft forever preferred_lft forever
[olej@fedora16vm virt.2]$ ping 192.168.56.1
PING 192.168.56.1 (192.168.56.1) 56(84) bytes of data.
64 bytes from 192.168.56.1: icmp_req=1 ttl=64 time=0.224 ms
64 bytes from 192.168.56.1: icmp_req=2 ttl=64 time=0.210 ms
^C
--- 192.168.56.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.210/0.217/0.224/0.007 ms

- на него устанавливаем виртуальный:

Код: Выделить всё

[olej@fedora16vm virt.2]$ sudo insmod ./virt.ko link=p7p1
[olej@fedora16vm virt.2]$ sudo ifconfig virt0 192.168.50.2
[olej@fedora16vm virt.2]$ ip addr show dev virt0
6: virt0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
    link/ether 08:00:27:9e:02:02 brd ff:ff:ff:ff:ff:ff
    inet 192.168.50.2/24 brd 192.168.50.255 scope global virt0
    inet6 fe80::a00:27ff:fe9e:202/64 scope link 
       valid_lft forever preferred_lft forever
[olej@fedora16vm virt.2]$ ping 192.168.50.1
PING 192.168.50.1 (192.168.50.1) 56(84) bytes of data.
64 bytes from 192.168.50.1: icmp_req=1 ttl=64 time=0.248 ms
64 bytes from 192.168.50.1: icmp_req=2 ttl=64 time=0.198 ms
^C
--- 192.168.50.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.198/0.223/0.248/0.025 ms
- всё работает ... я уже показывал через такой интерфейс установление и работу ssh-сессии ... что может быть убедительнее?
- но:

Код: Выделить всё

[olej@fedora16vm virt.2]$ ping 192.168.56.1
PING 192.168.56.1 (192.168.56.1) 56(84) bytes of data.
^C
--- 192.168.56.1 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2001ms
- родительский интерфейс - подменён.
- стоит убрать виртуальный и всё восстановится:

Код: Выделить всё

[olej@fedora16vm virt.2]$ sudo rmmod virt
[olej@fedora16vm virt.2]$ ping 192.168.56.1
PING 192.168.56.1 (192.168.56.1) 56(84) bytes of data.
64 bytes from 192.168.56.1: icmp_req=1 ttl=64 time=0.313 ms
64 bytes from 192.168.56.1: icmp_req=2 ttl=64 time=0.179 ms
64 bytes from 192.168.56.1: icmp_req=3 ttl=64 time=0.193 ms
^C
--- 192.168.56.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.179/0.228/0.313/0.061 ms
- а нужно бы, чтобы они (реальный и виртуальный), работая в разных подсетках (см. выше) работали одновременно, дополняли друг друга, а не замещали.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: простой виртуальный сетевой интерфейс

Непрочитанное сообщение Olej » 09 апр 2012, 14:21

Olej писал(а):- а нужно бы, чтобы они (реальный и виртуальный), работая в разных подсетках (см. выше) работали одновременно, дополняли друг друга, а не замещали.
И здесь всё понятно - новый интерфейс перехватывает весь входящий трафик:

Код: Выделить всё

static rx_handler_result_t handle_frame( struct sk_buff **pskb ) {
   struct sk_buff *skb = *pskb;
   if( child ) {
      struct priv *priv = netdev_priv( child );
      priv->stats.rx_packets++;
      priv->stats.rx_bytes += skb->len;
      LOG( "rx: injecting frame from %s to %s", skb->dev->name, child->name );
      skb->dev = child;
      return RX_HANDLER_ANOTHER;
   }
   return RX_HANDLER_PASS;
}
А нужно сделать, чтобы он перехватывал только трафик, направляемый непосредсвенно ему.
(а "не свои" просто не трогать)

Единственная неприятность (сложность, громоздкость) здесь в том, что фильтровать (по содержимому) нужно пакеты (struct sk_buff) 2-х сортов: а). IP пакеты + б). ARP-пакеты разрешения адресов ... причём ARP - в первую очередь (при том, что IP проще), иначе IP просто не дойдут до приёма.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: простой виртуальный сетевой интерфейс

Непрочитанное сообщение Olej » 09 апр 2012, 21:01

Вопрос к залу! (можно высказывать любые предположения)

Где? в структуре сетевого интерфейса (struct net_device) зашит IP адрес после выполнения над ним:

Код: Выделить всё

# ifconfig virt0 192.168.50.2
Где IP (оба) в структуре сокетного буфера (struct sk_buff) и как его достать - это понятно, так же как понятно как оттуда и ARP извлечь.
А вот с struct net_device - хуже :cry:

Адресные поля в описании struct net_device :

Код: Выделить всё

        unsigned char           perm_addr[MAX_ADDR_LEN]; // permanent hw address 
        unsigned char           addr_assign_type;        // hw address assignment type 
        unsigned char           addr_len;                // hardware address length      
        unsigned short          dev_id;                  // for shared network cards 

- это как я предполагаю - MAC, и то что я проверил, так это то, что addr_len = 6.

Это

Код: Выделить всё

        spinlock_t              addr_list_lock;
        struct netdev_hw_addr_list      uc;     /* Unicast mac addresses */
        struct netdev_hw_addr_list      mc;     /* Multicast mac addresses */
- нужно думать, то же...

Есть какие-то соображения?
Или, может, IP вообще не содержится в struct net_device?
Тем более, что IP должны бы содержаться списком - у интерфейса может быть куча алиасных IP.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: простой виртуальный сетевой интерфейс

Непрочитанное сообщение Olej » 09 апр 2012, 21:47

Olej писал(а): Или, может, IP вообще не содержится в struct net_device?
Так и есть!
Смущало то, что в заголовках даже 2.6.36 (http://lxr.free-electrons.com/source/in ... .6.36#L637) было безумно содержательно:

Код: Выделить всё

      /* Protocol specific pointers */
619         
620 #ifdef CONFIG_NET_DSA
621         void                    *dsa_ptr;       /* dsa specific data */
622 #endif
623         void                    *atalk_ptr;     /* AppleTalk link       */
624         void                    *ip_ptr;        /* IPv4 specific data   */  
...
И только позже, с 2.6.37, появляется внятное написание того, что из себя этот void* представляет.
Вот из 2.6.42 :

Код: Выделить всё

        /* Protocol specific pointers */
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
        struct vlan_group __rcu *vlgrp;         /* VLAN group */
#endif
#ifdef CONFIG_NET_DSA
        void                    *dsa_ptr;       /* dsa specific data */
#endif
        void                    *atalk_ptr;     /* AppleTalk link       */
        struct in_device __rcu  *ip_ptr;        /* IPv4 specific data   */
        struct dn_dev __rcu     *dn_ptr;        /* DECnet specific data */
        struct inet6_dev __rcu  *ip6_ptr;       /* IPv6 specific data */
        void                    *ec_ptr;        /* Econet specific data */
        void                    *ax25_ptr;      /* AX.25 specific data */
        struct wireless_dev     *ieee80211_ptr; /* IEEE 802.11 specific data,
                                                   assign before registering */
А далее: " ... в курице яйцо, в яйце игла ... "
<linux/inetdevice.h>:

Код: Выделить всё

struct in_device {
...
        struct in_ifaddr        *ifa_list;      /* IP ifaddr chain              */
...
}

Код: Выделить всё

struct in_ifaddr {
...
        __be32                  ifa_address;
        __be32                  ifa_mask;
        __be32                  ifa_broadcast;
...
}
Вот это оно и есть...

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: простой виртуальный сетевой интерфейс

Непрочитанное сообщение Olej » 10 апр 2012, 00:41

Olej писал(а):
Olej писал(а):- а нужно бы, чтобы они (реальный и виртуальный), работая в разных подсетках (см. выше) работали одновременно, дополняли друг друга, а не замещали.
А нужно сделать, чтобы он перехватывал только трафик, направляемый непосредсвенно ему.
(а "не свои" просто не трогать)
Сделано!
(интересующиеся могут взять в приложении поиграться)

Код: Выделить всё

[olej@fedora16vm virt]$ sudo insmod ./virt.ko link=p7p1 debug=1
(debug=1 - будет детальная пооперационная отладочная информация в лог)

Код: Выделить всё

[olej@fedora16vm virt]$ sudo ifconfig virt0 192.168.50.2
[olej@fedora16vm virt]$ dmesg | tail -n26
[58354.983782] ! module virt loaded
[58354.983785] ! virt: create link virt0
[58354.983786] ! virt: registered rx handler for p7p1
[58371.480100] ! virt0: device opened
[58371.480103] ! virt0: 192.168.50.2:255.255.255.0
[58371.482183] ! tx: injecting frame from virt0 to p7p1
[58371.482230] ! tx: injecting frame from virt0 to p7p1
...
интерфейс virt0 (192.168.50.2) сидит на аппаратном MAC интерфейса p7p1 (192.168.56.101)
P.S. никаких иных телодвижений для запуска модуля в работу (с таблицей роутинга и т.п.) - не нужно.

Снаружи (из LAN):

Код: Выделить всё

[olej@nvidia ~]$ ping 192.168.50.2
PING 192.168.50.2 (192.168.50.2) 56(84) bytes of data.
64 bytes from 192.168.50.2: icmp_req=1 ttl=64 time=0.473 ms
64 bytes from 192.168.50.2: icmp_req=2 ttl=64 time=0.256 ms
64 bytes from 192.168.50.2: icmp_req=3 ttl=64 time=0.281 ms
^C
--- 192.168.50.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.256/0.336/0.473/0.099 ms
[olej@nvidia ~]$ ping 192.168.56.101
PING 192.168.56.101 (192.168.56.101) 56(84) bytes of data.
64 bytes from 192.168.56.101: icmp_req=1 ttl=64 time=2.63 ms
64 bytes from 192.168.56.101: icmp_req=2 ttl=64 time=0.306 ms
64 bytes from 192.168.56.101: icmp_req=3 ttl=64 time=0.225 ms
^C
--- 192.168.56.101 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 0.225/1.053/2.630/1.115 ms
и наоборот, из virt0 в LAN:

Код: Выделить всё

[olej@fedora16vm virt]$ ping 192.168.50.1
PING 192.168.50.1 (192.168.50.1) 56(84) bytes of data.
64 bytes from 192.168.50.1: icmp_req=1 ttl=64 time=0.416 ms
64 bytes from 192.168.50.1: icmp_req=2 ttl=64 time=0.238 ms
64 bytes from 192.168.50.1: icmp_req=3 ttl=64 time=0.406 ms
^C
--- 192.168.50.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.238/0.353/0.416/0.083 ms
Модуль при этом (3-х пингах) видел:

Код: Выделить всё

[olej@fedora16vm virt]$ dmesg | tail -n30
[58391.368273] device virt0 entered promiscuous mode
[58409.904046] ! rx: IP4 to IP=192.168.50.2
[58409.904050] ! rx: injecting frame from p7p1 to virt0
[58409.904197] ! tx: injecting frame from virt0 to p7p1
[58409.904212] ! rx: ARP for 192.168.50.2
[58409.904214] ! rx: injecting frame from p7p1 to virt0
[58409.904262] ! tx: injecting frame from virt0 to p7p1
[58410.903427] ! rx: IP4 to IP=192.168.50.2
[58410.903431] ! rx: injecting frame from p7p1 to virt0
[58410.903531] ! tx: injecting frame from virt0 to p7p1
[58411.903447] ! rx: IP4 to IP=192.168.50.2
[58411.903451] ! rx: injecting frame from p7p1 to virt0
[58411.903547] ! tx: injecting frame from virt0 to p7p1
[58414.694485] ! rx: ARP for 192.168.56.101
[58414.696846] ! rx: IP4 to IP=192.168.56.101
[58415.696508] ! rx: IP4 to IP=192.168.56.101
[58416.696572] ! rx: IP4 to IP=192.168.56.101
[58419.712245] ! rx: ARP for 192.168.56.101
[58471.908318] ! tx: injecting frame from virt0 to p7p1
[58471.908329] ! rx: IP4 to IP=192.168.50.2
[58471.908330] ! rx: injecting frame from p7p1 to virt0
[58472.909327] ! tx: injecting frame from virt0 to p7p1
[58472.909354] ! rx: IP4 to IP=192.168.50.2
[58472.909357] ! rx: injecting frame from p7p1 to virt0
[58473.909450] ! tx: injecting frame from virt0 to p7p1
[58473.909639] ! rx: IP4 to IP=192.168.50.2
[58473.909642] ! rx: injecting frame from p7p1 to virt0
[58476.911445] ! rx: ARP for 192.168.50.2
[58476.911449] ! rx: injecting frame from p7p1 to virt0
[58476.911525] ! tx: injecting frame from virt0 to p7p1
- в отладке отлично видны ARP и IP4, их направления по адресам и т.д.

2 интерфейса (реальный и виртуальный, родительский и дочерний) - работают параллельно и независимо.
P.S. предполагаю (повозившись со структурой), что их может быть и не 2, а сколько угодно, навешанных гроздью друг на друга.
Вложения
virt-full.tgz
(4.02 КБ) 440 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: простой виртуальный сетевой интерфейс

Непрочитанное сообщение Olej » 10 апр 2012, 00:47

Olej писал(а):2 интерфейса (реальный и виртуальный, родительский и дочерний) - работают параллельно и независимо.
P.S. предполагаю (повозившись со структурой), что их может быть и не 2, а сколько угодно, навешанных гроздью друг на друга.
Вот таким образом получается замечательный отладочный стенд для сетевых проектов (модулей, драйверов):
- обычная проблема - откуда брать и куда направлять сетевой трафик...
- наличие специального оборудования для отработки - это достаточно редкая роскошь ;-)
- теперь можно "навесить" свой интерфейс поверх любого существующего (реального или виртуального), и отрабатывать на нём сетевую алгоритмику.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: простой виртуальный сетевой интерфейс

Непрочитанное сообщение Olej » 24 май 2012, 14:51

И всё-таки сильно интересно, как сделать дополнительный виртуальный интерфейс без использования netdev_rx_handler_register(), который появился только с 2.6.37?
Ведь виртуальные интерфейсы создавались задолго до 2.6.37? ... в том же Cisco-клиент VPN (2.6.30)... и мн.др.

То, что обсуждалось вот здесь: viewtopic.php?f=18&t=1624&start=40#p3838, но как-то потом заглохло ... по причине отсутствия участников разговора :lol:

Тот же Cisco-клиент VPN, как я глянул поверхностно, похоже использует обработку (искажение) пакетов на сетевом уровне.
Т.е., возможно, для таких дел можно использовать dev_add_pack(), как о том уже затрагивалось в обсуждениях.

P.S. Вот то, что на этой странице: http://rus-linux.net/MyLDP/BOOKS/Moduli ... 05-14.html, только при гораздо более изощрённой работе с struct packet_type (так же как и в показанном раньше примере, по отдельности обрабатывая буфера сокетов ARP и IP4).
Нужно будет поэкспериментировать.

Ответить

Вернуться в «Linux изнутри»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 5 гостей