Типы чипов
𝔯𝔱_𝔣𝔞𝔫CPU — Central Processing Unit.
Самый медленный, но самый гибкий элемент устройства — центральный процессор.
Он занимается обработкой протокольных пакетов и сложного поведения.

Его прелесть в том, что он управляется запущенными приложениями и «многозадачен». Логику легко изменить, просто поправив программный код. Такие вещи, как SPF, установка соседства по всем протоколам, генерация логов, аварий, подключение к пользовательским интерфейсам управления — все действия со сложной логикой — происходят на нём. Собственно, поэтому, например, вы можете наблюдать, что при высокой загрузке CPU становится некомфортно работать в консоли. Хотя трафик при этом ходит уверенно.
CPU берёт на себя функции Control Plane. На устройствах с программной пересылкой, участвует также и в Forwarding Plane. CPU может быть один на весь узел, а может быть отдельно на каждой плате в шасси при распределённой архитектуре. Результаты своей работы CPU записывает в оперативную память.
RAM — Random Access Memory.
Классическая оперативная память — куда без неё?

Мы ей адрес ячейки — она нам содержимое. В ней хранятся, так называемые Soft Tables (программные таблицы) — таблицы маршрутизации, меток, MAC-адресов. Когда вы выполняете команду «show ip route», запрос идёт именно в оперативку к Soft Tables. CPU работает именно с оперативной памятью — когда он посчитал маршрут, или построил LSP — результат записывается в неё. А уже оттуда изменения синхронизируются в Hard Tables в CAM/TCAM↓. Кроме того, периодически происходит синхронизация всего содержимого всех таблиц на случай, если вдруг по какой-то причине инкрементальные изменения не спустились корректно. Soft Tables не может быть непосредственно использован для передачи данных, потому что слишком медленно — обращение к оперативке идёт через ЦПУ и требуется алгоритмический поиск, затратный по времени. С оговоркой на NFV.
Кроме того на чипах RAM (DRAM) реализованы очереди: входные, выходные, интерфейсные.
CAM — Content-Addressable Memory.
Это особо-хитрый вид памяти.
Вы ей — значение, а она вам — адрес ячейки.
Content-Addressable означает, что адресация базируется на значениях (содержимом).

Значением, например, может быть, например DMAC. CAM прогоняет DMAC по всем своим записям и находит совпадение. В результате CAM выдаст адрес ячейки в классической RAM, где хранится номер выходного интерфейса. Дальше устройство обращается к этой ячейке и отправляет кадр, куда положено.
Для достижения максимальной скорости CAM и RAM располагаются очень близко друг к другу.
Не путать данную RAM с RAM, содержащей Soft Tables, описанной выше — это разные компоненты, расположенные в разных местах.

Прелесть CAM в том, что она возвращает результат за фиксированное время, не зависящее от количества и размера записей в таблице — О(1), выражаясь в терминах сложностей алгоритмов.
Достигается это за счёт того, что значение сравнивается одновременно со всеми записями. Одновременно! А не перебором.
На входе каждой ячейки хранения в CAM стоят сравнивающие элементы (мне очень нравится термин компараторы), которые могут выдавать 0 (разомкнуто) или 1 (замкнуто) в зависимости от того, что на них поступило и что записано.
В сравнивающих элементах записаны как раз искомые значения.
Когда нужно найти запись в таблице, соответствующую определённому значению, это значение прогоняется одновременно через ВСЕ сравнивающие элементы. Буквально, электрический импульс, несущий значения, попадает на все элементы, благодаря тому, что они подключены параллельно. Каждый из них выполняет очень простое действие, выдавая для каждого бита 1, если биты совпали, и 0, если нет, то есть замыкая и размыкая контакт. Таким образом та ячейка, адресом которой является искомое значение, замыкает всю цепь, электрический сигнал проходит и запитывает её.
Вот архитектура такой памяти:

Вот пример работы

А это схема реализации:

