پرش به مطلب اصلی

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‌های قدیمی پذیرفته می‌شود، اما منطق فعلی پروتکل از آن برای رمزنگاری یا احراز هویت استفاده نمی‌کند.

فیلدهای اجباری​

فیلدهای سطح اصلی:

فیلدنوعتوضیح
namestringنام یکتای node در config.
typestringباید دقیقاً "Bgp4Client" باشد.
nextstringnode stream بعدی که فریم‌های بسته‌بندی‌شده را می‌گیرد.

تنظیمات اختیاری​

گزینهنوعپیش‌فرضتوضیح
passwordstring—پذیرفته می‌شود اما نادیده گرفته می‌شود؛ برای رمزنگاری یا احراز هویت کاربردی ندارد.

در حال حاضر تنظیم دیگری خوانده نمی‌شود.

فرمت فریم​

همه 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.
bodypayload تونل‌شده؛ در نخستین فریم upstream شامل body ساختگی OPEN و سپس payload تونل‌شده است.

مقادیر نوع پشتیبانی‌شده:

نوعنام
1OPEN
2UPDATE
3NOTIFICATION
4KEEPALIVE
5ROUTE-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 time90 ثانیه.
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:

  1. بررسی می‌کند که هر ۱۶ بایت اول 0xff باشند.
  2. فیلد دوبایتی طول body را می‌خواند.
  3. فریم‌هایی را که طول body آن‌ها از فیلد یک‌بایتی type بیشتر نیست رد می‌کند.
  4. تا buffer شدن کل فریم منتظر می‌ماند.
  5. marker، length و type را حذف می‌کند.
  6. فریم‌هایی را که پس از آن payload‌ی ندارند نمی‌پذیرد.
  7. payload بازیابی‌شده را در جهت downstream به تونل قبلی می‌فرستد.

اگر فریم ناقص باشد، parser منتظر بایت‌های بعدی می‌ماند. اگر حجم داده buffer‌شده از سقف فعلی buffer بگذرد، line بسته می‌شود.

محدودیت‌ها و Padding​

مقدارمقداریادداشت
حداکثر طول body65535 بایتشامل type یک‌بایتی.
حداکثر payload در body عادی65534 بایتمجموع payload و type باید در 65535 بایت جا شود.
سقف بایت‌های نگه‌داری‌شده در هر جهت2162705مستقل از اندازهٔ pool، پروفایل حافظه و splice.
سقف فریم‌های خروجی در صف1024تعداد قطعه‌های ورودی محدود نمی‌شود.
required_padding_left39 بایتبرای پیشوند فریم و بزرگ‌ترین پیشوند ساختگی 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/resumenext tunnel upstream
downstream pause/resumeprevious tunnel downstream

نکته‌ها​

  • برای استفاده عملی از Bgp4Client باید آن را با Bgp4Server جفت کنید.
  • در پیاده‌سازی فعلی، password قابلیت امنیتی محسوب نمی‌شود.
  • فیلد طول در قالب شبیه BGP، بایت‌های marker و length را در نظر نمی‌گیرد.
  • اولین OPEN frame فقط وقتی اولین upstream payload برسد فرستاده می‌شود.
  • upstream est و downstream init غیرفعال هستند.
  • این node یک تونل stream لایه ۴ است، نه packet tunnel.

متادیتای نود​

metadata برگرفته از کد منبع:

ویژگیمقدار
node flagskNodeFlagSupportsSplice
can_have_prevtrue
can_have_nexttrue
layer_groupkNodeLayer4
layer_group_prev_nodekNodeLayer4
layer_group_next_nodekNodeLayer4
required_padding_left39 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 بدون اندازه‌گیری نیست.