Learning Platform
Глоссарий Troubleshooting
Урок 06.02 · 20 мин
Начальный
CIDRSubnetNetmaskIP Addressing

Subnetting и CIDR — как делить IP-пространство

В прошлом уроке мы увидели, что IP-адрес — 32 бита, и что классов A/B/C недостаточно для разумного использования. Сейчас поговорим о том, как современные сети делят адресное пространство гибко: с помощью subnet masks и CIDR-нотации.

Это самая «арифметическая» часть курса networking. Считать subnet’ы вы будете каждый день: разрабатывая VPC в облаке, создавая namespace в Kubernetes, настраивая VPN. Понимание того, что значит /24, /16, /27 — базовое умение. Без него вы будете гадать, поместится ли ваш кластер в 10.0.0.0/22 или нет.

Bridge network и публикация портов в Docker

Что такое подсеть

Подсеть (subnet) — это группа IP-адресов с общим префиксом. Все адреса в подсети считаются «соседями» — между ними работает прямая L2-связность (через свитч), и пакеты не нужно маршрутизировать.

Пример: подсеть 192.168.1.0/24 — это адреса от 192.168.1.0 до 192.168.1.255. Их 256, из них:

  • 192.168.1.0 — адрес сети (Network address). Не назначается хосту.
  • 192.168.1.255 — broadcast-адрес. Не назначается хосту.
  • 192.168.1.1192.168.1.254 — доступны для хостов. 254 полезных адреса.

Обозначение /24 называется CIDR-префиксом. Оно говорит, что первые 24 бита — это сетевая часть, а последние 8 бит — хостовая.

192.168.1.0/24 -- разбор префикса
11000000 10101000 00000001Первые 24 бита (сетевая часть). Они одинаковые для всех хостов в подсети
00000000 - 11111111Последние 8 бит (хостовая часть). Различаются для каждого хоста. 256 комбинаций
192.168.1Префикс в десятичной форме. Это общая часть для всех хостов в подсети
.0 ... .255Хостовая часть в десятичной. .0 = network, .255 = broadcast, .1-.254 = хосты
/24CIDR notation. Число после слэша -- сколько бит занимает сетевая часть

Subnet mask — альтернативная нотация

До CIDR использовали subnet mask — 32-битное число, в котором единицы стоят на месте сетевой части, нули — на месте хостовой. Для /24 маска 255.255.255.0:

11111111 11111111 11111111 00000000
^^^^^^^^ ^^^^^^^^ ^^^^^^^^ ^^^^^^^^
   255      255      255       0
^^^^^^^^^^^^^^^^^^^^^^^^^^
   24 единицы = /24

Соответствие маски и CIDR-префикса:

CIDRМаскаХостов
/8255.0.0.016,777,214
/16255.255.0.065,534
/24255.255.255.0254
/25255.255.255.128126
/26255.255.255.19262
/27255.255.255.22430
/28255.255.255.24014
/29255.255.255.2486
/30255.255.255.2522
/32255.255.255.2551 (single host)

Формула: для /N доступно 2^(32-N) - 2 адресов (минус network и broadcast).

В современных конфигах увидите оба формата:

# IP с маской через CIDR:
ip addr add 192.168.1.5/24 dev eth0

# То же с явной маской (старый стиль):
ifconfig eth0 192.168.1.5 netmask 255.255.255.0

# В AWS / GCP конфиге используется CIDR:
{ "vpc_cidr": "10.0.0.0/16", "subnet_cidr": "10.0.1.0/24" }

CIDR — современный стандарт. Маски — legacy. Если видите в туториале netmask 255.255.255.0, переводите в голове в /24.


Как посчитать диапазон подсети

Самая частая задача: дан CIDR-блок, какие в нём адреса? Например, 10.20.30.0/22. Сколько хостов? Где network, где broadcast?

