Перейти к содержанию
    

Самый быстрый и самый маленький TCP-стек.

Их никто и не складывает. Данные идут в одном направлении, а ACK'и - в другом.

 

Кстати, по фильтру не заметно. Ибо нет фильтрации. Так что оба направления считаются. Да и Ethereal тут показывает общий траффик - служебная информация (заголовки ETH, IP, TCP) - тоже в сумме.

 

Это и приводит к числу (Avg. MBit/s), больше 100мбит/с - что естественно, невозможно.

 

Пример - передача файла с MMC карточки.

 

А оно-то хоть заявленную скорость даст? Какая ФС используется? Сколько собственно в этой ФС буферов?

 

Можно читать данные с карты в колбеке - но это некамильфо, операция долгая, мало того что делать прийдется ее в прерывании

 

Делать ее придется не в самом приоритетном прерывании, так что не беда.

 

так еще и все другие сокеты встанут, приемный буфер сети переполнится (flow control нуна доделывать ) и так далее. Поэтому буферизация тут будет нужна без вариантов.

 

Встанут остальные сокеты - это да, это реальное ограничение. Хотя, конечно, его можно обойти.

 

А если надо наложить поверх такого TCP другой протокол со своими фреймами, типа PPTP или iSCSI, то без буферизации тут вешалка.

 

PPTP - это дело такое, там основной траффик GRE/IP, на рассматриваемый случай не ложится, а доп. TCP соединение для управления - ну просто замечательно укладывается на систему с колбеками - там машина состояний, все дела.

 

iSCSI - тоже песня, блоки с устройства читать. На колбеках как два пальца.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А оно-то хоть заявленную скорость даст? Какая ФС используется? Сколько собственно в этой ФС буферов?

...

Делать ее придется не в самом приоритетном прерывании, так что не беда.

Не в скорости дело, а в том что нельзя надолго заниматься своими делами в колбеке. И не всегда это "надолго" связано с тем что устройство медленное. OK, другой пример. Возьмем Web сервер, только ресурсы его положим не в программную флеш (допустим ресурсы большие, или флешки для программы и так не хватает), а во внешний чип, скажем AT45, подключенную по SPI. И добавим еще одну задачу - какой-нить логгер, который просто собирает свои данные и записывает в эту AT45. Объем AT45 разделим в каком-нить соотношении между логгером и ресурсами Web. И получается что аппаратура SPI+AT45 разделяется между двумя задачами, нужна синхронизация, и вот из-за этой самой синхронизации сетевой колбек банально может надолго задуматься. Конечно, можно сделать "закат солнца вручную" - придумать свою какую-то модель синхронизации, например не ждать в колбеке данные а сразу выходить без посылки и прочее. Но тут кто за что борется - Вы за чистую скорость в отдельно взятом проекте, а я, например, за максимальное наследование кода в кучке разнородных проектов.

 

Встанут остальные сокеты - это да, это реальное ограничение. Хотя, конечно, его можно обойти.

Конечно можно - с помошью буферизации ;). Или есть какие-то другие идеи?

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

 

PPTP - это дело такое, там основной траффик GRE/IP, на рассматриваемый случай не ложится, а доп. TCP соединение для управления - ну просто замечательно укладывается на систему с колбеками - там машина состояний, все дела.

А кому нужно управляющее соединение без канала данных? Я сейчас как раз PPTP обдумываю (для девайсов с GPRS весьма и весьма нужен туннель), без буфера ну никак не получится.

 

iSCSI - тоже песня, блоки с устройства читать. На колбеках как два пальца.

Угу, щаз :biggrin:. У меня есть искази инициатор, исказевые PDU без промежуточной буферизации ретрансмиттить будет просто нереально.

 

Ну в целом, имхо, у Вас получилось удачно - для многих несложных устройств вполне будет работать. Хорошо бы причесать код (по железкам файлы разнести - PHY отдельно, EMAC отдельно, чтобы порты делать), написать документацию (не слишком объемную притом) и придумать хорошее название (типа "Тисипец " :)) - многим вполне может быть интересно.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Подумал про передачу данных, например, с MMC. Да, для пущего профита желательно в стеке разделить этапы приготовления к передаче нового сегмента и собственно генерацию данных для передачи. Тогда, при необходимости передачи новых данных callback на приготовление запускает чтение с MMC и вываливает с прерывания. Когда от MMC приходит готовность, опять происходит wakeup стека и непосредственно чтение по SPI (ну или 4хбитному интерфейсу) происходит уже в буфер передачи.

 

Когда дело дойдет до ФС в проекте - сделаю.

 

