Привет, Хабр! Меня зовут Влад Редров, я старший инженер-программист в отделе разработки компонентов опорной сети 5G в YADRO. Сегодня расскажу про Policy and Charging Control (PCC): будем ставить проблемы, а потом через способы их решения наращивать набор PCC-фич и осознавать логику их работы. Разберем, как ограничивать скорость сессии для каждого мобильного устройства через Session-AMBR и QoS-характеристики, применять QoS-характеристики к разным сервисам, тарифицировать каждый сервис отдельно и еще много всего интересного.
Сессионные политики
Немного базы. Policy and Charging Control (PCC) — это архитектура для управления политиками и контроля тарификации услуг в телекоммуникационных сетях. С ее помощью операторы сети динамически контролируют сессии абонентов, применяют гибкие модели тарификации и в целом управляют качеством обслуживания (QoS). Как все это работает, посмотрим ниже.
Начнем с PDU-сессии. Простейшая модель выглядит так:

У нас есть мобильное устройство (UE), базовая станция (gNB), UPF и интернет. У мобильного устройства установлена сессия, то есть опорная сеть его авторизовала и предоставила в рассматриваемой модели неограниченный доступ в интернет. Но есть проблема: таких устройств много. Если все они будут потреблять трафик на полной скорости без ограничений, мы быстро упремся в пропускную способность gNB.

Чтобы решить проблему с пропускной способностью, давайте ограничим скорость на сессии для каждого устройства и сэкономим ресурсы базовой станции. Как это сделать?
Присоединяйтесь к команде! Сейчас у нас открыты вакансии:
Как ограничить скорость через Session-AMBR
Введем понятие Session-AMBR — это максимальный агрегированный битрейт для сессии. По сути, скорость пакетов или данных на этой сессии. Как Session-AMBR имплементировать в нашей сети?
Допустим, мы привязали Session-AMBR к мобильному устройству, сформировали JSON, в котором лежит мапа с ключом (идентификатор устройства) и value (Session-AMBR). Создали конфиг. Что дальше? Сессией на сети в 5G управляет функция SMF. У нее есть доступ ко всем участникам процесса передачи данных: UE, базовой станции, UPF. В SMF можно один раз положить Session-AMBR, а она позаботится о его доставке и применении.

Остановимся на том, как именно SMF будет это делать:

Во время установки сессии (PDU Session Establishment) SMF обменивается набором сообщений с каждым из упомянутых участников. Для UE это PDU Session Establishment Accept с отдельным полем Session AMBR. Для базовой станции — PDU Resource Setup Request и ниже PDU Session AMBR. А на UPF — PFCP Session Establishment ReqUEst с правилом QER, содержащее MBR. SMF просто скопирует Session-AMBR в эти поля.
Возвращаемся к проблеме: мы хотели ограничить скорость. Нам это удалось при помощи распределения Session-AMBR по участникам User Plane, которые, имея прямой доступ к данным, уже обеспечат его поддержку.
Ограничиваем скорость через QoS-характеристики
Session-AMBR — не единственный способ управления радиоресурсами. Есть и другие QoS-характеристики. Приведу в пример три:
Packet Delay Budget — максимальное время задержки пакета на пути от UE до выхода из UPF. Или, наоборот, от момента входа в UPF и до момента принятия мобильным устройством.
Guaranteed Bit Rate — гарантированная скорость данных.
Maximum Bit Rate — максимальная скорость данных.
Некоторые из этих характеристик довольно часто повторяются для определенных типов сервисов. Чтобы сэкономить сигнальный трафик и не передавать полный набор характеристик каждый раз, 3GPP предусмотрели стандартные наборы таких характеристик. Они кодируются одним числом — 5QI:

Мы ввели новые характеристики для управления ресурсами, но как сделать так, чтобы они соблюдались? Работает та же самая схема:

У нас есть SMF, в ней профиль мобильного устройства. Теперь рядом с Session-AMBR положим дефолтные QoS-характеристики. Возьмем 5QI, но мы могли бы использовать и полный набор характеристик. Дальше SMF снова начинает «разбрасывать» эти характеристики по участникам — UE, gNB и UPF:

Получается, в PDU Session Establishment Accept рядом с Session AMBR добавляется QoS Description, содержащий 5QI или набор QoS-характеристик. В gNB тоже добавляется описание QoS в виде 5QI. В UPF у нас тот же самый QER: в него нельзя положить 5QI, но можно загрузить QoS-характеристики.
Итак, хотели больше характеристик для управления ресурсами — получили:

Доставляем профиль в SMF
Посмотрите на схему:

Мы до сих пор не обсуждали, откуда SMF «знает» профили устройств. Мы могли бы просто положить эти профили в конфиг SMF, но тогда затруднили бы обновление профиля во время жизни сессии. А нам нужна возможность это делать — например, когда у пользователя сменился объем услуг.
В опорной сети есть другая сетевая функция — UDM. Она централизованно управляет данными абонентов, подписками, обеспечивает аутентификацию и политику доступа. Оттуда SMF как раз узнает профиль UE:

Во время установки сессии SMF сначала идет в UDM, запрашивает профиль мобильного устройства, оттуда узнает Session AMBR и дефолтные QoS-характеристики. Также UDM может уведомлять SMF о сменившемся профиле, и SMF применит изменения на сети.
Как классифицировать трафик по сервисам
Пойдем дальше и рассмотрим сам трафик. В нем мы увидим разные сервисы — это может быть набор пакетов по YouTube, Google, какой-нибудь музыкальный сервис и так далее:

В реальности далеко не всем сервисам нужна высокая скорость и низкий процент ошибок. Хочется иметь возможность гибко настраивать для них разные QoS-характеристики — и тем самым высвободить еще немного дорогостоящего радиоресурса. Например, для YouTube скорость сделаем побольше, а для поиска меньше.
Чтобы это провернуть, нужно проделать два шага:
Идентифицировать трафик. Понять, какой трафик относится к какому сервису. Создать референсные точки на сети, где мы сможем управлять трафиком для сервисов.
-
Применить QoS-характеристики для трафика конкретного сервиса.
Начнем с первой проблемы. Введем понятие Service Data Flow (SDF) — это весь трафик одного сервиса. Принадлежать SDF может любому сервису.
{ "SDFs": [ { "name":"youtube", "filter": { "srcIpRange": "srcIp1 - srcIp2", "srcPortRange": "srcPort1 - srcPort2", "dstIpRange": "dstIp1 - dstIp2", "dstPortRange": "dstPort1 - dstPort2" }, }, { "name":"google", "filter": { "srcIpRange": "srcIp3 - srcIp4", "srcPortRange": "srcPort3 - srcPort4", "dstIpRange": "dstIp3 - dstIp4", "dstPortRange": "dstPort3 - dstPort4" }, }, ] }
Теперь давайте идентифицируем трафик. Самый простой способ — указать диапазоны Source и Destination-адресов и портов. Получится своеобразный фильтр. Введем конфиг, где будем описывать фильтры для SDF. Если пакет подходит под этот фильтр, значит, он принадлежит к этому конкретному SDF — например, YouTube.
Звучит просто, но есть проблема. Что, если мы добавим широкий фильтр, который будет использоваться как дефолтный? Допустим, мы хотим его применять, если пакет не попал ни в какой другой фильтр. Сложность в том, что один и тот же пакет (например, YouTube) теперь подходит под два фильтра: конкретный для этого сервиса и дефолтный. Нам нужно приоритизировать один из них. Для этого мы добавим параметр precedence — чем меньше его значение, тем приоритетнее фильтр.
Чтобы понять, к какому сервису относится этот трафик, UPF будет идти по увеличению precedence. Первый фильтр, который ему попадет, и нужно применять.

Мы с вами получили набор описаний сервисов и загрузили его в SMF. Дальше SMF начинает применять этот конфиг на входных точках сети передачи данных — устройстве и UPF:

Во время установки сессии SMF передает указанные фильтры и precedence устройству в поле Authorized QoS Rules. Для UPF такой точкой будет PDR. Так UE и UPF «понимают», к какому SDF относится тот или иной трафик.
SMF раздала эти фильтры в UE и UPF:

И вот что у нас получается:

Итак, у UE и UPF есть референсные точки (фильтры). С их помощью они определяют, какой трафик относится к тому или иному сервису.
QoS Flow: как добавить характеристики к сервису
Теперь вспоминаем вторую задачу. Мы хотели применять к сервисам разные QoS-характеристики. Как это сделать?
Переходим к новому термину: QoS Flow — это набор SDF с одинаковыми QoS-характеристиками. По сути, наша цель — собрать сервисы с одинаковыми характеристиками в один условный агрегат. Дальше нам нужно будет «рассказать» мобильному устройству и UPF, какие QoS Flow у нас установлены и какие у них характеристики.

Идем все по тому же принципу — расширяем наш конфиг:

Обратите внимание на первую строчку кода: теперь это уже политики, а не просто описание SDF, ведь мы уже начинаем применять к ним правила. Заводим мапу с описанием QoS-характеристик — то есть как раз и описываем, какие QoS Flow и их характеристики у нас будут. Затем связываем каждый SDF с нужным QoS Flow через указание ссылки на элемент с QoS-характеристиками.
Обновленный конфиг кладем в SMF. Дальше SMF начинает строить похожие структуры на устройстве, gNB и UPF:

Помните, на предыдущем шаге мы создавали референсные точки, чтобы понимать соответствие SDF и пакета? Одна из таких точек — Authorized QoS Rules в UE, где указаны фильтры. Теперь давайте привяжем к этим фильтрам ссылки на QoS Flow и укажем их характеристики.
На UPF мы также расширяем описание PDR и добавляем к нему ссылку на соответствующий QER — в этом правиле описано, какие QoS-характеристики применять к пакету. Еще добавим QFI — им UPF будет помечать пакет.
Базовой станции фильтры не нужны — достаточно описания, какие есть QoS Flow. Какой пакет к какому QoS Flow относится, gNB определяет по:
полю в заголовке пакета (там указан QFI в DL);
DRB, по которому был получен пакет в UL.
Теперь UE, gNB и UPF «понимают», что у них есть определенный набор QoS Flow и какой трафик к ним относится. Если пакет попадает под конкретный QoS Rule, значит, нужно применить конкретные указанные QoS Rule-характеристики.
Что делать, если QoS Flow конкурируют
Мы гибко настроили характеристики сервисов и постарались избежать ситуации, когда менее нагруженный сервис отбирает ресурсы у более нагруженного. Теперь все участники сети передачи данных знают, какие QoS-характеристики должны быть выдержаны для пакетов. Но мы все равно не сможем избежать случаев, когда разные похожие по нагруженности сервисы конкурируют за ресурсы. Что тогда делать? Как понять, какому трафику отдать приоритет?

Для этого введем еще одну характеристику — Allocation and Retention Priority (ARP). Она показывает, может ли QoS Flow вытеснить ресурсы другого и может ли быть вытеснен сам.
"arp": { "preemptCap": "NOT_PREEMPT", "preemptVuln": "NOT_PREEMPTABLE", "priorityLevel": 1 }
Здесь у нас три параметра:
Pre-emption capability — показывает, может ли QoS Flow вытеснять чужие ресурсы.
Pre-emption vulnerability — показывает, может ли QoS Flow вытесняться.
Priority Level — показывает, какой QoS Flow победит, если их несколько и все пытаются вытеснить друг друга.
ARP нужна только для базовой станции: именно она выделяет радиоресурсы. Расширим описание QoS-характеристик, положим их в SMF, а она отправит эту характеристику в базовую станцию:

Теперь пора вспомнить начальную проблему: у нас была задача применять разные QoS-характеристики для разных типов сервисов. Для этого мы завели фильтры на каждый SDF и обязали UE, gNb и UPF выдерживать эти характеристики. Все получилось:

JSON довольно объемный:
"SDF policies": [ { "name": "youtube", "qosId": "qos1" }, { "name": "google", "qosId": "qos2" } ], "QoS Characteristics": [ { "id": "qos1", "fiveQi": 3, "arp": { "preemptCap": "NOT_PREEMPT", "preemptVuln": "NOT_PREEMPTABLE", "priorityLevel": 1 } }, { "id": "qos2", "fiveQi": 5, "arp": { "preemptCap": "NOT_PREEMPT", "preemptVuln": "NOT_PREEMPTABLE", "priorityLevel": 1 } } ] ]
Обратите внимание: нигде не указано, к какой сессии применять конкретный набор политик. До этого места в статье мы с вами условно считали, что для всех сессий набор одинаковый. Но нам нужна возможность динамически управлять тем, какие политики активировать: у разных абонентов могут быть тарифы с разными скоростями и гарантиями доставки. То есть мы хотим принимать решения для каждой конкретной сессии индивидуально и даже менять их на ходу в рантайме — например, если поменялся тариф. При этом заводить конфиг на SMF для этих нужд неудобно: он получится огромным, и изменения придется вносить руками. Значит, конфиг нужно куда-нибудь вынести.
Policy Control Function: выставляем rules для сессий
Вводим еще одно новое понятие — на этот раз Policy Control Function (PCF). Эта функция отвечает за управление политиками. SMF загружает ей на вход информацию по PDU-сессии, а в ответ ждет информацию о том, какие политики применить и можно ли эту сессию вообще устанавливать. Также интерфейс между PCF и SMF позволяет организовать отчет о каких-либо событиях, происходящих с сессией. Например, переход сессии в другую обслуживаемую зону или запрос повышения характеристик для какого-нибудь сервиса.

PCF может сам инициировать изменения политик через нотификацию. Тогда он идет в SMF и сообщает, что набор политик для этой сети поменялся и нужно взять актуальный. SMF попытается применить новые политики и ответит одобрением или отказом.

Как будет реализована процедура применения политик? Заведем в PCF структуру SmPolicyDecision и просто перечислим массивом, какие rule ID нужно активировать. Описания самих политик пока оставим в SMF:
"SmPolicyDecision": { "Policy Control rules": [ { "pcRuleId": "rule1" }, { "pcRuleId": "rule2" }, { "pcRuleId": "rule3" } ], }
Дальше во время установки сессии SMF обратится к PCF с запросом политик. В ответ PCF отдаст SmPolicyDecision, SMF возьмет список ruleId, найдет в конфиге подходящие политики и применит их к сессии.

Такой вариант называется Predefined rules — правила определены в SMF, а PCF только активирует или деактивирует их.
Другой вариант — можно выложить описание политик в PCF целиком, и она будет каждый раз отдавать полное описание правил в SMF. Это называется Dynamic Rules: правила в этом случае определяются в PCF. PCF может включать, выключать и обновлять их.

Вспомним про профиль UE и про то, что у UE может быть больше одной сессии. Чтобы иметь возможность сделать Session-AMBR и дефолтные QoS-характеристики посессионными, возьмем этот профиль, открутим от него SUPI и превратим остаток в Session Rule, который положим в структуру SmPolicyDesicion в PCF. Теперь эта часть тоже может динамически меняться для одной конкретной сессии:

Сессионные правила распространяются на всю сессию. На них наложено ограничение, что в конкретный момент времени для сессии может быть активно только одно из них.
Charging: тарифицируем сервисы
Тема тарификации заслуживает отдельной большой статьи, здесь пробежимся кратко по основным аспектам. Мы с вами накрутили разные QoS-характеристики для разных SDF, но еще можно по-разному тарифицировать сервисы. Допустим, дефолтный трафик у нас 1 рубль за мегабайт, YouTube и музыка — 5 рублей, Google — 10 рублей:

Для этого нам нужно, чтобы кто-нибудь из участников сети передачи данных формировал отчет о том, сколько трафика потреблено, и отправлял его в SMF. Дальше SMF будет собирать их у себя, но кто будет считать трафик и формировать отчет?
Пользователю с устройством доверять такое опасно, а у базовой станции нет фильтров, чтобы идентифицировать трафик (да и у нее и так забот хватает). Остается UPF. Получается, SMF должна каким-то образом сообщить UPF, как считать трафик, и обязать отчитываться.
Чтобы это сделать, снова расширим наши политики. Добавим «C» к Policy Control Rules — чтобы получился Policy Charging Control rules (PCC rules). Аналогично описаниям QoS-характеристик, заведем мапу описания правил чаржинга. В ней будет ID (чтобы сослаться на него из PCC-правил), режим обработки квоты: «онлайн» или «офлайн», а еще мы привяжем трафик к некоторому числу — Rating Group. Оно будет скрывать за собой информацию, как именно тарифицировать расход:
"PCC rules": [ { "name": "youtube", "chgId": "chg1" }, { "name": "google", "chgId": "chg1" }, { "name": "default", "chgId": "chg2" } ], "Charging Characteristics": [ { "id": "chg1", "offline": false, "online": true, "ratingGroup": 1 }, { "id": "chg2", "offline": false, "online": true, "ratingGroup": 2 } ]
Теперь SMF должна настроить UPF, чтобы та считала потребленный трафик и отчитывалась. Это делается по тому же принципу, что и во время установки сессии. В сообщении PFCP Session Establishment Request есть URR, который как раз отвечает за подсчет потраченного трафика и определяет правила формирования отчета:

В PDR прикручена ссылка на URR ID, чтобы можно было понять, какой Charging применять, если трафик подошел под этот PDR. В самом URR определены значения volume Quota и volume threshold, а также триггеры, по которым UPF должна отчитываться в SMF. Работает это так: выделяется некоторый объем трафика, который UE может потратить. Когда UPF «замечает», что объем превысил порог (threshold), то формирует отчет и отправляет его в SMF. Если новая квота в ответ на это не была выделена, то после превышения объема UPF формирует второй отчет в SMF и блокирует трафик по этому сервису.
Как и раньше, во время процедуры установки сессии PCF передает Rating Group в SMF. SMF конфигурирует UPF, чтобы та ему отчитывалась. Потом пролетает некоторый объем трафика, UPF отчитывается в SMF, а SMF — в PCF. Такая схема была в 4G, но в 5G пошли чуть дальше и вытащили кусок логики, отвечающий за Charging, из PCF в отдельный — Charging Function.

Сharging function (CHF) отвечает за сбор отчетов по использованному трафику и других charging-событиях. На вход для этой функции SMF загружает информацию по PDU-сессии и запрашивает unit: сколько трафика можно потреблять и в пределах какого времени. CHF тоже может инициировать общение в сторону SMF через нотификацию. Например, сообщить, что поменялись какие-либо правила и нужно отчитаться:

Теперь SDF привязана к конкретной RatingGroup — и так мы с вами получили разную тарификацию для сервисов. По RatingGroup собираются отчеты, потом отправляются в CHF, а она генерирует у себя репорты, которые видит оператор. И уже оператор может в связи с этим снимать деньги с баланса пользователя или применять другие способы тарификации.
Продолжать накручивать фичи можно еще очень долго, мы же здесь остановимся и взглянем на получившуюся архитектуру сети:

В 3GPP лежит почти такая картинка. На схеме не хватает еще трех блоков: AF, NEF и NWDAF. О них расскажем как-нибудь в другой раз:

У нас получился PCC Framework — набор сетевых функций, которые управляют политиками. PCF — центральное звено управления политиками. AMF и SMF — точки применения этих политик. UDR и UDM — хранители профиля устройства. Charging — точка сбора информации о тарификации.
Выше мы обсудили только группу сессионных политик, но на самом деле она не одна:
SM Policy (уже знакомая нам) — это набор правил, по которым осуществляется контроль за сессией и трафиком по ней. Позволяют управлять сессией, определять, какие сервисы могут в ней быть, как правильно их тарифицировать, какие QoS-характеристики применять.
AM Policy — набор правил для контроля доступа устройства к сети. С их помощью мы, например, регулируем UE-AMBR, можем запрещать или разрешать доступ из разных обслуживаемых зон и так далее.
И всеми этими политиками в совокупности можно управлять динамически при помощи PCF — прямо по ходу жизни сессии или жизни устройства в сети.
На сегодня у меня все. Напоследок ловите рекомендации, что почитать, если хотите детально изучить тот или иной аспект:
TS 23.501 — верхнеуровневые описания идеи QoS Flow и Policy Control;
TS 23.502 — стандартные процедуры;
TS 23.503 — детальная спека про архитектуру PCC фреймворка;
TS 29.512 — еще более детальная спека, но про сессионные политики.
5G/NR — QoS — статья про QoS Flow.
M_Bukhteev
Отличная статья