Sat, Jan 16, 2016

openSUSE :: MySQL & Ruby

Наконец-таки нашел немного времени для знакомства с Ruby. Присматривался к нему уже наверное лет 5. Сначала SUSE стала создавать свои web сервисы на Ruby, потом вышел WebYaST… Что связанно с SUSE, Ruby исползуется повсеместно. Наконец и YaST был переписан на Ruby, а это значит, что openSUSE стал первым дистрибутивом, где установщик полностью написан на этом языке. Сегодня его просто нельзя уже игнорировать. Итак, я собираюсь начать восхождение как можно быстрее. Вы со мной? 🙂

Я покажу, что Leap 42.1 прекрасно подходит для изучения Ruby. В качестве примера рассмотрим работу с MySQL (на работе мне постоянно приходится писать автономные программы, поведение которых зависит от данных в БД); что-нибудь самое простое.

Если вы уже работали с БД, к примеру, в Python или Lisp, то приведенный ниже код поймете сразу. Require подключает модуль mysql. Мы создаем mysql-объект con. С помошью его метода query создаем SQL-запрос. Пробегаемся по выводу при помощи each do, при этом каждой строке из вывода присваиваем имя row. Я использую puts для вывода информации на экран. В Ruby есть и всем известный print. Разница в том, что puts добавляет символ новой строки в конец вывода, а вот print этого не делает. 14-16 строки обрабатывают ошибку (показывают ее вывод, но программа продолжает работу), если такая возникнет при попытке соединиться и получить данные. В конце мы вызываем close, который закрывает соединине.

#!/usr/bin/ruby
require 'mysql'

begin
    con = Mysql::new('10.10.10.10',
                     'login',
                     'password',
                     'centreon')

    con.query('SHOW columns FROM nagios_server').each do |row|
         puts "#{row[0]} #{row[1]} #{row[2]} #{row[3]}"
    end

    rescue Mysql::Error => e
        puts e.errno
        puts e.error
    ensure
        con.close if con
end

При первом запуске (используем свежую Leap 42.1 x86_64) получаем ошибку:

> ./mysql-test.rb
/usr/lib64/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55: \
                   in `require': cannot load such file -- mysql (LoadError)
        from /usr/lib64/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from ./mysql-test.rb:2:in `'

Тут все понятно: require не может найти mysql. Для установки воспользуемся gem. Это аналог Lisp’овского QuickLisp или Python’овского pip.

> gem --help
RubyGems is a sophisticated package manager for Ruby.  This is a
basic help message containing pointers to more information.

  Usage:
    gem -h/--help
    gem -v/--version
    gem command [arguments...] [options...]

  Examples:
    gem install rake
    gem list --local
    gem build package.gemspec
    gem help install

  Further help:
    gem help commands            list all 'gem' commands
    gem help examples            show some examples of usage
    gem help platforms           show information about platforms
    gem help                     show help on COMMAND
                                   (e.g. 'gem help install')
    gem server                   present a web page at
                                 http://localhost:8808/
                                 with info about installed gems
  Further information:
    http://guides.rubygems.org

> gem list --local mysql

*** LOCAL GEMS ***


>

Нет ни одной установленной в системе mysql gem.
Обратите внимание на вывод gem’овской help – для команды list сказано только по поводу –local аргумента. Там есть еще –remote. Последний покажет доступные для установки gem’ы. Я не привожу тут вывод, потому что список слишком большой.
Для установки воспользуемся командой install:

# gem install mysql
Fetching: mysql-2.9.1.gem (100%)
Building native extensions.  This could take a while...
                 
ERROR:  Error installing mysql:
ERROR: Failed to build gem native extension.
/usr/bin/ruby.ruby2.1 extconf.rb
mkmf.rb can't find header files for ruby at /usr/lib64/ruby/include/ruby.h
extconf failed, exit code 1 

Gem files will remain installed in
/usr/lib64/ruby/gems/2.1.0/gems/mysql-2.9.1 for inspection.
Results logged to
/usr/lib64/ruby/gems/2.1.0/extensions/x86_64-linux/2.1.0/mysql-2.9.1/gem_make.out 