А кому нужно управляющее соединение без канала данных?

 

Так канал данных не через TCP организован. Посему мы его тут не рассматриваем.

 

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

 

Я, конечно, внимательно на досуге покурю соответствующий RFC ради спортивного интереса, но, думаю, Вы преувеличиваете. Если у Вас блочное устройство как источник данных - в любом случае нет проблем с откатом.

 

Возьмем Web сервер, только ресурсы его положим не в программную флеш (допустим ресурсы большие, или флешки для программы и так не хватает), а во внешний чип, скажем AT45

 

См. чуть выше, описал идею и метод, пока Вы писали свой пост.

 

Хорошо бы причесать код (по железкам файлы разнести - PHY отдельно, EMAC отдельно, чтобы порты делать)

 

Ну для этого нужно разбить примерно пополам файл emac.c. Только смысл? Ибо там того кода с гулькин куй и все прозрачно.

 

Выносить в отдельный файл работу с EMAC в собственно стеке считаю вредным и бесполезным.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

прерывания. Когда от MMC приходит готовность, опять происходит wakeup стека и непосредственно чтение по SPI (ну или 4хбитному интерфейсу) происходит уже в буфер передачи.

Угу, а если стек занят (ну по другому сокету что-то отдает или удаленный хост задумался, пакет пропал и тд) и этот wakeup задерживается? Причем в общем случае он так нехило на секунды задержаться может. При этом ресурс MMC+SPI заблокирован и никто им больше пользоваться в этот момент не может (ну там логгер чего писнуть хочет).

 

Еще интересно как тут с приемом. В нормальном стеке с внутренней буферизацией всегда можно четко вычислить свое окно и передать его удаленному хосту. А тут если по колбеку всегда выггребание непонятно как TCP-шный хендшейк себя вести будет. Или таки есть внутренни приемный буфер у сокета?

 

 

 

Так канал данных не через TCP организован. Посему мы его тут не рассматриваем.

Ага, это я упустил - не дошел до инкапсуляции еще.

 

Я, конечно, внимательно на досуге покурю соответствующий RFC ради спортивного интереса, но, думаю, Вы преувеличиваете. Если у Вас блочное устройство как источник данных - в любом случае нет проблем с откатом.

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

 

Ну для этого нужно разбить примерно пополам файл emac.c. Только смысл? Ибо там того кода с гулькин куй и все прозрачно.

Выносить в отдельный файл работу с EMAC в собственно стеке считаю вредным и бесполезным.

Вечером прокомментирую - мне щаз убегать нужно, сорри.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так а по-простому? Прикрутите к подходящему Вашему проекту тестовый сокет, в который скормится метров 100 рандома и вуаля. Я такой использую:

  r=r*1103515245+12345;

Софтик для теста можете у меня из архива взять.

Вчера таки поправил проект под ИАР 5, правда TCP заработал только в полном DEBUG-е. Получил примерно 3500-4500 кбит/с при разных замерах :(. РС с платкой соединен через 4-х портовый модем. А Вы тестировали точка-точка? Сегодня попробую разобраться, че там компилятор в TCP выкидывает. Платформа AT91SAM7X256 + DM9161. Компилировал в ARM-режиме.

 

Наверное у Вас реально самый быстрый стек :) :a14: :cheers:

 

Встанут остальные сокеты - это да, это реальное ограничение. Хотя, конечно, его можно обойти.

Конечно можно - с помошью буферизации ;) . Или есть какие-то другие идеи?

Можно, используя RTOS и вместо колбеков флаги. Относительно легко переделывается.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Угу, а если стек занят (ну по другому сокету что-то отдает или удаленный хост задумался, пакет пропал и тд) и этот wakeup задерживается? Причем в общем случае он так нехило на секунды задержаться может. При этом ресурс MMC+SPI заблокирован и никто им больше пользоваться в этот момент не может (ну там логгер чего писнуть хочет).

 

Почему? Задержка будет максимум на время приготовления или обработки пакета. Конечно, надо всегда минимизировать время обработки данных.

 

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

 

И тут всегда можно вычислить. А иногда - например, для разбора HTTP-запросов, оно и нафиг не нужно, все делается на лету.

 

В общем, при такой архитектуре принципиально иным должно быть построение остального кода. Только тогда будут скорости. Хотя, в общем-то и в обычных bsd-style дизайнах нельзя забывать о том, что, например, очень нежелательно кормить, скажем, функцию send по одному байту. Понятное дело, что есть буферизация, но накладные расходы на вызов будут просто феерические.

 