Это чем-то похоже на пару ключ-замок. Только ключ с правильной геометрией может поставить штифты замка в правильные положения и провернуть цилиндр. Вот только у нас много копий одного ключа и много разных конфигураций замков. И мы вставляем их все одновременно и пытаемся провернуть, а нужное значение лежит за той дверью, замок которой ключ откроет.
Для гибкого использования CAM мы берём не непосредственно значения из полей заголовков, а вычисляем их хэш. Хэш-функция используется для следующих целей:
- Длина результата значительно меньше, чем у входных значений. Так пространство MAC-адресов длиной 48 бит можно отобразить в 16-ибитовое значение, тем самым в 2^32 раза уменьшив длину значений, которые нужно сравнивать, и соответственно, размер CAM. Основная идея хэш-функции в том, что результат её выполнения для одинаковых входных данных всегда будет одинаков (например, как остаток от деления одного числа на другое — это пример элементарной хэш функции).
- Результат её выполнения на всём пространстве входных значений — это ± плоскость — все значения равновероятны. Это важно для снижения вероятности конфликта хэшей, когда два значения дают одинаковый результат. Конфликт хэшей, кстати, весьма любопытная проблема, которая описана в парадоксе дней рождения. Рекомендую почитать Hardware Defined Networking Брайна Петерсена, где помимо всего прочего он описывает механизмы избежания конфликта хэшей.
- Независимо от длины исходных аргументов, результат будет всегда одной длины. То есть на вход можно подать сложное сочетание аргументов, например, DMAC+EtherType, и для хранения не потребуется выделять более сложную структуру памяти.
Именно хэш закодирован в сравнивающие элементы. Именно хэш искомого значения будет сравниваться с ними. По принципу CAM схож с хэш-таблицами в программировании, только реализованными на чипах.
В этот принцип отлично укладывается также MPLS-коммутация, почему MPLS и сватали в своё время на IP.
Например:
- Пришёл самый первый Ethernet-кадр на порт коммутатора.
- Коммутатор извлёк SMAC, вычислил его хэш.
- Данный хэш он записал в сравнивающие элементы CAM, номер интерфейса откуда пришёл кадр в RAM, а в саму ячейку CAM адрес ячейки в RAM.
- Выполнил рассылку изначального кадра во все порты.
- Повторил пп. 1-5 ....
- Заполнена вся таблица MAC-адресов.
- Приходит Ethernet-кадр. Коммутатор сначала проверяет, известен ли ему данный SMAC (сравнивает хэш адреса с записанными хэшами в CAM) и, если нет, сохраняет.
- Извлекает DMAC, считает его хэш.
- Данный хэш он прогоняет через все сравнивающие элементы CAM и находит единственное совпадение.
- Узнаёт номер порта, отправляет туда изначальный кадр.
Резюме:
- Ячейки CAM адресуются хэшами.
- Ячейки CAM содержат (обычно) адрес ячейки в обычной памяти (RAM), потому что хранить конечную информацию — дорого.
- Каждая ячейка CAM имеет на входе сравнивающий элемент, который сравнивает искомое значение с хэш-адресом. От этого размер и стоимость CAM значительно больше, чем RAM.
- Проверка совпадения происходит одновременно во всех записях, отчего CAM дюже греется, зато выдаёт результат за константное время.
- CAM+RAM хранят Hard Tables (аппаратные таблицы), к которым обращается чип коммутации.
TCAM — Ternary Content-Addressable Memory.
Возвращаемся к вопросу, что не так с IP.
Если мы возьмём описанный выше CAM, то на любой DIP он очень редко сможет вернуть 1 во всех битах.
Дело в том, что DIP — это всегда один единственный адрес, а маршруты в таблице маршрутизации — это подсеть или даже агрегация более мелких маршрутов. Поэтому полного совпадения быть почти не может — кроме случая, когда есть маршрут /32.
Перед разработчиками чипов стояло два вопроса:
- Как это в принципе реализовать?
- Как из нескольких подходящих маршрутов выбрать лучший (с длиннейшей маской)?

Ответом стал TCAM, в котором «T» означает «троичный»". Помимо 0 и 1 вводится ещё одно значение Х — «не важно» (CAM иногда называют BCAM — Binary, поскольку там значения два — 0 и 1).
Тогда результатом поиска нужной записи в таблице коммутации будет содержимое той ячейки, где самая длинная цепочка 1 и самая короткая «не важно».
Например, пакет адресован на DIP 10.10.10.10.
В Таблице Маршрутизации у нас следующие маршруты:
0.0.0.0/0 10.10.10.8/29 10.10.0.0/16 10.8.0.0/13 Другие.
В сравнивающие элементы TCAM записываются биты маршрута, если в маске стоит 1, и «не важно», если 0.
При поиске нужной записи TCAM, как и CAM, прогоняет искомое значение одновременно по всем ячейкам. Результатом будет последовательность 0, 1 и «не важно».
Только те записи, которые вернули последовательность единиц, за которыми следуют «не важно» участвуют в следующем этапе селекции.
Далее из всех результатов выбирается тот, где самая длинная последовательность единиц — так реализуется правило Longest prefix match.
Очевидно, что мы-то своим зорким взглядом, сразу увидели, что это будет маршрут 10.10.10.8/29.

Решение на грани гениальности, за которое пришлось заплатить большую цену. Из-за очень высокой плотности транзисторов (у каждой ячейки их свой набор, а ячеек должны быть миллионы) они греются не меньше любого CPU — нужно решать вопрос отвода тепла. Кроме того, их производство стоит очень дорого, и не будет лукавством сказать, что стоимость сетевого оборудования и раньше и сейчас определяется именно наличием и объёмом TCAM.
Внимательный читатель обратил внимание на вопрос хэш-функций — ведь она преобразует изначальный аргумент во что-то совершенно непохожее на исходник, как же мы будем сравнивать 0, 1 и длины? Ответ: хэш функция здесь не используется. Описанный выше алгоритм — это сильное упрощения реальной процедуры, за деталями этого любознательного читателя отправлю к той же книге Hardware Defined Networking.
Однако память — это память — всего лишь хранит. Сама она трафик не передаёт — кто-то с ней должен взаимодействовать.
Автору не удалось найти общепринятые термины для обозначения тех или иных компонентов, поэтому он взял на себя смелость пользоваться собственным терминологическим аппаратом. Однако он готов в любой момент прислушаться к рекомендациям и адаптировать статью к универсальным определениям.
Тот компонент, который занимается передачей пакетов, называется чипом коммутации — FE — Forwarding Engine. Именно он парсит заголовки, запрашивает информацию в TCAM и перенаправляет пакеты к выходному интерфейсу. Работа с пакетом декомпозируется на множество мелких шагов, каждый из которых должен выполняться на скорости линии, и совокупное время отработки тракта должно быть адекватным требованиям сети. Реализован FE может быть на Сетевых Процессорах (NP), FPGA и элементарных ASIC или их последовательности.
Вот с элементарных ASIC и начнём.
ASIC — Application Specific Integrated Circuit.
Как следует из названия, это микросхема, решающая узкий спектр специфических задач. Алгоритм работы зашит в неё и не может быть изменён в дальнейшем.