И я вам скажу честно – так происходит со многоими gem’ами 🙂

Но на самом деле ничего страшного не случилось. Дело в том, что gem’у нужен файл из RPM-пакета. Какого-то RPM пакета… Вызывать zypper нам придется самим. Какой пакет устанавливать? Мне повезло, я вспомнил, что один RPM-пакет нужно было доустановить и в случае с Common Lisp. В том случае это был libmysqlclient, для Ruby же нужен libmysqlclient-devel. Очень рекомендую еще поставить пакет ruby-devel и весь pattern devel_basis. Там много библиотек, необходимых интерпретору.

> sudo zypper in -t pattern devel_basis
> sudo zypper in ruby-devel libmysqlclient-devel

После этого попытаемся установить mysql gem снова:

> gem install mysql
Building native extensions.  This could take a while...
Successfully installed mysql-2.9.1
Parsing documentation for mysql-2.9.1
Installing ri documentation for mysql-2.9.1
Done installing documentation for mysql after 0 seconds
1 gem installed

> echo $?
0

> gem list --local mysql

*** LOCAL GEMS ***

mysql (2.9.1)

Выглядит лучше, правда? Теперь вернемся к коду выше. Придумайте для теста какой-нибудь простой SQL запрос. Что-нибудь типа show tables, к примеру. Вывод скрипта, приведенного выше, выглядит так:

./mysql-test.rb
id int(11) NO PRI
name varchar(40) YES 
localhost enum('0','1') YES 
is_default int(11) YES 
last_restart int(11) YES 
ns_ip_address varchar(255) YES 
ns_activate enum('1','0') YES 
ns_status enum('0','1','2','3','4') YES 
init_script varchar(255) YES 
monitoring_engine varchar(20) YES 
nagios_bin varchar(255) YES 
nagiostats_bin varchar(255) YES 
nagios_perfdata varchar(255) YES 
centreonbroker_cfg_path varchar(255) YES 
centreonbroker_module_path varchar(255) YES 
centreonconnector_path varchar(255) YES 
ssh_port int(11) YES 
ssh_private_key varchar(255) YES 
init_script_snmptt varchar(255) YES 

Для сравнения, вот так выглядит вывод нашего SQL запроса в mysql(1):

> SHOW columns FROM nagios_server;
+----------------------------+---------------------------+------+-----+---------+
| Field                      | Type                      | Null | Key | Default |
+----------------------------+---------------------------+------+-----+---------+
| id                         | int(11)                   | NO   | PRI | NULL    |
| name                       | varchar(40)               | YES  |     | NULL    |
| localhost                  | enum('0','1')             | YES  |     | NULL    |
| is_default                 | int(11)                   | YES  |     | 0       |
| last_restart               | int(11)                   | YES  |     | NULL    |
| ns_ip_address              | varchar(255)              | YES  |     | NULL    |
| ns_activate                | enum('1','0')             | YES  |     | 1       |
| ns_status                  | enum('0','1','2','3','4') | YES  |     | 0       |                         
| init_script                | varchar(255)              | YES  |     | NULL    |                              
| monitoring_engine          | varchar(20)               | YES  |     | NULL    |                
| nagios_bin                 | varchar(255)              | YES  |     | NULL    |                    
| nagiostats_bin             | varchar(255)              | YES  |     | NULL    |                                 
| nagios_perfdata            | varchar(255)              | YES  |     | NULL    |                                  
| centreonbroker_cfg_path    | varchar(255)              | YES  |     | NULL    |                                          
| centreonbroker_module_path | varchar(255)              | YES  |     | NULL    |                                  
| centreonconnector_path     | varchar(255)              | YES  |     | NULL    |                                   
| ssh_port                   | int(11)                   | YES  |     | NULL    |                                           
| ssh_private_key            | varchar(255)              | YES  |     | NULL    |                              
| init_script_snmptt         | varchar(255)              | YES  |     | NULL    |                                              
+----------------------------+---------------------------+------+-----+---------+
19 rows in set (0.00 sec)

