הכירו את SCTP

זהירות, פוסט ארוך

לאחרונה התחלתי ללמוד קצת על מערכת אותות מספר 7 (SS7) במסגרת פרוייקט מאוד גדול שאני מתעסק בו כבר מספר חודשים לחברה מאוד גדולה וידועה.

עד עכשיו היה שימוש רק ב E1, אז החיבור הוא קווי באמצעות קו רגיל של ISDN, אבל יש לזה מגבלה של 30 ערוצי תקשורת פר חיבור (אם אין דחיסה).
אנחנו כמובן מעוניינים לספק כמה שיותר תעבורה, אז התחלנו לברר על משהו הנקרא SIGTRAN אשר הוא בעצם SS7 על גבי IP, אך הוא אינו משתמש ב TCP או UDP בשביל זה, אלא על גבי פרוטוקול (יחסית חדש) בשם  SCTP.

אני כבר מספר שנים יודע כי הפרוטוקול קיים, ומעולם לא הבנתי מדוע עולם ה VoIP לא לקח אותו לשימוש. ולאחר שלמדתי על HTTP/2 לא הבנתי גם מדוע הוא לא נבחר לשם.
הפוסט הבא מנסה להסביר בקצרה יחסית מהו הפרוטוקול, בתקווה שיעזור לכם להיחשף לעוד מידע שלרוב איננו נחשפים אליו.

מהו SCTP?

הקדמה

ישנם שני פרוטוקולים מעל רמת IP אשר מאוד מוכרים בעולם – TCP ו UDP.

על רגל אחת, כאשר מדברים על TCP, מדברים על פרוטוקול אשר יודע לטפל בנתונים העוברים תחת רשת ה IP, כשהוא מודע האם תוכן הגיע ליעדו או לא, מה הסדר שלו, והאם צריך לשדר אותו מחדש, כולל ניסיון לנהל עומס בבקשות החוזרות.

כאשר מדברים על UDP, אנו מדברים על מערכות הדורשות גישה של real-time. אין בפרוטוקול עצמו איזשהו מנהל אשר יודע מה קורה עם המידע, כלומר הוא לא יודע לזהות ולדווח האם הבקשה הגיעה ליעדה בהצלחה או לא, או האם הסדר הוא בכלל תקין, ובעצם הניהול הוא בפרוטוקול עצמו (שכבה 5 ולפעמים גם 7) המשתמש ב UDP ולא מתוך שיטת התעבורה הנקראת UDP.

אז מה הוא SCTP או Stream Control Transmission Protocol בשמו המלא?

הסבר הרעיון (TL;DR)

תארו לכם מצב בו אתם רוצים לדבר בהודעות, או מידע במקום בפקטות. אבל זה לא הכל, אתם רוצים לשלב כמה שיותר מידע שאפשר לשלוח ולספק עליו חיווי.

לפעמים נרצה לדעת אם זה נכשל, לפעמים לא. לפעמים נרצה להסביר את סדר החתיכות, ולפעמים אנחנו רוצים להפקיד שההודעה כמו שהיא אינה מחולקת בכלל.

כלומר אם אשווה את זה לבקשת HTTP, אני יכול להגיד כי תוכן מסוים של ווב, יהיה חייב להישלח כמו שהוא, בעוד שחלקים קטנים של מידע, למשל css ו JS, כולל דף ה HTML ישלחו בחלקים באותה בקשה.

כלומר יש לנו כאן סוג של פרוטוקול multiplexing .

במידה ואני רוצה שגודל הדף, גודל הפרמטרים, ורשימת הקבצים להוריד יגיעו בפעם אחת, אז הפרוטוקול מאפשר. כאשר התוכן של הקבצים יכולים להגיע בבקשה נפרדת, או מחולקת גם בבקשה הזו, בהתאם לגודל.

מוכר לכם ממשהו? למשל מגישה בשם HTTP/2?
אבל כאן זה פרוטוקול ברמה נמוכה יותר, ולא מימוש בשכבה 7.

אבל העניין הוא שזה ממש לא הכל. יש לפרוטוקול תמיכה בmultihoming – כלומר האפשרות להתחבר למספר שרתים במקביל, וכך להבטיח שרידות בקבלה ושליחה של המידע.
הפרוטוקול אפילו מאפשר תמיכה במציאות הנתיב עם האיכות הכי טובה שהגדרנו, כמו ש MPLS, DiffServ וכיוב' מספקים.
עוד פיטצ'ר נחמד, הוא תמיכה ב jumbo frames, אשר מאפשרים לשלוח עם MTU גדול יותר מ1500 בתים.

אז כיצד זה בעצם עובד?

הפקטה עצמה די פשוטה יחסית במבנה שלה:

sctp header

מציינים את הפורט אשר ניגשים ממנו, והפורט שניגשים אליו בצד השני.
אז מציינים מזהה בגודל של 32 ביט, שיהיה ייחודי לבקשה.
לאחר מכן, יש לציין גם את הchecksum של כל הבקשה. פעם החישוב היה של adler32 אך בגלל חולשה של החישוב, הוא עבר ל crc32c.