А с другой стороны сама по себе bsd-style архитектура не позволяет работать с zero-copy. А zero-copy - это не только в самом стеке, но и еще и в генераторе/приемнике данных. Т.е. проблему скорости надо решать в комплексе.

 

А Вы тестировали точка-точка?

 

Свич торчит 16типортовый между девайсом и большим братом.

 

Можно, используя RTOS и вместо колбеков флаги. Относительно легко переделывается.

 

Там все-же сложнее ситуация. И опять-же, повторюсь, решать ее надо в комплексе. Обработчик медленный и печальный - уносите его в низкоприоритетную задачу/прерывание (я просто разноприоритетными прерываниями как неким аналогом RTOS пользуюсь), разбивайте его на подзадачи, возможно - добавляйте ему необходимые буфера.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Итак, по просьбам трудящихся выкладываю порт своего стека на LPC1768, выдранный из текущего проекта, над которым щас тружусь.

 

Никаких шансов что это самый быстрый стек.

Еще года 3-и назад выкладывал результаты работы микриумовского стека.

Там без проблем было сделать 98 Mbit/s на 90 MГц процессоре, причем в среде RTOS!

 

Посмотрел ваш код и вижу вы даже не пытались оптимизировать расчет IP и TCP CRC, нет попыток оптимизировать пересылки в памяти.

Много мест где в программном цикле ожидаются сигналы.

Т.е. на RTOS код не портируется, а попытка исполнения одновременно с вашим TCP стеком других быстрых асинхронных задач, например с той же скоростью обслуживать USB приведет к полной деградации одной из задач.

 

Кстати называть ваш код "стеком" принципиально не верно. Как раз стек протоколов там не реализован ибо все уровни сведены в одну процедуру.

Т.е. нет элементов стека которые можно было бы несколько раз накладывать друг на друга получая тоннели или менять медиасреду.

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

и вижу вы даже не пытались оптимизировать расчет IP и TCP CRC

 

Это не так накладно, как кажется. Даже сейчас там чуть менее чем 2 такта на байт, т.е. на полновесный пакет имеем ~30мкс. Конечно, эту оптимизацию можно провести, но это копейки.

 

нет попыток оптимизировать пересылки в памяти

 

Там нет больших пересылок. Нечего оптимизировать.

 

Много мест где в программном цикле ожидаются сигналы.

 

Это место там одно - ожидание освобождения передатчика. Про это я упоминал, и да, оно поддается оптимизации.

 

Т.е. на RTOS код не портируется

 

Не вижу проблем, кстати, с портом под RTOS

 

а попытка исполнения одновременно с вашим TCP стеком других быстрых асинхронных задач, например с той же скоростью обслуживать USB приведет к полной деградации одной из задач.

 

Смысл этого комментария мне неясен. Если две задачи в сумме дают CPU load более 100%, то естественно, что вместе они будут давать меньшую производительность каждая.

 

Кстати называть ваш код "стеком" принципиально не верно.

 

Не согласен. Стек - он не потому что он в исходнике иерархичен, а от того, что иерархично обрабатывает протоколы.

 

Т.е. нет элементов стека которые можно было бы несколько раз накладывать друг на друга получая тоннели или менять медиасреду.

 

Именно это и приводит к потери производительности.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почему? Задержка будет максимум на время приготовления или обработки пакета. Конечно, надо всегда минимизировать время обработки данных.

Ну я понял Вас так - что когда надо читать данные с MMC в сокет, то вызывается колбек, на MMC посылается команда чтения сектора, и управление возвращается в стек. Потом некто в фоне прокручивает протокол MMC по SPI и по готовности снова пытаеся начать передачу в сокет. То есть - SPI занят, MMC готова давать данные, осталось только получить передающий буфер сети. А тут засада - идет передача по другому сокету, например, и все - аппаратный ресурс SPI+MMC тупо простаивает, потому как нет буфера. C MMC есть еще засада - SDHC карты отдают сектора только целиком, поэтому если REGENERATE будет невыравнен (а он в 99% невыравнен) по границе сектора, то возникает оверхед. В-общем, это я к тому что без буфера можно сделать, но коряво оно будет.

 

И тут всегда можно вычислить. А иногда - например, для разбора HTTP-запросов, оно и нафиг не нужно, все делается на лету.

А как тут вычислишь - если приложение всегда забирает данные, и ackno тупо инкрементитцо перед rx колбеком. А если приложение не может забрать данные - допустим пишет оно их в MMC, и темп поступления данных по сети выше темпа записи? Где тут "дульный компенсатор" который регулирует поток входящих данных?

 