Вот так выглядит мой первый шаг изучения Ruby. После опробывания парочки других библиотек (например SNMP, threading или SMTP), нужно браться за изучения типов данных. Это основа языка. Если приницип работы библиотек практически 1:1 как и в Python, то к отличиям типов данных стоит отнестись серьезнее. Еще меня интересует стиль языка, а именно функциональная парадигма. Ходят слухи, что на нем легче писать функциональный код, чем на python. В этом мне еще только придется убедиться.

На последок скажу, что открытой документации по Ruby очень много. Все больше и больше документации появляется сейчас и на русском. Удачи в изучении. Счастливо 😉

Tue, Jan 12, 2016

Некоторые исправления для OpenSUSE 42.1

1. При загрузке ядра система зависает намертво и… через 20 минут всё таки грузится. В 13.2 наблюдал такое на ядре kernel-desktop и лечил это тогда переходом на kernel-default. В OpenSUSE 42.1 нет в образе такого выбора ядер, а новый kernel-default стал зависать при загрузке именно так. Решение нашлось очень простое: к параметрам загрузки ядра нужно добавить dis_ucode_ldr. Нашёл тут.

2. На некоторых машинах система время от времени зависает сама и без видимых причин. В dmesg такое:

[   35.962355] systemd-journald[525]: File /var/log/journal/fde0e1438648364a342657f95654294e/user-1000.journal corrupted or uncleanly shut down, renaming and replacing.

Заметил, что проблема имеется только тогда, когда /var примонтирован на отдельном разделе (именно так предлагается по умолчанию при установке 42.1). Удалось вылечить следующим образом:

