Постановка задачи
Недавно передо мной встала задача отдавать различные параметры загрузки по сети различным группам сетевых устройств. Конкретнее говоря, приехала новая партия тонких клиентов, которые не грузятся со старым загрузчиком, а требуют новый (отличия в драйвере сетевой карты и т.п.).
Конечно, самый простой вариант – это прописать их MAC-адреса, определив для них отдельные параметры загрузки. Но, учитывая, что тонких клиентов приехало больше десятка, для их включения надо в каждый вставить память, а памяти на всех может и не быть, вводиться в строй они будут постепенно, а чтобы узнать MAC-адрес, надо все же включить, – прописывать руками – не вариант. Хотя основная движущая сила, толкающая на совершенствование – это все равно лень.
Решение при помощи классов и пулов (class и pool).
Обратившись к документации по dhcpd.conf я вычитал, что можно определять классы устройств, для них можно определять различные пулы, а в пулах можно указывать разные параметры. Отлично, основной механизм есть. Осталось только как-то определять принадлежность устройства к тому или иному классу. С точки зрения человеческой логики – все просто: старые клиенты имеют сетевые карты одного производителя, новые – другого. У сетевых карт одного производителя одинаковый начальный блок MAC-адреса. У разных производителей он, соответственно, разный. Но как объяснить DHCP-серверу, на что смотреть?
Здесь на помощь приходит условные оператор if и дополнительные функции по разбору строк и чисел. В итоге описание класса для карт, MAC-адрес которых начинается с «e0:69:95» выглядит вот так:
class "newTBoxes" {
match if binary-to-ascii (16,8,":",substring(hardware, 0, 4)) = "1:e0:69:95";
}
Здесь отдельно важно отметить, что в «переменной» hardware для сетевых карт идет лидирующий блок: «01:», так что приходится его учитывать. Также важно, что, если часть MAC-адреса начинается с нуля, то он при переводе отбрасывается. Таким образом, MAC-адрес с началом «00:05:EF» преобразуется в «0:5:ef».
После описания нужных классов, дополняем описание subnet следующим образом, вставляем туда:
pool {
allow members of "newTBoxes";
filename "/newTBoxes/pxelinux.0";
}
Однако на практике такая конструкция не заработала, заругавшись на то, что в пуле обязательно должна быть область выделяемых адресов (range). Встала проблема разделения имеющейся общей области на две, что не желательно. Выделение новой области – тоже не вариант, ибо никто не застрахован от появления третьей, четвертой и т.п. партии тонких клиентов.
Решение без классов и пулов: условия в dhcpd.conf (условное конфигурирование).
Дальнейшие изыскания привели к осознанию, что условный оператор можно вставлять непосредственно в описание subnet-а, не определяя классы. То есть все оказалось проще, чем виделось в начале. В итоге конструкция получилась вот такая:
if (binary-to-ascii (16,8,":",substring(hardware, 0, 4)) = "1:e0:69:95") {
filename "/newTBoxes/pxelinux.0";
} else {
filename "pxelinux.0";
}
При необходимости условный оператор может быть более сложным, как в условии, так и в количестве сравнений, например:
if option dhcp-user-class = "accounting" {
option domain-name "accounting.example.org";
} elsif (option dhcp-user-class = "sales") or (option dhcp-user-class = "engineering") {
option domain-name "users.example.org";
} else {
option domain-name "misc.example.org";
}
Отладка файла dhcpd.conf
Для сложных конструкций внутри конфигурационного файла DHCP-сервера иногда хочется каким-то образом понять, что же на самом деле содержится в условии, провести отладку выполнения конфигурации сервера. Для этого можно использовать функцию log() прямо внутри dhcp.conf. Для того чтобы понять, что не так с условием, я использовал вот такой вызов log:
log(info, concat("Client ",binary-to-ascii(16, 8, ":", substring(hardware, 0, 4))));
Результаты пишутся в log-файл. Мне они помогли понять две важные вещи:
- MAC-адрес при работе сервера содержит только маленькие буквы
- Сравнение в условных операторах регистрозависимое.