Spanning Tree не допускает образование петель в сети.

Производительность и надежность каналов связи — важнейшие характеристики любой сети, самым непосредственным образом влияющие на ее полноценную работу. Обычно наиболее жесткие требования, касающиеся поддержки высокой нагрузки и непрерывности обслуживания, предъявляются к производительности и надежности магистральных каналов, так как через них проходит трафик значительного числа узлов сети.

Какие же средства повышения надежности и производительности каналов связи имеются в распоряжении сетевого интегратора или администратора? Этот арсенал достаточно обширен и зависит от типа сети. Если говорить о локальных сетях, то нужной производительности можно добиться в первую очередь за счет рационального выбора для каждого канала той или иной технологии с необходимой пропускной способностью. Диапазон вариантов достаточно широк. Семейство Ethernet, которое сегодня практически вытеснило все остальные технологии локальных сетей, предлагает шкалу скоростей от 10 Мбит/c (классический Ethernet) и 100 Мбит/с (Fast Ethernet) до 1000 Мбит/с (Gigabit Ethernet) и даже 10 Гбит/с (хотя на стандарт 10 Gigabit Ethernet окончательно еще не принят, основные его параметры утверждены, и некоторые производители уже включают соответствующие модули в свои магистральные коммутаторы).

Однако десятикратное увеличение скорости при переходе от одного уровня Ethernet к другому не всегда удобно — в некоторых случаях это ведет к значительным и часто не оправданным затратам. Например, если в установленных в сети коммутаторах отсутствует возможность добавления модуля с портом Gigabit Ethernet, то повышение скорости на некоторых каналах до 1000 Мбит/с потребует их полной замены. В то же время, вполне возможно, что у таких коммутаторов имеются свободные порты Fast Ethernet, поэтому скорость передачи данных можно было бы повысить, задействовав не занятые ресурсы. При этом в сети появляются альтернативные пути следования трафика, которые иногда называют избыточными (по отношению к единственному основному пути).

Полезность альтернативных путей еще более очевидна для обеспечения необходимого уровня надежности связей. Надежность каждого физического канала локальной сети целиком определяется характеристиками надежности его компонентов (порта коммуникационного устройства, разъема, среды передачи, точек соединения разъемов со средой, кроссовых соединений), повлиять на которые администратор сети не в состоянии. Зато он способен повысить надежность канала за счет применения избыточных физических соединений, когда канал дублируется одним или несколькими другими.

Таким образом, повышение уровня связности сети, т. е. создание альтернативных маршрутов, — еще одно средство (причем достаточно мощное и масштабируемое) повышения эксплуатационных характеристик сети. Неизбежные дополнительные затраты могут оказаться меньше, чем при повышении производительности «в лоб», за счет применения более скоростной технологии канала, а для повышения надежности введение избыточных соединений чаще всего становится единственным практически осуществимым способом достижения цели.

Альтернативные соединения в сетях обычно используются двумя способами (см. Рисунок 1):

  • в режиме резервирования, когда одно из них функционирует, а остальные находятся в "горячем" резерве для замены отказавшего соединения (например, канал 2 резервный для канала 1, а канал 7 - для канала 6);
  • в режиме баланса нагрузки; при этом данные передаются параллельно по всем альтернативным соединениям (например, для передачи данных от устройства S2 к устройству S3 можно воспользоваться путем через канал 10 или транзитным альтернативным путем: канал 1 - устройство S1 - канал 3).

В первом случае улучшается только одна характеристика сети — надежность, а производительность остается неизменной. Второй способ позволяет повысить как производительность, так и надежность. Когда одно из альтернативных соединений оказывается неработоспособным, связь между узлами не разрывается, а просто уменьшается обеспечиваемая производительность — на величину пропускной способности отказавшего канала связи. Обычно такие системы называют «живучими» или отказоустойчивыми: их работоспособность снижается постепенно, по мере отказа составляющих его компонентов.

В тех локальных сетях, где технологии и оборудование реализуют только функции первого и второго уровня модели OSI/ISO, проблема использования альтернативных путей имеет свою специфику: базовые протоколы поддерживают только древовидные, т. е. не содержащие замкнутых контуров, топологии связей. А это означает, что для организации альтернативных каналов требуются особые протоколы и технологии, выходящие за рамки базовых, к которым относится Ethernet или алгоритм прозрачного моста (Transparent Bridge), описанный в стандарте 802.1D и применяемый в современных коммутаторах второго уровня.

