#!/bin/bash # Инструмент осмотра датапаса. Запускается внутри контейнера lb-router: # docker compose exec lb-router lbctl <команда> set -euo pipefail LB_DIR=/opt/lb # shellcheck disable=SC1091 source "$LB_DIR/topology.env" usage() { cat < вывести член из балансировки (пробы продолжаются) enable <член> вернуть член в балансировку metrics метрики в формате Prometheus conns таблица соединений ct (зона $CT_ZONE) fdb таблица коммутации сегментов: выученные MAC и порты trace [src_port] [сегмент] ofproto/trace для TCP-сессии клиент -> VIP. Сегмент: pub (по умолчанию), p2, p3 — определяет порт входа и адрес листенера reload перегенерировать и применить пайплайн USAGE } api() { curl -fsS --max-time 5 "http://$HC_API$1"; } case "${1:-}" in ports) ovs-vsctl show ovs-ofctl -O "$OF" show "$BR" | grep -E '^\s+[0-9]+\(' ;; flows) if [ -n "${2:-}" ]; then ovs-ofctl -O "$OF" dump-flows "$BR" "table=$2" else ovs-ofctl -O "$OF" dump-flows "$BR" fi ;; health) api /status.txt ;; status) api /status ;; slots) echo "Раскладка по данным датапаса (счётчики правил дают per-member статистику):" ovs-ofctl -O "$OF" dump-flows "$BR" table=11 \ | sed -n 's/.*n_packets=\([0-9]*\).*set_field:\(0x[0-9a-f]*\)->reg2.*/\2 \1/p' \ | awk '{slots[$1]++; pkts[$1]+=$2} END {for (m in slots) printf " член id=%s: слотов %d, пакетов %d\n", m, slots[m], pkts[m]}' \ | sort drops=$(ovs-ofctl -O "$OF" dump-flows "$BR" table=11 | sed -n 's/.*n_packets=\([0-9]*\).*priority=0.*/\1/p') echo " отброшено правилом fail-close: ${drops:-0}" api /status.txt | sed -n '2p' ;; drain) api "/drain?member=${2:?укажите имя члена}" ;; enable) api "/enable?member=${2:?укажите имя члена}" ;; metrics) api /metrics ;; conns) ovs-appctl dpctl/dump-conntrack | grep -F "zone=$CT_ZONE" || echo "соединений нет" ;; fdb) echo "Выученные MAC (таблица 25, reg0 — номер сегмента):" # priority=100 — только записи, созданные обучением; правила рассылки # (priority 50 и 10) отбрасываются, иначе маска broadcast выглядела бы # как выученный MAC. ovs-ofctl -O "$OF" dump-flows "$BR" table=25 \ | grep 'priority=100' \ | sed -n 's/.*n_packets=\([0-9]*\).*reg0=\(0x[0-9a-f]*\).*dl_dst=\([0-9a-f:]*\).*output:\([0-9]*\).*/ сегмент \2 MAC \3 -> порт \4 (пакетов \1)/p' \ | sort echo "Рассылка по сегменту (неизвестный MAC и broadcast):" ovs-ofctl -O "$OF" dump-flows "$BR" table=25 \ | sed -n 's/.*n_packets=\([0-9]*\).*priority=\(50\|10\),reg0=\(0x[0-9a-f]*\).*/ сегмент \3 приоритет \2: пакетов \1/p' \ | sort ;; trace) src_ip="${2:?укажите IP клиента}" src_port="${3:-40000}" case "${4:-pub}" in p2) in_port=$CLI2_OFPORT; gw_mac=$P2_MAC; vip=$P2_VIP; vip_port=$PRIV_VIP_PORT ;; p3) in_port=$CLI3_OFPORT; gw_mac=$P3_MAC; vip=$P3_VIP; vip_port=$PRIV_VIP_PORT ;; *) in_port=$PUB_OFPORT; gw_mac=$PUB_MAC; vip=$VIP; vip_port=$VIP_PORT ;; esac ovs-appctl ofproto/trace "$BR" \ "in_port=$in_port,dl_src=00:11:22:33:44:55,dl_dst=$gw_mac,dl_type=0x0800,nw_src=$src_ip,nw_dst=$vip,nw_proto=6,nw_ttl=64,tp_src=$src_port,tp_dst=$vip_port,tcp_flags=syn" ;; reload) "$LB_DIR/apply.sh" ;; *) usage ;; esac