Алгоритм:

  1. Найти размер подсети. Для /22: 2^(32-22) = 2^10 = 1024 адреса. Минус 2 — получаем 1022 полезных хостов.
  2. Найти, какие октеты затрагивает префикс. /22 = 16 (full first 2 octets) + 6 бит из третьего октета. Значит граница в третьем октете.
  3. Найти шаг (block size). В третьем октете 6 бит сетевой части и 2 бита хостовой. Шаг = 2^2 = 4. То есть подсети идут с шагом 4 в третьем октете: 10.20.0.0/22, 10.20.4.0/22, 10.20.8.0/22, …
  4. Найти, в какой подсети наш адрес. 10.20.30.0 — значит 30 / 4 = 7.5, ближайшее кратное 4 снизу — 28. Значит подсеть 10.20.28.0/22. То есть исходное 10.20.30.0/22 неточное — сеть фактически начинается с 10.20.28.0.
  5. Network и broadcast. Network = 10.20.28.0. Broadcast = network + (размер - 1) = 10.20.28.0 + 1024 - 1 = 10.20.31.255. Полезный диапазон: 10.20.28.1 - 10.20.31.254.

В Python это считается одной командой:

import ipaddress

net = ipaddress.IPv4Network('10.20.30.0/22', strict=False)
print(net.network_address)   # 10.20.28.0
print(net.broadcast_address) # 10.20.31.255
print(net.num_addresses)     # 1024
print(list(net.hosts())[:3]) # [IPv4Address('10.20.28.1'), '10.20.28.2', '10.20.28.3']
print(net.netmask)           # 255.255.252.0

Параметр strict=False нужен, если адрес в строке — не network address (как в нашем примере: .30.0 не выровнен на границу /22).

TIP

Запомните несколько ключевых блок-сайзов, и большинство расчётов будут в голове:

  • /30 — 4 адреса (2 полезных). Для point-to-point links.
  • /29 — 8 (6 полезных). Мелкая подсеть.
  • /28 — 16 (14). Для маленького отдела.
  • /27 — 32 (30). Средний офис.
  • /24 — 256 (254). Стандарт home/small office.
  • /16 — 65,536. VPC в AWS обычно /16 или /20.

CIDR — что это, откуда и зачем

CIDR (Classless Inter-Domain Routing, RFC 1519, 1993) — это отказ от классов A/B/C в пользу произвольных префиксов. До CIDR:

  • Если у вас 500 хостов, вам выдавали /16 (65K адресов).
  • 64,500 адресов просто пропадали.

С CIDR:

  • 500 хостов — /23 (512 адресов). Минимум потерь.
  • 1000 хостов — /22.
  • 100 хостов — /25.

CIDR также позволяет агрегацию (supernetting) в маршрутизации. Например, у провайдера 16 блоков /24 подряд от 10.20.0.0/24 до 10.20.15.0/24. Вместо 16 записей в routing table можно положить одну: 10.20.0.0/20 (включает всё). Это сильно уменьшает размер глобальных routing tables.

CIDR -- классы вне игры, размер любой
До CIDR (1980s)Класс A = /8, B = /16, C = /24. Между B и C разрыв в 257x по размеру. Маленькие компании брали B и тратили адреса
CIDR (1993+)Префикс /N может быть любой от /1 до /32. Подсеть подгоняется под нужный размер. Минимум потерь
AggregationНесколько мелких подсетей подряд можно объединить в одну запись. Уменьшает глобальные routing tables
SubnettingБольшую подсеть можно поделить на несколько маленьких. /16 -> 256 подсетей /24. Гибкое управление

Разделение /24 на меньшие подсети — пример

У вас есть 192.168.1.0/24 (256 адресов). Хотите разделить на 4 равные части.

Шаги:

  1. 4 подсети = 2^2, значит нужно «отдать» 2 бита из хостовой части в сетевую. Было /24, стало /26.
  2. Каждая /26 = 2^(32-26) = 2^6 = 64 адреса.
  3. Шаг между подсетями — 64 в последнем октете.

Получаем:

