В реальной сети трафик окрашивается тремя способами – IPv4/IPv6 TOS(DSCP), MPLS TC Field (старое название MPLS EXP bits) и 802.1p. Поскольку mpls на текущий момент отсутствует в ванильном ядре, вопрос об окраске mpls-трафика на Linux пока нет смысла рассматривать.
В прошлой заметке было рассказано о том, как linux priority(он же internal priority или skb->priority) может быть использован для приоритезации трафика((!) а не раскраски его). В этой заметке будет рассмотрен вопрос о том, каким образом можно использовать linux priority(далее LP) для установки 802.1p(окраска трафика на втором(ethernet) уровне), а также будет показано как можно установить LP для конкретного локального процесса средством net_prio cgroup(а не с помощью классификации по типу трафика).
Использование 802.1p актуально, как минимум, в двух случаях:
– коммутатор, к которому подключен сервер(или где-то дальше) не умеет учитывать TOS/DSCP
– для раскраски non-IP трафика (например pppoe, arp)
Для написания статьи использовался дистрибутив Linux Ubuntu 14.04 (ядро 3.13.0-24.46)
802.1p: egress-qos-map, ingress-qos-map
К счастью, в тот раз не потребуется иметь дело с реальным оборудованием и патчкордами. Весь стенд состоит из linux машины с одним дополнительным netns. Базовые настройки:
# ip link add veth type veth peer name vethC //создание пары veth-интерфейсов и линка между ними # ip link add link veth name veth.100 type vlan id 100 //создание dot1Q-сабынтерфейса # ip link set veth up //поднятие veth-интерфейса # ifconfig veth.100 192.0.2.1/30 up //задание IP и поднятие сабынтерфейса # ip netns add C //создание дополнительного netns # ip link set vethC netns C //ассоциация интерфейса vethC с netns C # hostname C ; ip netns exec C bash //переход в netns C (выполнять в новом терминале, №2) C:~# ip link set vethC up C:~# ip link add link vethC name vethC.100 type vlan id 100 C:~# ifconfig vethC.100 192.0.2.2/30 up
Для задания маппинга между LP и 802.1p используется egress-qos-map. Например мы хотим сделать маппинг LP=6 в 802.1p=5 и посмотреть весь mapping:
# ip link set dev veth.100 type vlan egress-qos-map 6:5 # cat /proc/net/vlan/veth.100 veth.100 VID: 100 REORDER_HDR: 1 dev->priv_flags: 1 total frames received 428 total bytes received 16768 Broadcast/Multicast Rcvd 8 total frames transmitted 431 total bytes transmitted 23265 Device: veth INGRESS priority mappings: 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 EGRESS priority mappings: 6:5
(для всех остальные значения LP(кроме 6), значение 802.1p будет равно 0)
Теперь нужно сгенерировать трафик для которого LP равен 6 и, например, 2(для сравнения), сделаем это с помощью установки поля TOS. В соответствии с таблицей TOS->LP возьмём TOS=0x14(LP=6) и 0x08(LP=2)
# ping -Q 0x14 192.0.2.2 -c 1 # ping -Q 0x08 192.0.2.2 -c 1 C:~# tcpdump -i vethC -n -nn -v -s 0 -e 00:05:05.722468 62:08:9a:f6:d6:1a > da:a8:55:50:88:e7, ethertype 802.1Q (0x8100), length 102: vlan 100, p 5, ethertype IPv4, (tos 0x14, ttl 64, id 17390, offset 0, flags [DF], proto ICMP (1), length 84) 192.0.2.1 > 192.0.2.2: ICMP echo request, id 3446, seq 1, length 64 00:05:05.722489 da:a8:55:50:88:e7 > 62:08:9a:f6:d6:1a, ethertype 802.1Q (0x8100), length 102: vlan 100, p 0, ethertype IPv4, (tos 0x14, ttl 64, id 43594, offset 0, flags [none], proto ICMP (1), length 84) 192.0.2.2 > 192.0.2.1: ICMP echo reply, id 3446, seq 1, length 64 00:05:25.403153 62:08:9a:f6:d6:1a > da:a8:55:50:88:e7, ethertype 802.1Q (0x8100), length 102: vlan 100, p 0, ethertype IPv4, (tos 0x8, ttl 64, id 17391, offset 0, flags [DF], proto ICMP (1), length 84) 192.0.2.1 > 192.0.2.2: ICMP echo request, id 3447, seq 1, length 64 00:05:25.403181 da:a8:55:50:88:e7 > 62:08:9a:f6:d6:1a, ethertype 802.1Q (0x8100), length 102: vlan 100, p 0, ethertype IPv4, (tos 0x8, ttl 64, id 43595, offset 0, flags [none], proto ICMP (1), length 84) 192.0.2.2 > 192.0.2.1: ICMP echo reply, id 3447, seq 1, length 64
Как видно из подсвеченных строчек, 802.1p маркировка установлена для TOS=0x14 и не установлена(равна 0) для TOS=0x08. icmp-reply для TOS=0x14 идёт без 802.1p маркировки потому что для интерфейса vethC.100(с которого уходит ответ) не задан egress-qos-map.
Теперь используем ingress-qos-map для задания LP тому или иному значению 802.1p, который потом можно учитывать. Воспользуемся ранее заданным egress-qos-map для интерфейса veth.100 (6:5), а на ответном интерфейсе(vethC.100) установим ingress-qos-map 5:4 (т.е. для трафика, приходящего с 802.1p=5 LP будет равен 4) и посчитаем трафик с LP=4 с помощью nftables(не смотря на то, что nftables присутствует в ядре 3.13, user space утилита для его конфигурирования отсутсвует в ubuntu 14.04, её можно собрать или взять из user-ppa).
C:~# ip link set dev vethC.100 type vlan ingress-qos-map 5:4 C:~# /etc/nftables/ipv4-filter //инициализация nftables filter C:~# nft add rule ip filter input meta priority 5 iifname vethC.100 counter C:~# nft add rule ip filter input meta priority 4 iifname vethC.100 counter C:~# nft add rule ip filter input meta priority 0 iifname vethC.100 counter # ping -Q 0x14 192.0.2.2 -c 2 //трафик уходит с veth.100 в строну vethC.100 с 802.1p=5 # ping -Q 0 192.0.2.2 -c 1 C:~# nft list table filter table ip filter { chain input { type filter hook input priority 0; meta priority :0005 iifname "vethC.100" counter packets 0 bytes 0 meta priority :0004 iifname "vethC.100" counter packets 2 bytes 168 meta priority none :0000 iifname "vethC.100" counter packets 1 bytes 84 } ... }
net_prio cgroup
Cgroups в Linux это механизм применения какого-либо ограничения или действия к группе процессов(ограничивать по памяти/cpu, изолировать друг от друга, осуществлять приоритезацию/классификацию трафика). По отношению к трафику есть 2 cgroup – net_cls и net_prio. Как видно из заголовка, речь пойдёт о net_prio.
# modprobe netprio_cgroup //загрузка модуля ядра # mkdir /sys/fs/cgroup/net_prio //точка монтирования cgroup # mount -t cgroup -o net_prio none /sys/fs/cgroup/net_prio //монтирование net_prio cgroup # cd /sys/fs/cgroup/net_prio ; mkdir LP6 ; cd LP6 //создание группы процессов с названием LP6 # echo "veth.100 6" > net_prio.ifpriomap //Для всего трафика, уходящего в интерфейс veth.100 от процессов этой группы устанавливать LP=6 # cat net_prio.ifpriomap //просмотр карты приоритетов lo 0 eth0 0 veth 0 veth.100 6
Для того, чтобы ассоциировать процесс с cgroup можно его запускать с помощью cgexec:
# cgexec -g net_prio:LP6 ping 192.0.2.2 -c 1 PING 192.0.2.2 (192.0.2.2) 56(84) bytes of data. 64 bytes from 192.0.2.2: icmp_seq=1 ttl=64 time=0.044 ms C:~# tcpdump -i vethC -e -v -n -s 0 14:56:20.767687 62:08:9a:f6:d6:1a > da:a8:55:50:88:e7, ethertype 802.1Q (0x8100), length 102: vlan 100, p 5, ethertype IPv4, (tos 0x0, ttl 64, id 17410, offset 0, flags [DF], proto ICMP (1), length 84) 192.0.2.1 > 192.0.2.2: ICMP echo request, id 32311, seq 1, length 64 14:56:20.767714 da:a8:55:50:88:e7 > 62:08:9a:f6:d6:1a, ethertype 802.1Q (0x8100), length 102: vlan 100, p 0, ethertype IPv4, (tos 0x0, ttl 64, id 43614, offset 0, flags [none], proto ICMP (1), length 84) 192.0.2.2 > 192.0.2.1: ICMP echo reply, id 32311, seq 1, length 64
Второй способ – ассоциация запущенного процесса с net_prio cgroup:
# echo TASK_PID > /sys/fs/cgroup/net_prio/LP6/tasks
Чтобы посмотреть к каким cgroup принадлежит тот или иной процесс есть псевдофайл cgroup:
# cat /proc/32313/cgroup 12:hugetlb:/ 11:perf_event:/ 10:blkio:/ 9:freezer:/ 8:devices:/ 7:memory:/ 6:cpuacct:/ 5:cpu:/ 4:cpuset:/ 3:net_prio:/LP6 2:name=systemd:/user/1000.user/1.session
Важно понимать, что net_prio cgroup это способ задания не 802.1p, а LP(linux priority). Применение этого механизма для задания 802.1p лишь один из возможных сценариев использования.
Pingback: QoS в Linux: pfifo, prio, tc filter, SO_PRIORITY socket | Net-Labs.in