А с другой стороны сама по себе bsd-style архитектура не позволяет работать с zero-copy. А zero-copy - это не только в самом стеке, но и еще и в генераторе/приемнике данных. Т.е. проблему скорости надо решать в комплексе.

А zero-copy вполне можно и без колбеков сделать - на прием в моей реализации это есть и сейчас, то есть сетевые буфера которые записал EMAC вполне можно отдать приложению в таком же виде, причем такой блочный интерфейс одновременно сосуществует и работает с bsd-style вызовами, эта архитектурная проблема решается без напряга. На передачу по UDP тоже сделан zero-copy - буфер аллоцируется сразу у нужного сетевого драйвера, при этом готовятся все нужные заголовки нижних уровней - с учетом физики, фрагментации и прочего. Но по TCP вот засада - именно из-за ретрансмитта, поэтому пока есть одно копирование. Вы из этой проблемы выскочили при помощи REGENERATE, но не всем такое катит.

 

Выносить в отдельный файл работу с EMAC в собственно стеке считаю вредным и бесполезным.

Эту работу можно вынести в отдельные .c/.h файлы так, что генерируемый код останется почти таким же самым - то есть основная идея "сплавить стек в единый кусок" ;) не пострадает, а вот портируемость и читабельность сильно возрастет. Соответственно ценен будет для большего количества людей.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кстати, о максимальной пропускной способности.

 

Имеем максимальный пакет 1518 байт с полезной TCP-нагрузкой 1460 байт. Плюс 96 бит IFG. Итого максимальная скорость в битах в секунду по полезной нагрузке равна 95424836. И те, кто заявляет больше (например - 98 у AlexandrY ;) ) привирают.

 

Ну я понял Вас так - что когда надо читать данные с MMC в сокет, то вызывается колбек, на MMC посылается команда чтения сектора, и управление возвращается в стек. Потом некто в фоне прокручивает протокол MMC по SPI и по готовности снова пытаеся начать передачу в сокет. То есть - SPI занят, MMC готова давать данные, осталось только получить передающий буфер сети. А тут засада - идет передача по другому сокету, например, и все - аппаратный ресурс SPI+MMC тупо простаивает, потому как нет буфера.

 

Буфер появится как только освободится предыдущий. А точнее, предыдущий передается, текущий - создается. Так что никаких задержек не будет. Если, конечно, вторая задача вменяема и не генерирует данные секундами.

 

C MMC есть еще засада - SDHC карты отдают сектора только целиком, поэтому если REGENERATE будет невыравнен (а он в 99% невыравнен) по границе сектора

 

Это надуманная проблема. Свести выравнивание к границе сектора - цена одного пакета. Так что никакого геморроя.

 

Где тут "дульный компенсатор" который регулирует поток входящих данных?

 

Крутите окно заранее. В принципе, можно и небольшой буфер использовать, только без фанатизма. Вообще грамотный выбор окна и MTU - залог успеха при ограниченных объемах ОЗУ.

 

Кстати, а дайте-ка описание SDHC протокола карт, попробую сделать пример реализации - все одно в хозяйстве пригодится.

 

Эту работу можно вынести в отдельные .c/.h файлы так, что генерируемый код останется почти таким же самым - то есть основная идея "сплавить стек в единый кусок" не пострадает, а вот портируемость и читабельность сильно возрастет. Соответственно ценен будет для большего количества людей.

 

Я попробую. Хотя, честно говоря, особо не вижу смысла. Стек сей - не для бездумного ^C^V в свой проект. Сначала надо подумать, потом сделать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Именно это и приводит к потери производительности.

 

Я думаю это на самом деле повышает производительность.

Ваш текст пересыщен прыганьями по двойным указателям.

Потому как в процессе обработки вы работает с разнородными разнесенными структурами.

 

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

Потом менеджеры net буферов не делают монолитный пакет в линейной области памяти, пакет рассредоточен по нескольким буферам с выровненными границами.

А передача делается цепочечным DMA.

 

Но вообще если вы не смогли достичь физического максимума скорости значит вы нагрузили проц на все 100%.

Т.е. любая дополнительная реальная задача резко уменьшит производительность вашего "стека" и не факт что линейно.

 

Правильнее было бы действительно продемонстрировать скорость при одновременной работе TCP и файловой системы.

А так это коня в вакууме напоминает.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Буфер появится как только освободится предыдущий. А точнее, предыдущий передается, текущий - создается. Так что никаких задержек не будет. Если, конечно, вторая задача вменяема и не генерирует данные секундами.

Буфер-то в стеке появится, но будет отдан другому сокету, например. И пока это другой сокет не прекратит передачу - MMC будет стоять.

 

