2. Упрощайте. Если есть сомнения, выбирайте самое простое решение. Уильям Оккам (William Occam) декларировал этот принцип еще в XIV веке (так называемая «Бритва Оккама»). Его можно кратко выразить так: «Борись с излишествами». Если какое-то свойство не является абсолютно необходимым, забудьте о нем, особенно если того же эффекта можно добиться комбинированием уже имеющихся свойств.
3. Всегда делайте четкий выбор. Если есть несколько способов реализации одного и того же, выбирайте только один из них. Увеличение количества способов приведет к проблемам. В стандартах часто можно встретить несколько опций, режимов или параметров лишь потому, что при разработке несколько авторитетных сторон настаивали на своем. Разработчики должны решительно сопротивляться подобным тенденциям. Надо просто уметь говорить «нет».
4. Используйте модульный принцип. Это правило напрямую ведет к идее стеков протоколов, в которых каждый уровень работает независимо от остальных. Таким образом, если обстоятельства требуют изменения одного модуля или уровня, то это не затрагивает другие части системы.
5. Учитывайте разнородность. Любая крупная сеть может содержать различные типы оборудования, средства передачи данных и приложения. Сетевая технология должна быть достаточно гибкой, простой и обобщенной, чтобы работать в таких условиях.
6. Избегайте статичности свойств и параметров. Если есть какие-то обязательные параметры (например, максимальный размер пакета), то лучше заставить отправителя и получателя договариваться об их конкретных значениях, чем жестко закреплять их.
7. Лучшее — враг хорошего. Очень часто разработчики создают хорошие проекты, но не могут предусмотреть какие-нибудь необычные частные случаи. Не стоит портить то, что в большинстве ситуаций работает нормально. Лучше переложить бремя ответственности за «улучшения» проекта на тех, кто предъявляет свои странные требования.
8. Будьте строги при отправке, но снисходительны при получении. Другими словами, передавайте только те пакеты, которые полностью соответствуют всем требованиям стандартов. При этом имейте в виду, что входящие пакеты не всегда идеальны и нужно постараться их обработать.
9. Продумайте масштабируемость. Если в сети работают миллионы хостов и миллиарды пользователей, о централизации можно забыть. Нагрузка должна быть распределена максимально равномерно между имеющимися ресурсами.
10. Помните о производительности и цене. Никто не будет использовать низкопроизводительную или дорогостоящую сеть.
Перейдем от общих принципов к деталям построения сетевого уровня интернета. Здесь интернет можно рассматривать как набор соединенных друг с другом сетей или автономных систем (АС). Структуры как таковой он не имеет, но все же существует несколько магистралей. Они состоят из высокопроизводительных линий и быстрых маршрутизаторов.
Самые крупные магистрали (к которым необходимо подключиться, чтобы получить доступ к остальной части интернета) называются сетями Tier 1 (Tier 1 networks). К ним присоединены провайдеры, обеспечивающие доступ к интернету для домашних пользователей и предприятий, дата-центров и станций колокации с большим числом серверов, а также для региональных сетей (сетей среднего уровня). Центры обработки данных обслуживают большую часть интернет-трафика. К региональным сетям присоединяются другие интернет-провайдеры, LAN многочисленных университетов и компаний, а также прочие периферийные сети. Эта квазииерархическая структура схематично показана на илл. 5.46.
Вся эта конструкция держится благодаря протоколу IP (Internet Protocol). В отличие от большинства ранних протоколов сетевого уровня, IP с самого начала разрабатывался для межсетевого обмена. Его задача — предоставить уровень обслуживания best effort (то есть без гарантий) при передаче пакетов от отправителя к получателю, независимо от того, находятся они в одной сети или нет.
Обмен данными в интернете происходит следующим образом. Транспортный уровень разбивает потоки данных так, чтобы их можно было отправить в виде IP-пакетов. В теории каждый пакет может достигать 64 Кбайт, но на практике он обычно не превышает 1500 байт (укладывается в один фрейм Ethernet). IP-маршрутизаторы передают пакеты по сети, от одного маршрутизатора к другому,
Илл. 5.46. Интернет представляет собой набор соединенных друг с другом сетей
пока они не достигнут места назначения. Там сетевой уровень отдает данные транспортному, а тот помещает их во входной поток принимающего процесса. Когда фрагменты приходят на устройство адресата, сетевой уровень собирает их в исходную дейтаграмму, которая затем передается транспортному уровню.
В примере на илл. 5.46 пакет, отправленный хостом домашней сети, пройдет через четыре сети и множество IP-маршрутизаторов, прежде чем доберется до сети предприятия, где расположен хост-получатель. Это обычная практика, а маршруты бывают значительно длиннее. С точки зрения связности интернет является избыточным: магистрали и провайдеры часто соединяются в нескольких точках. Отсюда и множественные пути между хостами. Задача IP — выбрать наилучший маршрут.
5.7.1. Протокол IP версии 4
Мы начнем изучение сетевого уровня интернета с формата IPv4-дейтаграмм. Такая дейтаграмма состоит из заголовка и основной части (пользовательских данных). Заголовок содержит фиксированную 20-байтную часть, а также необязательную часть, длина которой варьируется. Формат заголовка показан на илл. 5.47. Биты передаются слева направо и сверху вниз, то есть старший бит поля Version (Версия) идет первым. (Такой порядок байтов называется «от старшего к младшему» («big-endian»). На компьютерах с порядком «от младшего к старшему» («little-endian»), например Intel x86, требуется программное преобразование, как при передаче, так и при приеме.) Сегодня уже совершенно ясно, что для IP лучше было использовать порядок «от младшего к старшему», но на момент создания протокола это было не столь очевидно.
Поле Version содержит версию протокола, к которому принадлежит дейтаграмма. Сейчас в интернете доминирует версия 4, поэтому с нее мы и начали обсуждение IP. Указание версии в начале каждой дейтаграммы позволяет переходить от одной версии к другой в течение долгого времени. На самом деле протокол IPv6 (следующая версия IP) разработан более десяти лет назад, но применять его начинают только сегодня. О нем мы поговорим позже в этом разделе. Широкое распространение протокол IPv6 получит, когда у каждого из почти 231 жителей Китая будет настольный ПК, ноутбук и IP-телефон. Что касается нумерации, то ничего странного в ней нет: в свое время существовал малоизвестный экспериментальный потоковый протокол реального времени IPv5.
Илл. 5.47. Заголовок IPv4
Поскольку длина заголовка является переменной величиной, она указывается в поле IHL и выражается в 32-разрядных словах. Минимальное значение длины — при отсутствии поля Options (Опции) — равно 5. Максимальное значение этого 4-битного поля равно 15, что соответствует заголовку длиной 60 байт; таким образом, максимальный размер поля Options равен 40 байтам. Для некоторых функций, например для записи маршрута, пройденного пакетом, 40 байт недостаточно, и дополнительное поле оказывается бесполезным.
Поле Differentiated services (Дифференцированное обслуживание) — одно из немногих полей, смысл которых с годами слегка изменился. Изначально оно называлось Type of service (Тип службы). Его задача (была и остается) — определять различные классы обслуживания. Возможны разные комбинации надежности и скорости. Для цифрового голосового сигнала скорость доставки важнее точности. При передаче файла, наоборот, отсутствие ошибок важнее быстрой доставки. В поле Type of service 3 бита обозначали приоритет, еще 3 бита показывали, что беспокоит хост больше всего: задержка, пропускная способность или надежность. Никто не знал, что делать со всеми этими битами на маршрутизаторах, поэтому они не использовались в течение многих лет. Когда появилось дифференцированное обслуживание, IETF сдался и нашел этому полю другое применение. Теперь первые 6 бит задают класс обслуживания; о срочном и гарантированном обслуживании мы уже говорили ранее в этой главе. В последние два бита помещаются явные уведомления о перегрузке, которые обсуждались в разделе 5.3.
Поле Total length (Полная длина) содержит длину всей дейтаграммы: заголовок и данные. Максимальная длина дейтаграммы — 65 535 байт. В настоящий момент этого достаточно, однако для будущих сетей могут понадобиться дейтаграммы большего размера.
Поле Identification (Идентификация) позволяет хосту-получателю определить, какому пакету принадлежат принятые им фрагменты. Все фрагменты одного пакета содержат одно и то же значение идентификатора.
Далее идет неиспользуемый бит, что достаточно странно, так как место в IP-заголовке крайне ограниченно. В качестве первоапрельской шутки Белловин (Bellovin, 2003) предложил использовать его для обнаружения вредоносного трафика. Это значительно упростило бы защиту сети: пакеты с таким битом можно было бы просто удалять, зная, что они отправлены злоумышленниками. К сожалению, сетевую безопасность невозможно обеспечить столь простым способом, как бы заманчиво идея ни выглядела.
Затем следуют два однобитных поля, относящиеся к фрагментации. Бит DF означает «Don’t Fragment» («Не фрагментировать»); он запрещает маршрутизатору фрагментировать пакет. Изначально предполагалось, что это поле будет помогать хостам, которые не могут восстановить пакет из фрагментов. Сейчас оно используется при определении путевого значения MTU, которое равно максимальному размеру пакета, передаваемого по пути без фрагментации. Пометив дейтаграмму битом DF, отправитель гарантирует, что либо дейтаграмма дойдет единым блоком, либо отправитель получит сообщение об ошибке.
Бит MF означает «More Fragments» («Дополнительные фрагменты»). Он устанавливается во всех фрагментах, кроме последнего. По этому биту получатель узнает о прибытии последнего фрагмента дейтаграммы.