Search
Write a publication
Pull to refresh

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, и тогда это способ выглядел для меня подобно откровению.

Sign up to leave a comment.

Articles