Крутите окно заранее. В принципе, можно и небольшой буфер использовать, только без фанатизма. Вообще грамотный выбор окна и MTU - залог успеха при ограниченных объемах ОЗУ.

Что значит крутить окно заранее? Это вообще не задача приложения - крутить окно. Вы на примере, пожалуйста, прокомментируйте - нужно писать входящий поток из сокета в MMC, просто - последовательно по секторам, без всякой файловой системы. Как это предполагается сделать и где тут "крутить окно"? Скорость ММС ну пусть будет 512байт/мс. А сети - пусть 10Кбайт/мс.

 

Это надуманная проблема. Свести выравнивание к границе сектора - цена одного пакета. Так что никакого геморроя.

Это не надуманная проблема, это следствие необходимости удовлетворять REGENERATE по произвольной границе при отсутствии буфера. И допустим, слать выравнено по границе сектора еще можно (вообще дикость, ну и мы ж за пропускную бьемся, да? 1460 - наше фсе :)), а как это вы заставите удаленный хост подтверждать прием четко по границе сектора? То есть - в любой момент может прийти REGENERATE типа "а дайте-ка мне вот 5 байт из этого сектора и далее".

 

Кстати, а дайте-ка описание SDHC протокола карт, попробую сделать пример реализации - все одно в хозяйстве пригодится.

В закромах есть.

 

Я попробую. Хотя, честно говоря, особо не вижу смысла. Стек сей - не для бездумного ^C^V в свой проект. Сначала надо подумать, потом сделать.

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

 

 

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

Тут вроде бы проблем с таким нету - и данные заголовка влезут в кеш и сам код обработчика тоже влезет в кеш (насчет вот колбеков вопрос открыт, правда). Но хранить MAC-адрес удаленного хоста в TCP-сокете - это готично :biggrin:. А если нету вообще снизу MAC-адреса (кстати, а как тут с примитивной маршрутизацией - хотя бы на gw, есть такое?), например PPP вместо эзернета? А если несколько интерфейсов, один с эзернетом, другой с PPP, куда бедному TCP-сокету податься? :biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что значит крутить окно заранее? Это вообще не задача приложения - крутить окно.

 

То и значит. Приложение знает, чего происходит у него, а у сферического стека в вакууме один способ - буферизация. В условиях недостатка ОЗУ в микроконтроллерных применениях это единственный способ - смычка города с деревней более глубокое взаимодействие приложения и стека.

 

Как это предполагается сделать и где тут "крутить окно"? Скорость ММС ну пусть будет 512байт/мс. А сети - пусть 10Кбайт/мс.

 

Для таких скоростей проще выставить окно в 512 байт и закрыть вопрос. Получили пакет - запустили запись. По готовности - отправили Window Update. Все. Если хочется достичь теоретической производительности в данном случае - надо сделать буфер на один сектор. Это все при условии минимального Round Trip Time.

 

(кстати, а как тут с примитивной маршрутизацией - хотя бы на gw, есть такое?),

 

Все в порядке. Хотя и необычно реализовано.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для таких скоростей проще выставить окно в 512 байт и закрыть вопрос. Получили пакет - запустили запись.

Угу, и еще залезли в s->win и сделали его нулевым, потому как вдруг уйдет ACK с новым ACKNO и удаленный хост вышлет новые данные. Готична.

То и значит. Приложение знает, чего происходит у него, а у сферического стека в вакууме один способ - буферизация.

Угу, и еще достаточно много случаев когда приложение от буферизации никуда не денется, и все равно будет решать эту проблему. Попутно оно еще будет решать кучу проблем протокола типа "прикрутить окно" и требовать проверки-отладки при изменении сетевого окружения - конфигурации активных сокетов, скорости линка, смены среды передачи и т.д. Н-е-е-е-т, ну его нафиг - написание таких приложений.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но хранить MAC-адрес удаленного хоста в TCP-сокете - это готично :biggrin:. А если нету вообще снизу MAC-адреса (кстати, а как тут с примитивной маршрутизацией - хотя бы на gw, есть такое?), например PPP вместо эзернета? А если несколько интерфейсов, один с эзернетом, другой с PPP, куда бедному TCP-сокету податься? :biggrin:

Возможно я не прав, но реализация протокола от Rst7 заточена под вполне конкретное применение. Это позволяет выжать максимум скорости для данной реализации. Отсюда и MAC, и коллбэки, и не совсем четко разнесенная по уровням обработка. Но если устройство соответствует ТЗ, то это абсолютно не важно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...