su -
rm -rf /var/log/*
systemctl daemon-reload
reboot

Из того, что пока не удалось починить:

  1. При обновлении/установки ядра, создание initrd и обновление загрузчика занимает очень много времени (у меня — 40 минут). Опять же — только на некоторых конфигурациях, когда в системе определённое сочетание дисков с MBR и GPT.
  2. В Plasma 5 полная неразбериха в системном лотке. К тому же так и не починено отображение значка Dropbox. Xembed-sni-proxy не помогает.

В целом, OpenSUSE 42.1 — один из самых глючных и небрежно сделанных релизов OpenSUSE, что, безусловно, расстраивает. Я рассчитывал на качественную сборку KDE Plasma 5, но пока получается, что лучше всего Plasma 5 собрана в Rosa Desktop Fresh R6. Кстати, свежий образ системы «на посмотреть» можно взять тут.

 

Wed, Oct 28, 2015

qt4-fsarchiver — backup для ленивых

Раньше часто недооценивал backup, за что неоднократно поплатился временем. Да, приобрел много ценного опыта, но лучше бы это не на своей системе, а где нибудь … в другом месте. И теперь стараюсь делать запасы, особенно перед всякими экспериментами, которые по прежнему люблю.
Для себя лично нашел прекрасную программу, которая делает backup прямо на рабочей системе — qt4-fsarchiver. Это графическая оболочка для другой прекрасной программы — fsarchiver — с помощью которой в командной строке можно делать то же самое, а если написать скрипты, то это вообще просто. Но для написания скриптов нужно изучать параметры программы, и не всегда всё гладко получается (раньше пытался работать этой программой с live-cd, иногда бывали неприятности). А с qt4-fsarchiver все достаточно просто — выбираем что архивировать (раздел), куда архивировать, каким алгоритмом и степерь сжатия, нажимаем старт — и все, через пару часов (а то и меньше, в зависимости от размера раздела, у меня уходить минут 20 из-за ssd-диска и легких алгоритмов сжатия) backup готов. Так что если вы простой пользователь opensuse linux, как и я — программа подходит для вас на все 100%

Mon, Oct 12, 2015

Настройка звука в конфигурации с несколькими одинаковыми звуковыми картами

Имеется следующая конфигурация. Два звуковых устройства, оба управляются одним и тем же модулем snd-hda-intel. Первое устройство отвечает за звуковой канал в HDMI, встроенной в процессор графической системы. Второй устройство — обычный интегрированный на материнскую плату аудио-контроллер.
00:03.0 Audio device [0403]: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller [8086:0c0c] (rev 06)
00:1b.0 Audio device [0403]: Intel Corporation 9 Series Chipset Family HD Audio Controller [8086:8ca0]
Пользователи жалуются, что звук не работает. Проблема состоит в том, что YaST создаёт следующую конфигурацию в 50-sound.conf:
options snd slots=snd-hda-intel,snd-hda-intel
alias snd-card-0 snd-hda-intel
alias snd-card-1 snd-hda-intel
Здесь snd-card-0 — звуковое устройство "по умолчанию". Очевидно, что в таком подходе ситуация, когда один и тот же модуль отвечает за два устройства, обрабатывается не корректно. Кто из устройств первый попал в функцию azx_probe модуля, тот и станет snd-card-0. В нашем случае, это не то устройство, которое нам хотелось бы. Это можно проверить, сделав
ls -l /sys/class/sound/card0/device
lrwxrwxrwx 1 root root 0 окт  9 21:36 /sys/class/sound/card0/device -> ../../../0000:00:03.0

Для восстановления правильного порядка предлагается делать следующее.
Во-первых, внимательно изучив исходники модуля, добавляем в 50-sound.conf:
options snd-hda-intel index=1,0
Во-вторых, надеемся, что при следующих загрузках порядок инициализации не будет меняться случайным образом, потому-что кто первый попадет в функцию azx_probe, тот теперь и будет card1. И это всё происходит в 2015 году, когда повсюду systemd и прочий udev, а звуковую карту за её DeviceId привязать нельзя.

Настройка звука в конфигурации с несколькими одинаковыми звуковыми картами

Имеется следующая конфигурация. Два звуковых устройства, оба управляются одним и тем же модулем snd-hda-intel. Первое устройство отвечает за звуковой канал в HDMI, встроенной в процессор графической системы. Второй устройство — обычный интегрированный на материнскую плату аудио-контроллер.
00:03.0 Audio device [0403]: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller [8086:0c0c] (rev 06)
00:1b.0 Audio device [0403]: Intel Corporation 9 Series Chipset Family HD Audio Controller [8086:8ca0]
Пользователи жалуются, что звук не работает. Проблема состоит в том, что YaST создаёт следующую конфигурацию в 50-sound.conf:
options snd slots=snd-hda-intel,snd-hda-intel
alias snd-card-0 snd-hda-intel
alias snd-card-1 snd-hda-intel
Здесь snd-card-0 — звуковое устройство "по умолчанию". Очевидно, что в таком подходе ситуация, когда один и тот же модуль отвечает за два устройства, обрабатывается не корректно. Кто из устройств первый попал в функцию azx_probe модуля, тот и станет snd-card-0. В нашем случае, это не то устройство, которое нам хотелось бы. Это можно проверить, сделав
ls -l /sys/class/sound/card0/device
lrwxrwxrwx 1 root root 0 окт 9 21:36 /sys/class/sound/card0/device -> ../../../0000:00:03.0

Для восстановления правильного порядка предлагается делать следующее.
Во-первых, внимательно изучив исходники модуля, добавляем в 50-sound.conf:
options snd-hda-intel index=1,0
Во-вторых, надеемся, что при следующих загрузках порядок инициализации не будет меняться случайным образом, потому-что кто первый попадет в функцию azx_probe, тот теперь и будет card1. И это всё происходит в 2015 году, когда повсюду systemd и прочий udev, а звуковую карту за её DeviceId привязать нельзя.

Sat, Sep 26, 2015

Ставим Popcorn-Time в OpenSUSE

Любопытно, но готового пакета с Popcorn-Time для OpenSUSE не нашлось во всей OBS. В сети имеется установочный скрипт, который по идее должен ставить приложение, но скрипт, увы, устарел и больше не работает. Если вы хотите поставить Popcorn-Time вручную, то это сделать совсем не сложно. Но гораздо удобнее всё же воспользоваться обновлённым скриптом, который я сделал. Скрипт протестирован на OpenSUSE 13.2 64 bit.

Скачать.

Mon, Aug 17, 2015

Удаленная сетевая консоль ядра Linux

Иногда, когда ядро Linux испытывает проблемы, одними из способов сбора отладочной информации являются консоль последовательного порта или сетевая консоль. Сразу обратим внимание, что второй вариант имеет как недостатки, например, предполагает, что сетевая подсистема ядра остается функциональной во время возникновения проблем, так и преимущества, например, можно сконфигурировать удаленно.

Полное описание сетевой консоли находится в документации ядра. Для настройки достаточно добавить в modprobe.d/99-local.conf:
options netconsole netconsole=@/,514@192.168.10.7/00:0C:29:F3:92:97
Здесь, 514 - номер UDP порта, 192.168.10.7 - IP удаленного хоста куда будет отсылаться информация, 00:0C:29:F3:92:97 - его MAC адрес, если его не указать явно то будет использоваться широковещательный адрес FF:FF:FF:FF:FF:FF, что может затруднить передачу информации в зависимости от настроек сетевого оборудования.
И загрузить модуль netconsole или, по желанию, поставить его на автозагрузку при старте системы.

После загрузки модуля netconsole, сетевая консоль начинает немедленно функционировать, а в системном журнале можно увидеть примерно следующее:
May  1 18:57:51 192.168.10.4 kernel: [162255.522603] netconsole: local port 6665
May  1 18:57:51 192.168.10.4 kernel: [162255.522673] netconsole: local IP 0.0.0.0
May  1 18:57:51 192.168.10.4 kernel: [162255.522710] netconsole: interface eth0
May  1 18:57:51 192.168.10.4 kernel: [162255.522746] netconsole: remote port 514
May  1 18:57:51 192.168.10.4 kernel: [162255.522784] netconsole: remote IP 192.168.10.7
May  1 18:57:51 192.168.10.4 kernel: [162255.522826] netconsole: remote ethernet address 00:0c:29:f3:92:97
May  1 18:57:51 192.168.10.4 kernel: [162255.522881] netconsole: local IP 192.168.10.4
May  1 18:57:51 192.168.10.4 kernel: [162255.523032] console [netcon0] enabled
May  1 18:57:51 192.168.10.4 kernel: [162255.523349] netconsole: network logging started

Данные приходят в самом простом текстовом виде и их можно читать самым простым способом:
netcat -u -l 514
Если у нас в наличии есть syslog-ng — можно использовать его следующим образом:
source s_remote_udp {
        network(transport("udp") ip(0.0.0.0) port(514));
};
filter f_remote_remhost {
        netmask(192.168.10.4);
};
destination d_remote_remhost {
        file("/var/log/remote/remhost.log");
};
log {
        source(s_remote_udp);
        filter(f_remote_remhost);
        destination(d_remote_remhost);
};

Проверить, что всё работает можно следующим образом:
echo '<7>Hello world!' > /dev/kmsg
dmesg -n 8
Сообщение должно появиться в журнале и быть передано по сети на удаленный хост.

Tue, Aug 11, 2015

Удаленная отладка ядра Linux

Ядро Linux периодически ломается, иногда это происходит на стадии загрузки. Одним из методов исследования проблемы является удаленная отладка с использованием последовательного порта.

Опции конфигурации ядра должны быть такими:
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
Кроме того, драйвер последовательного порта должен быть включен в состояние Y.

Далее нам понадобятся отладочные символы и исходные коды ядра, которые находятся в пакетах -debuginfo и -debugsource. Скорее всего, архитектуры удаленной и локальной системы не будут совпадать, так как особенно часто ядро Linux не работает на архитектуре armv7l, поэтому просто распакуем данные следующим образом:
> rpm2cpio kernel-default-base-debuginfo-4.2.rc4-1.1.gaf243bc.armv7hl.rpm | cpio -id
> rpm2cpio kernel-default-debuginfo-4.2.rc4-1.1.gaf243bc.armv7hl.rpm | cpio -id
> rpm2cpio kernel-default-debugsource-4.2.rc4-1.1.gaf243bc.armv7hl.rpm | cpio -id
В текущей директории будет создана поддиректория /usr содержащая отладочные символы и исходные коды в стандартной иерархии. Кроме того, нам понадобятся сами бинарные файлы ядра:
> rpm2cpio kernel-default-base-4.2.rc4-1.1.gaf243bc.armv7hl.rpm | cpio -id
> rpm2cpio kernel-default-4.2.rc4-1.1.gaf243bc.armv7hl.rpm | cpio -id

Далее, следует подключить последовательный порт, и открыть удаленную консоль следующим, например, образом:
> screen /dev/ttyUSB0 115200
и начать загрузку целевого устройства. Для активации механизма kgdb потребуется добавить параметры командной строки ядра в загрузчике:
U-Boot# setenv append "kgdboc=ttyO0,115200 kgdbwait"
U-Boot# boot

Если все пойдет правильно, то загрузка ядра остановится после примерно следующих строк:
[    3.753423] 44e09000.serial: ttyO0 at MMIO 0x44e09000 (irq = 154, base_baud = 3000000) is a OMAP UART0
[    4.497783] console [ttyO0] enabled
[    4.502387] STMicroelectronics ASC driver initialized
[    4.507960] KGDB: Registered I/O driver kgdboc
[    4.512673] KGDB: Waiting for connection from remote gdb...

Entering kdb (current=0xdb0b3480, pid 1) on processor 0 due to Keyboard Entry
[0]kdb> 
kdb ождает ввода команд, среди прочего доступна команда help, выводящая список базовых команд. На этом консоль можно закрыть: Ctrl-A :quit и открыть отладчик gdb.

Для начала установим пути к отладочным символам и исходным кодам и загрузим объектный файл ядра целевой системы (внимание, сначала этот файл нужно будет распаковать командой gz).
(gdb) set debug-file-directory /tmp/dbg/usr/lib/debug
(gdb) directory /tmp/dbg/usr/src/debug/kernel-default-4.2.rc4/linux-4.2-rc4/linux-obj
(gdb) file /tmp/dbg/boot/vmlinux-4.2.0-rc4-1.gaf243bc-default
Reading symbols from /tmp/dbg/boot/vmlinux-4.2.0-rc4-1.gaf243bc-default...Reading symbols from /tmp/dbg/usr/lib/debug/boot/vmlinux-4.2.0-rc4-1.gaf243bc-default.debug...done.
done.
После этого нужно подключиться к целевой системе:
(gdb) target remote /dev/ttyUSB0
Remote debugging using /dev/ttyUSB0
0xc031dc08 in arch_kgdb_breakpoint () at ../arch/arm/include/asm/outercache.h:142

Далее можно использовать отладчик как обычно. Через команду monitor доступны все команды из консоли kdb, среди них есть достаточно полезные, например dmesg или lsmod:
(gdb) monitor lsmod
Module                  Size  modstruct     Used by
musb_am335x             1431  0xbf000278    1  (Loading) 0xbf000000 [ ]
Обратите внимание, что команда lsmod любезно нам показывает адрес 0xbf000000, куда в памяти загружен модуль musb_am335x. Этот адрес нужен чтобы отлаживать код из модуля:
(gdb) add-symbol-file /tmp/dbg/lib/modules/4.2.0-rc4-1.gaf243bc-default/kernel/drivers/usb/musb/musb_am335x.ko 0xbf000000

Mon, May 11, 2015

Устойчивые имена сетевых интерфейсов

Разработчики systemd продолжают вести нас в светлое будущее. В udev уже давно реализован механизм Predictable Network Interface Names, который представляет из себя кусочек кода на C, заполняющий переменные ID_NET_NAME_* исходя из свойств расположения физического сетевого устройства.

Считается, что подобный подход дает больше информации, чем прибитие гвоздями имен интерфейсов eth? к MAC-адресам в 70-persistent-net.rules. Однако, не обходится без недостатков. Например, при запуске системы под гипервизором VMWare ESXi, единственный сетевой интерфейс у меня называется eno16777728. Устройства, определяемые в DTB для одноплатных компьютеров на базе ARM, не поддерживаются схемой именования и имеют обычные имена eth?. А при подключении USB устройств, типа мобильных телефонов или модемов, схема именования генерирует скорее неустойчивые имена, потому-что в имя входит расположение устройства на шине USB, которое изменится при следующем подключении, таким образом придется настраивать интерфейс заново, потому-что предыдущие сохраненные настройки будут относиться к интерфейсу с другим именем.

К счастью, udev заполняет переменную ID_NET_NAME_MAC, представляющую имя интерфейса, основанное исключительно на его MAC-адресе. По-умолчанию, эта переменная не используется, но можно поменять стандартное поведение для USB-устройств. Один способ - через настройку udev, второй - используя systemd.link, файл, используемый systemd, для конфигурации сетевых интерфейсов.

Создадим файл /etc/systemd/network/90-usb.link следуя инструкции:
[Match]
Path=*-usb-*
[Link]
NamePolicy=mac
Юнит-файл состоит из двух секций: [Match] для описания устройств к которым он относится и [Link] для описания того, что с ними делать. В примере выше мы просим systemd использовать политику именования основанную на MAC-адресах для всех устройств подключенных через USB. После выполнения systemctl daemon-reload можно подключить устройство и увидеть его интерфейс с именем enx112233445566. Достаточно длинное, но уникальное (в известных пределах) и не изменится при следующем подключении устройства.

Кроме изменения имени через systemd.link можно настроить WOL, MTU, ограничить скорость на интерфейсе, назначить устройству другой MAC-адрес.

Устойчивые имена сетевых интерфейсов

Разработчики systemd продолжают вести нас в светлое будущее. В udev уже давно реализован механизм Predictable Network Interface Names, который представляет из себя кусочек кода на C, заполняющий переменные ID_NET_NAME_* исходя из свойств расположения физического сетевого устройства.

Считается, что подобный подход дает больше информации, чем прибитие гвоздями имен интерфейсов eth? к MAC-адресам в 70-persistent-net.rules. Однако, не обходится без недостатков. Например, при запуске системы под гипервизором VMWare ESXi, единственный сетевой интерфейс у меня называется eno16777728. Устройства, определяемые в DTB для одноплатных компьютеров на базе ARM, не поддерживаются схемой именования и имеют обычные имена eth?. А при подключении USB устройств, типа мобильных телефонов или модемов, схема именования генерирует скорее неустойчивые имена, потому-что в имя входит расположение устройства на шине USB, которое изменится при следующем подключении, таким образом придется настраивать интерфейс заново, потому-что предыдущие сохраненные настройки будут относиться к интерфейсу с другим именем.

К счастью, udev заполняет переменную ID_NET_NAME_MAC, представляющую имя интерфейса, основанное исключительно на его MAC-адресе. По-умолчанию, эта переменная не используется, но можно поменять стандартное поведение для USB-устройств. Один способ - через настройку udev, второй - используя systemd.link, файл, используемый systemd, для конфигурации сетевых интерфейсов.

Создадим файл /etc/systemd/network/90-usb.link следуя инструкции:
[Match]
Path=*-usb-*
[Link]
NamePolicy=mac
Юнит-файл состоит из двух секций: [Match] для описания устройств к которым он относится и [Link] для описания того, что с ними делать. В примере выше мы просим systemd использовать политику именования основанную на MAC-адресах для всех устройств подключенных через USB. После выполнения systemctl daemon-reload можно подключить устройство и увидеть его интерфейс с именем enx112233445566. Достаточно длинное, но уникальное (в известных пределах) и не изменится при следующем подключении устройства.

Кроме изменения имени через systemd.link можно настроить WOL, MTU, ограничить скорость на интерфейсе, назначить устройству другой MAC-адрес.