Соответственно, на ASIC ложатся рутинные операции, которые никогда не поменяются со временем. ASIC занимается: АЦП, подсчёт контрольной суммы кадра, восстановление синхросигнала из Ethernet, сбор статистики принятых и отправленных пакетов. Например, мы наверняка знаем, где в кадре поле DMAC, его длину, как различить броадкастовые кадры, мультикастовые и юникастовые. Эти фундаментальные константы никогда не поменяются, поэтому функции, их использующие, могут быть алгоритмизированы аппаратно, а не программно.
Процесс разработки и отладки ASIC достаточно трудоёмок, поскольку в финальном чипе нет места ошибкам, зато когда он завершён, их можно отгружать камазами. ASIC стоит дёшево, потому что производство простое, массовое, вероятность ошибки низкая, а рынок сбыта огромный.
Согласно документации Juniper, на части устройств их PFE (Packet Forwarding Engine) основан на последовательности ASIC'ов и не использует более сложных микросхем.
Хорошим примером использования ASIC'ов сегодня могут служить фермы по майнингу криптовалют. Эволюция привела этот процесс от CPU через кластеры GPU к ASIC'ам, специализированным исключительно на майнинге, что позволило, уменьшить размер, энергопотребление и тепловыделение, сделав процесс значительно дешевле и невероятно масштабируемым, напрочь сметя доморощенных крипто-бизнесменов с карты конкурентов.
Programmable ASIC.
В последние годы наблюдается тенденция к реализации большинства функций на ASIC. Однако хочется оставить возможность программировать поведение. Поэтому появились так называемые Программируемые ASIC, которые обладают низкой стоимостью, высокой производительность и некоторой гибкостью.

FPGA — Field Programmable Gate Array.
Не всё по силам ASIC'ам. Всё, что касается минимального интеллекта и возможности повлиять на поведение чипа — это к FPGA.

Это программируемая микросхема, в которую заливается прошивка, определяющая её роль в оборудовании. Как и ASIC, FPGA изначально нацелен на решение какой-то задачи. То есть FPGA для пакетной сети и для управления подачей топлива в инжектор двигателя — вещи разные и прошивкой одно в другое не превратишь. Итак, имеем специализированный чип с возможностью управлять его поведением и модернизировать алгоритмы.
FPGA может использоваться для маршрутизации пакетов, перемаркировки, полисинга, зеркалирования. Например, извне мы можем сообщить чипу, что нужно отлавливать все BGP и LDP пакеты, отправляемые на CPU, в .pcap файл.
Зачем здесь гибкость и возможность программирования? Примеров много:
- ситуация выше, где нужно заложить в него новое правило полисинга, зеркалирования, маркировки
- внедрения нового функционала
- активация лицензируемой опции
- модернизация существующих алгоритмов
- добавление нового правила для анализа полей заголовков, например, для обработки нового протокола.
Получается без разработки новых чипов, перепайки транзисторов, выбраковывания целых партий, просто новой прошивкой можно сделать всё вышеприведённое и больше.
Опять же, если обнаружена неисправность, то можно написать патч для ПО, который сможет её починить, и при этом обновить только конкретно данный чип, без влияния на всю остальную систему.
FPGA значительно дороже в разработке и производстве, главным образом из-за заранее заложенной гибкости.
Из-за гибкости возможностей FPGA иногда используются для обкатки какой-либо новой технологии, когда с помощью прошивки можно менять поведение компонента. И когда логика обкатана, можно запускать в производство ASIC, реализующий её.
NP — Network Processor.
В оборудовании операторского класса, где требования как к пропускной способности, так и к протоколам, запущенным на устройстве, довольно высоки, часто используются специализированные чипы — сетевые процессоры — NP. В некотором смысле можно считать их мощными FPGA, направленными именно на обработку и передачу пакетов.

Крупные телеком-вендоры разрабатывают свои собственные процессоры (Cisco, Juniper, Huawei, Nokia), для производителей помельче существуют предложения от нескольких гигантов, вроде Marvell, Mellanox.
Задачи и возможности примерно те же, что и у FPGA. Дьявол кроется в деталях.