Для автоматического перевода в резервное состояние всех альтернативных связей, не вписывающихся в топологию дерева, в локальных сетях используются алгоритм покрывающего дерева (Spanning Tree Algorithm, STA) и реализующий его протокол (Spanning Tree Protocol, STP) и расширения последнего. Задействовать одновременно несколько альтернативных соединений можно с помощью механизмов агрегирования каналов (Link Aggregation), как частных, например ISL компании Cisco или MultiPoint Link Aggregation компании 3Com, так и стандартных — по спецификации IEEE 802.3ad. Агрегированный канал часто называют транком (trunk).

НЕМНОГО О КОРНЯХ ДЕРЕВА

Алгоритм Spanning Tree был разработан достаточно давно, в 1983 г. сотрудницей компании DEC Радией Перлман. Он должен был решить проблему прозрачных мостов, популярность которых в то время быстро росла вместе с распространением сетей Ethernet. Прозрачные мосты по причине своей простоты не могут правильно работать в сетях с петлями — широковещательные пакеты при такой топологии размножаются и зацикливаются, да и таблица продвижения пакетов не всегда может быть построена корректно. Вместе с тем, производители оборудования для локальных сетей не хотели усложнять свои устройства, пытаясь сохранить низкую стоимость и простоту инсталляции и эксплуатации сети за счет отказа от поддержки функций сетевого уровня.

Найденное Радией Перлман решение позволило достичь желанного компромисса. Прозрачные мосты с поддержкой алгоритма STA остались простыми самообучающимися устройствами, не требующими предварительного конфигурирования. При этом появилась возможность без применения маршрутизаторов строить крупные локальные сети, обладающие высокой надежностью за счет наличия избыточных связей в сети с произвольной топологией, в том числе и петлевидной. Алгоритм Spanning Tree был признан IEEE удачным и включен в ту же спецификацию 802.1D, где описывается и сам алгоритм работы прозрачного моста.

Алгоритм STA по-прежнему остается очень важной составляющей локальных сетей. Хотя мосты, для которых алгоритм был разработан, сегодня уже относятся к практически «вымершему» виду коммуникационных устройств, STA широко применяется в наиболее массовых устройствах современных локальных сетей — коммутаторах второго уровня. Это неудивительно, поскольку последние функционально идентичны прозрачным мостам, а вот производительность у них существенно выше за счет параллельного продвижения пакетов процессорами портов. Поэтому производители оборудования, как правило, реализуют алгоритм STA в компьютерах для тех участков сети, к которым предъявляются повышенные требования по надежности, — в магистральных коммутаторах, а также в коммутаторах отделов и крупных рабочих групп.

Далее при описании алгоритма будет использоваться термин «коммутатор», хотя замена его на «мост» только придала бы тексту некоторый налет архаичности, но никоим образом не изменила бы суть алгоритма.

СЕТЬ И ЕЕ ГРАФ

Алгоритм STA формализует сеть в виде графа, вершинами которого являются коммутаторы и сегменты сети (см. Рисунок. 2). Сегмент — связная часть сети, не содержащая коммутаторов (и маршрутизаторов). Он может быть разделяемым (во время создания алгоритма STA это был единственный тип сегмента) и включать устройства физического уровня такие, как повторители/концентраторы, существование которых коммутатор, будучи устройством канального уровня, не замечает. Сегодня сегмент часто представляет собой дуплексный канал «точка-точка» между смежными портами двух коммутаторов.

Алгоритм Spanning Tree обеспечивает поиск древовидной топологии связей с единственным путем от каждого коммутатора и от каждого сегмента до некоторого выделенного коммутатора (корня дерева) при минимально возможном расстоянии. Единственность пути гарантирует отсутствие петель, а минимальность расстояния — рациональность маршрутов следования трафика от периферии сети к ее магистрали, роль которой выполняет корневой коммутатор.