ПодсетьNetworkBroadcastХосты
/26 #1192.168.1.0192.168.1.63.1 - .62
/26 #2192.168.1.64192.168.1.127.65 - .126
/26 #3192.168.1.128192.168.1.191.129 - .190
/26 #4192.168.1.192192.168.1.255.193 - .254

Каждая подсеть теперь имеет 62 полезных адреса. Достаточно для 4 отдельных команд / VLAN-ов / окружений.

В Python:

import ipaddress

parent = ipaddress.IPv4Network('192.168.1.0/24')
for subnet in parent.subnets(new_prefix=26):
    print(f'{subnet} | hosts: {subnet.network_address + 1} - {subnet.broadcast_address - 1}')

# 192.168.1.0/26 | hosts: 192.168.1.1 - 192.168.1.62
# 192.168.1.64/26 | hosts: 192.168.1.65 - 192.168.1.126
# 192.168.1.128/26 | hosts: 192.168.1.129 - 192.168.1.190
# 192.168.1.192/26 | hosts: 192.168.1.193 - 192.168.1.254

Это работает для любого CIDR-блока. Хотите разделить /22 (1024 адреса) на 4 части по /24parent.subnets(new_prefix=24).


Variable-length subnetting (VLSM)

CIDR позволяет не только равные, но и неравные подсети. Это называется VLSM (Variable Length Subnet Masking). Идея: у вас в офисе есть отделы разного размера, незачем всем давать одинаковый кусок.

Пример: дано 10.0.0.0/22 (1024 адреса). Нужно:

  • VLAN dev: 500 хостов
  • VLAN ops: 100 хостов
  • VLAN guests: 50 хостов
  • VLAN management: 10 хостов

Решение (берём подсети от больших к меньшим):

VLANНужноРазмерCIDRNetworkBroadcast
dev500512/2310.0.0.010.0.1.255
ops100128/2510.0.2.010.0.2.127
guests5064/2610.0.2.12810.0.2.191
mgmt1016/2810.0.2.19210.0.2.207

Остаток: 10.0.2.208 - 10.0.3.255 = 304 адреса свободно для будущих VLAN.

VLSM -- разный размер для разных нужд
dev /23500 хостов нужно. /23 даёт 510 полезных адресов. Минимальные потери. 10.0.0.0 - 10.0.1.255
ops /25100 хостов. /25 = 126 полезных. 10.0.2.0 - 10.0.2.127
guests /2650 хостов. /26 = 62 полезных. 10.0.2.128 - 10.0.2.191
mgmt /2810 хостов. /28 = 14 полезных. 10.0.2.192 - 10.0.2.207

VLSM — стандартная практика в дизайне VPC в облаках, в офисных сетях, в провайдерских инфраструктурах.


Longest prefix match — как роутер выбирает маршрут

Когда роутер получает пакет, он смотрит в routing table и выбирает запись с самым длинным префиксом, которая покрывает dst IP. Это правило называется longest prefix match.

Пример routing table:

10.0.0.0/8     via 192.168.100.1
10.0.5.0/24    via 192.168.100.2
10.0.5.100/32  via 192.168.100.3

Пакет идёт на 10.0.5.100:

  • Подходят все три записи.
  • Самый длинный префикс — /32.
  • Пакет идёт через 192.168.100.3.

Пакет идёт на 10.0.5.200:

  • Подходят /8 и /24. /32 не подходит (это другой адрес).
  • Самый длинный — /24.
  • Пакет идёт через 192.168.100.2.

Пакет идёт на 10.5.5.5:

  • Подходит только /8.
  • Пакет идёт через 192.168.100.1.

Этот принцип везде — от маленького домашнего роутера до BGP в глобальном интернете. Об этом будет урок «routing basics» в модуле 6.


Default gateway и /0

0.0.0.0/0 — особенный префикс. Покрывает все возможные IP. Это так называемый default route — куда отправлять пакеты, если ни одна более специфичная запись не подходит.

