Comments 5
Во-первых, awk? Что такое awk? Мы знаем только python, он — это всё! (Это был сарказм).
Вот полный аналог скрипта для для выдёргивания поля префикса из RIB, но на awk и с применением sort -u для обеспечения уникальности префиксов в полученном списке:
awk -F \| 'NF>6 { print $6; }' raw_full_view.txt \
| sort -u >parsed_full_view.txt
или, чтобы не ждать, пока sort -u переработает входные данные и выдаст отсортированный список уникальных префиксов, можно вести список префиксов в скрипте и не печатать повторы:
awk -F \| '
NF>6 \
{
if ($6 in was_seen) next;
was_seen[$6]=1; print $6;
}' raw_full_view.txt >parsed_full_view.txt
Во-вторых, скачав из упомянутого выше архива текущую RIB, я с огромным удивлением обнаружил в ней префиксы маршрутов по умолчанию 0.0.0.0/0 и ::/0 , да-да. Скорее всего, маршруты по умолчанию через blackhole не стоит скармливать ядру, поэтому такие префиксы следует исключить из вывода скрипта:
awk -F \| '
$6 ~ /0\.0\.0\.0\/0|::\/0/ { next; }
NF>6 \
{
if ($6 in was_seen) next;
was_seen[$6]=1; print $6;
}' raw_full_view.txt >parsed_full_view.txt
В-третьих, почему бы не конвертировать full-view вместо списка префиксов непосредственно в список команд ip route ПРЕФИКС blackhole и отправить его конвейером прямо в vtysh:
awk -F \| '
BEGIN { print "conf t"; }
$6 ~ /0\.0\.0\.0\/0|::\/0/ { next; }
NF>6 \
{
if ($6 in was_seen) next;
was_seen[$6]=1; print "ip route", $6, "blackhole";
}' raw_full_view.txt \
| vtysh
Немного некрасиво. ip route требует, чтобы первым параметром был префикс, но наш скрипт это жёстко не проверяет, надеясь на корректную работу bgpdump. Но лучше подстраховаться:
awk -F \| '
BEGIN { print "conf t"; }
$6 ~ /0\.0\.0\.0\/0|::\/0/ { next; }
$6 ~ /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}/ \
{
if ($6 in was_seen) next;
was_seen[$6]=1; print "ip route", $6, "blackhole";
}' raw_full_view.txt \
| vtysh
Ну и, наконец, зачем нужно хранить промежуточные результаты в виде разжатой RIB и списка префиксов? Проще организовать конвейер:
bgpdump -m /tmp/rib.20250304.2200.bz2 \
| awk -F \| '
BEGIN { print "conf t";}
$6 ~ /0\.0\.0\.0\/0|::\/0/ { next; }
$6 ~ /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}/ \
{
if ($6 in was_seen) next;
was_seen[$6]=1; print "ip route", $6, "blackhole";
}' \
| vtysh
Последний штрих.
Откусить кусок от full view можно, добавив в конвейер перед командой vtysh команду head -n НУЖНОЕ_КОЛИЧЕСТВО_ПРЕФИКСОВ. Например, если, как в статье, достаточно будет 10000 префиксов, последняя строка конвейера должна будет иметь вид "| head -n 10000 | vtysh":
bgpdump -m /tmp/rib.20250304.2200.bz2 \
| awk -F \| '
BEGIN { print "conf t";}
$6 ~ /0\.0\.0\.0\/0|::\/0/ { next; }
$6 ~ /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}/ \
{
if ($6 in was_seen) next;
was_seen[$6]=1; print "ip route", $6, "blackhole";
}' \
| head -n 10000 | vtysh
Сетевикам рассказали, что для них есть только Python для сетевых инженеров, так и живем (это тоже был сарказм).
Спасибо за комментарий и идею с awk.
Изначально я пытался добавлять маршруты через vtysh, но этот процесс занимал около часа. На виртуальной машине с 8 CPU и 16 GB RAM FRR начинал очень долго отвечать, и работать с ним становилось практически невозможно.
Фильтровать 0.0.0.0/0 и ::/0 в нашем случае было необязательно, потому стенд был изолированный, а соседние локальные хосты были доступны через 10/8 via gw. Итого, я бы оставил добавление маршрутов в route table хоста, а добавление в BGP frr через redistribute kernel, в этом сценарии frr легко справляется с таким количеством префиксов. Исправленный вариант с awk(фильтрацию дефолта оставил):
bgpdump -m rib.20250212.1600.bz2 \
| awk -F \| '
$6 ~ /0\.0\.0\.0\/0|::\/0/ { next; }
$6 ~ /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}/ \
{
if ($6 in was_seen) next;
was_seen[$6]=1; print "ip route add blackhole", $6;
}' | bash
Изначально я пытался добавлять маршруты через vtysh, но этот процесс занимал около часа. На виртуальной машине с 8 CPU и 16 GB RAM FRR начинал очень долго отвечать, и работать с ним становилось практически невозможно.
Похоже, vtysh не умеет в мультипроцессорность. Так что сколько ему процессоров ни дай, сможет работать только на одном. Но я решил обхитрить FRR, загнав префиксы непосредственно в секцию "address-family ipv4 unicast" файла конфигурации /etc/frr/frr.conf. Остановил frr, сгенерил из RIB файл с префиксами, добавив перед каждым из них команду network, вставил содержимое этого файла в нужную секцию конфига, запустил frr и с некоторым интересом принялся наблюдать, как zebra кушает процессор на 100%.
Что странно, vtysh при этом откликался на попытки взаимодействия и даже позволил сохранить текущий конфиг командой write, правда, с некоторыми тормозами. Как там при этом обстояло с отдачей маршрутов по BGP — не проверял, настраивать и поднимать пира было лень. А вот попытка потом остановить frr с помощью systemctl закончилась неудачей. После команды systemctl stop frr , помимо зебры, процессор на 100% принялся кушать ещё и bgpd, и оба они успешно проигнорировали SIGTERM, так что их обоих пришлось завершать командой SIGKILL.
не эксперт в awk, на ваш финальный скрипт у меня не заработал.
ИИ помог:
bgpdump -m ./rib.20250308.0200.bz2 \
| awk -F '|' '
BEGIN { print "conf t"; }
$6 != "" && $6 !~ /^0\.0\.0\.0\/0$/ && $6 !~ /^::\/0$/ {
if (!( $6 in was_seen )) {
print "ip route", $6, "blackhole";
was_seen[$6] = 1;
}
}
' | vtysh
не эксперт в awk, на ваш финальный скрипт у меня не заработал.
Прошу прощения, но все скрипты были проверены мною лично путём копипастинга в окно терминала. Ниже приведена копия вывода:
$ bgpdump -m /tmp/rib.20250304.2200.bz2 | awk -F \| '
BEGIN { print "conf t";}
$6 ~ /0\.0\.0\.0\/0|::\/0/ { next; }
$6 ~ /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}/ \
{ if ($6 in was_seen) next; was_seen[$6]=1; print "ip route", $6, "blackhole";
}' | head -n 10 | vtysh
2025-03-09 19:44:44 [info] logging to syslog
Hello, this is FRRouting (version 8.4.4).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
ws10# conf t
ws10(config)# ip route 1.0.0.0/24 blackhole
ws10(config)# ip route 1.0.4.0/22 blackhole
ws10(config)# ip route 1.0.4.0/24 blackhole
ws10(config)# ip route 1.0.5.0/24 blackhole
ws10(config)# ip route 1.0.6.0/24 blackhole
ws10(config)# ip route 1.0.7.0/24 blackhole
ws10(config)# ip route 1.0.16.0/24 blackhole
ws10(config)# ip route 1.0.64.0/18 blackhole
ws10(config)# ip route 1.0.128.0/17 blackhole
ws10(config)#
Сообщите, пожалуйста, какая у Вас версия awk (awk --version), и если не трудно, приведите в ответе то, что получаете в Вашем терминале, скопировав в него мой скрипт из текста моего первого сообщения в этой теме. Особенно меня интересует сообщение об ошибке awk.
ИИ помог:
Ответ ИИ рабочий, но в нём не проверяется, что в шестом поле содержится именно префикс, а не какой-нибудь случайный мусор. Кроме того, он не оптимален: условие $6 !="" совершенно лишнее и будет только впустую тормозить выполнение скрипта, потому что в данных никогда не бывает пустого поля 6, а пара условий $6 !~ /^0\.0\.0\.0\/0$/ && $6 !~ /^::\/0$/ проверяется дольше одного условия $6 ~ /^(0\.0\.0\.0\/0|::\/0)$/ с последующим next.
Более того, все вот эти проверки условий с отрицаниями, особенно вложенные (if (! условие1) { if (! условие2) { …} } ), операторные скобки за которыми тянутся аж до конца тела цикла, типа предложенного Вам ИИ — это крайне неоптимальный способ написания программ, которым грешат люди, получившие образование с математическим уклоном. Гораздо более оптимальным является серия отдельных проверок на недопустимость входных данных, каждая из которых приводит к выполнению next, то есть, к досрочному переходу к следующей итерации цикла, вместо перехода в конец его тела, а уже оттуда — к новой его итерации.
Первому варианту — проверке условий с отрицаниями, меня научил мой школьный математик на уроках программирования на алмире, а вот второму я уже научился сам, изучая исходники командных файлов RT-11, написанных на UCL, и тогда это способ выглядел для меня подобно откровению.
Анонсируем Full-View на изолированном стенде