В качестве расстояния в STA используется метрика, традиционная для протоколов маршрутизации, — величина, обратно пропорциональная пропускной способности сегмента. Более формально, метрика — это так называемое «условное время сегмента». Оно рассчитывается как время передачи одного бита информации и измеряется в 10-наносекундных единицах. Так, для сегмента Ethernet на 10 Мбит/с условное время равно 10 условным единицам, а для сегмента Token Ring на 16 Мбит/с — 6,25.

В качестве корневого коммутатора выбирается коммутатор с наименьшим значением идентификатора. Идентификатор коммутатора — это число длиной восемь байт, шесть младших байтов которого составляет МАС-адрес его блока управления, отрабатывающего алгоритм STA (напомним, что портам коммутаторов и мостов для выполнения своей основной функции MAC-адресов не требуется), а два старших байта конфигурируются вручную, что позволяет администратору сети влиять на процесс выбора корневого коммутатора.

На Рисунке 3 приведен пример сети, для которой коммутаторы уже нашли покрывающее дерево. Предположим, что идентификаторы коммутаторов совпадают с их порядковыми номерами. При равных значениях метрики для разрешения неоднозначности к процедуре выбора минимального расстояния привлекаются значения идентификаторов коммутаторов и портов. (Идентификатором порта служит число длиной в два байта. Младший байт содержит порядковый номер данного порта в коммутаторе, а значение старшего байта задается администратором.) Предпочтение отдается коммутатору с наименьшим идентификатором. Например, для сегмента 3 существуют два равноценных в отношении метрики пути к корневому коммутатору 1 — через коммутатор 3 и коммутатор 4. Выбранный путь проходит через коммутатор, с меньшим значением идентификатора, а именно 3 (номера портов внутри коммутатора в данном случае совпадают, но при сравнении сначала принимается во внимание идентификатор коммутатора, а потом уже номер порта). Все порты, не вошедшие в покрывающее дерево, блокируются для пользовательского трафика — на рисунке этому соответствует перечеркивание.

Отметим, что выбранная по алгоритму STA древовидная топология в общем случае не оптимальна для всех путей передачи трафика. Так, в примере на Рисунке 3 при передаче пакетов из сегмента 4 в сегмент 2 трафик проходит следующий путь: коммутатор 3 — сегмент 1 — коммутатор 1 — сегмент 2. Общая метрика этого пути — 30.

Если бы порт 2 коммутатора 4 не был заблокирован, то путь мог быть короче — через коммутатор 4. При этом метрика пути была бы равна 20 — лучше, чем в предыдущем случае. Такой вариант возможен при выборе кратчайшего пути к корневому коммутатору для сегмента 4 через коммутатор 4, а не 3 — например, за счет соответствующего назначения старших частей идентификаторов коммутаторов. Однако при таком варианте путь из сегмента 4 в сегмент 1 уже не окажется оптимальным.

Дело в том, что алгоритм STA для упрощения работы коммутатора создает единое дерево, не зависящее от адресов назначения пакетов, что принципиально отличается от подхода, принятого в протоколах маршрутизации при выборе маршрутов для трафика сетевого уровня. В последнем случае кратчайший маршрут выбирается для каждого сетевого адреса назначения, так что трафик всегда идет по оптимальному для принятой метрики маршруту.

ВЫРАЩИВАНИЕ ДЕРЕВА В ТРИ ПРИЕМА

Для автоматического определения начальной конфигурации дерева все коммутаторы сети после их инициализации начинают периодически обмениваться специальными пакетами, называемыми протокольными блоками данных моста (Bridge Protocol Data Unit, BPDU). Пакеты BPDU переносят данные об идентификаторах коммутаторов и портов, а также о расстоянии до корневого коммутатора. Интервал генерации пакетов BPDU, называемый в алгоритме интервалом приветствия (hello), настраивается администратором и обычно составляет от 1 до 4 с.

Алгоритм STA определяет активную конфигурацию сети за три этапа.

Сначала в сети определяется корневой коммутатор (Root Switch), от которого строится дерево. Если администратор не вмешается в этот процесс, корневой коммутатор будет выбран достаточно случайным образом — им станет устройство с минимальным MAC-адресом блока управления. Очевидно, что такой выбор может оказаться далеко не рациональным. Примером мог бы служить выбор корневого коммутатора 5 в сети, приведенной на Рисунке 3. При этом значительная часть трафика проходила бы через большое количество транзитных сегментов и коммутаторов. Поэтому ни в коем случае нельзя пускать данный процесс на самотек — лучше в него вмешаться и назначить корневой коммутатор осознанно (за счет соответствующего конфигурирования старших байтов идентификаторов коммутатора), чтобы выбранный коммутатор действительно занимал центральное место в соединениях сегментов.