עד כאן החלק של הפקטה עצמה, שמתארת את הבקשה.
עכשיו צריך בעצם להחזיק את המידע שיש צורך לשלוח איכשהו.
המידע הוא מידע חלקי ונקרא chunks. כלומר "חתיכה".

ה header שלו בנוי כך:

sctp chunk field

8 ביטים הראשונים נקראים Chunk Type, השדה מחזיק מידע על סוג ה"חתיכה". הערכים יכולים להיות מ0 ועד 254, כאשר הספרה 255 שמורה לשימוש עתידי.

שני הביטים הראשונים של Chunk Type מוגדרים בצורה כזו, אשר מאפשרים להתמודד עם תקשורת:

  • 00 – אל תעשה כלום עם הבקשה, התעלם ממנה, הפל את הבקשה, וchunks הקשורות אליה בבקשה, ואל תבקש אותה מחדש.
  • 01 – אל תעשה כלום עם הבקשה, התעלם ממנה, הפל את הבקשה,וchunks הקשורות אליה בבקשה, ואל תבקש אותה מחדש. אבל דווח על כך שאיך יודע מה לעשות עם הבקשה.
  • 10 – דלג על החתיכה הזו, אך המשך לשאר החתיכות.
  • 11 – דלג על החתיכה הזו, אך המשך לשאר החתיכות, ודווח על שגיאה שלא היה ניתן לטפל בחתיכה הזו.

שמונה הביטים הבאים, נקראים Chunk Flags, ותלויים בסוג ה Chunk שהיה מקודם. אלא אם צוין במיוחד, הוא לרוב יהיה בערך 0, ויזכה להתעלמות משני הצדדים.

שש עשרה הביטים הבאים הנקראים Chunk Length מחזיקים את אורך הבקשה במספר שלם ויכול להיות עד הטווח של 65,535.  הגודל מכיל גם את גודל ביחד עם Chunk Type ו Chunk Flags. במידת הצורך, השדה יהיה עם padding של אפסים בהתחלה, שלא יעלו על יותר מ3 בתים בפועל.

החלק האחרון הוא המידע בפועל של ה"חתיכה", בצורה שהיא משתנה בהתאם לסוג המידע בתוכה.

sctp chunk value

השדה הראשון הוא בגודל 16 ביט, וקיבל את השם Parameter Type. הוא יכול להיות מספר בין 0 ל65,534, כאשר המספר 65,535 הוא מספר שמור עבור הגדרת הרחבות של IETF.

השדה השני הוא בגודל 16 ביט, וקיבל את השם Chunk Parameter. הוא מחזיק את אורך ה value בבתיים כולל את עצמו ואת Parameter Type.
פרמטרים עם גודל אפס יהיה לו גודל של 4, ללא תוספת רווחים בהתחלה.

השדה השלישי הוא בגודל משתנה, והוא קיבל את השם Parameter Value. השדה מכיל את המידע בפועל שישלח עבור הפרמטר.

הגודל המקסימלי של כל המידע הזה, כולל השדות הראשונים חייב להיות מכפלה של 4 בתים. במידה והוא אינו כזה, יש padding לאחר סיום ה שדה השלישי של אפסים אשר אינם כלולים באורך הפרמטר. אך לשולח אסור לספק padding של יותר מ3 בתים. המקבל חייב להתעלם מהpadding.

סוג הפרמטר בנויים בצורה בה 2 הביטים הראשונים מציינים את סוג הפעולה שיש לקחת כאשר המקבל לא יודע לזהות את הפרמטר:

  • 00 – אל תעשה כלום עם הבקשה, התעלם ממנה, הפל את הבקשה, וchunks הקשורות אליה בבקשה, ואל תבקש אותה מחדש.
  • 01 – אל תעשה כלום עם הבקשה, התעלם ממנה, הפל את הבקשה,וchunks הקשורות אליה בבקשה, ואל תבקש אותה מחדש. אבל דווח על כך שאיך יודע מה לעשות עם הבקשה.
  • 10 – דלג על החתיכה הזו, אך המשך לשאר החתיכות.
  • 11 – דלג על החתיכה הזו, אך המשך לשאר החתיכות, ודווח על שגיאה שלא היה ניתן לטפל בחתיכה הזו.

המידע עצמו

עד עכשיו, דיברתי על החלק בו יש תיאור של מה נשלח. אבל יש את המידע עצמו שיש צורך לשלוח:

 

sctp payload

 

השדה שהוא Reserved הוא בגודל 5 ביטים ותמיד חייב להיות 0, ותמיד חייבים להתעלם ממנו בקבלת המידע.

