diff --git a/Dockerfile b/Dockerfile index ef14c3e..d684f71 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,27 @@ -FROM python:3.9-slim +FROM ubuntu:22.04 -# Установка системных зависимостей +# Установка системных зависимостей и FRR RUN apt-get update && apt-get install -y \ + frr \ + frr-pythontools \ + python3 \ + python3-pip \ iproute2 \ iputils-ping \ net-tools \ procps \ + vim \ + curl \ && rm -rf /var/lib/apt/lists/* -# Установка ExaBGP -RUN pip install exabgp +# Установка Python зависимостей +RUN pip3 install watchdog # Создание структуры директорий -RUN mkdir -p /app/scripts /app/data /app/logs /run/exabgp /var/run/exabgp /usr/local/run/exabgp /usr/local/var/run/exabgp +RUN mkdir -p /app/scripts /app/data /app/logs /etc/frr # Копирование файлов -COPY exabgp.conf /app/exabgp.conf +COPY frr.conf /etc/frr/frr.conf COPY scripts/ /app/scripts/ COPY data/ /app/data/ @@ -23,6 +29,7 @@ COPY data/ /app/data/ RUN chmod +x /app/scripts/start.sh RUN chmod +x /app/scripts/load_prefixes.py RUN chmod +x /app/scripts/generate_config.py +RUN chmod +x /app/scripts/monitor.py # Рабочая директория WORKDIR /app @@ -37,7 +44,8 @@ ENV BGP_NEIGHBOR_IP=192.168.1.1 ENV BGP_NEIGHBOR_AS=65001 ENV BGP_HOLD_TIME=90 ENV BGP_KEEPALIVE=30 -ENV BGP_LOG_LEVEL=INFO +ENV BGP_LOG_LEVEL=info +ENV FRR_DAEMONS="bgpd zebra" # Команда запуска ENTRYPOINT ["/app/scripts/start.sh"] \ No newline at end of file diff --git a/QUICKSTART.md b/QUICKSTART.md index 3366576..886b154 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -1,228 +1,324 @@ -# Быстрый старт BGP сервера +# Быстрый старт BGP Server (FRR) -## Минимальные требования +Этот документ поможет вам быстро запустить BGP сервер на базе FRR для раздачи префиксов. + +## Предварительные требования - Docker Desktop для Windows - PowerShell -- RouterOS 7.14+ (на стороне клиента) +- RouterOS 7.14+ (для клиентской стороны) -## Быстрый запуск (5 минут) +## Шаг 1: Подготовка файлов -### 1. Клонирование и подготовка +### Создание файла с префиксами -```powershell -# Клонирование репозитория (если нужно) -git clone -cd bgp-server - -# Создание необходимых директорий -mkdir logs -``` - -### 2. Настройка префиксов - -Отредактируйте файл `data/prefixes.txt`: +Создайте файл `data/prefixes.txt` с вашими префиксами: ``` +# Основные префиксы 192.168.1.0/24 +192.168.2.0/24 10.0.0.0/8 172.16.0.0/12 + +# Дополнительные префиксы +203.0.113.0/24 +198.51.100.0/24 ``` -### 3. Запуск сервера +### Создание дополнительного файла (опционально) + +Создайте файл `data/additional_prefixes.txt` для дополнительных префиксов: + +``` +# Дополнительные префиксы +192.168.100.0/24 +192.168.200.0/24 +``` + +## Шаг 2: Запуск сервера + +### Вариант A: Использование PowerShell скрипта (рекомендуется) ```powershell -# Запуск с автоматической сборкой +# Запуск с автоматической сборкой образа .\scripts\start-server.ps1 -Build -# Или вручную -docker-compose up -d --build +# Или запуск без пересборки +.\scripts\start-server.ps1 ``` -### 4. Проверка работы +### Вариант B: Использование Docker Compose ```powershell -# Проверка статуса -docker-compose ps +# Сборка и запуск +docker-compose up -d --build -# Просмотр логов -docker-compose logs -f bgp-server - -# Мониторинг -docker exec bgp-server python3 /app/scripts/monitor.py +# Или только запуск +docker-compose up -d ``` -### 5. Настройка RouterOS +### Вариант C: Ручной запуск -Выполните в RouterOS: +```powershell +# Сборка образа +docker build -t bgp-server-frr . + +# Запуск контейнера +docker run -d \ + --name bgp-server \ + --restart unless-stopped \ + -p 179:179 \ + -v ${PWD}/data:/app/data:ro \ + -v ${PWD}/logs:/app/logs \ + --cap-add NET_ADMIN \ + --privileged \ + bgp-server-frr +``` + +## Шаг 3: Проверка работы + +### Проверка статуса контейнера + +```powershell +# Статус контейнера +docker ps + +# Логи контейнера +docker logs bgp-server +``` + +### Проверка FRR + +```powershell +# Версия FRR +docker exec bgp-server vtysh -c "show version" + +# Статус BGP +docker exec bgp-server vtysh -c "show ip bgp summary" + +# Анонсированные маршруты +docker exec bgp-server vtysh -c "show ip bgp" +``` + +### Проверка загруженных префиксов + +```powershell +# Логи загрузки префиксов +docker exec bgp-server tail -f /app/logs/prefixes.log + +# Тестирование загрузки +docker exec bgp-server python3 /app/scripts/load_prefixes.py --test +``` + +## Шаг 4: Настройка RouterOS + +### Базовая настройка BGP ```routeros -/routing bgp instance add name=bgp-server as=65001 router-id=192.168.1.1 -/routing bgp network add network=192.168.1.0/24 -/routing bgp peer add name=bgp-server remote-address=192.168.1.100 remote-as=65000 instance=bgp-server +# Создание BGP экземпляра +/routing bgp instance +add name=bgp-server as=65001 router-id=192.168.1.1 + +# Настройка BGP сети +/routing bgp network +add network=192.168.1.0/24 + +# Настройка BGP пира +/routing bgp peer +add name=bgp-server remote-address=192.168.1.100 remote-as=65000 instance=bgp-server + +# Включение BGP /routing bgp instance set bgp-server disabled=no ``` -### 6. Проверка BGP сессии +### Проверка BGP сессии -В RouterOS: ```routeros +# Статус BGP /routing bgp peer print + +# Полученные маршруты +/routing bgp route print ``` -Ожидаемый результат: -``` -Flags: X - disabled, I - invalid, D - dynamic, E - established - 0 name="bgp-server" ... state=established uptime=1m30s prefix-count=8 -``` +## Шаг 5: Мониторинг -## Полезные команды - -### Управление сервером +### Просмотр логов ```powershell -# Запуск -.\scripts\start-server.ps1 +# Логи FRR +docker exec bgp-server tail -f /app/logs/frr.log -# Остановка +# Логи загрузки префиксов +docker exec bgp-server tail -f /app/logs/prefixes.log + +# Логи мониторинга +docker exec bgp-server tail -f /app/logs/monitor.log +``` + +### Статус системы + +```powershell +# Статус в JSON формате +docker exec bgp-server cat /app/logs/status.json + +# Запуск мониторинга +docker exec bgp-server python3 /app/scripts/monitor.py +``` + +### Команды vtysh + +```powershell +# Подключение к FRR CLI +docker exec -it bgp-server vtysh + +# Полезные команды внутри vtysh: +show ip bgp summary # Сводка BGP +show ip bgp # Все BGP маршруты +show ip route # Таблица маршрутизации +show interface # Интерфейсы +show running-config # Конфигурация +``` + +## Управление + +### Остановка сервера + +```powershell +# Остановка с сохранением контейнера .\scripts\stop-server.ps1 -# Перезапуск -docker-compose restart - -# Просмотр логов -docker-compose logs -f bgp-server +# Остановка с удалением контейнера +.\scripts\stop-server.ps1 -Force ``` -### Мониторинг +### Перезагрузка префиксов ```powershell -# Проверка статуса -docker-compose ps - -# Мониторинг ресурсов -docker stats bgp-server - -# Проверка BGP сессии -docker exec bgp-server exabgpcli show neighbor -``` - -### Обновление префиксов - -```powershell -# Перезагрузка префиксов без перезапуска +# Перезагрузка без перезапуска сервера docker exec bgp-server python3 /app/scripts/reload_prefixes.py - -# Или перезапуск сервера -docker-compose restart ``` -## Устранение неполадок +### Обновление контейнера + +```powershell +# Обновление с пересборкой +.\scripts\update-container.ps1 -Force +``` + +## Диагностика ### Проблема: Контейнер не запускается ```powershell # Проверка логов -docker-compose logs bgp-server +docker logs bgp-server # Проверка портов netstat -an | findstr :179 -# Пересборка образа -docker-compose build --no-cache +# Проверка Docker +docker system info ``` ### Проблема: BGP сессия не устанавливается ```powershell -# Проверка сетевого подключения +# Проверка сетевой связности docker exec bgp-server ping 192.168.1.1 -# Проверка конфигурации -docker exec bgp-server cat /app/exabgp.conf +# Проверка конфигурации FRR +docker exec bgp-server vtysh -c "show running-config" -# Проверка логов -docker-compose logs bgp-server +# Проверка статуса BGP +docker exec bgp-server vtysh -c "show ip bgp summary" ``` ### Проблема: Префиксы не анонсируются ```powershell -# Проверка файлов с префиксами +# Проверка файлов префиксов docker exec bgp-server cat /app/data/prefixes.txt -# Проверка логов загрузки префиксов -docker exec bgp-server cat /app/logs/prefixes.log +# Проверка логов загрузки +docker exec bgp-server tail -f /app/logs/prefixes.log -# Перезагрузка префиксов -docker exec bgp-server python3 /app/scripts/reload_prefixes.py +# Проверка статических маршрутов +docker exec bgp-server vtysh -c "show ip route static" ``` -## Настройка сети +## Настройка переменных окружения -### Изменение IP адресов - -Отредактируйте `docker-compose.yml`: - -```yaml -environment: - - BGP_ROUTER_ID=192.168.1.100 # IP сервера - - BGP_NEIGHBOR_IP=192.168.1.1 # IP RouterOS -``` - -И `exabgp.conf`: - -```ini -neighbor 192.168.1.1 { # IP RouterOS - router-id 192.168.1.100; # IP сервера - local-address 192.168.1.100; # IP сервера - # ... -} -``` - -### Изменение AS номеров - -В `docker-compose.yml`: -```yaml -environment: - - BGP_LOCAL_AS=65000 # AS сервера - - BGP_NEIGHBOR_AS=65001 # AS RouterOS -``` - -В `exabgp.conf`: -```ini -neighbor 192.168.1.1 { - local-as 65000; # AS сервера - peer-as 65001; # AS RouterOS -} -``` - -## Безопасность - -### MD5 аутентификация - -В `exabgp.conf`: -```ini -neighbor 192.168.1.1 { - # ... существующие настройки ... - md5-password "your-secure-password"; -} -``` - -В RouterOS: -```routeros -/routing bgp peer set bgp-server tcp-md5-key="your-secure-password" -``` - -### Firewall +Вы можете настроить BGP параметры через переменные окружения: ```powershell -# Windows Firewall (PowerShell) -New-NetFirewallRule -DisplayName "BGP Server" -Direction Inbound -Protocol TCP -LocalPort 179 -Action Allow +# Запуск с кастомными настройками +docker run -d \ + --name bgp-server \ + -p 179:179 \ + -v ${PWD}/data:/app/data:ro \ + -v ${PWD}/logs:/app/logs \ + -e BGP_LOCAL_AS=65000 \ + -e BGP_ROUTER_ID=192.168.1.100 \ + -e BGP_NEIGHBOR_IP=192.168.1.1 \ + -e BGP_NEIGHBOR_AS=65001 \ + -e BGP_HOLD_TIME=90 \ + -e BGP_KEEPALIVE=30 \ + --cap-add NET_ADMIN \ + --privileged \ + bgp-server-frr ``` -## Готово! +## Полезные команды -После выполнения всех шагов у вас должен работать BGP сервер, который раздает префиксы из текстовых файлов в RouterOS. +### Мониторинг в реальном времени -Для получения дополнительной информации см. основной файл `README.md`. \ No newline at end of file +```powershell +# Логи в реальном времени +docker logs -f bgp-server + +# Статус BGP каждые 5 секунд +while ($true) { + docker exec bgp-server vtysh -c "show ip bgp summary" + Start-Sleep 5 + Clear-Host +} +``` + +### Резервное копирование + +```powershell +# Копирование файлов префиксов +Copy-Item data/prefixes.txt data/prefixes.txt.backup + +# Экспорт конфигурации FRR +docker exec bgp-server vtysh -c "show running-config" > frr-config.backup +``` + +### Очистка + +```powershell +# Остановка и удаление контейнера +docker stop bgp-server +docker rm bgp-server + +# Удаление образа +docker rmi bgp-server-frr + +# Очистка логов +Remove-Item logs/* -Recurse -Force +``` + +## Следующие шаги + +1. **Настройка мониторинга**: Настройте алерты для критических событий +2. **Резервное копирование**: Настройте автоматическое резервное копирование конфигурации +3. **Безопасность**: Настройте firewall и аутентификацию BGP +4. **Масштабирование**: Рассмотрите использование нескольких экземпляров для высокой доступности + +## Поддержка + +- Документация FRR: https://frrouting.org/ +- GitHub проекта: https://github.com/FRRouting/frr +- Сообщество: https://lists.frrouting.org/ \ No newline at end of file diff --git a/README.md b/README.md index 047b5cc..d9e8171 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,38 @@ -# BGP Server для раздачи префиксов +# BGP Server для раздачи префиксов (FRR) -Этот проект представляет собой BGP сервер, который раздает префиксы из текстовых файлов. Сервер работает в Docker контейнере и предназначен для интеграции с RouterOS 7.14+. +Этот проект представляет собой BGP сервер на базе FRR (Free Range Routing), который раздает префиксы из текстовых файлов. Сервер работает в Docker контейнере и предназначен для интеграции с RouterOS 7.14+. ## Архитектура решения -- **BGP Server**: ExaBGP в Docker контейнере +- **BGP Server**: FRR (Free Range Routing) в Docker контейнере - **Источник данных**: Текстовые файлы с префиксами - **Клиент**: RouterOS 7.14+ для получения префиксов - **Протокол**: BGP (только исходящие анонсы) +## Преимущества FRR + +- **Стабильность**: Производственный уровень надежности +- **Производительность**: Оптимизирован для высоких нагрузок +- **Функциональность**: Полная поддержка BGP функций +- **Мониторинг**: Встроенные инструменты диагностики +- **Сообщество**: Активная поддержка и развитие + ## Структура проекта ``` bgp-server/ ├── docker-compose.yml # Конфигурация Docker -├── Dockerfile # Образ Docker -├── exabgp.conf # Конфигурация ExaBGP +├── Dockerfile # Образ Docker с FRR +├── frr.conf # Конфигурация FRR ├── scripts/ -│ ├── start.sh # Скрипт запуска -│ └── load_prefixes.py # Загрузка префиксов из файлов +│ ├── start.sh # Скрипт запуска FRR +│ ├── load_prefixes.py # Загрузка префиксов в FRR +│ ├── generate_config.py # Генерация конфигурации FRR +│ └── monitor.py # Мониторинг FRR ├── data/ │ ├── prefixes.txt # Основной файл с префиксами │ └── additional_prefixes.txt # Дополнительные префиксы -├── logs/ # Логи ExaBGP +├── logs/ # Логи FRR └── README.md # Эта инструкция ``` @@ -56,6 +66,9 @@ docker-compose logs -f bgp-server # Проверка статуса контейнера docker-compose ps + +# Проверка BGP сессии через vtysh +docker exec bgp-server vtysh -c "show ip bgp summary" ``` ## Подробная настройка @@ -91,45 +104,17 @@ docker-compose ps ### Шаг 2: Конфигурация BGP сервера -Отредактируйте `exabgp.conf`: +Конфигурация FRR генерируется автоматически из переменных окружения в `docker-compose.yml`: -```ini -# Основная конфигурация -process load-prefixes { - run /app/scripts/load_prefixes.py; - encoder json; -} - -# Настройки BGP -neighbor 192.168.1.1 { - router-id 192.168.1.100; - local-address 192.168.1.100; - local-as 65000; - peer-as 65001; - - # Только исходящие анонсы - capability { - graceful-restart; - } - - # Настройки сессии - hold-time 90; - keepalive 30; - - # Логирование - api { - processes [load-prefixes]; - neighbor-changes; - receive { - parsed; - update; - } - send { - parsed; - update; - } - } -} +```yaml +environment: + - BGP_LOCAL_AS=65000 + - BGP_ROUTER_ID=192.168.1.100 + - BGP_NEIGHBOR_IP=192.168.1.1 + - BGP_NEIGHBOR_AS=65001 + - BGP_HOLD_TIME=90 + - BGP_KEEPALIVE=30 + - BGP_LOG_LEVEL=info ``` ### Шаг 3: Настройка Docker @@ -155,6 +140,9 @@ services: - BGP_NEIGHBOR_AS=65001 networks: - bgp-network + cap_add: + - NET_ADMIN + privileged: true networks: bgp-network: @@ -195,70 +183,130 @@ docker-compose up -d docker-compose logs -f bgp-server # Проверка статуса BGP сессии -docker exec bgp-server exabgpcli show neighbor +docker exec bgp-server vtysh -c "show ip bgp summary" + +# Проверка анонсированных маршрутов +docker exec bgp-server vtysh -c "show ip bgp" ``` -## Мониторинг и логирование +## Управление и мониторинг -### Просмотр логов +### Команды vtysh ```powershell -# Все логи -docker-compose logs bgp-server +# Подключение к FRR CLI +docker exec -it bgp-server vtysh -# Логи в реальном времени -docker-compose logs -f bgp-server +# Просмотр BGP соседей +show ip bgp neighbors -# Логи за последние 100 строк -docker-compose logs --tail=100 bgp-server +# Просмотр BGP маршрутов +show ip bgp + +# Просмотр статических маршрутов +show ip route + +# Просмотр конфигурации +show running-config ``` -### Проверка статуса +### Мониторинг через скрипты ```powershell -# Статус контейнера -docker-compose ps +# Запуск мониторинга +docker exec bgp-server python3 /app/scripts/monitor.py -# Проверка BGP сессии -docker exec bgp-server exabgpcli show neighbor +# Просмотр статуса +docker exec bgp-server cat /app/logs/status.json -# Проверка загруженных префиксов -docker exec bgp-server cat /app/logs/prefixes.log +# Перезагрузка префиксов +docker exec bgp-server python3 /app/scripts/load_prefixes.py --test +``` + +### Логи + +```powershell +# Логи FRR +docker exec bgp-server tail -f /app/logs/frr.log + +# Логи загрузки префиксов +docker exec bgp-server tail -f /app/logs/prefixes.log + +# Логи мониторинга +docker exec bgp-server tail -f /app/logs/monitor.log +``` + +## Диагностика + +### Проверка статуса FRR + +```powershell +# Проверка процессов +docker exec bgp-server ps aux | grep -E "(zebra|bgpd)" + +# Проверка версии FRR +docker exec bgp-server vtysh -c "show version" + +# Проверка сетевых интерфейсов +docker exec bgp-server vtysh -c "show interface" +``` + +### Проверка BGP сессии + +```powershell +# Статус BGP соседей +docker exec bgp-server vtysh -c "show ip bgp summary" + +# Детальная информация о соседе +docker exec bgp-server vtysh -c "show ip bgp neighbors 192.168.1.1" +``` + +### Проверка маршрутов + +```powershell +# Все BGP маршруты +docker exec bgp-server vtysh -c "show ip bgp" + +# Статические маршруты +docker exec bgp-server vtysh -c "show ip route static" + +# Таблица маршрутизации +docker exec bgp-server vtysh -c "show ip route" ``` ## Обновление префиксов ### Автоматическое обновление -Сервер автоматически перезагружает префиксы при изменении файлов в папке `data/`. +Скрипт `load_prefixes.py` автоматически отслеживает изменения в файлах префиксов и обновляет маршруты в FRR. ### Ручное обновление ```powershell -# Перезапуск сервера -docker-compose restart bgp-server +# Перезагрузка всех префиксов +docker exec bgp-server python3 /app/scripts/load_prefixes.py -# Или перезагрузка только процесса загрузки префиксов -docker exec bgp-server pkill -f load_prefixes.py +# Тестирование загрузки префиксов +docker exec bgp-server python3 /app/scripts/load_prefixes.py --test ``` ## Устранение неполадок ### Проблема: BGP сессия не устанавливается -1. Проверьте сетевое подключение: +1. Проверьте сетевую связность: ```powershell docker exec bgp-server ping 192.168.1.1 ``` -2. Проверьте конфигурацию: +2. Проверьте конфигурацию BGP: ```powershell -docker exec bgp-server cat /app/exabgp.conf +docker exec bgp-server vtysh -c "show running-config" ``` -3. Проверьте логи: +3. Проверьте логи FRR: ```powershell -docker-compose logs bgp-server +docker exec bgp-server tail -f /app/logs/frr.log ``` ### Проблема: Префиксы не анонсируются @@ -268,106 +316,44 @@ docker-compose logs bgp-server docker exec bgp-server cat /app/data/prefixes.txt ``` -2. Проверьте логи процесса загрузки: +2. Проверьте логи загрузки префиксов: ```powershell -docker exec bgp-server cat /app/logs/prefixes.log +docker exec bgp-server tail -f /app/logs/prefixes.log ``` -### Проблема: Docker контейнер не запускается - -1. Проверьте порты: +3. Проверьте статические маршруты: ```powershell -netstat -an | findstr :179 +docker exec bgp-server vtysh -c "show ip route static" ``` -2. Проверьте Docker логи: +### Проблема: Высокое потребление ресурсов + +1. Проверьте использование памяти: ```powershell -docker-compose logs +docker exec bgp-server free -h +``` + +2. Проверьте количество маршрутов: +```powershell +docker exec bgp-server vtysh -c "show ip bgp summary" ``` ## Безопасность -### Рекомендации по безопасности - -1. **Ограничение доступа**: Настройте firewall для ограничения доступа к порту 179 -2. **Аутентификация**: Используйте MD5 аутентификацию в BGP -3. **Логирование**: Включите детальное логирование для аудита -4. **Обновления**: Регулярно обновляйте Docker образы - -### Настройка MD5 аутентификации - -В `exabgp.conf` добавьте: -```ini -neighbor 192.168.1.1 { - # ... существующие настройки ... - md5-password "your-secure-password"; -} -``` - -В RouterOS: -```routeros -/routing bgp peer set bgp-server password="your-secure-password" -``` +- FRR работает в привилегированном контейнере для доступа к сетевым интерфейсам +- Используйте route-maps для фильтрации трафика +- Ограничьте доступ к vtysh CLI +- Регулярно обновляйте образ Docker ## Производительность -### Оптимизация для больших объемов префиксов +- FRR оптимизирован для обработки большого количества маршрутов +- Поддерживает до 1 миллиона маршрутов +- Эффективное использование памяти +- Быстрое время сходимости -1. **Кэширование**: Используйте Redis для кэширования префиксов -2. **База данных**: Для больших объемов используйте PostgreSQL -3. **Мониторинг**: Настройте метрики производительности +## Поддержка -### Мониторинг ресурсов - -```powershell -# Использование ресурсов контейнера -docker stats bgp-server - -# Проверка дискового пространства -docker system df -``` - -## Альтернативные решения - -### 1. Bird BGP Daemon - -Если ExaBGP не подходит, можно использовать Bird: - -```dockerfile -FROM ubuntu:20.04 -RUN apt-get update && apt-get install -y bird -COPY bird.conf /etc/bird/bird.conf -CMD ["bird", "-f", "-d"] -``` - -### 2. FRRouting (FRR) - -Другой популярный вариант: - -```dockerfile -FROM ubuntu:20.04 -RUN apt-get update && apt-get install -y frr -COPY frr.conf /etc/frr/frr.conf -CMD ["/usr/lib/frr/frrinit", "start"] -``` - -### 3. GoBGP - -Для более современного подхода: - -```dockerfile -FROM golang:1.19-alpine -RUN go install github.com/osrg/gobgp/cmd/gobgpd@latest -COPY gobgpd.conf /etc/gobgpd.conf -CMD ["gobgpd", "-f", "/etc/gobgpd.conf"] -``` - -## Заключение - -Этот BGP сервер предоставляет простое и эффективное решение для раздачи префиксов из текстовых файлов. Docker контейнеризация обеспечивает легкое развертывание и управление, а интеграция с RouterOS позволяет быстро настроить клиентскую сторону. - -Для продакшн использования рекомендуется: -- Настроить мониторинг и алертинг -- Добавить резервное копирование конфигурации -- Реализовать автоматическое восстановление после сбоев -- Настроить централизованное логирование \ No newline at end of file +- Документация FRR: https://frrouting.org/ +- GitHub проекта: https://github.com/FRRouting/frr +- Сообщество: https://lists.frrouting.org/ \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index bb5814e..402987f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,10 +15,14 @@ services: - BGP_ROUTER_ID=192.168.1.100 - BGP_NEIGHBOR_IP=192.168.1.1 - BGP_NEIGHBOR_AS=65001 + - BGP_HOLD_TIME=90 + - BGP_KEEPALIVE=30 + - BGP_LOG_LEVEL=info networks: - bgp-network cap_add: - NET_ADMIN # Для работы с сетевыми интерфейсами + privileged: true # Для работы с FRR демонами networks: bgp-network: diff --git a/exabgp.conf b/exabgp.conf deleted file mode 100644 index 5c90769..0000000 --- a/exabgp.conf +++ /dev/null @@ -1,5 +0,0 @@ -# Этот файл будет перезаписан динамически сгенерированной конфигурацией -# из переменных окружения при запуске контейнера. -# -# Для просмотра текущей конфигурации используйте: -# docker exec bgp-server cat /app/exabgp.conf \ No newline at end of file diff --git a/frr.conf b/frr.conf new file mode 100644 index 0000000..90c88d4 --- /dev/null +++ b/frr.conf @@ -0,0 +1,46 @@ +# FRR Configuration File +# Этот файл будет перезаписан динамически сгенерированной конфигурацией +# из переменных окружения при запуске контейнера. +# +# Для просмотра текущей конфигурации используйте: +# docker exec bgp-server cat /etc/frr/frr.conf + +# Глобальные настройки +frr version 8.5.2 +frr defaults traditional +hostname bgp-server +log syslog informational +service integrated-vtysh-config + +# Настройки BGP +router bgp 65000 + bgp router-id 192.168.1.100 + bgp log-neighbor-changes + neighbor 192.168.1.1 remote-as 65001 + neighbor 192.168.1.1 description RouterOS Client + neighbor 192.168.1.1 timers 30 90 + neighbor 192.168.1.1 capability graceful-restart + neighbor 192.168.1.1 soft-reconfiguration inbound +! + address-family ipv4 unicast + neighbor 192.168.1.1 activate + neighbor 192.168.1.1 route-map OUTBOUND out + neighbor 192.168.1.1 route-map INBOUND in + exit-address-family +! + +# Route maps для фильтрации +route-map OUTBOUND permit 10 + description Allow all outbound routes +! +route-map INBOUND deny 10 + description Deny all inbound routes (receive-only mode) +! + +# Настройки интерфейса +interface eth0 + ip address 192.168.1.100/24 +! + +# Статические маршруты (будут добавлены динамически) +# ip route 192.168.1.0/24 Null0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 045d90a..8704a9c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1 @@ -exabgp>=4.2.0 -ipaddress -pathlib -typing \ No newline at end of file +watchdog>=2.1.0 \ No newline at end of file diff --git a/scripts/generate_config.py b/scripts/generate_config.py index 48b6a78..411ac91 100644 --- a/scripts/generate_config.py +++ b/scripts/generate_config.py @@ -1,85 +1,95 @@ #!/usr/bin/env python3 """ -Скрипт для генерации конфигурации ExaBGP из переменных окружения +Скрипт для генерации конфигурации FRR из переменных окружения """ import os import sys +from pathlib import Path -def get_env_var(name: str, default: str) -> str: +def get_env_var(name, default): """Получение переменной окружения с значением по умолчанию""" return os.environ.get(name, default) -def generate_exabgp_config(): - """Генерация конфигурации ExaBGP""" +def generate_frr_config(): + """Генерация конфигурации FRR""" - # Получение переменных окружения + # Получение настроек из переменных окружения local_as = get_env_var('BGP_LOCAL_AS', '65000') router_id = get_env_var('BGP_ROUTER_ID', '192.168.1.100') neighbor_ip = get_env_var('BGP_NEIGHBOR_IP', '192.168.1.1') neighbor_as = get_env_var('BGP_NEIGHBOR_AS', '65001') hold_time = get_env_var('BGP_HOLD_TIME', '90') keepalive = get_env_var('BGP_KEEPALIVE', '30') - md5_password = get_env_var('BGP_MD5_PASSWORD', '') - log_level = get_env_var('BGP_LOG_LEVEL', 'INFO') + log_level = get_env_var('BGP_LOG_LEVEL', 'info') - # Генерация конфигурации - config = f"""# Автоматически сгенерированная конфигурация ExaBGP -process load-prefixes {{ - run /app/scripts/load_prefixes.py; - encoder json; -}} + # Конфигурация FRR + config = f"""# FRR Configuration File +# Generated automatically from environment variables + +# Глобальные настройки +frr version 8.5.2 +frr defaults traditional +hostname bgp-server +log syslog {log_level} +service integrated-vtysh-config # Настройки BGP -neighbor {neighbor_ip} {{ - router-id {router_id}; - local-address {router_id}; - local-as {local_as}; - peer-as {neighbor_as}; - - # Только исходящие анонсы (не принимаем префиксы) - capability {{ - graceful-restart; - }} - - # Настройки сессии - hold-time {hold_time}; -""" +router bgp {local_as} + bgp router-id {router_id} + bgp log-neighbor-changes + neighbor {neighbor_ip} remote-as {neighbor_as} + neighbor {neighbor_ip} description RouterOS Client + neighbor {neighbor_ip} timers {keepalive} {hold_time} + neighbor {neighbor_ip} capability graceful-restart + neighbor {neighbor_ip} soft-reconfiguration inbound +! + address-family ipv4 unicast + neighbor {neighbor_ip} activate + neighbor {neighbor_ip} route-map OUTBOUND out + neighbor {neighbor_ip} route-map INBOUND in + exit-address-family +! - # Добавление MD5 пароля если указан - if md5_password: - config += f" md5-password \"{md5_password}\";\n" - - config += f""" - # Логирование - api {{ - processes [load-prefixes]; - neighbor-changes; - receive {{ - parsed; - update; - }} - send {{ - parsed; - update; - }} - }} -}} +# Route maps для фильтрации +route-map OUTBOUND permit 10 + description Allow all outbound routes +! +route-map INBOUND deny 10 + description Deny all inbound routes (receive-only mode) +! + +# Настройки интерфейса +interface eth0 + ip address {router_id}/24 +! + +# Статические маршруты (будут добавлены динамически) +# ip route 192.168.1.0/24 Null0 """ return config def main(): """Основная функция""" - if len(sys.argv) > 1 and sys.argv[1] == '--print': - # Вывод конфигурации в stdout - print(generate_exabgp_config()) - else: - # Запись конфигурации в файл - config = generate_exabgp_config() - with open('/app/exabgp.conf', 'w') as f: + try: + # Генерация конфигурации + config = generate_frr_config() + + # Запись в файл + config_path = Path('/etc/frr/frr.conf') + config_path.parent.mkdir(parents=True, exist_ok=True) + + with open(config_path, 'w') as f: f.write(config) - print("Configuration generated successfully") + + print(f"FRR configuration generated: {config_path}") + print("Configuration content:") + print(config) + + except Exception as e: + print(f"Error generating FRR configuration: {e}", file=sys.stderr) + sys.exit(1) if __name__ == "__main__": main() \ No newline at end of file diff --git a/scripts/load_prefixes.py b/scripts/load_prefixes.py index a9b3c46..a69106b 100644 --- a/scripts/load_prefixes.py +++ b/scripts/load_prefixes.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 """ -Скрипт для загрузки префиксов из текстовых файлов в ExaBGP +Скрипт для загрузки префиксов из текстовых файлов в FRR """ import sys import os import time -import json +import subprocess import ipaddress from pathlib import Path from typing import List, Set @@ -21,7 +21,7 @@ def log_message(message: str): timestamp = time.strftime("%Y-%m-%d %H:%M:%S") log_entry = f"[{timestamp}] {message}" - # Вывод в stdout для ExaBGP + # Вывод в stdout print(log_entry, flush=True) # Запись в файл (с обработкой ошибок) @@ -84,44 +84,84 @@ def load_all_prefixes() -> Set[str]: return all_prefixes +def run_vtysh_command(command: str) -> bool: + """Выполнение команды через vtysh""" + try: + result = subprocess.run( + ['vtysh', '-c', command], + capture_output=True, + text=True, + timeout=30 + ) + + if result.returncode != 0: + log_error(f"vtysh command failed: {command}") + log_error(f"stderr: {result.stderr}") + return False + + return True + except subprocess.TimeoutExpired: + log_error(f"vtysh command timeout: {command}") + return False + except Exception as e: + log_error(f"Error running vtysh command '{command}': {e}") + return False + def announce_prefixes(prefixes: Set[str]): - """Анонсирование префиксов через ExaBGP API""" - # Получение настроек из переменных окружения - neighbor_ip = os.environ.get('BGP_NEIGHBOR_IP', '192.168.1.1') - local_as = int(os.environ.get('BGP_LOCAL_AS', '65000')) - router_id = os.environ.get('BGP_ROUTER_ID', '192.168.1.100') + """Анонсирование префиксов через FRR""" + log_message(f"Announcing {len(prefixes)} prefixes...") for prefix in sorted(prefixes): - # Формат команды для ExaBGP (упрощенный) - command = { - "command": "announce route", - "neighbor": neighbor_ip, - "attribute": { - "origin": "igp", - "as-path": [local_as], - "next-hop": router_id - }, - "nlri": prefix - } - - # Отправка команды в ExaBGP - print(json.dumps(command), flush=True) - log_message(f"Announced prefix: {prefix}") + # Добавление статического маршрута в FRR + command = f"ip route {prefix} Null0" + if run_vtysh_command(command): + log_message(f"Announced prefix: {prefix}") + else: + log_error(f"Failed to announce prefix: {prefix}") def withdraw_prefixes(prefixes: Set[str]): - """Отзыв префиксов через ExaBGP API""" - # Получение настроек из переменных окружения - neighbor_ip = os.environ.get('BGP_NEIGHBOR_IP', '192.168.1.1') + """Отзыв префиксов через FRR""" + log_message(f"Withdrawing {len(prefixes)} prefixes...") for prefix in sorted(prefixes): - command = { - "command": "withdraw route", - "neighbor": neighbor_ip, - "nlri": prefix - } + # Удаление статического маршрута из FRR + command = f"no ip route {prefix} Null0" + if run_vtysh_command(command): + log_message(f"Withdrew prefix: {prefix}") + else: + log_error(f"Failed to withdraw prefix: {prefix}") + +def check_frr_status() -> bool: + """Проверка статуса FRR""" + try: + result = subprocess.run( + ['vtysh', '-c', 'show version'], + capture_output=True, + text=True, + timeout=10 + ) + return result.returncode == 0 + except Exception: + return False + +def wait_for_frr(): + """Ожидание запуска FRR""" + log_message("Waiting for FRR to start...") + max_attempts = 30 + attempt = 0 + + while attempt < max_attempts: + if check_frr_status(): + log_message("FRR is ready") + return True - print(json.dumps(command), flush=True) - log_message(f"Withdrew prefix: {prefix}") + attempt += 1 + time.sleep(2) + if attempt % 5 == 0: + log_message(f"Still waiting for FRR... (attempt {attempt}/{max_attempts})") + + log_error("FRR did not start within expected time") + return False def main(): """Основная функция""" @@ -138,8 +178,21 @@ def main(): print(f"Found {len(prefixes)} prefixes: {list(prefixes)}") return + # Проверка режима отзыва + if len(sys.argv) > 1 and sys.argv[1] == '--withdraw': + log_message("Withdraw mode: loading and withdrawing all prefixes...") + prefixes = load_all_prefixes() + if wait_for_frr(): + withdraw_prefixes(prefixes) + return + log_message("Starting prefix loader...") + # Ожидание запуска FRR + if not wait_for_frr(): + log_error("Cannot proceed without FRR") + return + # Загрузка префиксов prefixes = load_all_prefixes() log_message(f"Total prefixes loaded: {len(prefixes)}") @@ -152,29 +205,31 @@ def main(): announce_prefixes(prefixes) log_message("All prefixes announced successfully") - # Ожидание команд от ExaBGP + # Мониторинг изменений в файлах + log_message("Starting file monitoring...") + try: while True: - line = sys.stdin.readline() - if not line: - break + time.sleep(30) # Проверка каждые 30 секунд - line = line.strip() - if not line: # Пропуск пустых строк - continue - - # Обработка команд от ExaBGP - try: - data = json.loads(line) - log_message(f"Received command: {data}") - except json.JSONDecodeError: - # Не все сообщения от ExaBGP являются JSON - # Это может быть обычное текстовое сообщение - if line.startswith('[') and line.endswith(']'): - # Это может быть лог сообщение от ExaBGP - log_message(f"Received log message: {line}") - else: - log_message(f"Received non-JSON message: {line}") + # Перезагрузка префиксов + new_prefixes = load_all_prefixes() + + # Определение изменений + added = new_prefixes - prefixes + removed = prefixes - new_prefixes + + if added: + log_message(f"Adding {len(added)} new prefixes: {list(added)}") + announce_prefixes(added) + + if removed: + log_message(f"Removing {len(removed)} prefixes: {list(removed)}") + withdraw_prefixes(removed) + + if added or removed: + prefixes = new_prefixes + log_message(f"Updated prefix count: {len(prefixes)}") except KeyboardInterrupt: log_message("Received interrupt signal") diff --git a/scripts/monitor.py b/scripts/monitor.py index cf3d0e6..94d0268 100644 --- a/scripts/monitor.py +++ b/scripts/monitor.py @@ -1,93 +1,194 @@ #!/usr/bin/env python3 """ -Скрипт мониторинга BGP сервера +Скрипт мониторинга FRR BGP сервера """ +import sys +import os +import time import subprocess import json -import time -import sys -from datetime import datetime +from pathlib import Path +from typing import Dict, Any -def run_command(cmd): - """Выполнение команды и возврат результата""" +# Настройки +LOG_FILE = "/app/logs/monitor.log" +STATUS_FILE = "/app/logs/status.json" + +def log_message(message: str): + """Запись сообщения в лог""" + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + log_entry = f"[{timestamp}] {message}" + + print(log_entry, flush=True) + try: - result = subprocess.run(cmd, shell=True, capture_output=True, text=True) - return result.returncode == 0, result.stdout, result.stderr + with open(LOG_FILE, "a") as f: + f.write(log_entry + "\n") + except (PermissionError, OSError): + pass + +def run_vtysh_command(command: str) -> str: + """Выполнение команды через vtysh""" + try: + result = subprocess.run( + ['vtysh', '-c', command], + capture_output=True, + text=True, + timeout=30 + ) + + if result.returncode == 0: + return result.stdout.strip() + else: + log_message(f"vtysh command failed: {command}") + return "" except Exception as e: - return False, "", str(e) + log_message(f"Error running vtysh command '{command}': {e}") + return "" -def check_container_status(): - """Проверка статуса Docker контейнера""" - success, output, error = run_command("docker ps --filter name=bgp-server --format '{{.Status}}'") - if success and output.strip(): - return True, output.strip() - return False, "Container not running" +def get_bgp_summary() -> Dict[str, Any]: + """Получение сводки BGP""" + summary = run_vtysh_command("show ip bgp summary") + + if not summary: + return {"error": "Could not get BGP summary"} + + # Парсинг вывода BGP summary + lines = summary.split('\n') + neighbors = [] + + for line in lines: + if 'BGP neighbor' in line and 'remote AS' in line: + parts = line.split() + if len(parts) >= 8: + neighbor = { + "ip": parts[2].rstrip(','), + "remote_as": parts[7], + "state": parts[-1] if len(parts) > 7 else "Unknown" + } + neighbors.append(neighbor) + + return { + "neighbors": neighbors, + "raw_output": summary + } -def check_bgp_session(): - """Проверка BGP сессии""" - success, output, error = run_command("docker exec bgp-server exabgpcli show neighbor") - if success: - return True, output - return False, "Cannot check BGP session" +def get_bgp_routes() -> Dict[str, Any]: + """Получение BGP маршрутов""" + routes = run_vtysh_command("show ip bgp") + + if not routes: + return {"error": "Could not get BGP routes"} + + # Подсчет маршрутов + route_count = 0 + for line in routes.split('\n'): + if line.strip() and not line.startswith('BGP table') and not line.startswith('*>'): + if any(char.isdigit() for char in line): + route_count += 1 + + return { + "route_count": route_count, + "raw_output": routes + } -def check_prefixes(): - """Проверка загруженных префиксов""" +def get_frr_status() -> Dict[str, Any]: + """Получение статуса FRR""" + version = run_vtysh_command("show version") + + if not version: + return {"error": "Could not get FRR version"} + + return { + "version": version.split('\n')[0] if version else "Unknown", + "raw_output": version + } + +def get_system_status() -> Dict[str, Any]: + """Получение системного статуса""" try: - with open("/app/logs/prefixes.log", "r") as f: - lines = f.readlines() - return True, f"Found {len(lines)} log entries" - except FileNotFoundError: - return False, "Prefix log not found" + # Проверка процессов FRR + zebra_running = subprocess.run(['pgrep', 'zebra'], capture_output=True).returncode == 0 + bgpd_running = subprocess.run(['pgrep', 'bgpd'], capture_output=True).returncode == 0 + + # Проверка использования памяти + memory_info = {} + try: + with open('/proc/meminfo', 'r') as f: + for line in f: + if 'MemTotal:' in line: + memory_info['total'] = line.split()[1] + elif 'MemAvailable:' in line: + memory_info['available'] = line.split()[1] + except: + pass + + return { + "zebra_running": zebra_running, + "bgpd_running": bgpd_running, + "memory": memory_info + } + except Exception as e: + return {"error": f"Could not get system status: {e}"} -def check_network_connectivity(): - """Проверка сетевого подключения""" - success, output, error = run_command("docker exec bgp-server ping -c 1 192.168.1.1") - return success, "Network connectivity OK" if success else "Network connectivity failed" +def save_status(status: Dict[str, Any]): + """Сохранение статуса в файл""" + try: + with open(STATUS_FILE, 'w') as f: + json.dump(status, f, indent=2) + except Exception as e: + log_message(f"Error saving status: {e}") def main(): - """Основная функция мониторинга""" - print("=== BGP Server Monitoring ===") - print(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") - print() + """Основная функция""" + log_message("Starting FRR monitor...") - # Проверка контейнера - print("1. Container Status:") - status, details = check_container_status() - print(f" Status: {'✓ Running' if status else '✗ Stopped'}") - print(f" Details: {details}") - print() + # Создание директории для логов + try: + os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True) + os.makedirs(os.path.dirname(STATUS_FILE), exist_ok=True) + except (PermissionError, OSError): + pass - # Проверка сети - print("2. Network Connectivity:") - net_ok, net_details = check_network_connectivity() - print(f" Status: {'✓ OK' if net_ok else '✗ Failed'}") - print(f" Details: {net_details}") - print() - - # Проверка BGP сессии - print("3. BGP Session:") - bgp_ok, bgp_details = check_bgp_session() - print(f" Status: {'✓ Active' if bgp_ok else '✗ Inactive'}") - if bgp_ok: - print(f" Details: {bgp_details[:200]}...") - else: - print(f" Details: {bgp_details}") - print() - - # Проверка префиксов - print("4. Prefixes:") - prefix_ok, prefix_details = check_prefixes() - print(f" Status: {'✓ Loaded' if prefix_ok else '✗ Not loaded'}") - print(f" Details: {prefix_details}") - print() - - # Общий статус - overall_status = status and net_ok and bgp_ok and prefix_ok - print("=== Overall Status ===") - print(f"Status: {'✓ HEALTHY' if overall_status else '✗ UNHEALTHY'}") - - return 0 if overall_status else 1 + while True: + try: + # Сбор статуса + status = { + "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"), + "frr": get_frr_status(), + "bgp_summary": get_bgp_summary(), + "bgp_routes": get_bgp_routes(), + "system": get_system_status() + } + + # Сохранение статуса + save_status(status) + + # Логирование важной информации + bgp_summary = status["bgp_summary"] + if "neighbors" in bgp_summary: + for neighbor in bgp_summary["neighbors"]: + log_message(f"BGP neighbor {neighbor['ip']} (AS {neighbor['remote_as']}): {neighbor['state']}") + + bgp_routes = status["bgp_routes"] + if "route_count" in bgp_routes: + log_message(f"BGP routes: {bgp_routes['route_count']}") + + system = status["system"] + if "zebra_running" in system and "bgpd_running" in system: + if not system["zebra_running"] or not system["bgpd_running"]: + log_message("WARNING: FRR daemons not running properly") + + # Ожидание перед следующей проверкой + time.sleep(60) # Проверка каждую минуту + + except KeyboardInterrupt: + log_message("Monitor stopped by user") + break + except Exception as e: + log_message(f"Error in monitor loop: {e}") + time.sleep(30) # Короткая пауза при ошибке if __name__ == "__main__": - sys.exit(main()) \ No newline at end of file + main() \ No newline at end of file diff --git a/scripts/reload_prefixes.py b/scripts/reload_prefixes.py index 51faeb2..1fc361d 100644 --- a/scripts/reload_prefixes.py +++ b/scripts/reload_prefixes.py @@ -1,103 +1,205 @@ #!/usr/bin/env python3 """ -Скрипт для перезагрузки префиксов без перезапуска BGP сервера +Скрипт для перезагрузки префиксов в FRR """ -import subprocess import sys +import os import time +import subprocess +import ipaddress from pathlib import Path +from typing import Set -def run_command(cmd): - """Выполнение команды""" +# Настройки +DATA_DIR = "/app/data" +LOG_FILE = "/app/logs/reload.log" +PREFIX_FILES = ["prefixes.txt", "additional_prefixes.txt"] + +def log_message(message: str): + """Запись сообщения в лог""" + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + log_entry = f"[{timestamp}] {message}" + + print(log_entry, flush=True) + try: - result = subprocess.run(cmd, shell=True, capture_output=True, text=True) - return result.returncode == 0, result.stdout, result.stderr - except Exception as e: - return False, "", str(e) + with open(LOG_FILE, "a") as f: + f.write(log_entry + "\n") + except (PermissionError, OSError): + pass -def reload_prefixes(): - """Перезагрузка префиксов""" - print("Reloading prefixes...") - - # Остановка процесса загрузки префиксов - print("Stopping prefix loader process...") - success, output, error = run_command("docker exec bgp-server pkill -f load_prefixes.py") - - if not success: - print("Warning: Could not stop prefix loader process") - - # Ожидание завершения процесса - time.sleep(2) - - # Проверка что процесс остановлен - success, output, error = run_command("docker exec bgp-server pgrep -f load_prefixes.py") - if success: - print("Error: Prefix loader process is still running") - return False - - print("Prefix loader process stopped successfully") - - # Запуск нового процесса загрузки префиксов - print("Starting new prefix loader process...") - success, output, error = run_command("docker exec bgp-server /app/scripts/load_prefixes.py &") - - if success: - print("Prefix loader process started successfully") +def validate_prefix(prefix: str) -> bool: + """Валидация IP префикса""" + try: + ipaddress.ip_network(prefix, strict=False) return True - else: - print(f"Error starting prefix loader: {error}") + except ValueError: return False -def check_status(): - """Проверка статуса после перезагрузки""" - print("Checking status...") - time.sleep(5) +def load_prefixes_from_file(file_path: Path) -> Set[str]: + """Загрузка префиксов из файла""" + prefixes = set() - # Проверка процесса - success, output, error = run_command("docker exec bgp-server pgrep -f load_prefixes.py") - if success: - print("✓ Prefix loader process is running") - else: - print("✗ Prefix loader process is not running") + if not file_path.exists(): + log_message(f"File not found: {file_path}") + return prefixes + + try: + with open(file_path, 'r') as f: + for line_num, line in enumerate(f, 1): + line = line.strip() + + # Пропуск пустых строк и комментариев + if not line or line.startswith('#'): + continue + + # Валидация префикса + if validate_prefix(line): + prefixes.add(line) + else: + log_message(f"Invalid prefix in {file_path}:{line_num}: {line}") + + except Exception as e: + log_message(f"Error reading {file_path}: {e}") + + return prefixes + +def load_all_prefixes() -> Set[str]: + """Загрузка всех префиксов из всех файлов""" + all_prefixes = set() + + for filename in PREFIX_FILES: + file_path = Path(DATA_DIR) / filename + prefixes = load_prefixes_from_file(file_path) + all_prefixes.update(prefixes) + log_message(f"Loaded {len(prefixes)} prefixes from {filename}") + + return all_prefixes + +def get_current_routes() -> Set[str]: + """Получение текущих статических маршрутов из FRR""" + try: + result = subprocess.run( + ['vtysh', '-c', 'show ip route static'], + capture_output=True, + text=True, + timeout=30 + ) + + if result.returncode != 0: + log_message("Could not get current routes from FRR") + return set() + + routes = set() + for line in result.stdout.split('\n'): + line = line.strip() + if line and 'via Null0' in line: + # Парсинг строки маршрута + parts = line.split() + if len(parts) >= 2: + route = parts[1] + if validate_prefix(route): + routes.add(route) + + return routes + except Exception as e: + log_message(f"Error getting current routes: {e}") + return set() + +def run_vtysh_command(command: str) -> bool: + """Выполнение команды через vtysh""" + try: + result = subprocess.run( + ['vtysh', '-c', command], + capture_output=True, + text=True, + timeout=30 + ) + + if result.returncode != 0: + log_message(f"vtysh command failed: {command}") + return False + + return True + except Exception as e: + log_message(f"Error running vtysh command '{command}': {e}") return False + +def announce_prefixes(prefixes: Set[str]): + """Анонсирование префиксов через FRR""" + log_message(f"Announcing {len(prefixes)} prefixes...") - # Проверка логов - success, output, error = run_command("docker exec bgp-server tail -n 5 /app/logs/prefixes.log") - if success: - print("Recent log entries:") - print(output) - else: - print("No recent log entries found") + for prefix in sorted(prefixes): + command = f"ip route {prefix} Null0" + if run_vtysh_command(command): + log_message(f"Announced prefix: {prefix}") + else: + log_message(f"Failed to announce prefix: {prefix}") + +def withdraw_prefixes(prefixes: Set[str]): + """Отзыв префиксов через FRR""" + log_message(f"Withdrawing {len(prefixes)} prefixes...") - return True + for prefix in sorted(prefixes): + command = f"no ip route {prefix} Null0" + if run_vtysh_command(command): + log_message(f"Withdrew prefix: {prefix}") + else: + log_message(f"Failed to withdraw prefix: {prefix}") + +def check_frr_status() -> bool: + """Проверка статуса FRR""" + try: + result = subprocess.run( + ['vtysh', '-c', 'show version'], + capture_output=True, + text=True, + timeout=10 + ) + return result.returncode == 0 + except Exception: + return False def main(): """Основная функция""" - print("=== BGP Prefix Reloader ===") + log_message("Starting prefix reload...") - # Проверка что контейнер запущен - success, output, error = run_command("docker ps --filter name=bgp-server --format '{{.Status}}'") - if not success or not output.strip(): - print("Error: BGP server container is not running") - print("Please start the container first: docker-compose up -d") + # Проверка статуса FRR + if not check_frr_status(): + log_message("ERROR: FRR is not running") return 1 - print("BGP server container is running") + # Загрузка новых префиксов + new_prefixes = load_all_prefixes() + log_message(f"Loaded {len(new_prefixes)} prefixes from files") - # Перезагрузка префиксов - if reload_prefixes(): - print("Prefix reload completed successfully") - - # Проверка статуса - if check_status(): - print("✓ All checks passed") - return 0 - else: - print("✗ Some checks failed") - return 1 + # Получение текущих маршрутов + current_routes = get_current_routes() + log_message(f"Found {len(current_routes)} current routes in FRR") + + # Определение изменений + to_add = new_prefixes - current_routes + to_remove = current_routes - new_prefixes + + log_message(f"Changes: {len(to_add)} to add, {len(to_remove)} to remove") + + # Применение изменений + if to_remove: + withdraw_prefixes(to_remove) + + if to_add: + announce_prefixes(to_add) + + # Финальная проверка + final_routes = get_current_routes() + log_message(f"Final route count: {len(final_routes)}") + + if len(final_routes) == len(new_prefixes): + log_message("Reload completed successfully!") + return 0 else: - print("✗ Prefix reload failed") + log_message("WARNING: Route count mismatch after reload") return 1 if __name__ == "__main__": diff --git a/scripts/start-server.ps1 b/scripts/start-server.ps1 index 3aebafb..766f539 100644 --- a/scripts/start-server.ps1 +++ b/scripts/start-server.ps1 @@ -1,96 +1,123 @@ -# PowerShell скрипт для запуска BGP сервера +# Скрипт запуска BGP Server (FRR) param( + [string]$ContainerName = "bgp-server", + [string]$DataPath = "./data", + [string]$LogsPath = "./logs", [switch]$Build, - [switch]$Logs, - [switch]$Monitor + [switch]$Force ) -Write-Host "=== BGP Server Management ===" -ForegroundColor Green +Write-Host "=== BGP Server (FRR) Startup Script ===" -ForegroundColor Green -# Проверка Docker -Write-Host "Checking Docker..." -ForegroundColor Yellow -try { - docker --version | Out-Null - Write-Host "✓ Docker is available" -ForegroundColor Green -} catch { - Write-Host "✗ Docker is not available. Please install Docker Desktop." -ForegroundColor Red - exit 1 +# Проверка существования контейнера +$containerExists = docker ps -a --filter "name=$ContainerName" --format "table {{.Names}}" | Select-String $ContainerName + +if ($containerExists) { + Write-Host "Found existing container: $ContainerName" -ForegroundColor Yellow + + if (-not $Force) { + $response = Read-Host "Do you want to stop and remove the existing container? (y/N)" + if ($response -ne "y" -and $response -ne "Y") { + Write-Host "Operation cancelled." -ForegroundColor Red + exit 0 + } + } + + # Остановка и удаление старого контейнера + Write-Host "Stopping container..." -ForegroundColor Yellow + docker stop $ContainerName + + Write-Host "Removing container..." -ForegroundColor Yellow + docker rm $ContainerName } -# Проверка Docker Compose -Write-Host "Checking Docker Compose..." -ForegroundColor Yellow -try { - docker-compose --version | Out-Null - Write-Host "✓ Docker Compose is available" -ForegroundColor Green -} catch { - Write-Host "✗ Docker Compose is not available." -ForegroundColor Red - exit 1 +# Создание директорий если не существуют +if (-not (Test-Path $DataPath)) { + Write-Host "Creating data directory: $DataPath" -ForegroundColor Yellow + New-Item -ItemType Directory -Path $DataPath -Force | Out-Null } -# Создание необходимых директорий -Write-Host "Creating directories..." -ForegroundColor Yellow -if (!(Test-Path "logs")) { - New-Item -ItemType Directory -Path "logs" | Out-Null - Write-Host "✓ Created logs directory" -ForegroundColor Green +if (-not (Test-Path $LogsPath)) { + Write-Host "Creating logs directory: $LogsPath" -ForegroundColor Yellow + New-Item -ItemType Directory -Path $LogsPath -Force | Out-Null } -if (!(Test-Path "data")) { - New-Item -ItemType Directory -Path "data" | Out-Null - Write-Host "✓ Created data directory" -ForegroundColor Green +# Создание файла с префиксами если не существует +$prefixesFile = Join-Path $DataPath "prefixes.txt" +if (-not (Test-Path $prefixesFile)) { + Write-Host "Creating default prefixes file..." -ForegroundColor Yellow + @" +# Default prefixes file +# Add your prefixes here, one per line +192.168.1.0/24 +10.0.0.0/8 +172.16.0.0/12 +"@ | Out-File -FilePath $prefixesFile -Encoding UTF8 } # Сборка образа если требуется if ($Build) { Write-Host "Building Docker image..." -ForegroundColor Yellow - docker-compose build + docker build -t bgp-server-frr . + if ($LASTEXITCODE -ne 0) { - Write-Host "✗ Build failed" -ForegroundColor Red + Write-Host "Failed to build image. Exiting." -ForegroundColor Red exit 1 } - Write-Host "✓ Build completed" -ForegroundColor Green } -# Остановка существующего контейнера -Write-Host "Stopping existing container..." -ForegroundColor Yellow -docker-compose down 2>$null -Write-Host "✓ Existing container stopped" -ForegroundColor Green +# Запуск контейнера +Write-Host "Starting BGP Server container..." -ForegroundColor Yellow +$currentPath = Get-Location +$dataVolume = "${currentPath}\${DataPath}:/app/data:ro" +$logsVolume = "${currentPath}\${LogsPath}:/app/logs" -# Запуск сервера -Write-Host "Starting BGP server..." -ForegroundColor Yellow -docker-compose up -d +docker run -d ` + --name $ContainerName ` + --restart unless-stopped ` + -p 179:179 ` + -v $dataVolume ` + -v $logsVolume ` + --cap-add NET_ADMIN ` + --privileged ` + bgp-server-frr if ($LASTEXITCODE -eq 0) { - Write-Host "✓ BGP server started successfully" -ForegroundColor Green + Write-Host "Container started successfully!" -ForegroundColor Green # Ожидание запуска - Write-Host "Waiting for server to initialize..." -ForegroundColor Yellow + Write-Host "Waiting for container to start..." -ForegroundColor Yellow Start-Sleep -Seconds 10 # Проверка статуса - Write-Host "Checking server status..." -ForegroundColor Yellow - $status = docker-compose ps - Write-Host $status + $status = docker ps --filter "name=$ContainerName" --format "table {{.Status}}" + Write-Host "Container status: $status" -ForegroundColor Cyan - if ($Logs) { - Write-Host "Showing logs..." -ForegroundColor Yellow - docker-compose logs -f bgp-server + # Проверка FRR статуса + Write-Host "Checking FRR status..." -ForegroundColor Cyan + docker exec $ContainerName vtysh -c "show version" 2>$null + + if ($LASTEXITCODE -eq 0) { + Write-Host "FRR is running successfully!" -ForegroundColor Green + + # Показ BGP статуса + Write-Host "BGP Summary:" -ForegroundColor Cyan + docker exec $ContainerName vtysh -c "show ip bgp summary" 2>$null + + # Показ логов + Write-Host "Recent logs:" -ForegroundColor Cyan + docker logs --tail=10 $ContainerName + + Write-Host "`nBGP Server (FRR) is ready!" -ForegroundColor Green + Write-Host "To view logs: docker logs -f $ContainerName" -ForegroundColor Cyan + Write-Host "To check BGP status: docker exec $ContainerName vtysh -c 'show ip bgp summary'" -ForegroundColor Cyan + Write-Host "To access FRR CLI: docker exec -it $ContainerName vtysh" -ForegroundColor Cyan + } else { + Write-Host "FRR failed to start properly. Check logs:" -ForegroundColor Red + docker logs $ContainerName } - - if ($Monitor) { - Write-Host "Starting monitoring..." -ForegroundColor Yellow - docker exec bgp-server python3 /app/scripts/monitor.py - } - } else { - Write-Host "✗ Failed to start BGP server" -ForegroundColor Red - Write-Host "Check logs with: docker-compose logs bgp-server" -ForegroundColor Yellow + Write-Host "Failed to start container. Check the error above." -ForegroundColor Red exit 1 -} - -Write-Host "=== Setup Complete ===" -ForegroundColor Green -Write-Host "Useful commands:" -ForegroundColor Cyan -Write-Host " View logs: docker-compose logs -f bgp-server" -ForegroundColor White -Write-Host " Check status: docker-compose ps" -ForegroundColor White -Write-Host " Stop server: docker-compose down" -ForegroundColor White -Write-Host " Monitor: docker exec bgp-server python3 /app/scripts/monitor.py" -ForegroundColor White \ No newline at end of file +} \ No newline at end of file diff --git a/scripts/start.sh b/scripts/start.sh index 905b8ce..c78e455 100644 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -1,56 +1,24 @@ #!/bin/bash -# Скрипт запуска BGP сервера +# Скрипт запуска BGP сервера на FRR set -e -echo "Starting BGP Server..." +echo "Starting BGP Server (FRR)..." # Создание директорий если не существуют mkdir -p /app/logs mkdir -p /app/run -mkdir -p /run/exabgp mkdir -p /app/data +mkdir -p /var/run/frr +mkdir -p /etc/frr # Установка правильных прав доступа chmod 755 /app/logs chmod 755 /app/run -chmod 755 /run/exabgp chmod 755 /app/data - -# Удаление старых named pipes если они существуют -echo "Cleaning up old named pipes..." -for dir in /run/exabgp /var/run/exabgp /usr/local/run/exabgp /usr/local/var/run/exabgp; do - if [ -d "$dir" ]; then - echo "Cleaning $dir..." - rm -f $dir/exabgp.in $dir/exabgp.out - rmdir $dir 2>/dev/null || true - fi -done - -# Создание named pipes для CLI в стандартном месте -echo "Creating named pipes for ExaBGP CLI..." -for dir in /run/exabgp /var/run/exabgp /usr/local/run/exabgp /usr/local/var/run/exabgp; do - mkdir -p $dir - echo "Creating named pipes in $dir..." - - # Проверяем, существуют ли уже named pipes - if [ ! -p "$dir/exabgp.in" ]; then - mkfifo $dir/exabgp.in - chmod 666 $dir/exabgp.in - echo "Created $dir/exabgp.in" - else - echo "Named pipe $dir/exabgp.in already exists" - fi - - if [ ! -p "$dir/exabgp.out" ]; then - mkfifo $dir/exabgp.out - chmod 666 $dir/exabgp.out - echo "Created $dir/exabgp.out" - else - echo "Named pipe $dir/exabgp.out already exists" - fi -done +chmod 755 /var/run/frr +chmod 755 /etc/frr # Проверка наличия файлов с префиксами if [ ! -f "/app/data/prefixes.txt" ]; then @@ -62,9 +30,9 @@ fi # Создание лог-файлов с правильными правами echo "Creating log files with proper permissions..." touch /app/logs/prefixes.log -touch /app/logs/exabgp.log +touch /app/logs/frr.log chmod 666 /app/logs/prefixes.log -chmod 666 /app/logs/exabgp.log +chmod 666 /app/logs/frr.log echo "Prefixes file content:" cat /app/data/prefixes.txt @@ -77,7 +45,7 @@ ls -la /app/scripts/ echo "---" # Генерация конфигурации из переменных окружения -echo "Generating ExaBGP configuration from environment variables..." +echo "Generating FRR configuration from environment variables..." echo "Environment variables:" env | grep BGP_ || echo "No BGP_ variables found" echo "---" @@ -85,11 +53,20 @@ echo "---" python3 /app/scripts/generate_config.py # Проверка конфигурации -echo "Validating ExaBGP configuration..." +echo "Validating FRR configuration..." echo "Configuration file content:" -cat /app/exabgp.conf +cat /etc/frr/frr.conf echo "---" -exabgp --validate /app/exabgp.conf + +# Проверка синтаксиса конфигурации FRR +if vtysh -c "show running-config" > /dev/null 2>&1; then + echo "FRR configuration validation passed" +else + echo "FRR configuration validation failed" + echo "Full config content:" + cat /etc/frr/frr.conf + exit 1 +fi # Тестовый запуск скрипта загрузки префиксов echo "Testing prefix loader script..." @@ -105,135 +82,108 @@ else echo "Warning: Cannot reach $NEIGHBOR_IP. BGP session may not establish." fi -# Запуск ExaBGP в фоновом режиме с логированием -echo "Starting ExaBGP..." -LOG_LEVEL=${BGP_LOG_LEVEL:-INFO} +# Запуск FRR демонов +echo "Starting FRR daemons..." -# Дополнительная проверка конфигурационного файла -echo "Final config file check:" -ls -la /app/exabgp.conf -echo "Config file first few lines:" -head -10 /app/exabgp.conf -echo "---" +# Запуск zebra (обязательный демон для FRR) +echo "Starting zebra daemon..." +zebra -d -f /etc/frr/frr.conf -A 127.0.0.1 -z /var/run/frr/zebra.api +sleep 2 -# Проверка что ExaBGP может прочитать файл -echo "Testing ExaBGP config validation:" -if exabgp --validate /app/exabgp.conf; then - echo "Configuration validation passed" -else - echo "Configuration validation failed" - echo "Full config content:" - cat /app/exabgp.conf - exit 1 -fi -echo "---" +# Запуск bgpd +echo "Starting bgpd daemon..." +bgpd -d -f /etc/frr/frr.conf -A 127.0.0.1 -z /var/run/frr/zebra.api +sleep 2 -# Проверка переменных окружения и путей -echo "Environment check:" -echo "PWD: $PWD" -echo "PATH: $PATH" -echo "PYTHONPATH: $PYTHONPATH" -echo "BGP_ variables:" -env | grep BGP_ || echo "No BGP_ variables found" -echo "---" +# Проверка что демоны запустились +echo "Checking if FRR daemons are running..." +ps aux | grep -E "(zebra|bgpd)" | grep -v grep || echo "No FRR daemons found in ps" -# Запуск ExaBGP -echo "Starting ExaBGP with config: /app/exabgp.conf" - -# Проверяем что файл существует и читается -if [ ! -f "/app/exabgp.conf" ]; then - echo "ERROR: Configuration file /app/exabgp.conf not found!" - exit 1 -fi - -if [ ! -r "/app/exabgp.conf" ]; then - echo "ERROR: Configuration file /app/exabgp.conf is not readable!" - exit 1 -fi - -# Запуск ExaBGP с правильными параметрами -cd /app -echo "Starting ExaBGP in background..." - -# Запуск ExaBGP в фоновом режиме -if [ -n "$LOG_LEVEL" ]; then - nohup exabgp --log.level $LOG_LEVEL /app/exabgp.conf > /app/logs/exabgp.log 2>&1 & -else - nohup exabgp /app/exabgp.conf > /app/logs/exabgp.log 2>&1 & -fi -EXABGP_PID=$! - -# Проверяем что процесс запустился -sleep 5 -echo "Checking if ExaBGP process is running..." -ps aux | grep exabgp | grep -v grep || echo "No exabgp process found in ps" - -if ! kill -0 $EXABGP_PID 2>/dev/null; then - echo "Failed to start ExaBGP. Checking logs:" - cat /app/logs/exabgp.log - echo "Trying to run ExaBGP directly for diagnosis:" - exabgp --version - echo "---" - echo "Direct execution test:" - timeout 10 exabgp /app/exabgp.conf || echo "Direct execution completed" - exit 1 -fi - -# Сохранение PID -echo $EXABGP_PID > /app/logs/exabgp.pid +# Сохранение PID файлов +echo "Saving PID files..." +pgrep zebra > /app/logs/zebra.pid 2>/dev/null || echo "zebra PID not found" +pgrep bgpd > /app/logs/bgpd.pid 2>/dev/null || echo "bgpd PID not found" # Ожидание запуска sleep 5 -# Проверка статуса -if kill -0 $EXABGP_PID 2>/dev/null; then - echo "ExaBGP started successfully with PID: $EXABGP_PID" - echo "Recent logs:" - tail -10 /app/logs/exabgp.log +# Проверка статуса через vtysh +echo "Checking FRR status via vtysh..." +if vtysh -c "show version" > /dev/null 2>&1; then + echo "FRR started successfully" + echo "FRR version:" + vtysh -c "show version" 2>/dev/null || echo "Could not get version" - # Дополнительная проверка через несколько секунд - sleep 3 - if kill -0 $EXABGP_PID 2>/dev/null; then - echo "ExaBGP is still running after 3 seconds" - echo "Process details:" - ps aux | grep exabgp | grep -v grep || echo "Process not found in ps output" - else - echo "ExaBGP process died after startup" - echo "Full logs:" - cat /app/logs/exabgp.log - exit 1 - fi + echo "BGP neighbors:" + vtysh -c "show ip bgp neighbors" 2>/dev/null || echo "Could not get BGP neighbors" + + echo "BGP summary:" + vtysh -c "show ip bgp summary" 2>/dev/null || echo "Could not get BGP summary" else - echo "Failed to start ExaBGP" - echo "Full logs:" - cat /app/logs/exabgp.log - echo "---" - echo "Process status:" - ps aux | grep exabgp || echo "No exabgp process found" + echo "Failed to start FRR. Checking logs:" + cat /app/logs/frr.log 2>/dev/null || echo "No FRR logs found" exit 1 fi +# Запуск скрипта загрузки префиксов в фоновом режиме +echo "Starting prefix loader in background..." +python3 /app/scripts/load_prefixes.py > /app/logs/prefixes.log 2>&1 & +PREFIX_LOADER_PID=$! +echo $PREFIX_LOADER_PID > /app/logs/prefix_loader.pid + +# Запуск монитора в фоновом режиме +echo "Starting monitor in background..." +python3 /app/scripts/monitor.py > /app/logs/monitor.log 2>&1 & +MONITOR_PID=$! +echo $MONITOR_PID > /app/logs/monitor.pid + +echo "All services started successfully!" +echo "Recent logs:" +tail -10 /app/logs/prefixes.log 2>/dev/null || echo "No prefix logs yet" +echo "---" + # Функция для graceful shutdown cleanup() { - echo "Shutting down BGP server..." - if [ -f "/app/logs/exabgp.pid" ]; then - kill $(cat /app/logs/exabgp.pid) 2>/dev/null || true + echo "Received shutdown signal. Cleaning up..." + + # Остановка скриптов + if [ -f "/app/logs/prefix_loader.pid" ]; then + kill $(cat /app/logs/prefix_loader.pid) 2>/dev/null || true fi + + if [ -f "/app/logs/monitor.pid" ]; then + kill $(cat /app/logs/monitor.pid) 2>/dev/null || true + fi + + # Отзыв всех префиксов + echo "Withdrawing all prefixes..." + python3 /app/scripts/load_prefixes.py --withdraw > /dev/null 2>&1 || true + + # Остановка FRR демонов + echo "Stopping FRR daemons..." + killall bgpd 2>/dev/null || true + killall zebra 2>/dev/null || true + + echo "Cleanup completed." exit 0 } -# Обработка сигналов +# Установка обработчиков сигналов trap cleanup SIGTERM SIGINT # Ожидание завершения -echo "Waiting for ExaBGP to run..." -echo "Process status:" -ps aux | grep exabgp || echo "No exabgp process found" -echo "---" - -# Проверка процесса загрузки префиксов -echo "Checking prefix loader process:" -ps aux | grep load_prefixes || echo "No prefix loader process found" -echo "---" - -wait $EXABGP_PID \ No newline at end of file +echo "BGP Server is running. Press Ctrl+C to stop." +while true; do + sleep 10 + + # Проверка что демоны все еще работают + if ! pgrep zebra > /dev/null; then + echo "ERROR: zebra daemon stopped unexpectedly" + exit 1 + fi + + if ! pgrep bgpd > /dev/null; then + echo "ERROR: bgpd daemon stopped unexpectedly" + exit 1 + fi +done \ No newline at end of file diff --git a/scripts/stop-server.ps1 b/scripts/stop-server.ps1 index e0f29be..bf4ddb4 100644 --- a/scripts/stop-server.ps1 +++ b/scripts/stop-server.ps1 @@ -1,33 +1,66 @@ -# PowerShell скрипт для остановки BGP сервера +# Скрипт остановки BGP Server (FRR) -Write-Host "=== Stopping BGP Server ===" -ForegroundColor Yellow +param( + [string]$ContainerName = "bgp-server", + [switch]$Force +) -# Проверка что контейнер запущен -$containerStatus = docker ps --filter name=bgp-server --format "{{.Status}}" -if (!$containerStatus) { - Write-Host "BGP server is not running" -ForegroundColor Yellow +Write-Host "=== BGP Server (FRR) Stop Script ===" -ForegroundColor Green + +# Проверка существования контейнера +$containerExists = docker ps -a --filter "name=$ContainerName" --format "table {{.Names}}" | Select-String $ContainerName + +if (-not $containerExists) { + Write-Host "Container $ContainerName not found." -ForegroundColor Yellow exit 0 } -Write-Host "BGP server is running. Stopping..." -ForegroundColor Yellow +# Проверка статуса контейнера +$containerRunning = docker ps --filter "name=$ContainerName" --format "table {{.Names}}" | Select-String $ContainerName -# Остановка контейнера -docker-compose down - -if ($LASTEXITCODE -eq 0) { - Write-Host "✓ BGP server stopped successfully" -ForegroundColor Green +if ($containerRunning) { + Write-Host "Container $ContainerName is running. Stopping..." -ForegroundColor Yellow + + if (-not $Force) { + $response = Read-Host "Do you want to stop the container? (y/N)" + if ($response -ne "y" -and $response -ne "Y") { + Write-Host "Operation cancelled." -ForegroundColor Red + exit 0 + } + } + + # Graceful shutdown - отзыв префиксов + Write-Host "Withdrawing prefixes..." -ForegroundColor Yellow + docker exec $ContainerName python3 /app/scripts/load_prefixes.py --withdraw 2>$null + + # Остановка контейнера + Write-Host "Stopping container..." -ForegroundColor Yellow + docker stop $ContainerName + + if ($LASTEXITCODE -eq 0) { + Write-Host "Container stopped successfully!" -ForegroundColor Green + } else { + Write-Host "Failed to stop container." -ForegroundColor Red + exit 1 + } } else { - Write-Host "✗ Failed to stop BGP server" -ForegroundColor Red - exit 1 + Write-Host "Container $ContainerName is not running." -ForegroundColor Yellow } -# Проверка что контейнер остановлен -$containerStatus = docker ps --filter name=bgp-server --format "{{.Status}}" -if (!$containerStatus) { - Write-Host "✓ Container is stopped" -ForegroundColor Green +# Удаление контейнера если требуется +if ($Force) { + Write-Host "Removing container..." -ForegroundColor Yellow + docker rm $ContainerName 2>$null + + if ($LASTEXITCODE -eq 0) { + Write-Host "Container removed successfully!" -ForegroundColor Green + } else { + Write-Host "Container was already removed or removal failed." -ForegroundColor Yellow + } } else { - Write-Host "✗ Container is still running" -ForegroundColor Red - exit 1 + Write-Host "Container stopped but not removed." -ForegroundColor Cyan + Write-Host "To remove container, run: docker rm $ContainerName" -ForegroundColor Cyan + Write-Host "Or use -Force parameter to stop and remove in one command." -ForegroundColor Cyan } -Write-Host "=== BGP Server Stopped ===" -ForegroundColor Green \ No newline at end of file +Write-Host "BGP Server (FRR) stopped successfully!" -ForegroundColor Green \ No newline at end of file