После выбора корневого коммутатора все остальные коммутаторы сети перестают генерировать пакеты BPDU и продолжают только ретранслировать пакеты BPDU корневого моста — для того, чтобы каждый коммутатор определил минимальные расстояния от всех своих портов до корневого коммутатора. Эти данные используются на следующих этапах работы STA.

Выбор корневого порта для каждого коммутатора — второй этап создания покрывающего дерева. Корневой порт коммутатора (Root Port) должен иметь кратчайшее расстояние до корневого коммутатора (точнее, до любого из портов корневого коммутатора). Расстояние определяется по пакетам BPDU, ретранслируемым коммутатором.

И, наконец, на третьем этапе из всех портов всех коммутаторов каждого сегмента сети выбирается так называемый назначенный порт (Designated Port) с минимальным расстоянием до корневого коммутатора. Коммутатор, которому принадлежит назначенный порт для данного сегмента, объявляется назначенным коммутатором (Designated Switch) сегмента.

Все остальные порты, кроме корневых и назначенных, переводятся в заблокированное состояние. Математически доказано, что при таком выборе активных портов в сети исключаются петли, и оставшиеся связи образуют покрывающее дерево (если оно вообще может быть построено при существующих связях в сети).

ПАКЕТЫ BPDU И ВЫБОР КОРНЕВОГО КОММУТАТОРА

Пакеты BPDU помещаются в поле данных кадров канального уровня, например кадров Ethernet или FDDI. Желательно, чтобы все коммутаторы поддерживали общий групповой адрес, с помощью которого кадры, содержащие пакеты BPDU, могли одновременно передаваться всем коммутаторам сети. В противном случае пакеты BPDU рассылаются широковещательно.

Пакет BPDU имеет следующие поля.

  • Идентификатор версии протокола STA (2 байт).
  • Тип BPDU (1 байт). BPDU бывают двух типов - конфигурационный BPDU, т. е. заявка на статус корневого коммутатора, на основании которой происходит определение активной конфигурации, и пакет BPDU, служащий для уведомления о реконфигурации. Последний посылается коммутатором при обнаружении им события, наступление которого требует проведения реконфигурации: например, отказ соединения, отказ порта, изменение приоритетов коммутатора или портов.
  • Флаги (1 байт). Один бит содержит флаг изменения конфигурации, второй - флаг подтверждения изменения конфигурации.
  • Идентификатор корневого коммутатора (8 байт).
  • Расстояние до корня (2 байт).
  • Идентификатор данного коммутатора (8 байт).
  • Идентификатор порта (2 байт).
  • Время жизни сообщения (2 байт). Оно измеряется в единицах по 0,5 с и служит для выявления устаревших сообщений.
  • Максимальное время жизни сообщения (2 байт).
  • Интервал приветствия (2 байт), через который посылаются пакеты BPDU.
  • Задержка смены состояний (2 байт).

У пакета BPDU с уведомлением о реконфигурации отсутствуют все поля, кроме двух первых.

После инициализации каждый коммутатор по умолчанию считает себя корневым. Поэтому он начинает периодически с интервалом приветствия, генерировать через все свои порты сообщения BPDU конфигурационного типа. В них он указывает свой идентификатор в качестве идентификатора корневого коммутатора (и в качестве идентификатора данного коммутатора также), расстояние до корня устанавливается равным 0, а в поле идентификатора порта помещается идентификатор того порта, через который передается данный пакет BPDU. Как только коммутатор получает BPDU, где значение идентификатора корневого коммутатора меньше его собственного, он перестает генерировать пакеты BPDU и переходит в режим ретрансляции пакетов BPDU нового претендента на звание корневого коммутатора. На Рисунке 2 наименьшее значение идентификатора имеет коммутатор 1, поэтому именно он становится корневым.

ВЫБОР КОРНЕВЫХ И НАЗНАЧЕННЫХ ПОРТОВ