האותיות U, B ו E הן בעלות גודל של ביט בודד, ויכולות להיות בעלות הערך של 0 או 1:

  • U – מציין את המילה Unordered. במידה והשדה מכיל את הערך 1, זה מציין כי המידע אינו מסודר. כלומר אין מספר סיריאלי כלשהו המציין את הסדר של המידע, ולכן אם נשלח מספר שכזה, המקבל חייב להתעלם ממנו.
    לאחר הרכבה מחודשת (במידת הצורך), חתיכות של מידע לא מסודר חייבות להישלח לשכבה העליונה של המקבל, בלי הניסיון לסדר את המידע מחדש.
    במידה ומידע לא מסודר הוא מחולק (fragmented), כל חלק בהודעה חייב שהשדה U יהיה עם הערך 1.
  • B – מציין את המילה Beginning. במידה והשדה מכיל את הספרה 1, זה אומר כי זהו החלק הראשון של ההודעה.
  • E – מציין את המילה Ending. במידה והערך הוא 1, זה אומר כי המידע הוא החלק האחרון של מידע מחולק.

במידה והמידע אינו מחולק (fragmented), אז הערכים של B ו E צריכים להיות עם הערך 1. כאשר אם שניהם מחזיקים ב0, הכוונה היא שזה האמצע של ההודעה.
במידה וגם B וגם E מכילים את הערך 1, מדובר במידע שאינו מחולק.

sctp payload fragments

במידה, ומדובר במידע מחולק, אז השדה של TSN, צריך להיות בשימוש על ידי המקבל עבור הרכבה מחודשת של ההודעה. כלומר, שדה ה TSN חייב להיות מספר עוקב בשביל להצליח להרכיב חזרה את ההודעה.

השדה Length הוא בגודל 16 ביט, והוא בטווח של עד 65,535. השדה מציין את אורך או גודל המידע בבתים, כולל ההתחלה של השדה type ועד למעשה ה Data עצמו כולל, לא כולל איזשהו padding.
שדה ה Data עם בית בודד של מידע מהמשתמש, יכיל את המספר 17, בשביל לציין 17 בתים.
כאשר מידע מהמשתמש יהיה בגודל המצויין באות L, יכיל את האורך של 16+L, אשר מציין 16+L בתים. חשוב לציין כי L חייב להיות גדול מ0.

השדה TSN הוא בגודל 32 ביטים ויכול להיות מ0 ועד המספר 4,294,967,295. כאשר לאחר הגעה למספר הזה, הוא יחזור להיות 0.
תפקיד השדה הוא להחזיק את הערך של Transmission sequence number – מזהה עבור אותה חתיכה שנשלחה. וכאמור יהיה בשימוש כאשר יש להרכיב מחדש הודעה המחולקת למספר פקטות.

השדה של Stream Identifier S, הוא בגודל של 16 ביט, והוא בטווח של 0 ועד 65,535. תפקידו הוא לזהות לאן ה stream שייך.

השדה של Stream Sequence Number הוא בגודל של 16 ביט, והוא בטווח של 0 ועד 65,535. תפקידו הוא לדעת מה הסדר של ה stream אשר נשלח, לפי השייכות שלו המוגדרת ב Stream Identifier S.
כאשר ההודעה מתחלקת (fragmented) על מספר בקשות, אותו מספר עוקב חייב להיות עם כל החלקים של ההודעה.

השדה של Payload Protocol Identifier הוא שדה בגודל של 32 ביט. המקום הזה מייצג בערך מידע של התוכנה או שכבה כבוהה, כמספר הפרוטוקול. המידע הזה מועבר על ידי SCTP לשכבה הגבוהה יותר, ונשלח ל peer. המזהה אינו נמצא בשימוש של SCTP עצמו, אך יכול להיות בשימוש על ידי מערכות תקשורת שונות, וכן על ידי התוכנה עצמה הזקוקה למידע הזה בשביל לזהות את סוג המידע הנשלח בחלק המידע למשתמש.
השדה חייב להישלח כחלק ממידע מחולק (fragmented), בשביל שיהיה נגיש למפרשים שונים).
חשוב להדגיש כי SCTP אינו נוגע על ידי מימוש ה SCTP, ולכן המידע שבו אינו חייב להופיע כ Big Endian.
שכבת התוכנה היא זו שאחראית על המרת המידע.
במידה והשדה מחזיק בערך 0, זה אומר כי אין הגדרה למזהה שכבת תוכנה על במידע המשתמש עצמו.

השדה של User Data, הוא בגודל משתנה. השדה הזה הוא המידע עצמו שנשלח על ידי המשתמש. המימוש חייב לשים padding של 4 בתים בערך של 0 בסוף. תוספת 4 הבתים, אסורה להיכלל בחישוב אורך המידע.

זה הבסיס של הפרוטוקול עצמו. ב RFC4960 תוכלו למצוא את כל הפרוטקול, ובנוסף מידע שלא הכנסתי לכאן, למשל חוקים נוספים לכל שדה, איך עושים multihoming ועוד.

עוד מקומות מעניינים לחקור: הם בוויקיפדיה, בערך המסביר על SCTP, ובערך המלמד על המבנה של הפרוטוקול.

כתיבת תגובה

הזינו את פרטיכם בטופס, או לחצו על אחד מהאייקונים כדי להשתמש בחשבון קיים:

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s