Почему IPv6 /64 не помещается в IPRange NetBox и как учитывать большие блоки без миллионов записей
Пытаетесь завести IPv6 /64 как IP Range в NetBox — получаете «Defined range exceeds maximum supported size», а не подсеть в системе. /64 — это 2^64 адресов, а IPRange ограничен 2^32−1 независимо от протокола. Разбираю, почему так устроено, чем заменить диапазон и как я перестроил учёт IPv6 клиенту на 49 рабочих мест.
Почему NetBox отказывается сохранять IPv6 /64 как IPRange
Сценарий одинаковый у всех, кто первый раз заводит IPv6 в NetBox: провайдер выдал делегацию, вы честно решили задокументировать её так же, как делали с IPv4-диапазонами — через IP Range, — и получили красную ошибку вместо созданной записи. Ситуация обидная именно потому, что с IPv4 всё работало годами, а тут NetBox как будто не понимает, что такое /64. На самом деле понимает — просто модель IPRange для таких блоков не предназначена, и я обычно первым делом объясняю это на входе, когда берём внедрение NetBox для клиента, у которого в плане IPv6.
Текст ошибки у всех одинаковый: «Defined range exceeds maximum supported size (4294967295)». Число не случайное — это 2^32−1, то есть максимум, который вообще может занимать поле IPRange, сколько бы адресов теоретически ни допускал протокол. У IPv4 это ограничение почти никогда не всплывает: /0 никто не заводит диапазоном. А вот у IPv6 уже /64 даёт 2^64 адресов, что на много порядков больше лимита, и NetBox обрывает попытку сохранения на уровне валидации модели, до записи в базу.
Важно: это не баг конкретной сборки и не то, что почему-то не успели поправить. В обсуждении на GitHub ограничение подтверждено в исходном коде NetBox 3.5.3, и тот же самый лимит независимо поймал пользователь на 4.3.6-Docker-3.3.0, пытаясь завести именно /64. Формулировка лимита в актуальной документации модели IPRange не делает исключения для IPv6 — максимум остаётся 2^32−1 адресов вне зависимости от версии протокола. Я отдельно открыл текущий исходник модели в ветке main (линейка 4.6, последний на сегодня релиз — 4.6.10 от 1 сентября 2026 года): в методе проверки IPRange по-прежнему стоит константа MAX_SIZE = 2 ** 32 - 1. Значит, ждать, что в следующем минорном релизе лимит уберут, не стоит: это осознанное ограничение модели, а не забытый край.
Как устроена модель IPRange и для чего она вообще нужна
Чтобы понять, почему лимит не «доработка», а осознанный дизайн, полезно посмотреть, из чего вообще состоит IPRange. По документации модели у неё есть VRF, начальный и конечный адрес, роль, статус и два флага — Mark Populated и Mark Utilized, которые управляют тем, как диапазон учитывается в статистике использования. Границы включительные: диапазон 192.0.2.10–192.0.2.20 в документации явно назван содержащим одиннадцать адресов, а не десять и не двенадцать — это тот нюанс, который стоит проверить один раз и больше не путать при расчёте размеров пулов.
Свойство size у IPRange — не абстрактное: это поле, которое NetBox сам вычисляет при сохранении как «конечный адрес минус начальный плюс один» и записывает в базу, а пользователь его не редактирует. Перед сохранением срабатывает валидация модели: она берёт ту же разницу адресов и сравнивает её с константой MAX_SIZE = 2^32−1. Для /64 разница — 2^64, проверка проваливается, и объект до базы просто не доходит. Отсюда и практический вывод: лимит — это не «тормоза интерфейса» и не особенность импорта CSV, одинаково откажут и веб-форма, и REST API, и скрипт через pynetbox, потому что все они проходят через одну и ту же валидацию модели.
Второй важный момент из документации — это назначение модели. IPRange задуман как способ описать произвольный диапазон отдельных адресов IPv4 или IPv6 для конкретной практической задачи, например пул под DHCP, а не как замену объекту IP-адреса для интерфейсов. Одноадресный диапазон (когда start и end совпадают) NetBox тоже разрешает — документация прямо называет его вариантом для DHCP- или NAT-пула из одного адреса и отдельно предупреждает, что он не заменяет объект IP Address на интерфейсе. Иными словами: IPRange — инструмент для описания «куска» внутри уже существующей подсети, а не способ завести всю подсеть целиком, особенно когда эта подсеть размером с /64 или больше.
Правильная модель для больших блоков: Prefix со статусом Container
Ответ на вопрос «куда девать /64, /56 или /48» дала та же ветка обсуждения на GitHub: для крупных блоков используется не IPRange, а Prefix со статусом Container, а IPRange остаётся для участка внутри префикса — например, под конкретный DHCP-пул. По документации Prefix — это IPv4- или IPv6-сеть с маской в нотации CIDR, а статус «container» означает, что префикс существует исключительно как контейнер для организации дочерних префиксов. Дерево строится естественно: /48 от провайдера — контейнер, /56 на площадку — контейнер, /64 на VLAN — обычный активный префикс.
Отдельно стоит держать в голове то, что явно оговорено в документации: статус родительского префикса не влияет на статус дочерних IP-адресов — они назначаются независимо. То есть вы можете сделать /48 контейнером, не боясь, что все адреса внутри него автоматически «замёрзнут» или получат неверный статус. VRF у префикса необязателен: если не назначен, NetBox считает такую сеть существующей в глобальной таблице, что для делегации провайдера обычно и требуется — отдельный VRF под IPv6 нужен не всем.
Ключевая практическая выгода Container-подхода в том, что он не требует заводить ни единой записи IP-адреса, пока адрес не понадобится физически — интерфейсу, DNS-записи или резервации DHCPv6. Именно поэтому подход и масштабируется: /48 в виде дерева префиксов — это условно пара сотен объектов на реальную инфраструктуру, а не миллионы строк, если бы кто-то попытался материализовать все адреса /64 по отдельности.
Как я перестроил учёт IPv6 у МобилМастер
МобилМастер — сеть точек ремонта мобильных телефонов, 49 рабочих мест, где мы ведём документацию инфраструктуры в NetBox вместо старых Excel-таблиц — пять салонов и центральный склад. Провайдер при подключении второго канала выдал делегацию /48 по IPv6 — до этого компания жила на IPv4 и NAT, и коллеги на месте честно попытались завести весь /48 одной записью IPRange, по привычке из IPv4-мира, где диапазон «от и до» — обычная практика для пула статических адресов. Итог — та самая ошибка максимального размера, и запрос ко мне «сломался NetBox».
Решение строилось по схеме из предыдущего раздела. Я завёл /48 как Prefix со статусом Container на уровне всей компании, внутри — по одному /56 на каждый из пяти салонов и склад (тоже Container, с запасом на будущие точки), а внутри каждого /56 — активные /64 на VLAN: пользовательский сегмент, гостевой Wi-Fi, сегмент касс и терминалов оплаты, техническая сеть видеонаблюдения. Ни один /64 при этом не создавался как IPRange — только как обычный Prefix со статусом Active, привязанный к своему сайту в NetBox.
IPRange в этой схеме тоже нашёл применение, но точечное: внутри конкретного активного /64 центрального склада, где стоят management-интерфейсы коммутаторов и точек доступа, я завёл диапазон под ручные резервации — условно полсотни адресов, а не 2^64. Такой диапазон прекрасно укладывается в лимит 2^32−1 и честно показывает утилизацию именно этого небольшого пула, а не всей /64 разом.
На перестройку схемы ушло около четырёх часов, включая проверку, что скрипты синхронизации DHCP-сервера смотрят на правильные объекты. Итог: дерево из тридцати с небольшим префиксов вместо попытки создать один невозможный диапазон, и понятная точка роста — когда откроется шестой салон, под него заводится ещё один /56 контейнер, без пересмотра всей структуры.
На сегменты внутри /56 у МобилМастер отдельно легли списки контроля доступа между VLAN — кассовый сегмент и видеонаблюдение не видят друг друга, а пользовательская сеть не достаёт до management-адресов коммутаторов из точечного IPRange. Адресация в NetBox и ACL на коммутаторах — разные системы, но проектировать их лучше вместе: имена VLAN и границы /64 из NetBox один в один ложатся в правила ACL, и не приходится потом сверять два независимых списка вручную.
Что меняется в автоматизации при переходе с IPRange на Prefix Container
Разница между моделями — не только концептуальная, она бьёт по интеграциям. У Prefix и у IPRange в REST API NetBox отдельные подресурсы available-ips: /api/ipam/prefixes/<id>/available-ips/ и /api/ipam/ip-ranges/<id>/available-ips/ — оба принимают GET для получения списка свободных адресов и POST для выдачи следующего свободного. Если ваш скрипт резервирования адресов был написан под ip-ranges, а вы перешли на схему Prefix Container с активными /64 внутри, дергать нужно уже эндпоинт префикса — причём не самого контейнера, а конкретного дочернего активного /64, потому что именно там NetBox знает, какие адреса заняты.
Второй момент, который стоит проверить перед миграцией, — как автоматика вообще ищет нужную запись: по имени, по тегу, по кастомному полю. Если скрипт искал IPRange по совпадению границ, после перехода на Prefix Container такого объекта уже не будет — вместо него дерево из нескольких префиксов, и логику поиска нужно переписывать под фильтрацию по within или contains в GraphQL или REST-запросах. Я обычно делаю это на этапе внедрения: набрасываю тестовый /48 в песочнице и прогоняю через него интеграцию, прежде чем переносить прод.
Частые грабли при вводе IPv6 в NetBox, кроме самого лимита
Первая типичная ошибка — попытка материализовать /64 отдельными записями IP-адресов «на всякий случай», по аналогии с тем, как некоторые заводят полностью занятую /24 по IPv4. Для IPv6 это математически бессмысленно: даже частичная материализация нескольких тысяч адресов раздувает таблицу без пользы, потому что реальных устройств в сети — десятки или сотни, а не миллионы. Правило простое: адрес заводится в NetBox тогда, когда он реально назначен интерфейсу, DNS-записи или зарезервирован под конкретное оборудование, а не заранее «про запас».
Вторая грабля — путаница с VRF при дублирующихся префиксах. NetBox допускает одинаковые по границам префиксы в разных VRF, и если часть команды заводит IPv6 без VRF (в глобальной таблице), а часть — с VRF «на всякий случай», в отчётах по утилизации начинается путаница: один и тот же /64 визуально существует в системе дважды. Я фиксирую правило VRF (или его отсутствие) для IPv6 одним решением на весь проект, до того как заводится первый префикс, и прописываю это в внутренней инструкции для сетевых инженеров.
Третье — флаги Mark Populated и Mark Utilized на IPRange, которые управляют тем, как диапазон учитывается в статистике использования на дашборде. Если диапазон завели, а флаги не выставили осознанно, отчёт по утилизации может показывать не то, что вы ожидаете — например, полностью свободный на вид пул, который на деле уже роздан вручную за пределами NetBox. Документация здесь конкретна: Mark Utilized заставляет считать диапазон занятым на 100 %, а Mark Populated ведёт себя так, будто все адреса внутри уже созданы, и запрещает заводить в диапазоне отдельные IP-адреса — для пула, которым рулит внешний DHCP-сервер, обычно включают оба флага. Это тот случай, когда одна лишняя проверка при заведении объекта экономит час разбирательства через полгода.
Четвёртое — включение IPv6 на самих шлюзах и коммутаторах часто идёт отдельным проектом от документирования адресации, и там свои сюрпризы: например, после включения IPv6 forwarding сервер неожиданно остаётся без маршрута по умолчанию из-за accept_ra. Я всегда развожу эти две задачи по времени — сначала фиксирую схему адресации в NetBox, потом включаю форвардинг и проверяю маршруты отдельно, чтобы не путать ошибку модели данных с ошибкой сетевого стека.
Чек-лист: что делать, если вы уже упёрлись в эту ошибку
Если ошибка максимального размера уже выскочила у вас, порядок действий такой. Сначала не пытайтесь обойти лимит уменьшением диапазона «пока не пройдёт» — это даст вам произвольный кусок /64 без смысловой границы, который потом придётся объяснять коллегам. Вместо этого сразу переходите к дереву префиксов: делегация целиком — Prefix Container, дочерние блоки по площадкам или сегментам — тоже Container при необходимости, а листовые /64 (или /127 для точка-точка линков, если работаете на таком уровне) — обычный Active Prefix.
Дальше проверьте, что уже успело сломаться в интеграциях: скрипты синхронизации DHCP/DNS, экспорт в системы мониторинга, отчёты по утилизации — всё, что раньше опиралось на объект IPRange, нужно перевести на работу с деревом префиксов и, при необходимости, на точечные IPRange внутри конкретных активных /64. И последнее — зафиксируйте схему VRF и правило «когда заводим адрес, а когда только префикс» письменно, чтобы следующий инженер в команде не наступил на те же грабли, что и вы сегодня.
- Лимит IPRange — 2^32−1 адресов, одинаков для IPv4 и IPv6; в актуальной ветке 4.6 он не изменился.
- Для делегаций и крупных блоков — Prefix со статусом Container, а не IPRange.
- IPRange оставляйте для точечных пулов внутри активного /64 (DHCP-пул, диапазон ручных резерваций).
- У Prefix и IPRange разные REST-эндпоинты available-ips — при миграции схемы проверьте интеграции.
- Не материализуйте /64 отдельными IP-адресами «про запас» — адрес заводится по факту назначения.
Частые вопросы
Какой именно лимит у IPRange и почему он одинаков для IPv4 и IPv6?
Максимум — 2^32−1 адресов (4294967295). Ограничение задано на уровне модели IPRange в NetBox, а не на уровне протокола, поэтому /64 IPv6 (2^64 адресов) в него не помещается точно так же, как не поместился бы гипотетический диапазон такого же размера в IPv4.
Можно ли вообще завести /64 в NetBox одной записью?
Да, но не как IPRange, а как Prefix. Для делегаций и крупных блоков используйте статус Container на верхних уровнях иерархии и обычный Active Prefix на листовом /64 — это ровно один объект на подсеть.
Если сделать родительский /48 контейнером, не «поломаются» ли статусы адресов внутри?
Нет. По документации статус родительского префикса не влияет на статус дочерних IP-адресов — они назначаются и меняются независимо друг от друга.
Где тогда уместен IPRange при работе с IPv6?
Внутри конкретного активного /64 — например, диапазон под ручные резервации management-адресов коммутаторов или под явно ограниченный DHCPv6-пул. Такой диапазон на порядки меньше лимита в 2^32−1 и осмысленно показывает утилизацию именно этого участка.
Нужно ли назначать VRF на IPv6-префиксы?
Не обязательно: VRF в Prefix — опциональное поле, а без него NetBox считает сеть существующей в глобальной таблице. Решение стоит зафиксировать одно на весь проект, чтобы не завести один и тот же /64 дважды — с VRF и без.
Актуально ли это ограничение в свежих релизах NetBox?
Да. Ограничение зафиксировано в исходном коде и в документации модели IPRange без оговорок про IPv6, а обсуждение на GitHub фиксирует одну и ту же ошибку и в старых, и в относительно новых сборках — это осознанный дизайн модели, а не временный баг конкретной версии.
Источники
- NetBox Labs Docs — IP Ranges — Максимальный размер IPRange 2^32−1 адресов, включительные границы (пример 192.0.2.10–192.0.2.20 = 11 адресов), поля VRF/Start/End/Role/Status/Mark Populated/Mark Utilized, назначение модели: https://netboxlabs.com/docs/netbox/models/ipam/iprange/
- NetBox Labs Docs — Prefixes — CIDR-нотация для IPv4/IPv6, статус container как способ организации дочерних префиксов, независимость статуса дочерних IP-адресов, опциональность VRF: https://netboxlabs.com/docs/netbox/models/ipam/prefix/
- GitHub Discussion #12846 — IP-ranges — Текст ошибки «Defined range exceeds maximum supported size (4294967295)», подтверждение лимита в NetBox 3.5.3, повтор на 4.3.6-Docker-3.3.0 для IPv6 /64, рекомендация использовать Prefix Container для крупных блоков: https://github.com/netbox-community/netbox/discussions/12846
- NetBox Labs Blog — An In-Depth Guide to NetBox for IPAM — Общий контекст модели IPAM в NetBox и место IPRange/Prefix в иерархии учёта адресного пространства: https://netboxlabs.com/blog/netbox-ipam/
- GitHub — исходный код NetBox, ipam/models/ip.py — Метод clean() модели IPRange: MAX_SIZE = 2 ** 32 - 1 и текст ошибки «Defined range exceeds maximum supported size»; поле size (PositiveIntegerField, editable=False) вычисляется в save(): https://github.com/netbox-community/netbox/blob/main/netbox/ipam/models/ip.py