При ретрансляции пакетов каждый коммутатор увеличивает расстояние до корня, указанное в полученном BPDU, на условное время того сегмента, из которого принят данный пакет. Тем самым в пакете BPDU, по мере прохождения через коммутаторы, наращивается расстояние до корневого коммутатора. Например, если считать, что все сегменты в рассматриваемом примере являются сегментами Ethernet на 10 Мбит/с, то коммутатор 2, приняв из сегмента 1 сообщение BPDU c расстоянием, равным 0, увеличивает его на 10 единиц.

Ретранслируя пакеты, каждый коммутатор для каждого своего порта запоминает минимальное расстояние до корня, встретившееся во всех принятых этим портом пакетах BPDU. По завершении процедуры определения конфигурации покрывающего дерева (по времени) каждый коммутатор находит свой корневой порт (с минимальным расстоянием до корня).

Так, в примере на Рисунке 3 коммутатор 3 выбирает порт 1 в качестве корневого, так как для него минимальное расстояние до корня равно 10 (BPDU с таким расстоянием принят от корневого коммутатора через сегмент 1). Порт 2 коммутатора 3 на основании принятых пакетов установил, что минимальное расстояние равно 20 единицам — это соответствовало случаю прохождения пакета от порта 2 корневого моста через сегмент 2, затем через коммутатор 4 и сегмент 3. Коммутатор 2 при выборе корневого порта «столкнулся» с ситуацией, когда у его портов 1 и 2 равное расстояние до корня — по 10 единиц (порт 1 принимает пакеты от порта 1 корневого коммутатора через один промежуточный сегмент — сегмент 1, так же как порт 2 получает пакеты от порта 2 корневого коммутатора через сегмент 2). Поскольку числовое значение идентификатора 1 меньше, чем у 2, то корневым и был выбран порт 1.

Кроме корневого порта коммутаторы распределенным образом выбирают назначенный порт для каждого сегмента сети. Каждый коммутатор сегмента прежде всего исключает из рассмотрения свой корневой порт (для сегмента, к которому он подключен, всегда существует другой коммутатор, который расположен ближе к корню). Для каждого из оставшихся портов выполняется сравнение принятых по ним минимальных расстояний до корня (еще до наращивания на условное время сегмента) с расстоянием до корня корневого порта данного коммутатора. Если все принятые на этом порту расстояния оказываются больше, чем расстояние от собственного корневого порта, значит, для сегмента, к которому подключен порт, кратчайший путь к корневому коммутатору проходит через него, и он становится назначенным. Коммутатор делает все свои порты, для которых такое условие выполняется, назначенными.

Когда имеется несколько портов с одинаковым кратчайшим расстоянием до корневого коммутатора, выбирается порт с наименьшим идентификатором.

В рассматриваемом примере коммутатор 2 при проверке порта 2 обнаружил, что через этот порт принимались пакеты с минимальным расстоянием 0 (это были пакеты от порта 2 корневого коммутатора 1). Так как собственный корневой порт у коммутатора 2 имеет расстояние до корня 10, то порт 2 этого коммутатора не является назначенным для сегмента 2.

НА ВСЕ ТРЕБУЕТСЯ ВРЕМЯ

Для корректной передачи пользовательских пакетов сетью коммутаторов алгоритм STA формализует состояния портов и определяет правила их смены только после того, как конфигурация покрывающего дерева установится во всех коммутаторах сети и для всех портов.

Каждый порт коммутатора, поддерживающего алгоритм STA, может находиться в одном из пяти состояний (см. Рисунок 4):

  • отключен (disabled);
  • заблокирован (blocked);
  • прослушивание (listening);
  • обучение (learning);
  • продвижение (forwarding).

В состояние «Отключен» порт может быть переведен только по команде конфигурирования, поданной администратором локально или удаленно по протоколу управления. В таком режиме порт не участвует ни в работе протокола STA, ни в продвижении пакетов данных. Вывести порт из этого состояния можно тоже только командой конфигурирования.

При инициализации коммутатора, поддерживающего STA, все порты (за исключением отключенных) автоматически переводятся в состояние «Заблокирован». В этом случае порт генерирует, принимает, обрабатывает и ретранслирует пакеты BPDU. Коммутатор, которому принадлежит порт, принимает участие в выборе корневого коммутатора, а также решает, какой из его портов является корневым, а какой — назначенным. Однако пакеты данных порт пока не передает — этим полезным делом он занимается только в состоянии «Продвижение».

