Bgp4Client
Bgp4Client یک تونل stream در لایه ۴ است. payloadهای upstream را در فریمهایی شبیه BGP قرار میدهد و فریمهای downstream ساختهشده توسط Bgp4Server را باز میکند.
این node باید با Bgp4Server استفاده شود:
TcpListener -> Bgp4Client -> ... -> Bgp4Server -> TcpConnector
در استقرار واقعی، ... معمولاً مسیر transport میان دو طرف است؛ مانند TCP، TLS، mux، reverse یا بخشی دیگر از chain در WaterWall.
Bgp4Client مسیریابی واقعی BGP، برقراری BGP peering، تبادل route یا احراز هویت BGP را پیادهسازی نمیکند. شکل فریم شبیه BGP فقط برای استتار و فریمبندی stream به کار میرود.
این نود چه میکند؟
- هنگام
initدر جهت upstream، برای هر line یک stream خواندن و state مربوط به اولین فریم را مقداردهی اولیه میکند. - در اولین payloadِ upstream، یک body ساختگی BGP OPEN را پیش از بایتهای برنامه prepend میکند.
- payloadهای upstream را در فریمهای شبیه BGP قرار میدهد.
- یک نوع BGP غیر-OPEN تصادفی برای frameهای payload upstream بعدی انتخاب میکند.
- فریمهای شبیه BGP در جهت downstream را از یک stream buffer میخواند.
- اطلاعات فریم downstream را حذف و payload بازیابیشده را به تونل قبلی میفرستد.
- در صورت دریافت فریم نامعتبر، هر دو جهت را میبندد.
Bgp4Client یک تونل stream معمولی است. socket شبکه یا packet line نمیسازد و packet lineای را نیز آزاد نمیکند.
نمونه تنظیم
سمت کلاینت:
{
"name": "bgp4-client",
"type": "Bgp4Client",
"settings": {
"password": "compat-value"
},
"next": "transport-out"
}
سمت سرور متناظر:
{
"name": "bgp4-server",
"type": "Bgp4Server",
"settings": {
"password": "compat-value"
},
"next": "target"
}
فیلد password برای سازگاری با configهای قدیمی پذیرفته میشود، اما منطق فعلی پروتکل از آن برای رمزنگاری یا احراز هویت استفاده نمیکند.
فیلدهای اجباری
فیلدهای سطح اصلی:
| فیلد | نوع | توضیح |
|---|---|---|
name | string | نام یکتای node در config. |
type | string | باید دقیقاً "Bgp4Client" باشد. |
next | string | node stream بعدی که فریمهای بستهبندیشده را میگیرد. |
تنظیمات اختیاری
| گزینه | نوع | پیشفرض | توضیح |
|---|---|---|---|
password | string | — | پذیرفته میشود اما نادیده گرفته میشود؛ برای رمزنگاری یا احراز هویت کاربردی ندارد. |
در حال حاضر تنظیم دیگری خوانده نمیشود.
فرمت فریم
همه payloadهای upstream با این ساختار بستهبندی میشوند:
16-byte marker | 2-byte body length | 1-byte BGP type | body
جزئیات فیلد:
| فیلد | مقدار |
|---|---|
| marker | شانزده بایت با مقدار 0xff. |
| body length | یک uint16_t با ترتیب big-endian؛ شامل بایت type بهعلاوه بایتهای body. |
| BGP type | مقدار 1 برای نخستین فریم OPEN؛ یکی از مقادیر تصادفی 2 تا 5 برای فریمهای بعدی payload. |
| body | payload تونلشده؛ در نخستین فریم upstream شامل body ساختگی OPEN و سپس payload تونلشده است. |
مقادیر نوع پشتیبانیشده:
| نوع | نام |
|---|---|
1 | OPEN |
2 | UPDATE |
3 | NOTIFICATION |
4 | KEEPALIVE |
5 | ROUTE-REFRESH |
طول فریم با طول استاندارد پیام BGP یکسان نیست. قالب قدیمی شبیه BGP در WaterWall، طول را برابر بایت type بهعلاوه بایتهای body در نظر میگیرد و marker شانزدهبایتی و فیلد طول دوبایتی را حساب نمیکند.
اولین Upstream Payload
Bgp4Client هنگام init فریم OPEN مستقلی نمیفرستد. در عوض، نخستین payloadِ upstream را با BGP type برابر 1 فریم میکند و پیش از بایتهای برنامه یک body ساختگی OPEN قرار میدهد.
فیلدهای synthetic OPEN:
| فیلد | رفتار |
|---|---|
| version | همیشه 4. |
| AS number | یک uint16_t تصادفی که هنگام ساخت instance تونل تولید میشود. |
| hold time | 90 ثانیه. |
| router id | مقدار تصادفی تولیدشده در هنگام ساخته شدن tunnel instance. |
| optional parameter length | طول تصادفی بین 3 تا 10 بایت. |
| optional parameter bytes | بایتهای تصادفی در بازه 0 تا 199. |
پس از نخستین فریم، open_sent برای line تنظیم میشود. payloadهای بعدی upstream بدون پیشوند ساختگی OPEN بستهبندی میشوند و یک type تصادفی غیر از OPEN میگیرند.
از آنجا که Bgp4Server انتظار دارد داده تونلشده برنامه پس از پیشوند OPEN قرار بگیرد، نخستین فریم OPEN باید بعد از body ساختگی OPEN دارای بایتهای payload باشد.
Downstream Parsing
بایتهای downstream در یک splice_stream_t جمع میشوند.
Bgp4Client برای هر فریم کامل downstream:
- بررسی میکند که هر ۱۶ بایت اول
0xffباشند. - فیلد دوبایتی طول body را میخواند.
- فریمهایی را که طول body آنها از فیلد یکبایتی type بیشتر نیست رد میکند.
- تا buffer شدن کل فریم منتظر میماند.
- marker، length و type را حذف میکند.
- فریمهایی را که پس از آن payloadی ندارند نمیپذیرد.
- payload بازیابیشده را در جهت downstream به تونل قبلی میفرستد.
اگر فریم ناقص باشد، parser منتظر بایتهای بعدی میماند. اگر حجم داده bufferشده از سقف فعلی buffer بگذرد، line بسته میشود.
محدودیتها و Padding
| مقدار | مقدار | یادداشت |
|---|---|---|
| حداکثر طول body | 65535 بایت | شامل type یکبایتی. |
| حداکثر payload در body عادی | 65534 بایت | مجموع payload و type باید در 65535 بایت جا شود. |
| سقف بایتهای نگهداریشده در هر جهت | 2162705 | مستقل از اندازهٔ pool، پروفایل حافظه و splice. |
| سقف فریمهای خروجی در صف | 1024 | تعداد قطعههای ورودی محدود نمیشود. |
required_padding_left | 39 بایت | برای پیشوند فریم و بزرگترین پیشوند ساختگی OPEN کافی است. |
دادهٔ بزرگ به چند فریم با حداکثر ۶۵۵۳۴ بایت payload عادی تقسیم میشود. فضای واقعی پیشوند OPEN از فریم نخست کم میشود و فقط یک OPEN فرستاده میشود.
جریان داده
جهت upstream:
previous node -> Bgp4Client wraps -> next node
جهت downstream:
next node -> Bgp4Client unwraps -> previous node
Bgp4Client انتظار دارد در سمت مقابل Bgp4Server قرار گرفته باشد. هر peer ناسازگاری که فریم مورد انتظار را نسازد، خطای پروتکل ایجاد میکند.
رفتار Lifecycle
با دریافت init در جهت upstream، Bgp4Client state مربوط به line را مقداردهی اولیه میکند و init را در همان جهت به تونل بعدی میفرستد.
با دریافت est در جهت downstream، هر اعلان، حتی تکراری، را به تونل قبلی میفرستد.
payloadهای upstream را فریمبندی و به تونل بعدی میفرستد. payloadهای downstream را buffer و تجزیه میکند، فریم را باز میکند و داده بازیابیشده را به تونل قبلی میفرستد.
با دریافت finish از هر جهت، state مربوط به line را از بین میبرد و finish را در همان جهت منتشر میکند: در upstream به تونل بعدی و در downstream به تونل قبلی.
در صورت دریافت فریم نامعتبر، Bgp4Client state محلی را از بین میبرد و هر دو جهت را با ترتیب لازم برای یک تونل میانی میبندد: ابتدا finish در upstream و سپس finish در downstream.
Pause و Resume اعلانهای راهنمای تکرارپذیر هستند. callbackهای پیشفرض هر اعلان را فوراً در همان جهت منتقل میکنند؛ وضعیت توقف مصرفکننده ذخیره نمیشود و ارسال payload به Resume وابسته نیست:
| callback | مقصد ارسال |
|---|---|
| upstream pause/resume | next tunnel upstream |
| downstream pause/resume | previous tunnel downstream |
نکتهها
- برای استفاده عملی از
Bgp4Clientباید آن را باBgp4Serverجفت کنید. - در پیادهسازی فعلی،
passwordقابلیت امنیتی محسوب نمیشود. - فیلد طول در قالب شبیه BGP، بایتهای marker و length را در نظر نمیگیرد.
- اولین OPEN frame فقط وقتی اولین upstream payload برسد فرستاده میشود.
- upstream
estو downstreaminitغیرفعال هستند. - این node یک تونل stream لایه ۴ است، نه packet tunnel.
متادیتای نود
metadata برگرفته از کد منبع:
| ویژگی | مقدار |
|---|---|
| node flags | kNodeFlagSupportsSplice |
can_have_prev | true |
can_have_next | true |
layer_group | kNodeLayer4 |
layer_group_prev_node | kNodeLayer4 |
layer_group_next_node | kNodeLayer4 |
required_padding_left | 39 bytes |
Splice، فریمبندی و کنترل فشار
هر دو جهت buffer عادی، بدنهٔ داخل pipe خصوصی و ترکیب این دو را میپذیرند. فریم تکتکه با استفاده از padding موجود در همان buffer ساخته میشود؛ بودجهٔ padding کلاینت ۳۹ و سرور ۱۹ بایت است. ورودی بزرگ پیش از نخستین callback به یک دستهٔ کامل از فریمهای مستقل تبدیل میشود. شکست ساخت pipe یا پرشدن مقصد برای همان فریم به buffer عادی با اندازهٔ کافی برمیگردد؛ کل ورودی به یک buffer عادی تجمیع نمیشود.
گیرنده header نوزدهبایتی را cache میکند و body هر فریم را جداگانه تحویل میدهد. سرور فقط ۱۰ بایت ثابت OPEN و حداکثر ۲۵۵ بایت اختیاری را بررسی یا مصرف میکند؛ بقیهٔ payload میتواند داخل pipe بماند. کلاینت ۳ تا ۱۰ بایت اختیاری تولید میکند و اندازهٔ واقعی آن را از ظرفیت فریم نخست کم میکند. ورودی خالی فریمی تولید نمیکند و وضعیت نخستین OPEN را مصرف نمیکند. روی هر line کلاینت دقیقاً یک OPEN پذیرفته میشود.
سقف ثابت هر جهت ۲٬۱۶۲٬۷۰۵ بایت منطقی (2 MiB + 65553) است و به پروفایل
حافظه، اندازهٔ buffer، ظرفیت واقعی pipe، پلتفرم یا misc.splice وابسته نیست.
گیرنده بایتهای wire نگهداریشده، شامل header کششده، را میشمارد؛ فرستنده
بایتهای فریمهای خروجی، شامل headerهای تولیدشده، را حساب میکند.
صف خروجی حداکثر ۱۰۲۴ فریم دارد؛ این سقف برای تعداد قطعههای ورودی نیست.
حداکثر فریم کامل ۶۵٬۵۵۳ و payload فریم غیر-OPEN حداکثر ۶۵٬۵۳۴ بایت است.
هر فریم دریافتی callback جداگانه دارد. هر دو نود از همان line عادی قرضگرفتهشده استفاده میکنند و تمام payloadها را تبدیل میکنند؛ بنابراین bypass دائمی ندارند. Pause و Resume، حتی اگر تکراری باشند، با callbackهای پیشفرض در هر دو جهت شفاف منتقل میشوند. فریمهای کامل پذیرفتهشده بدون انتظار برای Resume تخلیه میشوند. محافظ تخلیه در هر جهت ترتیب FIFO را هنگام callbackهای بازگشتی حفظ میکند؛ stream ورودی دادهٔ ناقص را نگه میدارد و صف محدود خروجی، دستههای کامل فریمبندیشده را پیش از ورودی بازگشتی ارسال میکند. هر ورودی پیش از نخستین callback مربوط به خود با سقفهای ثابت نگهداری بررسی میشود. دادهٔ نامعتبر، عبور از سقف نگهداری یا رد شدن بهدلیل محدودیت ظرفیت صف فقط همان اتصال را از طریق مالک line میبندد. Finish منابع محلی را پیش از ارسال در جهت دور از فرستنده آزاد میکند. این پشتیبانی تضمین zero-copy یا افزایش throughput بدون اندازهگیری نیست.