# Linux routing table:
ip route show
# default via 192.168.1.1 dev eth0 proto dhcp
# 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.42
# 169.254.0.0/16 dev eth0 scope link

# default -- это псевдоним для 0.0.0.0/0

Когда вы пингуете 8.8.8.8:

  1. 8.8.8.8 не входит в 192.168.1.0/24 (не локальная сеть).
  2. Не входит в 169.254.0.0/16.
  3. Падает на default — идёт через 192.168.1.1.

Без default gateway машина может ходить только по локальной сети. Интернет недоступен.


Попробуй сам

# 1. Посмотреть свои подсети:
ip addr show
# inet 192.168.1.42/24 ...  -- ваш IP и маска

# 2. Посмотреть routing table:
ip route show
# Вы увидите вашу подсеть и default gateway

# 3. Посчитать подсеть в Python:
python3 -c "
import ipaddress
net = ipaddress.IPv4Network('10.0.0.0/22', strict=False)
print(f'Network: {net.network_address}')
print(f'Broadcast: {net.broadcast_address}')
print(f'Hosts: {net.num_addresses - 2}')
print(f'Mask: {net.netmask}')
"

# 4. Поделить подсеть на 8 равных:
python3 -c "
import ipaddress
parent = ipaddress.IPv4Network('10.0.0.0/24')
for s in parent.subnets(prefixlen_diff=3):
    print(s)
"
# Вывод: 8 подсетей /27 по 32 адреса каждая

# 5. Проверить, входит ли IP в подсеть:
python3 -c "
import ipaddress
ip = ipaddress.IPv4Address('192.168.1.100')
net = ipaddress.IPv4Network('192.168.1.0/24')
print(ip in net)
"

# 6. Сколько / какой CIDR нужен для N хостов:
# 100 хостов -> минимум /25 (126 полезных)
# 1000 хостов -> минимум /22 (1022 полезных)
# Формула: bits = ceil(log2(N+2)), prefix = 32-bits

# 7. Полезный калькулятор онлайн (для проверки):
# https://www.calculator.net/ip-subnet-calculator.html

Полезно вручную пройтись по нескольким /24 -> /26 разбиениям, чтобы прочувствовать арифметику. После 5-10 примеров будете считать в голове.


Проверка знанийKnowledge check
Вы проектируете VPC в AWS, нужно вместить 3 окружения: prod (200 серверов), staging (50 серверов), dev (30 серверов), плюс зарезервировать место под рост в 2 раза. Какой CIDR выбрать на VPC и как разбить на подсети? Учтите, что AWS забирает по 5 адресов из каждой подсети для своих нужд.
ОтветAnswer
Считаем потребности с учётом запаса x2 и резерва AWS: prod 200*2+5 = 405, staging 50*2+5 = 105, dev 30*2+5 = 65, итого 575 адресов. Округляем до степеней двойки с запасом: prod нужен минимум /23 (512 хостов -- немного маловато для 405 с запасом, лучше /22 = 1022); staging нужен /25 (128 -- покрывает 105); dev нужен /26 (64 -- покрывает 65 впритык, лучше /25 для запаса). Итого VPC должен включать /22 + /25 + /25 = 1024+128+128 ~ 1280 адресов. Выбираем VPC /20 (4096 адресов) -- это даёт огромный запас и стандартный размер для AWS. Например, VPC 10.0.0.0/20. Подсети: prod 10.0.0.0/22 (10.0.0.0-10.0.3.255), staging 10.0.4.0/25 (10.0.4.0-10.0.4.127), dev 10.0.4.128/25 (10.0.4.128-10.0.4.255). Свободно: 10.0.5.0 -- 10.0.15.255 (около 2800 адресов на будущее). Дополнительно: каждая prod-подсеть в AWS обычно дублируется в 3 availability zones -- это значит prod /22 на самом деле надо разбить на 3 /24 в разных AZ. Это типичный VPC design.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Что означает '/24' в CIDR-нотации 192.168.1.0/24?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5