Если порт претендует на роль корневого или назначенного, он переходит в состояние «Прослушивание», что происходит обычно в начальный момент работы алгоритма STA, когда BPDU от других мостов еще не получены, и коммутатор считает себя корневым, а все свои порты — назначенными. Режим «Прослушивание» устанавливается на время, определяемое таймером смены состояний (Forwarding Timer). Интервал, выдерживаемый с помощью этого таймера и равный обычно 15 с (его значение может конфигурироваться), необходим для гарантированного получения всех BPDU, сгенерированных коммутаторами сети. Порт продолжает генерировать (если он принадлежит коммутатору, который считает себя корневым), принимать, обрабатывать и ретранслировать BPDU. Если в течение этого времени порт получит BPDU с лучшими параметрами, чем собственные (расстояние, идентификатор коммутатора или порта), то он перейдет в состояние «Заблокирован». В противном случае порт переводится в состояние «Обучение».

Теперь коммутатор начинает принимать (но не продвигать) пакеты данных и на основе их адресов источника строить таблицу продвижения. Это обычный режим обучения прозрачного моста, который ранее нельзя было активизировать, так как порт не был уверен в том, что он останется корневым или назначенным и будет передавать пакеты данных. Состояние «Обучение» также выдерживается в течение интервала таймера смены состояний, т. е. 15 с по умолчанию. При этом порт продолжает участвовать в работе STA, так что поступление BPDU с лучшими параметрами переводит его в состояние «Заблокирован».

И только после двукратной выдержки по таймеру порт переходит в состояние «Продвижение» и обрабатывает пакеты данных в соответствии с построенной таблицей (которая продолжает модифицироваться, отражая изменения в структуре сети).

В процессе нормальной работы корневой коммутатор продолжает генерировать конфигурационные BPDU с интервалом приветствия, а остальные коммутаторы получают их через свои корневые порты и ретранслируют назначенными. У коммутатора могут отсутствовать назначенные порты, как у коммутаторов 2 и 4, но он все равно участвует в работе протокола STA, так как корневой порт принимает служебные пакеты BPDU.

Если по истечении максимального времени жизни сообщения (по умолчанию — 20 с) корневой порт любого коммутатора сети не получит служебный пакет BPDU, то он инициализирует новую процедуру построения покрывающего дерева. При этом на все порты генерируется и передается BPDU, в котором коммутатор указывает себя в качестве корневого. Аналогичным образом поступают и другие коммутаторы сети с истекшим таймером максимального времени жизни сообщения, в результате чего выбирается новая активная конфигурация.

НЕДОСТАТКИ КАК ПРОДОЛЖЕНИЕ ДОСТОИНСТВ

Одним из основных достоинств алгоритма Spanning Tree является то, что в отличие от многих упрощенных алгоритмов, где переход на резервное соединение осуществляется исключительно при отказе непосредственного соседа-устройства, он принимает решение о реконфигурации с учетом не только связей с соседями, но и связей в отдаленных сегментах сети.

А вот то, что в сетях с большим количеством коммутаторов время определения новой активной конфигурации может оказаться слишком большим, можно отнести к недостаткам алгоритма. Если в сети используются значения тайм-аутов по умолчанию, переход на новую конфигурацию может занять свыше 50 с: 20 с понадобится на констатацию факта потери связи с корневым коммутатором (истечение таймера — единственный способ узнать об этом событии в стандартном варианте STA), и еще 2x15 с потребуется для перехода портов в состояние «Продвижение».

Имеющиеся многочисленные нестандартные версии STA позволяют сократить время реконфигурации за счет усложнения алгоритма, например добавления новых типов служебных сообщений. В настоящее время разрабатывается новая версия Spanning Tree — спецификация IEEE 802.1w — для ускорения работы протокола, но уже стандартным способом.

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

О таком применении избыточных соединений в сетях речь пойдет в следующем выпуске рубрики.

Наталья Олифер — обозреватель «Журнал сетевых решений/LAN». С ней можно связаться по адресу: olifer@lanmag.ru.

Поделитесь материалом с коллегами и друзьями