diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..5a77a805 --- /dev/null +++ b/404.html @@ -0,0 +1,604 @@ + + + + + + + + + + + + + + + + + + free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..934a4e59 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +free5gc.org diff --git a/assets/golden.png b/assets/golden.png new file mode 100644 index 00000000..21c8eb9a Binary files /dev/null and b/assets/golden.png differ diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 00000000..95fee280 Binary files /dev/null and b/assets/icon.png differ diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 00000000..1cf13b9f Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/javascripts/bundle.b4d07000.min.js b/assets/javascripts/bundle.b4d07000.min.js new file mode 100644 index 00000000..3c0bdad9 --- /dev/null +++ b/assets/javascripts/bundle.b4d07000.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Ci=Object.create;var gr=Object.defineProperty;var Ri=Object.getOwnPropertyDescriptor;var ki=Object.getOwnPropertyNames,Ht=Object.getOwnPropertySymbols,Hi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,nn=Object.prototype.propertyIsEnumerable;var rn=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&rn(e,r,t[r]);if(Ht)for(var r of Ht(t))nn.call(t,r)&&rn(e,r,t[r]);return e};var on=(e,t)=>{var r={};for(var n in e)yr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Ht)for(var n of Ht(e))t.indexOf(n)<0&&nn.call(e,n)&&(r[n]=e[n]);return r};var Pt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Pi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ki(t))!yr.call(e,o)&&o!==r&&gr(e,o,{get:()=>t[o],enumerable:!(n=Ri(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Ci(Hi(e)):{},Pi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var sn=Pt((xr,an)=>{(function(e,t){typeof xr=="object"&&typeof an!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(O){return!!(O&&O!==document&&O.nodeName!=="HTML"&&O.nodeName!=="BODY"&&"classList"in O&&"contains"in O.classList)}function f(O){var Qe=O.type,De=O.tagName;return!!(De==="INPUT"&&s[Qe]&&!O.readOnly||De==="TEXTAREA"&&!O.readOnly||O.isContentEditable)}function c(O){O.classList.contains("focus-visible")||(O.classList.add("focus-visible"),O.setAttribute("data-focus-visible-added",""))}function u(O){O.hasAttribute("data-focus-visible-added")&&(O.classList.remove("focus-visible"),O.removeAttribute("data-focus-visible-added"))}function p(O){O.metaKey||O.altKey||O.ctrlKey||(a(r.activeElement)&&c(r.activeElement),n=!0)}function m(O){n=!1}function d(O){a(O.target)&&(n||f(O.target))&&c(O.target)}function h(O){a(O.target)&&(O.target.classList.contains("focus-visible")||O.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(O.target))}function v(O){document.visibilityState==="hidden"&&(o&&(n=!0),Y())}function Y(){document.addEventListener("mousemove",N),document.addEventListener("mousedown",N),document.addEventListener("mouseup",N),document.addEventListener("pointermove",N),document.addEventListener("pointerdown",N),document.addEventListener("pointerup",N),document.addEventListener("touchmove",N),document.addEventListener("touchstart",N),document.addEventListener("touchend",N)}function B(){document.removeEventListener("mousemove",N),document.removeEventListener("mousedown",N),document.removeEventListener("mouseup",N),document.removeEventListener("pointermove",N),document.removeEventListener("pointerdown",N),document.removeEventListener("pointerup",N),document.removeEventListener("touchmove",N),document.removeEventListener("touchstart",N),document.removeEventListener("touchend",N)}function N(O){O.target.nodeName&&O.target.nodeName.toLowerCase()==="html"||(n=!1,B())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),Y(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var cn=Pt(Er=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},s=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(B,N){d.append(N,B)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(O){throw new Error("URL unable to set base "+c+" due to "+O)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,Y=!0,B=this;["append","delete","set"].forEach(function(O){var Qe=h[O];h[O]=function(){Qe.apply(h,arguments),v&&(Y=!1,B.search=h.toString(),Y=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var N=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==N&&(N=this.search,Y&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},s=i.prototype,a=function(f){Object.defineProperty(s,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){a(f)}),Object.defineProperty(s,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(s,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er)});var qr=Pt((Mt,Nr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Mt=="object"&&typeof Nr=="object"?Nr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Mt=="object"?Mt.ClipboardJS=r():t.ClipboardJS=r()})(Mt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return Ai}});var s=i(279),a=i.n(s),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(T){return!1}}var d=function(T){var E=p()(T);return m("cut"),E},h=d;function v(j){var T=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[T?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=j,E}var Y=function(T,E){var H=v(T);E.container.appendChild(H);var I=p()(H);return m("copy"),H.remove(),I},B=function(T){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof T=="string"?H=Y(T,E):T instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(T==null?void 0:T.type)?H=Y(T.value,E):(H=p()(T),m("copy")),H},N=B;function O(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?O=function(E){return typeof E}:O=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},O(j)}var Qe=function(){var T=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=T.action,H=E===void 0?"copy":E,I=T.container,q=T.target,Me=T.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&O(q)==="object"&&q.nodeType===1){if(H==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return N(Me,{container:I});if(q)return H==="cut"?h(q):N(q,{container:I})},De=Qe;function $e(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$e=function(E){return typeof E}:$e=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},$e(j)}function Ei(j,T){if(!(j instanceof T))throw new TypeError("Cannot call a class as a function")}function tn(j,T){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=$e(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var q=this;this.listener=c()(I,"click",function(Me){return q.onClick(Me)})}},{key:"onClick",value:function(I){var q=I.delegateTarget||I.currentTarget,Me=this.action(q)||"copy",kt=De({action:Me,container:this.container,target:this.target(q),text:this.text(q)});this.emit(kt?"success":"error",{action:Me,text:kt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(I){return vr("action",I)}},{key:"defaultTarget",value:function(I){var q=vr("target",I);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(I){return vr("text",I)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(I){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return N(I,q)}},{key:"cut",value:function(I){return h(I)}},{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof I=="string"?[I]:I,Me=!!document.queryCommandSupported;return q.forEach(function(kt){Me=Me&&!!document.queryCommandSupported(kt)}),Me}}]),E}(a()),Ai=Li},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,f){for(;a&&a.nodeType!==o;){if(typeof a.matches=="function"&&a.matches(f))return a;a=a.parentNode}}n.exports=s},438:function(n,o,i){var s=i(828);function a(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?a.apply(null,arguments):typeof m=="function"?a.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return a(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=s(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(n,o,i){var s=i(879),a=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(h))throw new TypeError("Third argument must be a Function");if(s.node(m))return c(m,d,h);if(s.nodeList(m))return u(m,d,h);if(s.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return a(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),s=f.toString()}return s}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,s,a){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var f=this;function c(){f.off(i,c),s.apply(a,arguments)}return c._=s,this.on(i,c,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=a.length;for(f;f{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var rs=/["'&<>]/;Yo.exports=ns;function ns(e){var t=""+e,r=rs.exec(t);if(!r)return t;var n,o="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],s;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(a){s={error:a}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(s)throw s.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||a(m,d)})})}function a(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof et?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){a("next",m)}function u(m){a("throw",m)}function p(m,d){m(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function pn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Ee=="function"?Ee(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(s){return new Promise(function(a,f){s=e[i](s),o(a,f,s.done,s.value)})}}function o(i,s,a,f){Promise.resolve(f).then(function(c){i({value:c,done:a})},s)}}function C(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var It=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Ee(s),f=a.next();!f.done;f=a.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var u=this.initialTeardown;if(C(u))try{u()}catch(v){i=v instanceof It?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=Ee(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{ln(h)}catch(v){i=i!=null?i:[],v instanceof It?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new It(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ln(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Sr=Ie.EMPTY;function jt(e){return e instanceof Ie||e&&"closed"in e&&C(e.remove)&&C(e.add)&&C(e.unsubscribe)}function ln(e){C(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,s=o.isStopped,a=o.observers;return i||s?Sr:(this.currentObservers=null,a.push(r),new Ie(function(){n.currentObservers=null,Ve(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,s=n.isStopped;o?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,n){return new xn(r,n)},t}(F);var xn=function(e){ie(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Sr},t}(x);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ie(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,s=n._infiniteTimeWindow,a=n._timestampProvider,f=n._windowTime;o||(i.push(r),!s&&i.push(a.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,s=o._buffer,a=s.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var s=r.actions;n!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Wt);var Sn=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Dt);var Oe=new Sn(wn);var _=new F(function(e){return e.complete()});function Vt(e){return e&&C(e.schedule)}function Cr(e){return e[e.length-1]}function Ye(e){return C(Cr(e))?e.pop():void 0}function Te(e){return Vt(Cr(e))?e.pop():void 0}function zt(e,t){return typeof Cr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Nt(e){return C(e==null?void 0:e.then)}function qt(e){return C(e[ft])}function Kt(e){return Symbol.asyncIterator&&C(e==null?void 0:e[Symbol.asyncIterator])}function Qt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Yt=zi();function Gt(e){return C(e==null?void 0:e[Yt])}function Bt(e){return un(this,arguments,function(){var r,n,o,i;return $t(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,et(r.read())];case 3:return n=s.sent(),o=n.value,i=n.done,i?[4,et(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,et(o)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Jt(e){return C(e==null?void 0:e.getReader)}function U(e){if(e instanceof F)return e;if(e!=null){if(qt(e))return Ni(e);if(pt(e))return qi(e);if(Nt(e))return Ki(e);if(Kt(e))return On(e);if(Gt(e))return Qi(e);if(Jt(e))return Yi(e)}throw Qt(e)}function Ni(e){return new F(function(t){var r=e[ft]();if(C(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function qi(e){return new F(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?A(function(o,i){return e(o,i,n)}):de,ge(1),r?He(t):Dn(function(){return new Zt}))}}function Vn(){for(var e=[],t=0;t=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,f=a===void 0?!0:a;return function(c){var u,p,m,d=0,h=!1,v=!1,Y=function(){p==null||p.unsubscribe(),p=void 0},B=function(){Y(),u=m=void 0,h=v=!1},N=function(){var O=u;B(),O==null||O.unsubscribe()};return y(function(O,Qe){d++,!v&&!h&&Y();var De=m=m!=null?m:r();Qe.add(function(){d--,d===0&&!v&&!h&&(p=$r(N,f))}),De.subscribe(Qe),!u&&d>0&&(u=new rt({next:function($e){return De.next($e)},error:function($e){v=!0,Y(),p=$r(B,o,$e),De.error($e)},complete:function(){h=!0,Y(),p=$r(B,s),De.complete()}}),U(O).subscribe(u))})(c)}}function $r(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function z(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),V(e===_e()),J())}function Xe(e){return{x:e.offsetLeft,y:e.offsetTop}}function Kn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>Xe(e)),V(Xe(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>rr(e)),V(rr(e)))}var Yn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Wr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),va?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Wr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ba.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Gn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Jn=typeof WeakMap!="undefined"?new WeakMap:new Yn,Xn=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=ga.getInstance(),n=new La(t,r,this);Jn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Xn.prototype[e]=function(){var t;return(t=Jn.get(this))[e].apply(t,arguments)}});var Aa=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:Xn}(),Zn=Aa;var eo=new x,Ca=$(()=>k(new Zn(e=>{for(let t of e)eo.next(t)}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ye(e){return Ca.pipe(S(t=>t.observe(e)),g(t=>eo.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(()=>he(e)))),V(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var to=new x,Ra=$(()=>k(new IntersectionObserver(e=>{for(let t of e)to.next(t)},{threshold:0}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function sr(e){return Ra.pipe(S(t=>t.observe(e)),g(t=>to.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function ro(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=he(e),o=bt(e);return r>=o.height-n.height-t}),J())}var cr={drawer:z("[data-md-toggle=drawer]"),search:z("[data-md-toggle=search]")};function no(e){return cr[e].checked}function Ke(e,t){cr[e].checked!==t&&cr[e].click()}function Ue(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),V(t.checked))}function ka(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ha(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(V(!1))}function oo(){let e=b(window,"keydown").pipe(A(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:no("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),A(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!ka(n,r)}return!0}),pe());return Ha().pipe(g(t=>t?_:e))}function le(){return new URL(location.href)}function ot(e){location.href=e.href}function io(){return new x}function ao(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)ao(e,r)}function M(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)ao(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function so(){return location.hash.substring(1)}function Dr(e){let t=M("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Pa(e){return L(b(window,"hashchange"),e).pipe(l(so),V(so()),A(t=>t.length>0),X(1))}function co(e){return Pa(e).pipe(l(t=>ce(`[id="${t}"]`)),A(t=>typeof t!="undefined"))}function Vr(e){let t=matchMedia(e);return er(r=>t.addListener(()=>r(t.matches))).pipe(V(t.matches))}function fo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(V(e.matches))}function zr(e,t){return e.pipe(g(r=>r?t():_))}function ur(e,t={credentials:"same-origin"}){return ue(fetch(`${e}`,t)).pipe(fe(()=>_),g(r=>r.status!==200?Ot(()=>new Error(r.statusText)):k(r)))}function We(e,t){return ur(e,t).pipe(g(r=>r.json()),X(1))}function uo(e,t){let r=new DOMParser;return ur(e,t).pipe(g(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),X(1))}function pr(e){let t=M("script",{src:e});return $(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(g(()=>Ot(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),R(()=>document.head.removeChild(t)),ge(1))))}function po(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function lo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(po),V(po()))}function mo(){return{width:innerWidth,height:innerHeight}}function ho(){return b(window,"resize",{passive:!0}).pipe(l(mo),V(mo()))}function bo(){return G([lo(),ho()]).pipe(l(([e,t])=>({offset:e,size:t})),X(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(ee("size")),o=G([n,r]).pipe(l(()=>Xe(e)));return G([r,t,o]).pipe(l(([{height:i},{offset:s,size:a},{x:f,y:c}])=>({offset:{x:s.x-f,y:s.y-c+i},size:a})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(s=>{let a=document.createElement("script");a.src=i,a.onload=s,document.body.appendChild(a)})),Promise.resolve())}var r=class extends EventTarget{constructor(n){super(),this.url=n,this.m=i=>{i.source===this.w&&(this.dispatchEvent(new MessageEvent("message",{data:i.data})),this.onmessage&&this.onmessage(i))},this.e=(i,s,a,f,c)=>{if(s===`${this.url}`){let u=new ErrorEvent("error",{message:i,filename:s,lineno:a,colno:f,error:c});this.dispatchEvent(u),this.onerror&&this.onerror(u)}};let o=document.createElement("iframe");o.hidden=!0,document.body.appendChild(this.iframe=o),this.w.document.open(),this.w.document.write(` + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Use network namespace to separate the 5G core (5GC) and RAN simulator

+
+

Note

+

Author: Jimmy Chang
+Date: 2023/7/5

+
+

Overview

+

This technique leverages namespace to run UERANSIM, an opensource 5G-UE and RAN(gNodeB) simulator, and connect to free5GC.
+UERANSIM follows the 3GPP specification for developing and can support multiple 5G core (5GC) including free5GC.

+

Why are we using namespace? Well, you can follow ULCL and free5GC compose to set up the environment with VM and docker, but there are limitations for hardware’s capability. With network namespace, you can have different and separate network instances of network
+interfaces and routing tables that operate independently.

+

So, what is network namespace? Network namespace makes a copy of network stack with its own routing table, firewall and devices. A named network namespace is an object at /var/run/netns/. The file descriptor resulting from opening /var/run/netns/ refers to the specified network namespace. Holding that file descriptor open
+keeps the network namespace alive.

+

And how to make both namespaces communicating? A virtual Ethernet device (veth) pair provides the abstraction that can be used to create tunnels between network namespaces, and can be used to create bridge to a physical network device in another namespace. Veth pair also be used as standalone network devices.
+When the namespace freed, veth device which attatch to would be destroyed.

+

The environment is as follow. Suppose you have already installed as well as set up free5GC and UERANSIM properly.

+
    +
  • free5GC v3.3.0
  • +
  • UERANSIM v3.1.0
  • +
+
+

Note

+

Namespace free5GC represents host network namespace. And enp0s5 is an ethernet interface connectting to external.

+
+

+
Each devices as follow
+| Device        | IP             |
+| ------------- | -------------  |
+| veth0         | 10.200.200.1   |
+| veth1         | 10.200.200.2   |
+| br-veth0      | none           |
+| br-veth1      | none           |
+| enp0s5        | 10.211.55.23   |
+
+
+UE information in UERANSIM as follow. Already 
+| IMSI             | DNN           |
+| ---------------- | ------------- |
+| 208930000000003  | internet      |
+
+

Configuration file of free5GC and UERANSIM

+

free5GC

+
    +
  • free5gc/config/amfcfg.yaml
  • +
+

Replace ngapIpList IP from 127.0.0.18 to 10.200.200.2:

+

info:
+  version: 1.0.9
+  description: AMF initial local configuration
+
+configuration:
+  amfName: AMF # the name of this AMF
+  ngapIpList:  # the IP list of N2 interfaces on this AMF
+    - 10.200.200.2 # 127.0.0.18
+  ngapPort: 38412 # the SCTP port listened by NGAP
+  sbi: # Service-based interface information
+    scheme: http # the protocol for sbi (http or https)
+    registerIPv4: 127.0.0.18 # IP used to register to NRF
+    bindingIPv4: 127.0.0.18  # IP used to bind the service
+    port: 8000 # port used to bind the service
+    tls: # the local path of TLS key
+      pem: cert/amf.pem # AMF TLS Certificate
+      key: cert/amf.key # AMF TLS Private key
+  serviceNameList: # the SBI services provided by this AMF, refer to TS 29.518
+    - namf-comm # Namf_Communication service
+    - namf-evts # Namf_EventExposure service
+    - namf-mt   # Namf_MT service
+    - namf-loc  # Namf_Location service
+    - namf-oam  # OAM service
+  servedGuamiList: # Guami (Globally Unique AMF ID) list supported by this AMF
+    # <GUAMI> = <MCC><MNC><AMF ID>
+    - plmnId: # Public Land Mobile Network ID, <PLMN ID> = <MCC><MNC>
+        mcc: 208 # Mobile Country Code (3 digits string, digit: 0~9)
+        mnc: 93 # Mobile Network Code (2 or 3 digits string, digit: 0~9)
+      amfId: cafe00 # AMF identifier (3 bytes hex string, range: 000000~FFFFFF)
+  supportTaiList:  # the TAI (Tracking Area Identifier) list supported by this AMF
+    - plmnId: # Public Land Mobile Network ID, <PLMN ID> = <MCC><MNC>
+        mcc: 208 # Mobile Country Code (3 digits string, digit: 0~9)
+        mnc: 93 # Mobile Network Code (2 or 3 digits string, digit: 0~9)
+      tac: 000001 # Tracking Area Code (3 bytes hex string, range: 000000~FFFFFF)
+  plmnSupportList: # the PLMNs (Public land mobile network) list supported by this AMF
+    - plmnId: # Public Land Mobile Network ID, <PLMN ID> = <MCC><MNC>
+        mcc: 208 # Mobile Country Code (3 digits string, digit: 0~9)
+        mnc: 93 # Mobile Network Code (2 or 3 digits string, digit: 0~9)
+      snssaiList: # the S-NSSAI (Single Network Slice Selection Assistance Information) list supported by this AMF
+        - sst: 1 # Slice/Service Type (uinteger, range: 0~255)
+          sd: 010203 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)
+        - sst: 1 # Slice/Service Type (uinteger, range: 0~255)
+          sd: 112233 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)
+  supportDnnList:  # the DNN (Data Network Name) list supported by this AMF
+    - internet
+  nrfUri: http://127.0.0.10:8000 # a valid URI of NRF
+  security:  # NAS security parameters
+    integrityOrder: # the priority of integrity algorithms
+      - NIA2
+      # - NIA0
+    cipheringOrder: # the priority of ciphering algorithms
+      - NEA0
+      # - NEA2
+  networkName:  # the name of this core network
+    full: free5GC
+    short: free
+  ngapIE: # Optional NGAP IEs
+    mobilityRestrictionList: # Mobility Restriction List IE, refer to TS 38.413
+      enable: true # append this IE in related message or not
+    maskedIMEISV: # Masked IMEISV IE, refer to TS 38.413
+      enable: true # append this IE in related message or not
+    redirectionVoiceFallback: # Redirection Voice Fallback IE, refer to TS 38.413
+      enable: false # append this IE in related message or not
+  nasIE: # Optional NAS IEs
+    networkFeatureSupport5GS: # 5gs Network Feature Support IE, refer to TS 24.501
+      enable: true # append this IE in Registration accept or not
+      length: 1 # IE content length (uinteger, range: 1~3)
+      imsVoPS: 0 # IMS voice over PS session indicator (uinteger, range: 0~1)
+      emc: 0 # Emergency service support indicator for 3GPP access (uinteger, range: 0~3)
+      emf: 0 # Emergency service fallback indicator for 3GPP access (uinteger, range: 0~3)
+      iwkN26: 0 # Interworking without N26 interface indicator (uinteger, range: 0~1)
+      mpsi: 0 # MPS indicator (uinteger, range: 0~1)
+      emcN3: 0 # Emergency service support indicator for Non-3GPP access (uinteger, range: 0~1)
+      mcsi: 0 # MCS indicator (uinteger, range: 0~1)
+  t3502Value: 720  # timer value (seconds) at UE side
+  t3512Value: 3600 # timer value (seconds) at UE side
+  non3gppDeregTimerValue: 3240 # timer value (seconds) at UE side
+  # retransmission timer for paging message
+  t3513:
+    enable: true     # true or false
+    expireTime: 6s   # default is 6 seconds
+    maxRetryTimes: 4 # the max number of retransmission
+  # retransmission timer for NAS Deregistration Request message
+  t3522:
+    enable: true     # true or false
+    expireTime: 6s   # default is 6 seconds
+    maxRetryTimes: 4 # the max number of retransmission
+  # retransmission timer for NAS Registration Accept message
+  t3550:
+    enable: true     # true or false
+    expireTime: 6s   # default is 6 seconds
+    maxRetryTimes: 4 # the max number of retransmission
+  # retransmission timer for NAS Authentication Request/Security Mode Command message
+  t3560:
+    enable: true     # true or false
+    expireTime: 6s   # default is 6 seconds
+    maxRetryTimes: 4 # the max number of retransmission
+  # retransmission timer for NAS Notification message
+  t3565:
+    enable: true     # true or false
+    expireTime: 6s   # default is 6 seconds
+    maxRetryTimes: 4 # the max number of retransmission
+  # retransmission timer for NAS Identity Request message
+  t3570:
+    enable: true     # true or false
+    expireTime: 6s   # default is 6 seconds
+    maxRetryTimes: 4 # the max number of retransmission
+  locality: area1 # Name of the location where a set of AMF, SMF, PCF and UPFs are located
+  sctp: # set the sctp server setting <optinal>, once this field is set, please also add maxInputStream, maxOsStream, maxAttempts, maxInitTimeOut
+    numOstreams: 3 # the maximum out streams of each sctp connection
+    maxInstreams: 5 # the maximum in streams of each sctp connection
+    maxAttempts: 2 # the maximum attempts of each sctp connection
+    maxInitTimeout: 2 # the maximum init timeout of each sctp connection
+  defaultUECtxReq: false # the default value of UE Context Request to decide when triggering Initial Context Setup procedure
+
+logger: # log output setting
+  enable: true # true or false
+  level: info # how detailed to output, value: trace, debug, info, warn, error, fatal, panic
+  reportCaller: false # enable the caller report or not, value: true or false
+

+- free5gc/config/smfcfg.yaml

+

Replace userplaneInformation / upNodes / UPF / interfaces / endpoints from 127.0.0.8 to 10.200.200.2:

+

info:
+  version: 1.0.7
+  description: SMF initial local configuration
+
+configuration:
+  smfName: SMF # the name of this SMF
+  sbi: # Service-based interface information
+    scheme: http # the protocol for sbi (http or https)
+    registerIPv4: 127.0.0.2 # IP used to register to NRF
+    bindingIPv4: 127.0.0.2 # IP used to bind the service
+    port: 8000 # Port used to bind the service
+    tls: # the local path of TLS key
+      key: cert/smf.key # SMF TLS Certificate
+      pem: cert/smf.pem # SMF TLS Private key
+  serviceNameList: # the SBI services provided by this SMF, refer to TS 29.502
+    - nsmf-pdusession # Nsmf_PDUSession service
+    - nsmf-event-exposure # Nsmf_EventExposure service
+    - nsmf-oam # OAM service
+  snssaiInfos: # the S-NSSAI (Single Network Slice Selection Assistance Information) list supported by this AMF
+    - sNssai: # S-NSSAI (Single Network Slice Selection Assistance Information)
+        sst: 1 # Slice/Service Type (uinteger, range: 0~255)
+        sd: 010203 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)
+      dnnInfos: # DNN information list
+        - dnn: internet # Data Network Name
+          dns: # the IP address of DNS
+            ipv4: 8.8.8.8
+            ipv6: 2001:4860:4860::8888
+    - sNssai: # S-NSSAI (Single Network Slice Selection Assistance Information)
+        sst: 1 # Slice/Service Type (uinteger, range: 0~255)
+        sd: 112233 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)
+      dnnInfos: # DNN information list
+        - dnn: internet # Data Network Name
+          dns: # the IP address of DNS
+            ipv4: 8.8.8.8
+            ipv6: 2001:4860:4860::8888
+  plmnList: # the list of PLMN IDs that this SMF belongs to (optional, remove this key when unnecessary)
+    - mcc: 208 # Mobile Country Code (3 digits string, digit: 0~9)
+      mnc: 93 # Mobile Network Code (2 or 3 digits string, digit: 0~9)
+  locality: area1 # Name of the location where a set of AMF, SMF, PCF and UPFs are located
+  pfcp: # the IP address of N4 interface on this SMF (PFCP)
+    # addr config is deprecated in smf config v1.0.3, please use the following config
+    nodeID: 127.0.0.1 # the Node ID of this SMF
+    listenAddr: 127.0.0.1 # the IP/FQDN of N4 interface on this SMF (PFCP)
+    externalAddr: 127.0.0.1 # the IP/FQDN of N4 interface on this SMF (PFCP)
+  userplaneInformation: # list of userplane information
+    upNodes: # information of userplane node (AN or UPF)
+      gNB1: # the name of the node
+        type: AN # the type of the node (AN or UPF)
+      UPF: # the name of the node
+        type: UPF # the type of the node (AN or UPF)
+        nodeID: 127.0.0.8 # the Node ID of this UPF
+        addr: 127.0.0.8 # the IP/FQDN of N4 interface on this UPF (PFCP)
+        sNssaiUpfInfos: # S-NSSAI information list for this UPF
+          - sNssai: # S-NSSAI (Single Network Slice Selection Assistance Information)
+              sst: 1 # Slice/Service Type (uinteger, range: 0~255)
+              sd: 010203 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)
+            dnnUpfInfoList: # DNN information list for this S-NSSAI
+              - dnn: internet
+                pools:
+                  - cidr: 10.60.0.0/16
+                staticPools:
+                  - cidr: 10.60.100.0/24
+          - sNssai: # S-NSSAI (Single Network Slice Selection Assistance Information)
+              sst: 1 # Slice/Service Type (uinteger, range: 0~255)
+              sd: 112233 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)
+            dnnUpfInfoList: # DNN information list for this S-NSSAI
+              - dnn: internet
+                pools:
+                  - cidr: 10.61.0.0/16
+                staticPools:
+                  - cidr: 10.61.100.0/24
+        interfaces: # Interface list for this UPF
+          - interfaceType: N3 # the type of the interface (N3 or N9)
+            endpoints: # the IP address of this N3/N9 interface on this UPF
+              - 10.200.200.2 # 127.0.0.8
+            networkInstances:  # Data Network Name (DNN)
+              - internet
+    links: # the topology graph of userplane, A and B represent the two nodes of each link
+      - A: gNB1
+        B: UPF
+  # retransmission timer for pdu session modification command
+  t3591:
+    enable: true     # true or false
+    expireTime: 16s   # default is 6 seconds
+    maxRetryTimes: 3 # the max number of retransmission
+  # retransmission timer for pdu session release command
+  t3592:
+    enable: true     # true or false
+    expireTime: 16s   # default is 6 seconds
+    maxRetryTimes: 3 # the max number of retransmission
+  nrfUri: http://127.0.0.10:8000 # a valid URI of NRF
+  #urrPeriod: 10 # default usage report period in seconds
+  #urrThreshold: 1000 # default usage report threshold in bytes
+
+logger: # log output setting
+  enable: true # true or false
+  level: info # how detailed to output, value: trace, debug, info, warn, error, fatal, panic
+  reportCaller: false # enable the caller report or not, value: true or false
+

+- free5gc/config/upfcfg.yaml

+

Replace gtpu from 127.0.0.8to 10.200.200.2:

+
version: 1.0.3
+description: UPF initial local configuration
+
+# The listen IP and nodeID of the N4 interface on this UPF (Can't set to 0.0.0.0)
+pfcp:
+  addr: 127.0.0.8   # IP addr for listening
+  nodeID: 127.0.0.8 # External IP or FQDN can be reached
+  retransTimeout: 1s # retransmission timeout
+  maxRetrans: 3 # the max number of retransmission
+
+gtpu:
+  forwarder: gtp5g
+  # The IP list of the N3/N9 interfaces on this UPF
+  # If there are multiple connection, set addr to 0.0.0.0 or list all the addresses
+  ifList:
+    - addr: 10.200.200.2 # 127.0.0.8
+      type: N3
+      # name: upf.5gc.nctu.me
+      # ifname: gtpif
+      # mtu: 1400
+
+# The DNN list supported by UPF
+dnnList:
+  - dnn: internet # Data Network Name
+    cidr: 10.60.0.0/24 # Classless Inter-Domain Routing for assigned IPv4 pool of UE
+    # natifname: eth0
+
+logger: # log output setting
+  enable: true # true or false
+  level: info # how detailed to output, value: trace, debug, info, warn, error, fatal, panic
+  reportCaller: false # enable the caller report or not, value: true or false
+
+

UERANSIM

+
    +
  • +

    UERANSIM/config/free5gc-gnb.yaml

    +
  • +
  • +

    Replace ngapIp from 127.0.0.1to 10.200.200.1

    +
  • +
  • +

    Replace gtpIp from 127.0.0.1to 10.200.200.1

    +
  • +
  • +

    Replace amfConfigs / address from 127.0.0.1to 10.200.200.2

    +
  • +
+

mcc: '208'          # Mobile Country Code value
+mnc: '93'           # Mobile Network Code value (2 or 3 digits)
+
+nci: '0x000000010'  # NR Cell Identity (36-bit)
+idLength: 32        # NR gNB ID length in bits [22...32]
+tac: 1              # Tracking Area Code
+
+linkIp: 127.0.0.1   # gNB's local IP address for Radio Link Simulation (Usually same with local IP)
+ngapIp: 10.200.200.1 # 127.0.0.1   # gNB's local IP address for N2 Interface (Usually same with local IP)
+gtpIp: 10.200.200.1 # 127.0.0.1    # gNB's local IP address for N3 Interface (Usually same with local IP)
+
+# List of AMF address information
+amfConfigs:
+  - address: 10.200.200.2 # 127.0.0.1
+    port: 38412
+
+# List of supported S-NSSAIs by this gNB
+slices:
+  - sst: 0x1
+    sd: 0x010203
+
+# Indicates whether or not SCTP stream number errors should be ignored.
+ignoreStreamIds: true
+

+- UERANSIM/config/free5gc-ue.yaml
+
# IMSI number of the UE. IMSI = [MCC|MNC|MSISDN] (In total 15 or 16 digits)
+supi: 'imsi-208930000000003'
+# Mobile Country Code value
+mcc: '208'
+# Mobile Network Code value (2 or 3 digits)
+mnc: '93'
+
+# Permanent subscription key
+key: '8baf473f2f8fd09487cccbd7097c6862'
+# Operator code (OP or OPC) of the UE
+op: '8e27b6af0e692e750f32667a3b14605d'
+# This value specifies the OP type and it can be either 'OP' or 'OPC'
+opType: 'OP'
+# Authentication Management Field (AMF) value
+amf: '8000'
+# IMEI number of the device. It is used if no SUPI is provided
+imei: '356938035643803'
+# IMEISV number of the device. It is used if no SUPI and IMEI is provided
+imeiSv: '4370816125816151'
+
+# List of gNB IP addresses for Radio Link Simulation
+gnbSearchList:
+  - 127.0.0.1
+
+# Initial PDU sessions to be established
+sessions:
+  - type: 'IPv4'
+    apn: 'internet'
+    slice:
+      sst: 0x01
+      sd: 0x010203
+
+# List of requested S-NSSAIs by this UE
+slices:
+  - sst: 0x01
+    sd: 0x010203
+
+# Supported encryption and integrity algorithms by this UE
+integrity:
+  IA1: true
+  IA2: true
+  IA3: true
+ciphering:
+  EA1: true
+  EA2: true
+  EA3: true
+

+

Environment set up of free5GC and UERANSIM

+

First, create a namespace:

+
+

Note

+

Assume that you are either running as root, or it behoves you to prepend sudo to commands as necessary.

+
+

ip netns add ueransim
+

+Next, add the bridge:
+
ip link add free5gc-br type bridge
+

+Add two pairs of veth:
+
ip link add veth0 type veth peer name br-veth0
+ip link add veth1 type veth peer name br-veth1
+

+Now, it could be like:
+
root@free5gc:~# ip a
+1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
+    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
+    inet 127.0.0.1/8 scope host lo
+       valid_lft forever preferred_lft forever
+    inet6 ::1/128 scope host
+       valid_lft forever preferred_lft forever
+2: enp0s5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
+    link/ether 00:1c:42:b1:ba:f4 brd ff:ff:ff:ff:ff:ff
+    inet 10.211.55.23/24 brd 10.211.55.255 scope global dynamic enp0s5
+       valid_lft 1714sec preferred_lft 1714sec
+    inet6 fdb2:2c26:f4e4:0:21c:42ff:feb1:baf4/64 scope global dynamic mngtmpaddr noprefixroute
+       valid_lft 2591750sec preferred_lft 604550sec
+    inet6 fe80::21c:42ff:feb1:baf4/64 scope link
+       valid_lft forever preferred_lft forever
+3: enp0s6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
+    link/ether 00:1c:42:f1:11:c6 brd ff:ff:ff:ff:ff:ff
+    inet 10.37.129.20/24 brd 10.37.129.255 scope global enp0s6
+       valid_lft forever preferred_lft forever
+    inet6 fdb2:2c26:f4e4:1:21c:42ff:fef1:11c6/64 scope global dynamic mngtmpaddr noprefixroute
+       valid_lft 2591750sec preferred_lft 604550sec
+    inet6 fe80::21c:42ff:fef1:11c6/64 scope link
+       valid_lft forever preferred_lft forever
+4: free5gc-br: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
+    link/ether 4e:f6:d7:9c:50:de brd ff:ff:ff:ff:ff:ff
+5: br-veth0@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
+    link/ether c2:31:0c:5f:45:81 brd ff:ff:ff:ff:ff:ff
+6: veth0@br-veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
+    link/ether 4a:0f:1e:80:9b:be brd ff:ff:ff:ff:ff:ff
+7: br-veth1@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
+    link/ether 56:99:b0:82:78:0d brd ff:ff:ff:ff:ff:ff
+8: veth1@br-veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
+    link/ether 12:5a:56:00:5b:be brd ff:ff:ff:ff:ff:ff
+

+

Next, assign interface to namespace:
+

ip link set dev veth0 netns ueransim
+

+Set ip address:
+
ip netns exec ueransim ip a add 10.200.200.1/24 dev veth0
+

+Enable both interface. Don't forget lo:
+
ip netns exec ueransim ip link set lo up
+ip netns exec ueransim ip link set veth0 up
+

+Check with ip a:
+
root@free5gc:~# ip netns exec ueransim ip a
+1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
+    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
+    inet 127.0.0.1/8 scope host lo
+       valid_lft forever preferred_lft forever
+    inet6 ::1/128 scope host
+       valid_lft forever preferred_lft forever
+6: veth0@if5: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN group default qlen 1000
+    link/ether 4a:0f:1e:80:9b:be brd ff:ff:ff:ff:ff:ff link-netnsid 0
+    inet 10.200.200.1/24 scope global veth0
+       valid_lft forever preferred_lft forever
+

+Set for veth1 as well:
+
ip a add 10.200.200.2/24 dev veth1
+ip link set veth1 up
+

+Let two interfaces attatch to bridge:
+
ip link set dev br-veth0 master free5gc-br
+ip link set dev br-veth1 master free5gc-br
+ip link set br-veth0 up
+ip link set br-veth1 up
+ip link set free5gc-br up
+

+Using bridge link to check:
+
root@free5gc:~# bridge link
+5: br-veth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master free5gc-br state forwarding priority 32 cost 2
+7: br-veth1@veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master free5gc-br state forwarding priority 32 cost 2
+

+Now it looks like:
+
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
+    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
+    inet 127.0.0.1/8 scope host lo
+       valid_lft forever preferred_lft forever
+    inet6 ::1/128 scope host
+       valid_lft forever preferred_lft forever
+2: enp0s5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
+    link/ether 00:1c:42:b1:ba:f4 brd ff:ff:ff:ff:ff:ff
+    inet 10.211.55.23/24 brd 10.211.55.255 scope global dynamic enp0s5
+       valid_lft 1000sec preferred_lft 1000sec
+    inet6 fdb2:2c26:f4e4:0:21c:42ff:feb1:baf4/64 scope global dynamic mngtmpaddr noprefixroute
+       valid_lft 2591870sec preferred_lft 604670sec
+    inet6 fe80::21c:42ff:feb1:baf4/64 scope link
+       valid_lft forever preferred_lft forever
+3: enp0s6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
+    link/ether 00:1c:42:f1:11:c6 brd ff:ff:ff:ff:ff:ff
+    inet 10.37.129.20/24 brd 10.37.129.255 scope global enp0s6
+       valid_lft forever preferred_lft forever
+    inet6 fdb2:2c26:f4e4:1:21c:42ff:fef1:11c6/64 scope global dynamic mngtmpaddr noprefixroute
+       valid_lft 2591870sec preferred_lft 604670sec
+    inet6 fe80::21c:42ff:fef1:11c6/64 scope link
+       valid_lft forever preferred_lft forever
+4: free5gc-br: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
+    link/ether 56:99:b0:82:78:0d brd ff:ff:ff:ff:ff:ff
+    inet6 fe80::5499:b0ff:fe82:780d/64 scope link
+       valid_lft forever preferred_lft forever
+5: br-veth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master free5gc-br state UP group default qlen 1000
+    link/ether c2:31:0c:5f:45:81 brd ff:ff:ff:ff:ff:ff link-netns ueransim
+    inet6 fe80::c031:cff:fe5f:4581/64 scope link
+       valid_lft forever preferred_lft forever
+7: br-veth1@veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master free5gc-br state UP group default qlen 1000
+    link/ether 56:99:b0:82:78:0d brd ff:ff:ff:ff:ff:ff
+    inet6 fe80::5499:b0ff:fe82:780d/64 scope link
+       valid_lft forever preferred_lft forever
+8: veth1@br-veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
+    link/ether 12:5a:56:00:5b:be brd ff:ff:ff:ff:ff:ff
+    inet 10.200.200.2/24 scope global veth1
+       valid_lft forever preferred_lft forever
+    inet6 fe80::105a:56ff:fe00:5bbe/64 scope link
+       valid_lft forever preferred_lft forever
+

+Let's test it:

+
+

Note

+

You can perform ip netns exec ueransim /bin/bash --rcfile <(echo "PS1=\"ueransim> \"") to enter namespace and modify shell prefix.

+
+

root@free5gc:~# ip netns exec ueransim /bin/bash --rcfile <(echo "PS1=\"ueransim> \"")
+ueransim> ping -c2 10.200.200.2
+PING 10.200.200.2 (10.200.200.2) 56(84) bytes of data.
+64 bytes from 10.200.200.2: icmp_seq=1 ttl=64 time=0.089 ms
+64 bytes from 10.200.200.2: icmp_seq=2 ttl=64 time=0.226 ms
+
+--- 10.200.200.2 ping statistics ---
+2 packets transmitted, 2 received, 0% packet loss, time 1020ms
+rtt min/avg/max/mdev = 0.089/0.157/0.226/0.068 ms
+

+Insert default routing rule:
+
ueransim> ip route add default via 10.200.200.2
+ueransim> netstat -rn
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
+0.0.0.0         10.200.200.2    0.0.0.0         UG        0 0          0 veth0
+10.200.200.0    0.0.0.0         255.255.255.0   U         0 0          0 veth0
+

+Try to ping 8.8.8.8:
+
ueransim> ping -c2 8.8.8.8
+PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
+
+--- 8.8.8.8 ping statistics ---
+2 packets transmitted, 0 received, 100% packet loss, time 1028ms
+

+It is because the main host must translate the source addresses. Besides, the main host need to forward packet:
+
root@free5gc:~# iptables -t nat -A POSTROUTING -o enp0s5 -j MASQUERADE
+root@free5gc:~# sysctl -w net.ipv4.ip_forward=1
+root@free5gc:~# sudo iptables -I FORWARD 1 -j ACCEPT
+

+And then:
+
ueransim> ping -c2 8.8.8.8
+PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
+64 bytes from 8.8.8.8: icmp_seq=1 ttl=127 time=13.9 ms
+64 bytes from 8.8.8.8: icmp_seq=2 ttl=127 time=28.0 ms
+
+--- 8.8.8.8 ping statistics ---
+2 packets transmitted, 2 received, 0% packet loss, time 1002ms
+rtt min/avg/max/mdev = 13.866/20.939/28.012/7.073 ms
+

+

After free5GC execute run.sh, it's time for UERANSIM:

+

In terminal 1:
+

ueransim> build/nr-gnb -c config/free5gc-gnb.yaml
+UERANSIM v3.1.0
+[2023-07-05 19:58:26.368] [sctp] [info] Trying to establish SCTP connection... (10.200.200.2:38412)
+[2023-07-05 19:58:26.373] [sctp] [info] SCTP connection established (10.200.200.2:38412)
+[2023-07-05 19:58:26.374] [sctp] [debug] SCTP association setup ascId[3]
+[2023-07-05 19:58:26.375] [ngap] [debug] Sending NG Setup Request
+[2023-07-05 19:58:26.380] [ngap] [debug] NG Setup Response received
+[2023-07-05 19:58:26.380] [ngap] [info] NG Setup procedure is successful
+[2023-07-05 19:58:35.804] [mr] [info] New UE connected to gNB. Total number of UEs is now: 1
+[2023-07-05 19:58:35.806] [rrc] [debug] Sending RRC Setup for UE[3]
+[2023-07-05 19:58:35.807] [ngap] [debug] Initial NAS message received from UE 3
+[2023-07-05 19:58:35.869] [ngap] [debug] Initial Context Setup Request received
+[2023-07-05 19:58:36.108] [ngap] [info] PDU session resource is established for UE[3] count[1]
+

+In terminal 2:
+
ueransim> sudo build/nr-ue -c config/free5gc-ue.yaml
+UERANSIM v3.1.0
+[2023-07-05 19:58:35.803] [nas] [debug] NAS layer started
+[2023-07-05 19:58:35.803] [rrc] [debug] RRC layer started
+[2023-07-05 19:58:35.804] [nas] [info] UE switches to state: MM-DEREGISTERED/PLMN-SEARCH
+[2023-07-05 19:58:35.804] [nas] [info] UE connected to gNB
+[2023-07-05 19:58:35.804] [nas] [info] UE switches to state: MM-DEREGISTERED/NORMAL-SERVICE
+[2023-07-05 19:58:35.804] [nas] [info] UE switches to state: MM-REGISTERED-INITIATED/NA
+[2023-07-05 19:58:35.805] [rrc] [debug] Sending RRC Setup Request
+[2023-07-05 19:58:35.806] [rrc] [info] RRC connection established
+[2023-07-05 19:58:35.806] [nas] [info] UE switches to state: CM-CONNECTED
+[2023-07-05 19:58:35.838] [nas] [debug] Received rand[61262F32A617D0BAD716603B1CBDA477] autn[44778026F4238000FC14B59D68855328]
+[2023-07-05 19:58:35.838] [nas] [debug] Calculated res[47759045F5ACEA59] ck[1C559301F29EF49572F5D150B3B99288] ik[D223317F752F233CE4C7AA253644D882] ak[528433D1FBE6] mac_a[FC14B59D68855328]
+[2023-07-05 19:58:35.838] [nas] [debug] Used snn[5G:mnc093.mcc208.3gppnetwork.org] sqn[16F3B3F70FC5]
+[2023-07-05 19:58:35.838] [nas] [debug] Derived kSeaf[7FC8B7FB1B141B6579B9C0FAEB9CCF1312FE9F9634868E234756DE49FD67C5F1] kAusf[FA0402A892E6046D52F4DECACA40B2A75B698FCEAD5EB320139FC69B77BD4C46] kAmf[3D4AD68E153B9642ACBECC67AD399015F7CB578F9DF4C88A35EED99C72C9B95B]
+[2023-07-05 19:58:35.843] [nas] [debug] Derived kNasEnc[1F829EB2BA238DD0226C3484E6A79D1F] kNasInt[251C0412B1BAD88A9DD0008F32D6F216]
+[2023-07-05 19:58:35.843] [nas] [debug] Selected integrity[2] ciphering[0]
+[2023-07-05 19:58:35.869] [nas] [debug] T3512 started with int[3600]
+[2023-07-05 19:58:35.869] [nas] [info] UE switches to state: MM-REGISTERED/NORMAL-SERVICE
+[2023-07-05 19:58:35.869] [nas] [info] Initial Registration is successful
+[2023-07-05 19:58:35.869] [nas] [info] Initial PDU sessions are establishing [1#]
+[2023-07-05 19:58:35.869] [nas] [debug] Sending PDU session establishment request
+[2023-07-05 19:58:36.108] [nas] [info] PDU Session establishment is successful PSI[1]
+[2023-07-05 19:58:36.113] [app] [info] Connection setup for PDU session[1] is successful, TUN interface[uesimtun0, 10.60.0.1] is up.
+

+In terminal 3:
+
ueransim> ip a
+1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
+    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
+    inet 127.0.0.1/8 scope host lo
+       valid_lft forever preferred_lft forever
+    inet6 ::1/128 scope host
+       valid_lft forever preferred_lft forever
+2: uesimtun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
+    link/none
+    inet 10.60.0.1/32 scope global uesimtun0
+       valid_lft forever preferred_lft forever
+    inet6 fe80::b5ef:5b4:e3f6:af64/64 scope link stable-privacy
+       valid_lft forever preferred_lft forever
+6: veth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
+    link/ether 4a:0f:1e:80:9b:be brd ff:ff:ff:ff:ff:ff link-netnsid 0
+    inet 10.200.200.1/24 scope global veth0
+       valid_lft forever preferred_lft forever
+    inet6 fe80::480f:1eff:fe80:9bbe/64 scope link
+       valid_lft forever preferred_lft forever
+ueransim> ping -c2 -I uesimtun0 8.8.8.8
+PING 8.8.8.8 (8.8.8.8) from 10.60.0.1 uesimtun0: 56(84) bytes of data.
+64 bytes from 8.8.8.8: icmp_seq=1 ttl=127 time=19.5 ms
+64 bytes from 8.8.8.8: icmp_seq=2 ttl=127 time=33.2 ms
+
+--- 8.8.8.8 ping statistics ---
+2 packets transmitted, 2 received, 0% packet loss, time 1006ms
+rtt min/avg/max/mdev = 19.478/26.348/33.219/6.870 ms
+

+Also ping to google.com:
+
ueransim> ping -c2 -I uesimtun0 google.com
+PING google.com (172.217.160.110) from 10.60.0.1 uesimtun0: 56(84) bytes of data.
+64 bytes from tsa03s06-in-f14.1e100.net (172.217.160.110): icmp_seq=1 ttl=127 time=17.3 ms
+64 bytes from tsa03s06-in-f14.1e100.net (172.217.160.110): icmp_seq=2 ttl=127 time=29.5 ms
+
+--- google.com ping statistics ---
+2 packets transmitted, 2 received, 0% packet loss, time 1005ms
+rtt min/avg/max/mdev = 17.295/23.385/29.476/6.090 ms
+

+

What if two UERANSIMs with two namespaces?

+

+

Same as before, you should create another namespace for UERANSIM, called it ueransim2:
+

root@free5gc:~# ip netns ls
+ueransim2 (id: 1)
+ueransim (id: 0)
+

+And then:
+
ip link add veth2 type veth peer name br-veth2
+ip link set dev veth2 netns ueransim2
+ip link set br-veth2 master free5gc-br
+ip link set br-veth2 up
+ip netns exec ueransim2 ip a add 10.200.200.3/24 dev veth2
+ip netns exec ueransim2 ip link set lo up
+ip netns exec ueransim2 ip link set veth2 up
+ip netns exec ueransim2 ip route add default via 10.200.200.2
+

+

Copy UERANSIM/config/free5gc-gnb.yaml and UERANSIM/config/free5gc-ue.yaml to free5gc-gnb2.yaml and free5gc-ue2.yaml, modify:

+

free5gc-gnb2.yaml

+
    +
  • Replace ngapIp from 127.0.0.1 to 10.200.200.3
  • +
  • Replace gtpIp from 127.0.0.1 to 10.200.200.3
  • +
+

...
+ngapIp: 10.200.200.3 # 127.0.0.1   # gNB's local IP address for N2 Interface (Usually same with local IP)
+gtpIp: 10.200.200.3 # 127.0.0.1    # gNB's local IP address for N3 Interface (Usually same with local IP)
+
+# List of AMF address information
+amfConfigs:
+  - address: 10.200.200.2 # 127.0.0.1
+    port: 38412
+...
+

+free5gc-ue2.yaml

+

supi change to imsi-208930000000004

+
...
+# IMSI number of the UE. IMSI = [MCC|MNC|MSISDN] (In total 15 or 16 digits)
+supi: 'imsi-208930000000004'
+...
+
+
+

Note

+

Should register ue to webconsole first.

+
+

The result:
+

ueransim> ip a
+1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
+    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
+    inet 127.0.0.1/8 scope host lo
+       valid_lft forever preferred_lft forever
+    inet6 ::1/128 scope host
+       valid_lft forever preferred_lft forever
+6: veth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
+    link/ether 4a:0f:1e:80:9b:be brd ff:ff:ff:ff:ff:ff link-netnsid 0
+    inet 10.200.200.1/24 scope global veth0
+       valid_lft forever preferred_lft forever
+    inet6 fe80::480f:1eff:fe80:9bbe/64 scope link
+       valid_lft forever preferred_lft forever
+7: uesimtun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
+    link/none
+    inet 10.60.0.1/32 scope global uesimtun0
+       valid_lft forever preferred_lft forever
+    inet6 fe80::f6d7:dd81:fe7f:496a/64 scope link stable-privacy
+       valid_lft forever preferred_lft forever
+ueransim> ping -c2 -I uesimtun0 google.com
+PING google.com (172.217.160.110) from 10.60.0.1 uesimtun0: 56(84) bytes of data.
+64 bytes from tsa03s06-in-f14.1e100.net (172.217.160.110): icmp_seq=1 ttl=127 time=17.2 ms
+64 bytes from tsa03s06-in-f14.1e100.net (172.217.160.110): icmp_seq=2 ttl=127 time=28.5 ms
+
+--- google.com ping statistics ---
+2 packets transmitted, 2 received, 0% packet loss, time 1003ms
+rtt min/avg/max/mdev = 17.200/22.863/28.527/5.663 ms
+

+
ueransim2> ip a
+1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
+    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
+    inet 127.0.0.1/8 scope host lo
+       valid_lft forever preferred_lft forever
+    inet6 ::1/128 scope host 
+       valid_lft forever preferred_lft forever
+5: uesimtun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
+    link/none 
+    inet 10.60.0.2/32 scope global uesimtun0
+       valid_lft forever preferred_lft forever
+    inet6 fe80::16a4:523a:a86:bf83/64 scope link stable-privacy 
+       valid_lft forever preferred_lft forever
+12: veth2@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
+    link/ether fa:12:bb:9c:fa:40 brd ff:ff:ff:ff:ff:ff link-netnsid 0
+    inet 10.200.200.3/24 scope global veth2
+       valid_lft forever preferred_lft forever
+    inet6 fe80::f812:bbff:fe9c:fa40/64 scope link 
+       valid_lft forever preferred_lft forever
+ueransim2> ping -c2 -I uesimtun0 google.com
+PING google.com (172.217.160.110) from 10.60.0.2 uesimtun0: 56(84) bytes of data.
+64 bytes from tsa03s06-in-f14.1e100.net (172.217.160.110): icmp_seq=1 ttl=127 time=18.9 ms
+64 bytes from tsa03s06-in-f14.1e100.net (172.217.160.110): icmp_seq=2 ttl=127 time=15.8 ms
+
+--- google.com ping statistics ---
+2 packets transmitted, 2 received, 0% packet loss, time 1002ms
+rtt min/avg/max/mdev = 15.786/17.353/18.921/1.567 ms
+
+

About

+

Hi, my name is Jimmy Chang. The current research topic is 5G LAN with a focus on the 5G Data Plane. Any questions or errors in the article are welcome for correction. Please feel free to send an email to provide feedback.

+
    +
  • Graduate student major in 5GC Research
  • +
  • LinkedIn
  • +
+

Reference

+
    +
  • https://github.com/s5uishida/free5gc_ueransim_ulcl_sample_config
  • +
  • https://github.com/free5gc/free5gc/blob/main/test_ulcl.sh
  • +
  • https://blog.scottlowe.org/2013/09/04/introducing-linux-network-namespaces/
  • +
  • https://man7.org/linux/man-pages/man7/namespaces.7.html
  • +
  • https://linux.die.net/man/8/iptables
  • +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/blog/20230802/20230802figure1.png b/blog/20230802/20230802figure1.png new file mode 100644 index 00000000..ed460590 Binary files /dev/null and b/blog/20230802/20230802figure1.png differ diff --git a/blog/20230802/20230802figure2.png b/blog/20230802/20230802figure2.png new file mode 100644 index 00000000..13382fff Binary files /dev/null and b/blog/20230802/20230802figure2.png differ diff --git a/blog/20230802/20230802figure3.png b/blog/20230802/20230802figure3.png new file mode 100644 index 00000000..674347c5 Binary files /dev/null and b/blog/20230802/20230802figure3.png differ diff --git a/blog/20230802/20230802figure4.png b/blog/20230802/20230802figure4.png new file mode 100644 index 00000000..35ae2096 Binary files /dev/null and b/blog/20230802/20230802figure4.png differ diff --git a/blog/20230802/20230802table1.png b/blog/20230802/20230802table1.png new file mode 100644 index 00000000..60d0681f Binary files /dev/null and b/blog/20230802/20230802table1.png differ diff --git a/blog/20230802/20230802table2.png b/blog/20230802/20230802table2.png new file mode 100644 index 00000000..20c33c7e Binary files /dev/null and b/blog/20230802/20230802table2.png differ diff --git a/blog/20230802/20230802table3.png b/blog/20230802/20230802table3.png new file mode 100644 index 00000000..1ce9d74f Binary files /dev/null and b/blog/20230802/20230802table3.png differ diff --git a/blog/20230802/20230802table4.png b/blog/20230802/20230802table4.png new file mode 100644 index 00000000..40120cd3 Binary files /dev/null and b/blog/20230802/20230802table4.png differ diff --git a/blog/20230802/index.html b/blog/20230802/index.html new file mode 100644 index 00000000..77faf895 --- /dev/null +++ b/blog/20230802/index.html @@ -0,0 +1,956 @@ + + + + + + + + + + + + + + + + + + Authentication Mechanism in NRF: What Is OAuth? - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +

Authentication Mechanism in NRF: What Is OAuth?

+
+

Note

+

Author: Wilson
+Date: 2023/8/2

+
+

Abstract

+

Regarding the theme this time, I will briefly introduce OAuth. OAuth 2.0 defines four types of authorization flows. I choose the Client Credentials Flow to explain because the authentication mechanism in NRF is closely related to the Client Credentials Flow.

+

Next, I will explain how to apply the concept of the Client Credentials Flow to NRF and introduce Nnrf_AccessToken Service, because Nnrf_AccessToken Service is closely related to the Client Credentials Flow.

+

Finally, I will make a simple experiment of the authentication mechanism in NRF and share the environment settings and methods of operation.

+

OAuth

+

Before explaining the authentication mechanism in NRF, I will introduce OAuth. Regarding the OAuth flow, we can log in to the account through the platform before accessing an application. After logging in, we agree that an application can limitedly obtain the information of the user on the platform. The application can be LinkedIn, YouTube, etc. The platform can be Google, Facebook, etc.

+

The full English name of OAuth is Open standard Authorization. OAuth is an open standard, and it's used to deal with authorization-related behaviors. OAuth 2.0 defines four types of authorization flows. The four types of the authorization flows are:

+
    +
  • Authorization Code
  • +
  • Implicit
  • +
  • Resource Owner Password Credentials
  • +
  • Client Credentials
  • +
+

This article explains the entire authorization of the Client Credentials Flow only, because the authentication mechanism in NRF adopts the Client Credentials.

+
+

If you're interested in how authorization mechanism works, please refer to this article for more details.

+
+

Client Credentials Flow

+


+
Figure 1. Client Credentials Flow

+

Referring to the Figure 1, the Client Credentials Flow is mainly composed of:

+
    +
  • Client
  • +
  • Authorization Server
  • +
  • Resource Server
  • +
+

The entire authorization of the Client Credentials Flow can be devided into 3 steps:

+
    +
  • First, the Client provdies Client ID, Client Secret Token, Scope, and Grant Type to the Authorization Server.
  • +
  • Second, the Authorization Server verifies the information provided by the Client. After the Authorization Server verifies the information, it signs with the private key and sends the Access Token to the Client.
  • +
  • Third, the Client obtains resources from the Resource Server with the Access Token.
  • +
+

In addition, the Client and the Authorization Server have their own Scope list. The Scope list records a series of the actions. The Client or the Authorization Server is permitted to do the actions for obtaining the user’s name, deleting posts, etc.

+

Below I will explain how to apply the Client Credentials Flow to NRF after talking about the Client Credentials Flow.

+

Client Credentials Flow in NRF

+

The Figure 2 and the Figure 3 originate from the Figure 13.4.1.1-1 and the Figure 13.4.1.1-2 of the TS 33.501.

+


+
Figure 2. NF Service Consumer Obtaining Access Token before NF Service Access

+

The entire flow in Figure 2 is the same as Step 1 and Step 2 in the Figure 1. The role of the Client is played by the NF Service Consumer, and the role of the Authorization Server is played by the NRF.

+

First, the NF Service Consumer registers with NRF. Then the NF Service Consumer sends the Nnrf_AccessToken_Get Request to NRF. The Nnrf_AccessToken_Get Request includes:

+
    +
  • Consumer NF Type
  • +
  • Expected NF Type
  • +
  • Expected NF Service Name
  • +
  • Client ID
  • +
+

The NF Type can be AMF, SMF, etc. , and the NF Service Name can be namf-comm, nsmf-pdusession, etc.

+

NRF verifies the information provided by the NF Service Consumer after it receives the Nnrf_AccessToken_Get Request. NRF generates an Access Token and uses the NRF private key to sign on the Access Token after the verification is successful.

+

Finally, NRF returns the Nnrf_AccessToken_Get Response to the NF Service Consumer. The NF Service Consumer stores the Access Token within the validity period after it gets the Access Token. The services provided by the NF Service Producer are in the Expected NF Service Name. The NF Service Consumer doesn’t need to verify again when it wants to use the services provided by the NF Service Producer.

+


+
Figure 3. NF Service Consumer Requesting Service Access with an Access Token

+

The entire flow in Figure 3 is the same as Step 3 in the Figure 1. The role of the Client is played by the NF Service Consumer, and the role of the Resource Server is played by the NF Service Producer.

+

First, the NF Service Consumer sends the NF Service Request to the NF Service Producer with the Access Token. Simply put, the NF Service Consumer wants to consume the service provided by the NF Service Producer.

+

The NF Service Producer uses the NRF public key to verify the signed Access Token after it receives the NF Service Request. If the verification is successful, the NF Service Producer will send the NF Service Response to the NF Service Consumer.

+

Now I will talk about the Nnrf_AccessToken Service after explaining how to apply the Client Credentials Flow to NRF.

+

Nnrf_AccessToken Service

+


+
Figure 4. Access Token Request

+

The Figure 4 originates from the Figure 5.4.2.2.1-1 of the TS 29.510.

+

First, the NF Service Consumer sends the POST /oauth2/token to NRF, and the data is stored in the AccessTokenReq. The attribute name, the data type, and the formulation rule of the AccessTokenReq are shown in the Table 1. The Table 1 originates from the Table 6.3.5.2.2-1 of the TS 29.510.

+


+
Table 1. Definition of Type AccessTokenReq

+

Definition of type AccessTokenReq:

+
    +
  • grant_type: The value must be set to the client_credentials, and it is checked in the Snippet 1.
  • +
  • nfInstanceId: The value stores the ID of the NF Service Consumer.
  • +
  • targetNfInstanceId: The value stores the ID of the NF Service Producer.
  • +
  • nfType: The value stores the network function name of the NF Service Consumer. The network function name can be the AMF, SMF, etc.
  • +
  • targetNfType: The value stores the network function name of the NF Service Producer.
  • +
  • scope: It stores the services. The services can be the namf-comm, nsmf-pdusession, etc. When the NF Service Consumer requests the services. The services will be provided by the NF Service Producer.
  • +
  • requesterPlmn: It is mainly used in the roaming.
  • +
  • targetPlmn: It is mainly used in the roaming.
  • +
+

if reqGrantType != "client_credentials" {
+    return &models.AccessTokenErr{
+        Error: "unsupported_grant_type",
+    }
+}
+

+Snippet 1. Grant Type Value Checking

+

NRF sends AccessTokenRsp to the NF Service Consumer in the Step 2a of the Figure 4. The attribute name, the data type, and the formulation rule of the AccessTokenRsp are shown in the Table 2. The Table 2 originates from the Table 6.3.5.2.3-1 of the TS 29.510.

+


+
Table 2. Definition of Type AccessTokenRsp

+

The AccessTokenRsp contains four attribute names. The four attribute names are:

+
    +
  • access_token: It stores all the attribute names and values of the AccessTokenClaims in the Table 3. The Table 3 originates form the Table 6.3.5.2.4-1 of the TS 29.510.
  • +
  • token_type: It must be set to the Bearer and can be seen in the Snippet 2.
  • +
  • expires_in: It stores information related to the expiration date.
  • +
  • scope: The NF Service Consumer and the NF Service Producer have their own scope list. The scope in the AccessTokenRsp has a series of these services, and the NF Service Producer is permitted to consume these services.
  • +
+


+
Table 3. Definition of Type AccessTokenClaims

+

Definition of Type AccessTokenClaims:

+
    +
  • iss: It is called issuer, and the content usually stores the ID of NRF.
  • +
  • sub: It is called subject, and the content stores the ID of the NF Service Consumer.
  • +
  • aud: It is called audience, and the content stores the ID of the NF Service Producer.
  • +
  • scope: The scope in the AccessTokenClaims has a series of these services, and the NF Service Consumer is authorized by the NF Service Producer and permitted to consume these services.
  • +
  • exp: It stores information related to the validity period.
  • +
+

func AccessTokenProcedure(request models.AccessTokenReq) (
+    *models.AccessTokenRsp, *models.AccessTokenErr,
+) {
+    logger.AccTokenLog.Infoln("In AccessTokenProcedure")
+
+    var expiration int32 = 1000
+    scope := request.Scope
+    tokenType := "Bearer"
+    now := int32(time.Now().Unix())
+
+    errResponse := AccessTokenScopeCheck(request)
+    if errResponse != nil {
+        return nil, errResponse
+    }
+
+    // Create AccessToken
+    nrfCtx := nrf_context.GetSelf()
+    accessTokenClaims := models.AccessTokenClaims{
+        Iss:            nrfCtx.Nrf_NfInstanceID,    // NF instance id of the NRF
+        Sub:            request.NfInstanceId,       // nfInstanceId of service consumer
+        Aud:            request.TargetNfInstanceId, // nfInstanceId of service producer
+        Scope:          request.Scope,              // TODO: the name of the NF services for which the
+        Exp:            now + expiration,           // access_token is authorized for use
+        StandardClaims: jwt.StandardClaims{},
+    }
+    accessTokenClaims.IssuedAt = int64(now)
+
+    // Use NRF private key to sign AccessToken
+    token := jwt.NewWithClaims(jwt.GetSigningMethod("RS512"), accessTokenClaims)
+    accessToken, err := token.SignedString(nrfCtx.NrfPrivKey)
+    if err != nil {
+        logger.AccTokenLog.Warnln("Signed string error: ", err)
+        return nil, &models.AccessTokenErr{
+            Error: "invalid_request",
+        }
+    }
+
+    response := &models.AccessTokenRsp{
+        AccessToken: accessToken,
+        TokenType:   tokenType,
+        ExpiresIn:   expiration,
+        Scope:       scope,
+    }
+    return response, nil
+}
+

+Snippet 2. AccessTokenProcedure Function

+

The Snippet 2 is the AccessTokenProcedure() function. The function is executed in NRF.

+

The function mainly processes:

+
    +
  1. The NRF receives the AccessTokenReq sent by the NF Service Customer.
  2. +
  3. The function calls the AccessTokenScopeCheck() function. The AccessTokenScopeCheck() function checks whether the content of the attribute name in the AccessTokenReq complies with the requirements of the TS 29.510. If not, the AccessTokenProcedure() function immediately returns the AccessTokenErr to the NF Service Customer.
  4. +
  5. The function starts to create the Access Token. The Access Token is stored in the AccessTokenRsp. The AccessTokenRsp is sent back to the NF Service Customer. The Iss in the AccessToken obtains its own ID in NRF. The Sub and Aud are obtained from the NfInstancedId and the TargetNfInstanceId in the AccessTokenReq respectively. The Scope is obtained from the scope in the AccessTokenReq. The expiration is set to the 1000 in the Snippet 2. Therefore, the value of the exp is the current time + 1000.
  6. +
  7. After the Access Token is created, the function uses the NRF private key to sign on the Access Token. After signing, the function checks whether there is an error. If so, the function immediately sends the AccessTokenErr to the NF Service Customer.
  8. +
  9. The function puts the signed Access Token into the AccessTokenRsp. The value of the TokenType is set to the Bearer by the function. The function sets the ExprieIn and the Scope in the Snippet 2.
  10. +
+

Finally, I make a simple experiment about the Access Token and share the environment setting and method of operation with you.

+

Experiment

+

The Table 4 is my environment setting. I provide the Table 4 for you. You can refer it.

+


+
Table 4. Environment

+

Remove the part of the tls and add the content of the cert, rootcert and oauth under sbi in the nrfcfg.yaml before implementing about the Access Token.

+

info:
+  version: 1.0.2
+  description: NRF initial local configuration
+
+configuration:
+  MongoDBName: free5gc # database name in MongoDB
+  MongoDBUrl: mongodb://127.0.0.1:27017 # a valid URL of the mongodb
+  sbi: # Service-based interface information
+    scheme: http # the protocol for sbi (http or https)
+    registerIPv4: 127.0.0.10 # IP used to serve NFs or register to another NRF
+    bindingIPv4: 127.0.0.10  # IP used to bind the service
+    port: 8000 # port used to bind the service
+    cert:
+      pem: cert/nrf.pem
+      key: cert/nrf.key
+    rootcert:
+      pem: cert/nrf.pem
+      key: cert/nrf.key
+    oauth: true
+  DefaultPlmnId:
+    mcc: 208 # Mobile Country Code (3 digits string, digit: 0~9)
+    mnc: 93 # Mobile Network Code (2 or 3 digits string, digit: 0~9)
+  serviceNameList: # the SBI services provided by this NRF, refer to TS 29.510
+    - nnrf-nfm # Nnrf_NFManagement service
+    - nnrf-disc # Nnrf_NFDiscovery service
+
+logger: # log output setting
+  enable: true # true or false
+  level: info # how detailed to output, value: trace, debug, info, warn, error, fatal, panic
+  reportCaller: false # enable the caller report or not, value: true or false
+

+nrfcfg.yaml

+

Find the http://127.0.0.10:8000/nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531 in the NRF log, and you will get the 8f7891b4-b127-4f59-9ec2-b5e6aade5531. The 8f7891b4-b127-4f59-9ec2-b5e6aade5531 is the nfInstanceID.

+
2023-08-02T20:07:43.300826205Z [INFO][NRF][NFM] Handle NFRegisterRequest
+2023-08-02T20:07:43.308259291Z [INFO][NRF][NFM] urilist create
+2023-08-02T20:07:43.311674255Z [INFO][NRF][NFM] Create NF Profile
+2023-08-02T20:07:43.318192771Z [INFO][NRF][NFM] Location header:  http://127.0.0.10:8000/nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531
+2023-08-02T20:07:43.325073275Z [INFO][NRF][GIN] | 201 |       127.0.0.1 | PUT     | /nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531 |
+
+

Execute $curl -X GET {apiRoot}/nnrf-nfm/v1/nf-instances/{nfInstanceID}, and you will obtain the detail information about the nfInstanceID. You can see the nfType of the nfInstanceID is NSSF, and the information about the nfInstanceID is used when you implement the Access Token.

+
ubuntu@free5GC:~/free5gc/NFs/nrf$ curl -X GET http://127.0.0.10:8000/nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531
+{"ipv4Addresses":["127.0.0.31"],"nfInstanceId":"8f7891b4-b127-4f59-9ec2-b5e6aade5531","nfServices":[{"apiPrefix":"http://127.0.0.31:8000","ipEndPoints":[{"ipv4Address":"127.0.0.31","port":8000,"transport":"TCP"}],"nfServiceStatus":"REGISTERED","scheme":"http","serviceInstanceId":"0","serviceName":"nnssf-nsselection","versions":[{"apiFullVersion":"1.0.2","apiVersionInUri":"v1"}]},{"apiPrefix":"http://127.0.0.31:8000","ipEndPoints":[{"ipv4Address":"127.0.0.31","port":8000,"transport":"TCP"}],"nfServiceStatus":"REGISTERED","scheme":"http","serviceInstanceId":"1","serviceName":"nnssf-nssaiavailability","versions":[{"apiFullVersion":"1.0.2","apiVersionInUri":"v1"}]}],"nfStatus":"REGISTERED","nfType":"NSSF","plmnList":[{"mcc":"208","mnc":"93"}]}
+
+

Then you execute this command, see below.
+

$curl -X POST -H "Content-Type: application/json" -d '{"nfInstanceId": {nfInstanceID}, "grant_type": "client_credentials", "nfType": {nfType}, "targetNfType": "UDR", "scope": "nudr-dr"}' {apiRoot}/oauth2/token
+

+You will get the long symbols. The long symbols is that the Access Token is encrypted by the private key of NRF and stored in the AccessTokenRsp.

+
ubuntu@free5GC:~/free5gc/NFs/nrf$ curl -X POST -H "Content-Type: application/json" -d '{"nfInstanceId": "8f7891b4-b127-4f59-9ec2-b5e6aade5531", "grant_type": "client_credentials", "nfType": "NSSF", "targetNfType": "UDR", "scope": "nudr-dr"}' http://127.0.0.10:8000/oauth2/token
+"eyJhY2Nlc3NfdG9rZW4iOiJleUpoYkdjaU9pSlNVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKcGMzTWlPaUlpTENKemRXSWlPaUk0WmpjNE9URmlOQzFpTVRJM0xUUm1OVGt0T1dWak1pMWlOV1UyWVdGa1pUVTFNekVpTENKaGRXUWlPaUlpTENKelkyOXdaU0k2SW01MVpISXRaSElpTENKbGVIQWlPakUyT1RFd01EZzBPRGdzSW1saGRDSTZNVFk1TVRBd056UTRPSDAuY3VHSkkwTndfV280S2lQbS1fZEZVdnVTQWM1WVEwMmRKYk5PTUhmMV9IOHdIZ2JKWFhUam9xU1Y2OTNYSmFKemkweGIxdC1DMW14TWhVZkZjbXpNMC1Nd2oxTXZYaWhyTTktdDFRUFItSFcxQlBlN0tHMUxBV3d5MEJfcXpIalltRlR6eGhONVlyNkpURDhBbkMxaFJFeEh4WHBjV1NqbV9vZnV0NVhfUFRFRkZtaHZrbmtVbU8waWFrTmdRWElRVTc1NnlvZ29ZTlFDRnJvSmRWamJMdnpFdkJLYTVFN0hQeXc3RkRDRHpTZU5WT2t2WTlobU11eldYZ3dOVmRIT3c1c2lNbmppbTlmTVZ0RTFxS1hjWDlScXlUdXlsWjM2ZlJ1QjdVZ2hkLU15Q19xd2VJRE41ZFdYOWZqdnA3VUNZZ01mVHhSLUI2M3d5OWFjQ183eThRIiwidG9rZW5fdHlwZSI6IkJlYXJlciIsImV4cGlyZXNfaW4iOjEwMDAsInNjb3BlIjoibnVkci1kciJ9"
+
+

NSSF sends the AccessTokenReq to NRF after you execute the above command. In the AccessTokenReq, the nfInstanceId is set to 8f7891b4-b127-4f59-9ec2-b5e6aade5531. The grant_type is set to the client_credentials. The nfType is set to NSSF. The targetNfType is set to UDR. The scope is set to nudr-dr. The information is shown in the NRF log. The value of the targetNfInstanceId, requesterPlmn, and targetPlmn is empty because they are not set.

+
2023-08-02T20:18:08.127557565Z [INFO][NRF][Token] In AccessTokenProcedure
+2023-08-02T20:18:08.127586736Z [INFO][NRF][Token] Access Token Request
+2023-08-02T20:18:08.127611885Z [INFO][NRF][Token] Grant Type: client_credentials
+2023-08-02T20:18:08.127637480Z [INFO][NRF][Token] NF Instance ID: 8f7891b4-b127-4f59-9ec2-b5e6aade5531
+2023-08-02T20:18:08.127664415Z [INFO][NRF][Token] Target NF Instance ID:
+2023-08-02T20:18:08.127689792Z [INFO][NRF][Token] NF Type: NSSF
+2023-08-02T20:18:08.127712916Z [INFO][NRF][Token] Target NF Type: UDR
+2023-08-02T20:18:08.127734827Z [INFO][NRF][Token] Scope: nudr-dr
+2023-08-02T20:18:08.127758317Z [INFO][NRF][Token] Requester PLMN: <nil>
+2023-08-02T20:18:08.127781052Z [INFO][NRF][Token] Target PLMN: <nil>
+
+

Next, you can see the Access Token in the NRF log. The value of the Sub is 8f7891b4-b127-4f59-9ec2-b5e6aade5531. The Sub represents NSSF, and NSSF belongs to the NF Service Customer. The value of the Scope is the nudr-dr. The value of the Exp is 1691008488.

+
2023-08-02T20:18:08.134096785Z [INFO][NRF][Token] Access Token Claims
+2023-08-02T20:18:08.138100978Z [INFO][NRF][Token] Iss:
+2023-08-02T20:18:08.138185972Z [INFO][NRF][Token] Sub: 8f7891b4-b127-4f59-9ec2-b5e6aade5531
+2023-08-02T20:18:08.138228925Z [INFO][NRF][Token] Aud:
+2023-08-02T20:18:08.138264519Z [INFO][NRF][Token] Scope: nudr-dr
+2023-08-02T20:18:08.138298628Z [INFO][NRF][Token] Exp: 1691008488
+
+

Next, you can see the AccessTokenRsp. You can see that the Access Token has become the long symbols. The value of the Token Type is set to the Bearer. The value of the ExpiresIn is set to 1000. The value of the Scope is set to nudr-dr.

+
2023-08-02T20:18:08.149587382Z [INFO][NRF][Token] Access Token Response
+2023-08-02T20:18:08.150006665Z [INFO][NRF][Token] Access Token: eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIiLCJzdWIiOiI4Zjc4OTFiNC1iMTI3LTRmNTktOWVjMi1iNWU2YWFkZTU1MzEiLCJhdWQiOiIiLCJzY29wZSI6Im51ZHItZHIiLCJleHAiOjE2OTEwMDg0ODgsImlhdCI6MTY5MTAwNzQ4OH0.cuGJI0Nw_Wo4KiPm-_dFUvuSAc5YQ02dJbNOMHf1_H8wHgbJXXTjoqSV693XJaJzi0xb1t-C1mxMhUfFcmzM0-Mwj1MvXihrM9-t1QPR-HW1BPe7KG1LAWwy0B_qzHjYmFTzxhN5Yr6JTD8AnC1hRExHxXpcWSjm_ofut5X_PTEFFmhvknkUmO0iakNgQXIQU756yogoYNQCFroJdVjbLvzEvBKa5E7HPyw7FDCDzSeNVOkvY9hmMuzWXgwNVdHOw5siMnjim9fMVtE1qKXcX9RqyTuylZ36fRuB7Ughd-MyC_qweIDN5dWX9fjvp7UCYgMfTxR-B63wy9acC_7y8Q
+2023-08-02T20:18:08.150094277Z [INFO][NRF][Token] Token Type: Bearer
+2023-08-02T20:18:08.150133189Z [INFO][NRF][Token] Expires In: 1000
+2023-08-02T20:18:08.150167371Z [INFO][NRF][Token] Scope: nudr-dr
+
+

Finally, you can see 200. 200 means that AUSF sends the AccessTokenReq to NRF. NRF successfully sends to AUSF after verification.

+
2023-08-02T20:18:08.150302345Z [INFO][NRF][GIN] | 200 |       127.0.0.1 | POST    | /oauth2/token |
+
+

Reference

+ +

About

+

Hi, my name is Wilson. I am a master’s student. My main area of research is network slicing. In the future, I will introduce more information about 5G. Hope you enjoy it.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/blog/CSRF/20230823/index.html b/blog/CSRF/20230823/index.html new file mode 100644 index 00000000..4b49c0c3 --- /dev/null +++ b/blog/CSRF/20230823/index.html @@ -0,0 +1,1112 @@ + + + + + + + + + + + + + + + + + + Web security: CSRF vulnerability in webconsole - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +

Web security: CSRF vulnerability in webconsole

+

Abstract

+

This article is intended for individuals who possess an interest in free5gc/webconsole and hold concerns regarding security matters. It aims to provide a concise introduction to the webconsole, followed by an exposition of a significant security concern along with our corresponding solution. Within webconsole v1.2.0, aligning with the most recent iteration of free5gc v3.3.0, certain vulnerabilities have been identified that could potentially lead to the exposure of subscriber data. It is my responsibility to address and rectify these vulnerabilities, enhancing the webconsole's resilience against cyber attacks.

+

Webconsole Overview

+

The Webconsole serves as a web-based tool designed to manage User Equipment (UE) subscription data. It plays a crucial role in aiding the free5GC Core Network manager by facilitating the configuration of UEs and providing the ability to monitor the status of activated UEs.

+

Environment

+
    +
  • Frontend
      +
    • React v17.0.2
    • +
    • node.js v20.2.0
    • +
    • yarn v1.22.19
    • +
    +
  • +
  • Backend
      +
    • Golang v1.17
    • +
    • Gin v1.9.0
    • +
    • MongoDB v3.6.8
    • +
    +
  • +
+

Install & Run webconsole

+

Prior to building webconsole, install nodejs and yarn package first:

+
sudo apt remove cmdtest
+sudo apt remove yarn
+curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
+echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
+sudo apt-get update
+sudo apt-get install -y nodejs yarn
+
+

To run free5GC webconsole server. The following steps are to be considered.

+
git clone https://github.com/free5gc/webconsole.git
+cd frontend
+yarn install
+yarn build
+rm -rf ../public
+cp -R build ../public
+cd ..
+go run server.go
+
+

Default account and password is admin/free5gc

+

+

Pages

+

SUBSCRIBERS

+

Creation/deletion/editing the subscriber's data:

+

+

A Subscriber data contains these informations:
+- PLMN ID
+- SUPI (UE ID)
+- AKA parameters
+- S-NSSAI Configurations
+ - Sst/Sd
+ - DNN
+ - Name
+ - AMBR
+ - Flow Rules
+ - IP Filter
+ - Precedence
+ - 5QI
+ - GBR
+ - MBR

+

+

TENANT AND USER

+

The Webconsole also allows for the creation, deletion, and editing of tenants. A tenant functions as an access control group, delineating specific permissions and boundaries. In this setup, if you do not possess admin privileges, you are unable to access subscriber data generated by other tenants, ensuring data privacy and security.

+

+

Furthermore, the capability to incorporate users within a tenant is available. To illustrate, by selecting the brian1 tenant and clicking on the New User option, it becomes possible to introduce a new user. As an example, a user with the email address aaabbb@gmail.com can be added through this process.

+

+

The data within MongoDB can be accessed and reviewed using the MongoDBCompass tool.

+

+

CSRF (Cross-Site Request Forgery) Vulnerability

+

The vulnerability was discovered by INCIBE, and they promptly notified the free5GC team via email.
+

+

The corresponding issue related to this vulnerability is also documented in the free5gc repository. Despite the typical deployment of the webconsole within LAN or Docker environments, it's essential to exercise caution regarding users who operate this service on a public IP or within an insecure network environment.

+

In a nutshell, an attacker can gain unauthorized access to the database by merely setting the token to the term 'admin'.
+

$ curl '<webconsole's IP>:5000/api/subscriber' -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.0' -H 'Accept: application/json' -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate' -H 'Referer: http://<webconsole's IP>:5000/' -H 'Connection: keep-alive' -H 'X-Requested-With: XMLHttpRequest' -H 'Token: admin' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache'
+

+

Subsequently, they can directly retrieve subscriber information from the server's MongoDB.
+

[{"plmnID":"20893","ueId":"imsi-208930000000003"}]
+

+

Undoubtedly, this vulnerability is of significant concern since the intended safeguard, allowing access solely to admin, has been compromised, thereby enabling easy access for anyone.

+

Trace Code

+

Frontend

+

In webconsole/frontend/src/util/AuthHelper.js
+- In scenarios where the default username and password (admin/free5gc) are employed, the ApiHelper.login() function remains untouched. This practice might expedite agile development, but it comes at the cost of compromising security.

+

+

Backend

+

In webconsole/frontend/WebUI/api_webui.go
+- In situations where a webconsole client configures the tokenStr as 'admin', the backend process will omit the execution of ParseJWT().

+

+

JSON Web Token (JWT)

+

The Webconsole relies on JSON Web Token (JWT) as its authentication mechanism, a specification outlined in RFC 7519.

+
+

JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.

+
+

When a client employs a web browser to initiate a login via the HTTP(s) protocol, the Web server is expected to furnish the client with a JWT token in response. Subsequently, the client employs this JWT token to interact with resources by sending requests through the RESTful API (such as GET, POST, PUT, etc.).

+

A JSON Web Token (JWT) consists of three distinct parts. In the context of the webconsole backend, the following fields are relevant:
+- Header: This section contains information about the type of token and the signing algorithm used. It often includes the "alg" (algorithm) and "typ" (type) fields.
+- Payload: The payload holds the actual claims or data that are being conveyed by the token. For the webconsole backend, specific fields within this section could include:
+ - Claim (JSON object)
+ - sub: identifies the principal that is the subject of the JWT.
+ - iat: identifies the time at which the JWT was issued.
+ - exp: identifies the expiration time onor after which the JWT MUST NOT be accepted for processing.
+ - email
+ - tenantId
+ - ...(you can design the attribute yourself)
+- Signature: This component is created by combining the encoded header and payload with a secret key (or a public/private key pair) to ensure the token's integrity and authenticity. The signature allows the recipient to verify that the token hasn't been tampered with.

+
+

The JWT Claims Set represents a JSON object whose members are the claims conveyed by the JWT. The Claim Names within a JWT Claims Set MUST be unique; JWT parsers MUST either reject JWTs with duplicate Claim Names or use a JSON parser that returns only the lexically last duplicate member name

+
+

The image depicted below illustrates the process of using jwt.io to both encode and decode JWT tokens. These tokens are segmented into distinct sections denoted by the red, purple and blue divisions, separated by periods dots.

+

+

Given that the Payload can be decoded using the algorithm specified in the Header, it's essential to refrain from including sensitive details like passwords or credit card numbers within it. Instead, the Payload typically holds claims and application-specific metadata.

+

To maintain the security of the process, the server retains a confidential key used to validate the signature. In situations where a client endeavors to access a resource using a JWT token that possesses an incorrect Verify Signature, an error response will be generated. This stringent signature verification mechanism ensures that the authenticity and integrity of both the token and its enclosed data are upheld.

+

Trace Code (Cont.)

+

In webconsole/frontend/WebUI/api_webui.go, we can find the implementation of JWT.
+- JWT() is for encoding:
+```go=394
+func JWT(email, userId, tenantId string) string {
+ token := jwt.New(jwt.SigningMethodHS256)

+
claims := token.Claims.(jwt.MapClaims)
+claims["sub"] = userId
+claims["iat"] = time.Now()
+claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
+claims["email"] = email
+claims["tenantId"] = tenantId
+
+if jwtKey == "" {
+    return ""
+}
+
+tokenString, err := token.SignedString([]byte(jwtKey))
+if err != nil {
+    logger.ProcLog.Errorf("JWT err: %+v", err)
+    return ""
+}
+
+return tokenString
+
+

}
+- `ParseJWT()` is for decoding:go=491
+func ParseJWT(tokenStr string) (jwt.MapClaims, error) {
+ token, err := jwt.Parse(tokenStr, func(token jwt.Token) (interface{}, error) {
+ return []byte(jwtKey), nil
+ })
+ if err != nil {
+ return nil, errors.Wrap(err, "ParseJWT error")
+ }
+
+ claims, _ := token.Claims.(jwt.MapClaims)
+
+ return claims, nil
+}
+- The function `CheckAuth()` serves the purpose of determining whether a user possesses the authorization to access a particular resource.go=505
+func CheckAuth(c
gin.Context) bool {
+ tokenStr := c.GetHeader("Token")
+ if tokenStr == "admin" {
+ return true
+ } else {
+ return false
+ }
+}
+`` + +::: +- The secret key utilized for signature verification is obtained throughos.Getenv("SIGNINGKEY"). However, there's a possibility thatSIGNINGKEYmight not be exported as an environment variable, leading to a potential return of an empty value. Under such circumstances, an implication arises: an admin in Webconsole A could potentially gain access to subscriber data within Webconsole B. +- Within theCheckAuth()` function, if the client sets the JWT token to 'admin', the function will evaluate to true, effectively allowing the check to be passed.
+:::
+

+

Implementation

+

Check Authentication

+

Initially, I have revised the design of the CheckAuth() function to ensure the mandatory execution of ParseJWT().
+go= +func CheckAuth(c *gin.Context) bool { + tokenStr := c.GetHeader("Token") + claims, err := ParseJWT(tokenStr) + + if err == nil && claims["email"] == "admin" { + return true + } else { + return false + } +}
+Furthermore, I've implemented a second change where, considering that the webconsole v1.2.0 doesn't inherently establish a tenant named 'admin' or a user named 'admin', I propose a more effective approach. During the initialization of the webconsole backend, it is recommended to generate an 'admin' tenant and user. This means that executing go run server.go within the webconsole/ directory should consistently generate an admin user, thereby fulfilling the initial login requirement.

+

+

Certainly, in the backend/WebUI/api_webui.go file, I propose the addition of a function named SetAdmin(). To streamline the process and maintain consistency with the rest of the free5GC project, it is recommended to leverage the mongoapi module established within the free5gc/util repository. Given the project's heavy reliance on MongoDB, employing mongoapi over frequent calls to mongo-driver is essential to ensure efficiency and coherence.

+

```go=
+func SetAdmin() {
+ err := mongoapi.RestfulAPIDeleteOne("tenantData", bson.M{"tenantName": "admin"})
+ if err != nil {
+ logger.InitLog.Errorf("RestfulAPIDeleteOne err: %+v", err)
+ }
+ err = mongoapi.RestfulAPIDeleteOne("userData", bson.M{"email": "admin"})
+ if err != nil {
+ logger.InitLog.Errorf("RestfulAPIDeleteOne err: %+v", err)
+ }

+
// Create Admin tenant
+logger.InitLog.Infoln("Create tenant: admin")
+
+adminTenantData := bson.M{
+    "tenantId":   uuid.Must(uuid.NewRandom()).String(),
+    "tenantName": "admin",
+}
+
+_, err = mongoapi.RestfulAPIPutOne("tenantData", bson.M{"tenantName": "admin"}, adminTenantData)
+if err != nil {
+    logger.InitLog.Errorf("RestfulAPIPutOne err: %+v", err)
+}
+
+AmdinTenant, err := mongoapi.RestfulAPIGetOne("tenantData", bson.M{"tenantName": "admin"})
+if err != nil {
+    logger.InitLog.Errorf("RestfulAPIGetOne err: %+v", err)
+}
+
+// Create Admin user
+logger.InitLog.Infoln("Create user: admin")
+
+hash, err := bcrypt.GenerateFromPassword([]byte("free5gc"), 12)
+if err != nil {
+    logger.InitLog.Errorf("GenerateFromPassword err: %+v", err)
+}
+
+adminUserData := bson.M{
+    "userId":            uuid.Must(uuid.NewRandom()).String(),
+    "tenantId":          AmdinTenant["tenantId"],
+    "email":             "admin",
+    "encryptedPassword": string(hash),
+}
+
+_, err = mongoapi.RestfulAPIPutOne("userData", bson.M{"email": "admin"}, adminUserData)
+if err != nil {
+    logger.InitLog.Errorf("RestfulAPIPutOne err: %+v", err)
+}
+
+

}
+```
+

+

JWT Verify Signature

+

Certainly, within the backend/WebUI/api_webui.go file, I recommend introducing a string variable named jwtKey to serve as the private key for JWT Verify Signature. Although the length of jwtKey is specified as 256 bytes, it's worth noting that the distinction between 256 bytes and 256 bits is inconsequential in this context. The jwt module will adeptly transform the key to a 256-bit form. For further insights, you can refer to issue 28.
+
+go= +var jwtKey = "" // for generating JWT + +/* ... */ + +func InitJwtKey() error { + randomBytes := make([]byte, 256) + _, err := rand.Read(randomBytes) + if err != nil { + return errors.Wrap(err, "Init JWT key error") + } else { + jwtKey = string(randomBytes) + } + return nil +}

+

Backend Initialization

+

In backend/webui_service/webui_init.go:

+

```go=
+func (a WebuiApp) Start(tlsKeyLogPath string) {
+ /
... /
+ WebUI.SetAdmin()
+ if err := WebUI.InitJwtKey(); err != nil {
+ logger.InitLog.Errorln(err)
+ return
+ }
+ /
... */
+}
+

### Frontend Login
+
+Certainly, in the `frontend/src/util/AuthHelper.js` file, it is advised to remove the section of code that could be considered a "cheating snippet." To ensure a robust authentication process, all users should be required to successfully pass through the `ApiHelper.login` function and receive a response code of 200. This approach ensures a consistent and legitimate authentication mechanism.
+
+```javascript
+static async login(username, password) {
+    let response = await ApiHelper.login({username: username, password: password});
+
+    if (response !== undefined && response.status === 200) {
+      var user = null
+      if (username == "admin") {
+        user = new User(username, "System Administrator", response.data.access_token);
+      } else {
+        user = new User(username, "User", response.data.access_token);
+      }
+      LocalStorageHelper.setUserInfo(user);
+      store.dispatch(authActions.setUser(user));
+      return true;
+    } else {
+      return false;
+    }
+  }
+

+

Conclusion

+

In this endeavor, we've successfully addressed the CSRF vulnerability issue, as highlighted in issue #387 and acknowledged by INCIBE. Furthermore, I've introduced the concept of JWT tokens in this article, detailing their implementation and the corresponding adjustments made within the webconsole. You can locate the detailed implementation in the merged PR #44 of the webconsole repository. I'd like to extend my gratitude to the contributors kishiguro and LaumiH for their significant role in refactoring the webconsole. As a result of their efforts, the webconsole UI has been notably enhanced. Our upcoming focus involves the integration of the charging function, which we are actively pursuing.

+

Reference

+

free5gc/webconsole
+merged PR #44
+free5gc issue #387
+free5gc issue #28
+JSON Token
+RFC 7519
+MongoDBCompass

+

About

+

Hello everyone,

+

I'm Brian Chen (陳煜盛), and I've been immersed in the realm of 5G Core Network technologies. Over the course of seven months, I've had the privilege of serving as an intern at Saviah. In this role, my responsibilities encompass a spectrum of tasks including maintenance, development, and rigorous testing of the free5GC project.

+

Should any inquiries, questions, or bug reports regarding free5GC arise, I encourage you to reach out by creating an issue in the free5gc repository or by participating in discussions on the forum. I'm here to assist and collaborate with the community as we navigate the intricacies of this project.

+

Warm regards,
+Brian Chen (陳煜盛)
+- Github
+- LinkedIn

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/blog/CSRF/img/1.png b/blog/CSRF/img/1.png new file mode 100644 index 00000000..08dcfb9f Binary files /dev/null and b/blog/CSRF/img/1.png differ diff --git a/blog/CSRF/img/10.png b/blog/CSRF/img/10.png new file mode 100644 index 00000000..2ce66b8f Binary files /dev/null and b/blog/CSRF/img/10.png differ diff --git a/blog/CSRF/img/11.png b/blog/CSRF/img/11.png new file mode 100644 index 00000000..a257f925 Binary files /dev/null and b/blog/CSRF/img/11.png differ diff --git a/blog/CSRF/img/2.png b/blog/CSRF/img/2.png new file mode 100644 index 00000000..a2693342 Binary files /dev/null and b/blog/CSRF/img/2.png differ diff --git a/blog/CSRF/img/3.png b/blog/CSRF/img/3.png new file mode 100644 index 00000000..f42aed7f Binary files /dev/null and b/blog/CSRF/img/3.png differ diff --git a/blog/CSRF/img/4.png b/blog/CSRF/img/4.png new file mode 100644 index 00000000..b2c2ec3c Binary files /dev/null and b/blog/CSRF/img/4.png differ diff --git a/blog/CSRF/img/5.png b/blog/CSRF/img/5.png new file mode 100644 index 00000000..adae8fd8 Binary files /dev/null and b/blog/CSRF/img/5.png differ diff --git a/blog/CSRF/img/6.png b/blog/CSRF/img/6.png new file mode 100644 index 00000000..0e61cc0f Binary files /dev/null and b/blog/CSRF/img/6.png differ diff --git a/blog/CSRF/img/7.png b/blog/CSRF/img/7.png new file mode 100644 index 00000000..35d78638 Binary files /dev/null and b/blog/CSRF/img/7.png differ diff --git a/blog/CSRF/img/8.png b/blog/CSRF/img/8.png new file mode 100644 index 00000000..9088c7ce Binary files /dev/null and b/blog/CSRF/img/8.png differ diff --git a/blog/CSRF/img/9.png b/blog/CSRF/img/9.png new file mode 100644 index 00000000..769317df Binary files /dev/null and b/blog/CSRF/img/9.png differ diff --git a/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/Service_Monitoring.jpg b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/Service_Monitoring.jpg new file mode 100644 index 00000000..1497eba3 Binary files /dev/null and b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/Service_Monitoring.jpg differ diff --git a/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/check_free5gc_pod.jpg b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/check_free5gc_pod.jpg new file mode 100644 index 00000000..afd638ca Binary files /dev/null and b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/check_free5gc_pod.jpg differ diff --git a/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/check_helm.jpg b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/check_helm.jpg new file mode 100644 index 00000000..80f7f0fb Binary files /dev/null and b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/check_helm.jpg differ diff --git a/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/check_prometheus_pod.jpg b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/check_prometheus_pod.jpg new file mode 100644 index 00000000..50f89b7c Binary files /dev/null and b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/check_prometheus_pod.jpg differ diff --git a/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/grafana_login.jpg b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/grafana_login.jpg new file mode 100644 index 00000000..6e78d2c0 Binary files /dev/null and b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/grafana_login.jpg differ diff --git a/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/image.png b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/image.png new file mode 100644 index 00000000..1742fb97 Binary files /dev/null and b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/image.png differ diff --git a/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/kubernetes_architecture.jpg b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/kubernetes_architecture.jpg new file mode 100644 index 00000000..3c1cdc49 Binary files /dev/null and b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/kubernetes_architecture.jpg differ diff --git a/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/index.html b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/index.html new file mode 100644 index 00000000..9d98d27f --- /dev/null +++ b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/index.html @@ -0,0 +1,1105 @@ + + + + + + + + + + + + + + + + + + Introduce Kubernetes and Deploy free5GC on Kubernetes with helm - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +

Introduce Kubernetes and Deploy free5GC on Kubernetes with helm

+
+

Note

+

Author: Elisa Lee
+Date: 2023/8/16

+
+

Abstract

+

In the initial section of the article, I will provide an introduction to Kubernetes. Moving on to the subsequent part, I will delve into the utilization of Kubernetes for facilitating the deployment of free5GC. Lastly, in the final segment of the article, I will elaborate on the effective utilization of Kubernetes for monitoring services.

+

Introduce Kubernetes

+

Do you know why Kubernetes is called k8s?

+

It's due to a shorthand notation that uses the first letter "k," followed by the number "8," and ending with the last letter "s" to represent the full name.
+Kubernetes,stands as an open-source container orchestration platform that bestows organizations with the capacity to adeptly govern, deploy, and expand containerized applications. Initially conceived by Google and presently overseen by the Cloud Native Computing Foundation (CNCF), Kubernetes has ascended to become a pivotal technological underpinning within the realm of contemporary cloud-native computing.

+

For those who find themselves unacquainted with the intricacies of Kubernetes, let us embark on an exploration of its architectural framework.

+


+I understand that the image presented above might appear intricate at first glance. However, there's no need for concern. Allow me to guide you through each component step by step.

+

Pods

+

A "Pod" stands as the most diminutive executable entity within the Kubernetes ecosystem. It possesses the capability to encompass either an individual container or a collective assembly of containers. The subsequent enumeration outlines several salient distinctions that set it apart from the act of directly launching a standalone container.

+

Notably, a Pod possesses its dedicated network interface, affording all enclosed containers the ability to intercommunicate seamlessly by interfacing with the "localhost." Furthermore, connectivity to other Pods is conveniently established through direct usage of their respective IP addresses within the Kubernetes environment.

+

The Pod's inherent duplicability and capacity for effortless restarts, even from the point of its most recent execution, distinguish it. Additionally, the versatility of including a functioning container within its initial state further characterizes its nature.

+

Collectively, these attributes contribute to the refinement and streamlined nature of networking within the Kubernetes ecosystem. Such qualities not only facilitate smoother scalability but also offer enhanced capabilities for restarting services with utmost ease.

+

Nodes

+

Consider a "node" as a tangible computing entity akin to a physical machine. Analogous to our personal machines, these nodes possess the capacity to concurrently execute multiple tasks, akin to the pods referenced earlier. The orchestration of nodes is overseen by a pivotal component known as the Kubernetes control plane, which, in an automated fashion, allocates pods across the available nodes. Within each node, a minimum of two services operate in tandem.

+
    +
  1. +

    Kubelet: This crucial service undertakes the responsibility of facilitating seamless communication between the Kubernetes control plane and the individual node. It serves as the intermediary that relays instructions and status updates, ensuring synchronization and cooperation.

    +
  2. +
  3. +

    Container Runtime: Operating in tandem with Kubelet, the container runtime undertakes pivotal functions. These encompass retrieving container images from registries, the unpacking of containers, and the actual execution of applications. A prime example of such a container runtime is Docker, renowned for its role in enabling containerization.

    +
  4. +
+

In essence, this intricate interplay of nodes, services, and orchestration elements underscores the dynamism and efficiency inherent to the Kubernetes ecosystem. Through these interlocking mechanisms, the platform optimizes resource utilization, ensures effective communication, and enables the seamless execution of applications across a distributed infrastructure.

+

Master Nodes

+

We've now explored all the scalable components and the task runner. Undoubtedly, to orchestrate and oversee everything, a central command hub is necessary – this is referred to as the master node. Although direct intervention within these nodes isn't typically required to ensure the seamless operation of the entire system, it's still beneficial for you to grasp a basic understanding of its functionality.

+

API server

+

It determines which interface among all nodes can be externally accessed. Any subsequent commands you execute will be channeled through this service to the designated node or pod. Furthermore, essential cluster information can also be obtained from this service.

+

Scheduler

+

Similar to an airport's control tower, its function is akin to orchestrating the deployment of pods on specific nodes based on the rules you've established and the data obtained from the API server. The effectiveness of these rules is pivotal, as they often determine the system's overall efficiency.

+

Controller Manager

+

When the need arises to enact concrete modifications on a pod, such as terminating or pausing its operation, a fundamental prerequisite is pinpointing the pod's process location and establishing the means to interact with it. This is precisely the role fulfilled by the controller manager. Additionally, this manager oversees vital components, including accounts, services, and more.

+

Etcd

+

For a simplified understanding, we can view this as essentially a comprehensive backup of the entire cluster.

+

Service

+

In Kubernetes, a "service" is an abstraction that enables communication between different sets of pods, usually to provide a stable network endpoint for accessing a specific group of pods. Pods in Kubernetes are ephemeral and can be created, terminated, or scaled dynamically, which makes their IP addresses and lifecycles unpredictable. Services provide a way to decouple the frontend of an application from the backend pods, making it easier for other components or users to access the application without having to know the exact locations or IP addresses of the pods.

+

A service can be defined in Kubernetes using a YAML or JSON configuration file, and it is associated with a set of pods based on a label selector. The service acts as a load balancer, distributing incoming network traffic among the pods that match the specified selector. This distribution ensures that even if pods are scaled up or down, the service remains available and reachable.

+

There are different types of services in Kubernetes:

+
    +
  1. +

    ClusterIP: This is the default service type, and it exposes the service on a cluster-internal IP address. It is accessible only within the cluster.

    +
  2. +
  3. +

    NodePort: This type exposes the service on each node's IP address at a static port. It allows external access to the service using the node's IP and the specified static port.

    +
  4. +
  5. +

    LoadBalancer: This type automatically provisions a cloud provider load balancer to expose the service externally. It works in environments that support external load balancers.

    +
  6. +
  7. +

    ExternalName: This type provides an alias for an external service by returning a CNAME record with the configured DNS name.

    +
  8. +
+

Services are a fundamental concept in Kubernetes and play a crucial role in enabling communication and load balancing between pods and external clients. They provide a stable and abstracted network endpoint that allows applications to scale and be more resilient without disrupting access from users or other components.

+

In the upcoming section, I will delve into the process of deploying free5GC on Kubernetes.

+

Deploying 5G core network with free5GC

+

Now I'm going to introduce how to implement free5GC on Kubernetes with helm

+

Install require packages

+
sudo apt update -y
+sudo apt upgrade -y
+
+

Install apt-transport-https

+

"apt-transport-https" is a crucial package that equips your system with the essential tools and libraries required to seamlessly integrate the HTTPS protocol. This integration ensures secure and encrypted communication when connecting to package repositories while utilizing the Advanced Package Tool (APT) for effective package management.
+

sudo apt install -y curl wget apt-transport-https
+

+

Install gtp5g

+

"gtp5g" refers to a customized Linux kernel module specifically designed to handle packets by PFCP (Packet Forwarding Control Protocol) Information Elements (IEs) such as PDR (Packet Detection Rule) and FAR (Forwarding Action Rule). For comprehensive insights, you can delve into the 3GPP specifications TS 29.281 and TS 29.244.
+To employ the UPF (User Plane Function) component effectively, it's imperative to operate on either the 5.0.0-23-generic or 5.4.x version of the Linux kernel. This ensures optimal compatibility and seamless integration with the necessary functionalities.
+

sudo apt install gcc
+sudo apt install make
+git clone -b v0.8.1 https://github.com/free5gc/gtp5g.git
+cd gtp5g
+make
+sudo make install
+

+

Install docker

+

"docker" is a platform that enables developers to build, package, and distribute applications as containers. Containers are lightweight, portable, and self-sufficient units that encapsulate everything an application needs to run, including the code, runtime, system tools, system libraries, and settings. Docker provides a consistent environment across different development and deployment stages, from local development to testing and production.
+

for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done
+sudo apt-get update
+sudo apt-get install ca-certificates curl gnupg
+sudo install -m 0755 -d /etc/apt/keyrings
+curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
+sudo chmod a+r /etc/apt/keyrings/docker.gpg
+echo \
+  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
+  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
+  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
+  sudo apt-get update
+  sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
+

+

Install minikube

+

"minikube" is an open-source tool that enables developers to set up and run a single-node Kubernetes cluster locally on their own computer. It's particularly useful for learning, development, and testing purposes. Minikube provides an easy way to experience Kubernetes without needing access to a full-scale cluster, making it a great tool for getting familiar with Kubernetes concepts and features.
+

wget https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
+sudo cp minikube-linux-amd64 /usr/local/bin/minikube
+sudo chmod +x /usr/local/bin/minikube
+

+

Install kubectl

+

"kubectl" is the command-line tool used to interact with and manage Kubernetes clusters. It is an essential component for working with Kubernetes, allowing users to perform various tasks and operations on Kubernetes clusters directly from the terminal.
+

curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
+chmod +x kubectl
+sudo mv kubectl /usr/local/bin/
+

+

Install helm

+

"helm" is a package manager for Kubernetes that simplifies the deployment and management of applications and services on a Kubernetes cluster. It allows you to define, install, and upgrade complex applications using pre-configured templates called "charts." These charts encapsulate all the necessary resources, configurations, and dependencies required to run an application.
+

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
+chmod 700 get_helm.sh
+./get_helm.sh
+helm list -A
+

+

+

Install multus-cni

+

"multus-cni" is a project that provides a Kubernetes network plugin, specifically a "Container Network Interface" (CNI) plugin, which enables the attachment of multiple network interfaces to pods in a Kubernetes cluster.
+

git clone https://github.com/k8snetworkplumbingwg/multus-cni.git 
+

+

Deploy free5GC

+

Useful kubectl command

+

Now, I will proceed to introduce a selection of kubectl command that can be employed during the deployment of free5GC.

+

"kubectl get pods" retrieves a list of running pods in the current namespace along with their names, statuses, and other relevant information.
+

kubectl get pods 
+

+"kubectl describe pod" is used to get detailed information about a specific pod, including its status, events, labels, and more.

+

kubectl describe pod [pod-name]
+

+"kubectl logs" fetches the logs of a specific pod, helping you troubleshoot issues and monitor application output.

+

kubectl logs [pod-name]
+

+"kubectl exec -it" allows you to execute a command inside a running pod. The -it flag enables interactive terminal access.
+
kubectl exec -it [pod-name] -- [command]
+

+"kubectl apply -f " deploys resources defined in a YAML file, such as pods, services, or deployments, to your cluster.
+
kubectl apply -f [yaml-file]
+

+"kubectl delete" deletes a specific resource by specifying its type and name, freeing up resources and cleaning the cluster.
+
kubectl delete [resource-type] [resource-name]
+

+"kubectl expose deployment" creates a new service, typically of type LoadBalancer, to expose a deployment's pods to external network traffic.
+
kubectl expose deployment [deployment-name] --type=LoadBalancer --port=[port]
+

+

"kubectl get services" lists all services running in the current namespace along with their details, including ClusterIP, external IP (if applicable), and ports.
+

kubectl get services
+

+"kubectl get nodes" retrieves information about the worker nodes in the cluster, displaying their statuses, roles, and other essential data.
+
kubectl get nodes
+

+"kubectl describe node" provides detailed information about a specific node, including its capacity, allocated resources, and conditions.
+
kubectl describe node [node-name]
+

+"kubectl get namespaces" displays all available namespaces in the cluster, which are used to isolate resources and manage multi-tenancy.
+
kubectl get namespaces
+

+"kubectl create namespace" creates a new namespace, allowing you to logically separate and organize resources.
+
kubectl create namespace [namespace-name]
+

+"kubectl port-forward" enables you to create a network tunnel between your local machine and a specific pod running within a Kubernetes cluster. This allows you to access services or applications running inside the pod as if they were running on your local machine. The command forwards traffic from a specified local port to a port on the selected pod.
+
kubectl port-forward [pod-name] [local-port]:[remote-port]
+

+

Start minikube

+

Use flannel as cni plugin to start minikue. Flannel is a popular "Container Network Interface" (CNI) plugin used for networking in Kubernetes and other container orchestration platforms. It provides a simple and lightweight network fabric designed to facilitate communication between containers and pods in a distributed environment, such as a Kubernetes cluster.
+

sudo usermod -aG docker $USER && newgrp docker
+minikube start --driver=docker --cpus=4 --memory=8g --disk-size=20g --cni=flannel
+## verify minikube installation
+minikube status 
+

+

+

Enable Multus-CNI Plugin

+
cd multus-cni
+cat ./deployments/multus-daemonset.yml | kubectl apply -f -
+
+

Install free5GC and UERANSIM

+

If you have only one interface on each Kubernetes node and its name is toto. Then you have to set these parameters to toto:
+global.n2network.masterIf
+global.n3network.masterIf
+global.n4network.masterIf
+global.n6network.masterIf
+global.n9network.masterIf

+

kubectl create ns free5gc
+git clone https://github.com/Orange-OpenSource/towards5gs-helm.git
+cd towards5gs-helm/charts/
+helm -n free5gc install free5gc-v1 ./free5gc/
+helm -n free5gc install ueransim-v1 ./ueransim/
+watch kubectl get pods -n free5gc
+

+

+

Start WebConsole

+

free5GC offers a user-friendly web tool called WebConsole, designed to facilitate the creation and management of User Equipment (UE) registrations. This tool serves as a valuable resource for multiple 5G network functions (NFs), streamlining the process of handling UE registrations and associated tasks.
+

kubectl port-forward --namespace free5gc svc/webui-service 5000:5000
+

+Execute the following command in your local machine's terminal, and subsequently, you will be able to access the WebConsole via localhost:5000.
+You can login with username admin and password free5gc.
+
ssh -L localhost:5000:localhost:5000 ubuntu@[VM ip]
+

+
+

+

Service Monitoring

+

install Prometheus/Grafana services

+

For monitoring Kubernetes, I utilized Prometheus and Grafana. The installation of Prometheus and Grafana services is facilitated through the Helm chart provided by the prometheus-community.
+

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
+helm repo update
+kubectl create namespace prometheus
+helm install prometheus prometheus-community/kube-prometheus-stack -n prometheus
+watch kubectl get pods -n prometheus
+

+

+

kubectl port-forward -n prometheus svc/prometheus-grafana 8080:80
+

+Execute the following command in your local machine's terminal, and subsequently, you will be able to access the WebConsole via localhost:8080.
+
ssh -L localhost:8080:localhost:8080 ubuntu@[VM ip]
+

+
+A variety of dashboards are available, offering different perspectives for those who are interested. Below is a snapshot of one such dashboard option.

+

+

Reference

+

https://free5gc.org/

+

https://medium.com/rahasak/deploying-5g-core-network-with-free5gc-kubernets-and-helm-charts-29741cea3922

+

https://github.com/Orange-OpenSource/towards5gs-helm

+

https://github.com/k8snetworkplumbingwg/multus-cni

+

About

+

Hello, I am Elisa Lee. My ongoing research revolves around VoNR (Voice over New Radio). I encourage any inquiries or identification of errors within the article, as they are welcomed for correction. Your feedback is invaluable, so please don't hesitate to reach out via email to share your insights.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/minikube_status.jpg b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/minikube_status.jpg new file mode 100644 index 00000000..185fafd0 Binary files /dev/null and b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/minikube_status.jpg differ diff --git a/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/webconsole_login.jpg b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/webconsole_login.jpg new file mode 100644 index 00000000..69cd8f25 Binary files /dev/null and b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/webconsole_login.jpg differ diff --git a/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/webconsole_subscribe.jpg b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/webconsole_subscribe.jpg new file mode 100644 index 00000000..0ce1f9b5 Binary files /dev/null and b/blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/webconsole_subscribe.jpg differ diff --git a/blog/TSN/index.html b/blog/TSN/index.html new file mode 100644 index 00000000..f92fed49 --- /dev/null +++ b/blog/TSN/index.html @@ -0,0 +1,843 @@ + + + + + + + + + + + + + + + + + + TSN - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Time-Sensitive Networking over 5G system - Introduction (Rel-16)

+
+

Note

+

Author: Ya-shih Tseng
+Date: 2023/7/12

+
+

This blog focuses on the role of the 5G system in 3GPP Release 16 TSN (Time-Sensitive Networking).

+

What is Time-Sensitive Network (TSN)

+

Traditional Ethernet technology can only achieve "best-effort" communication and cannot meet the high reliability and low latency requirements of industrial manufacturing applications.
+Therefore, in the context of industrial automation, there is a need to upgrade the traditional "best-effort" Ethernet to provide "deterministic" services.

+

Time Sensitive Networking (TSN) brings determinism and real-time communication to standard Ethernet through mechanisms and protocols defined by the IEEE 802.1 standard, which is used by Audio Video Bridging (AVB) and TSN. It offers reliable message delivery, minimized jitter, and guaranteed delivery through central management, time scheduling, and other key features. The introduction of TSN technology holds great potential and benefits for real-time applications in industrial control, automation, and other fields.
+

+
+

TSN_OSI_layer

+
+

TSN Standard

+

There are a lot of standards that TSN task group has completed or ongoing projects. Here are some base standards.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StandardTitle
IEEE 1588 V2Precision Clock Synchronization Protocol for Networked Measurement and Control Systems
IEEE 802.1Q-2022Bridges and Bridged Networks
IEEE 802.1AB-2016Station and Media Access Control Connectivity Discovery (specifies the Link Layer Discovery Protocol (LLDP))
IEEE 802.1AS-2020Timing and Synchronization for Time-Sensitive Applications
IEEE 802.1AX-2020Link Aggregation
IEEE 802.1CB-2017Frame Replication and Elimination for Reliability
IEEE 802.1CS-2020Link-local Registration Protocol
+

The role of 5G system in TSN

+

With the increasing demands for wireless control in applications such as industrial automation, remote surgical operations, smart grid distribution automation, transportation safety, autonomous driving, and more, there is a growing need to meet the low-latency requirements of these applications while achieving management, scheduling, and traffic planning. Time synchronization becomes a critical aspect. The following will explain how the interaction between TSN and 5G systems enables time synchronization.

+

Time Synchronization

+

To achieve time synchronization between TSN and 5G systems, TSN utilizes the time synchronization method defined in IEEE 802.1AS, which is the generalized Precision Time Protocol (gPTP). gPTP supports time synchronization for Time-aware end stations and Time-aware Bridges in Layer 2. In the 3GPP TS23.501 release 16 specification, the 5G system plays the role of a "Time-aware system" as defined in IEEE 802.1AS and is designated as a Logical bridge, connecting TSN system end stations.

+
+

Note

+

gPTP is an extended version of PTP (Precision Time Protocol) that primarily expands support for second-layer network devices.

+
+

How can we synchronize the time of two end stations into the same time domain?

+

First, the time synchronization architecture includes Master clocks and Slave clocks. The Master regularly sends sync messages to allow the Slave to obtain the Master's time. The Slave, in turn, periodically sends peer delay requests to exchange messages with the Master, obtaining the delay time between the two devices for time correction. Additionally, the resident time, which is the message propagation delay introduced by bridges, should also be taken into account. By considering all these factors, the time synchronization of both sides can be achieved within the TSN time domain.
+

+
+

Time Synchronization process of gPTP

+
+

Check the link for more detail about how PTP works.

+

Intergration of TSN and 5G

+

By now, I believe you have gained an understanding of the time synchronization mechanism in TSN. Let's briefly explain how the 5G system supports TSN as a logical TSN bridge.
+The 3GPP has defined new functionalities such as NW-TT, DS-TT, and TSN-AF, as well as TSN control nodes like CUC and CNC. Please check TS 23.501 Release 16 for more details.
+

+
+

System architecture of 5G support TSN

+
+

Support Ethernet type PDU session

+

To archive the intergration, 5G system should support ingress port and egress port pair via an Ethernet Type PDU session between the corresponding UE and UPF. As mentioned above, gPTP supports layer 2 (Ethernet) only.

+

DS-TT and NW-TT

+

In the 5G system, DS-TT (Device-side TSN translator) and NW-TT (Network-side TSN translator) serve as TSN translators. DS-TT is responsible for connecting TSN Slave endpoints with the UE, while NW-TT connects TSN Master endpoints with the UPF.

+

When the sync message generated by the Master clock reaches the bridge, NW-TT captures its Ingress Timestamp and measures the delay between NW-TT and the Master clock. These timestamps are then embedded within the sync message and transmitted to the UE. Once the UE receives the sync message, DS-TT calculates the resident time by subtracting the Ingress Timestamp provided in the sync message, from the Egress Timestamp which represents the time of sync message reception. The resident time is added to the delay time mentioned in the sync message to determine the corrected time. Through the assistance of the TSN translators, the Slave endpoint receives the message and obtains information about time deviation and other relevant data for further adjustment.

+
+

Note

+

DS-TT and NW-TT enable the 5G system to function as a virtual bridge. The bridge is also called "Transparent clock" which is definded in IEEE 1588 and required in IEEE 802.1AS. You can say that Master and Slaver don't know the exist of the 5G TSN bridge, since it's logical transparent.

+
+

"Transparent clocks are used to route timing messages within a network. Used when: Ethernet timing must pass through switches." - different type of clocks

+

TSN-AF

+

With TSN-AF, CNC can manage the 5G system functioning as a logical bridge and achieve the integration of the 5G TSN bridge with the TSN network in collaboration with NW-TT and DS-TT. Additionally, TSN-AF gathers information and capability lists of the 5G TSN Bridge and transmits them to CNC.

+

TSN control nodes

+

To meet the requirements of application services and control TSN, there are two key functions utilized in the TSN system.
+CNC (Centralized Network Controller), as the central controller in the TSN system, receives the information from CUC (Centralized User Configuration) and performs scheduling and planning tasks. It calculates the optimal transmission schedule for the TSN traffic based on factors such as bandwidth requirements, latency constraints, and network conditions. Once the transmission schedule is computed and confirmed, CNC proceeds to deploy the necessary network resource configuration on the TSN switches. This ensures that the TSN network operates efficiently and effectively in delivering the required QoS (Quality of Service) for the application services.

+

Reference

+
    +
  • IEEE Std 802.1AS-2020: “IEEE Standard for Local and metropolitan area networks--Timing and Synchronization for Time-Sensitive Applications”.
  • +
  • IEEE Std 1588: “IEEE Standard for a Precision Clock Synchronization Protocol for Networked Measurement and Control Systems”, Edition 2019.
  • +
  • 3GPP TS 23.501 Release 16
  • +
  • Time-Sensitive Networking - Wikipedia
  • +
  • Time-Sensitive Networking (TSN) Task Group | - IEEE 802.1
  • +
+

About

+

Hi, This is Ya-shih Tseng. I am currently researching the implementation of 5G TSN (Time-Sensitive Networking) as part of my master's studies. In the future, I will introduce more information about TSN. Hope you enjoy it.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/blog/TSN_OSI_layer.png b/blog/TSN_OSI_layer.png new file mode 100644 index 00000000..3211e881 Binary files /dev/null and b/blog/TSN_OSI_layer.png differ diff --git a/blog/UDM_introduce/index.html b/blog/UDM_introduce/index.html new file mode 100644 index 00000000..93e3e641 --- /dev/null +++ b/blog/UDM_introduce/index.html @@ -0,0 +1,1103 @@ + + + + + + + + + + + + + + + + + + Network function UDM introduction - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +

Network function UDM introduction

+
+

Note

+

Author: 張哲睿
+Date: 2023/7/19

+
+

Overview

+

In this article, I will introduce UDM and its three services that will be used in the general UE registration procedure (Nudm_UECM service, Nudm_SubscriberDataManagement Service, and Nudm_UEAuthentication service) to let everyone understand UDM more clearly.

+

UDM

+

Unified Data Management is responsible for managing information related to UE. When other NFs need to use the UE subscription information, they will obtain it from UDM through the SBI of UDM.

+

Nudm_UEAuthentication Service

+

This service is used by AUSF to retrieve authentication-related information and, after authentication, confirm the result.

+

upload_dde9cead3e40f645128a006d5bc56681

+
+

3GPP TS33.501 v15.2.0

+
+

In Authentication, AUSF uses the GET operation to retrieve authentication information for the UE. The request contains the UE’s identity (supi or suci) and the serving network name. The serving network name is used in the derivation of the anchor key, which is used by subsensual authentication. UE’s identity will be contained in the URI, and the serving network name will be contained in the request body.

+

Upon reception of the Nudm_UEAuthentication_Get Request, the UDM shall de-conceal SUCI to gain SUPI if SUCI is received. At this time, UDM will query the authentication subscription data from UDR. Then, UDM shall select the authentication method based on SUPI, and if required (e.g., 5G-AKA), UDM will calculate the authentication vector and pass it to AUSF.

+
    +
  • SUPI: A globally unique 5G Subscription Permanent Identifier, used to identify UE.
  • +
  • SUCI: Subscription concealed identifier, obtained by encrypting supi through the Home Network Public Key so that supi will not be obtained by a third party on the network.
  • +
+
logger.UeauLog.Traceln("In GenerateAuthDataProcedure")
+
+response = &models.AuthenticationInfoResult{}
+rand.Seed(time.Now().UnixNano())
+supi, err := suci.ToSupi(supiOrSuci, udm_context.Getself().SuciProfiles)
+if err != nil {
+    problemDetails = &models.ProblemDetails{
+        Status: http.StatusForbidden,
+        Cause:  authenticationRejected,
+        Detail: err.Error(),
+    }
+
+    logger.UeauLog.Errorln("suciToSupi error: ", err.Error())
+    return nil, problemDetails
+}
+
+logger.UeauLog.Tracef("supi conversion => [%s]", supi)
+
+client, err := createUDMClientToUDR(supi)
+if err != nil {
+    return nil, openapi.ProblemDetailsSystemFailure(err.Error())
+}
+authSubs, res, err := client.AuthenticationDataDocumentApi.QueryAuthSubsData(context.Background(), supi, nil)
+
+//in the udm/internal/sbi/producer/generate_auth_data.go, GenerateAuthDataProcedure function.
+
+

From the code, we can see UDM first de-conceal SUCI (line 5), then use QueryAuthSubsData to get authSub from UDR. After that, UDM uses this information to create the authentication vector.

+

Then we record the packet sent in the registration process and find the packet according to the URI specified by the specification. We can find the packet corresponding to this service.

+

upload_3b177b07a98719c89de8d2cce9594c36

+

Open the response packet, and we can see the response body matches the AuthenticationInfoResult data type.

+

upload_3acf4b96a27e13f8b35712d5efc402da

+

upload_f24e1640d05c1614d277517d35b6520f

+
+

3GPP TS29.503 v15.2.1

+
+

After AUSF authenticates the UE, it will confirm the result with UDM. These details will be used in linking authentication confirmation to the Nudm_UECM_Registration procedure from AMF.

+
func communicateWithUDM(ue *context.AmfUe, accessType models.AccessType) error {
+    ue.GmmLog.Debugln("communicateWithUDM")
+    amfSelf := context.GetSelf()
+
+    // UDM selection described in TS 23.501 6.3.8
+    // TODO: consider udm group id, Routing ID part of SUCI, GPSI or External Group ID (e.g., by the NEF)
+    param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{
+        Supi: optional.NewString(ue.Supi),
+    }
+    resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_UDM, models.NfType_AMF, &param)
+    if err != nil {
+        return errors.Errorf("AMF can not select an UDM by NRF: SendSearchNFInstances failed")
+    }
+
+    var uecmUri, sdmUri string
+    for _, nfProfile := range resp.NfInstances {
+        ue.UdmId = nfProfile.NfInstanceId
+        uecmUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NUDM_UECM, models.NfServiceStatus_REGISTERED)
+        sdmUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NUDM_SDM, models.NfServiceStatus_REGISTERED)
+        if uecmUri != "" && sdmUri != "" {
+            break
+        }
+    }
+    ue.NudmUECMUri = uecmUri
+    ue.NudmSDMUri = sdmUri
+    if ue.NudmUECMUri == "" || ue.NudmSDMUri == "" {
+        return errors.Errorf("AMF can not select an UDM by NRF: SearchNFServiceUri failed")
+    }
+
+    problemDetails, err := consumer.UeCmRegistration(ue, accessType, true)
+    if problemDetails != nil {
+        return errors.Errorf(problemDetails.Cause)
+    } else if err != nil {
+        return errors.Wrap(err, "UECM_Registration Error")
+    }
+
+    // TS 23.502 4.2.2.2.1 14a-c.
+    // "After a successful response is received, the AMF subscribes to be notified
+    //      using Nudm_SDM_Subscribe when the data requested is modified"
+    problemDetails, err = consumer.SDMGetAmData(ue)
+    if problemDetails != nil {
+        return errors.Errorf(problemDetails.Cause)
+    } else if err != nil {
+        return errors.Wrap(err, "SDM_Get AmData Error")
+    }
+
+    problemDetails, err = consumer.SDMGetSmfSelectData(ue)
+    if problemDetails != nil {
+        return errors.Errorf(problemDetails.Cause)
+    } else if err != nil {
+        return errors.Wrap(err, "SDM_Get SmfSelectData Error")
+    }
+
+    problemDetails, err = consumer.SDMGetUeContextInSmfData(ue)
+    if problemDetails != nil {
+        return errors.Errorf(problemDetails.Cause)
+    } else if err != nil {
+        return errors.Wrap(err, "SDM_Get UeContextInSmfData Error")
+    }
+
+    problemDetails, err = consumer.SDMSubscribe(ue)
+    if problemDetails != nil {
+        return errors.Errorf(problemDetails.Cause)
+    } else if err != nil {
+        return errors.Wrap(err, "SDM Subscribe Error")
+    }
+    ue.ContextValid = true
+    return nil
+}
+
+
+//in the amf/internal/gmm/handler.go.
+
+

Next, let's take a look at this function. It is called in HandleInitialRegistration, which handles UE's initial registration. UeCmRegistration will use the Nudm_UECM (UECM) service to store related UE Context Management information in UDM. In lines 40, 47, and 54, AMF uses the Nudm_SubscriberDataManagement (SDM) Service to get some subscribe data.

+

Nudm_UEContextManagement Service

+

In the UeCmRegistration function, AMF registers as UE's serving NF on UDM and stores related UE Context Management information in UDM. Looking at the packet, you can see that the request body contains amfInstanceId and guami, representing the amf identity, and ratType, representing the radio access technology type used by UE.

+

upload_c3e5e7c63f1bb7a934877e7fa29b82ec

+
// TS 29.503 5.3.2.2.2
+func RegistrationAmf3gppAccessProcedure(registerRequest models.Amf3GppAccessRegistration, ueID string) (
+    header http.Header, response *models.Amf3GppAccessRegistration, problemDetails *models.ProblemDetails,
+) {
+    // TODO: EPS interworking with N26 is not supported yet in this stage
+    var oldAmf3GppAccessRegContext *models.Amf3GppAccessRegistration
+    if udm_context.Getself().UdmAmf3gppRegContextExists(ueID) {
+        ue, _ := udm_context.Getself().UdmUeFindBySupi(ueID)
+        oldAmf3GppAccessRegContext = ue.Amf3GppAccessRegistration
+    }
+
+    udm_context.Getself().CreateAmf3gppRegContext(ueID, registerRequest)
+
+    clientAPI, err := createUDMClientToUDR(ueID)
+    if err != nil {
+        return nil, nil, openapi.ProblemDetailsSystemFailure(err.Error())
+    }
+
+    var createAmfContext3gppParamOpts Nudr_DataRepository.CreateAmfContext3gppParamOpts
+    optInterface := optional.NewInterface(registerRequest)
+    createAmfContext3gppParamOpts.Amf3GppAccessRegistration = optInterface
+    resp, err := clientAPI.AMF3GPPAccessRegistrationDocumentApi.CreateAmfContext3gpp(context.Background(),
+        ueID, &createAmfContext3gppParamOpts)
+    if err != nil {
+        logger.UecmLog.Errorln("CreateAmfContext3gpp error : ", err)
+        problemDetails = &models.ProblemDetails{
+            Status: int32(resp.StatusCode),
+            Cause:  err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails).Cause,
+            Detail: err.Error(),
+        }
+        return nil, nil, problemDetails
+    }
+    defer func() {
+        if rspCloseErr := resp.Body.Close(); rspCloseErr != nil {
+            logger.UecmLog.Errorf("CreateAmfContext3gpp response body cannot close: %+v", rspCloseErr)
+        }
+    }()
+
+    // TS 23.502 4.2.2.2.2 14d: UDM initiate a Nudm_UECM_DeregistrationNotification to the old AMF
+    // corresponding to the same (e.g. 3GPP) access, if one exists
+    if oldAmf3GppAccessRegContext != nil {
+        deregistData := models.DeregistrationData{
+            DeregReason: models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN,
+            AccessType:  models.AccessType__3_GPP_ACCESS,
+        }
+        callback.SendOnDeregistrationNotification(ueID, oldAmf3GppAccessRegContext.DeregCallbackUri,
+            deregistData) // Deregistration Notify Triggered
+
+        return nil, nil, nil
+    } else {
+        header = make(http.Header)
+        udmUe, _ := udm_context.Getself().UdmUeFindBySupi(ueID)
+        header.Set("Location", udmUe.GetLocationURI(udm_context.LocationUriAmf3GppAccessRegistration))
+        return header, &registerRequest, nil
+    }
+}
+
+//in the udm/internal/sbi/producer/ue_context_management.go
+
+

In the RegistrationAmf3gppAccessProcedure function, UDM first checks whether the context has been established for that UE; if UDM has such a context, it initiates a Nudm_UECM_DeregistrationNotification to the old AMF later. UDM used the received information to create context and stored it in UDR.

+

Nudm_SubscriberDataManagement (SDM) Service

+

The SDM service is used to retrieve the UE's individual subscription data relevant to the consumer's NF from the UDM. In the SDMGetAmData function, AMF gets subscription data used in registration and mobility management. In the response packet, AMF got gpsis, subscribedUeAmbr, and nssai.

+

upload_6793e16d2435baf3f235d61178245873

+

The GPSI (Generic Public Subscription Identifier) is used to address a 3GPP subscription in data networks outside the realms of a 3GPP system. It contains either an External ID or an MSISDN (Mobile Subscriber ISDN Number).The subscribedUeAmbr is The Maximum Aggregated uplink and downlink MBRs (max. bit rate) to be shared across all Non-GBR (non-guaranteed Bit Rate) QoS Flows according to the subscription of the user.

+

upload_e45012750cc609c51d59437c24f8fc4f

+

In the SDMGetSmfSelectData function, AMF gets subscribed S-NSSAIs (Single Network Slice Selection Assistance Information) and Data Network Names for these S-NSSAIs. AMF will use this information to select an SMF that manages the PDU Session.

+
func HandleInitialRegistration(ue *context.AmfUe, anType models.AccessType) error {
+    ue.GmmLog.Infoln("Handle InitialRegistration")
+
+    amfSelf := context.GetSelf()
+
+    // update Kgnb/Kn3iwf
+    ue.UpdateSecurityContext(anType)
+
+    // Registration with AMF re-allocation (TS 23.502 4.2.2.2.3)
+    if len(ue.SubscribedNssai) == 0 {
+        getSubscribedNssai(ue)
+    }
+
+    if err := handleRequestedNssai(ue, anType); err != nil {
+        return err
+    }
+
+//in the amf/internal/gmm/handler.go.
+
+

In the initialization of HandleInitialRegistration, AMF sends a request to the UDM to receive the UE's NSSAI (Network Slice Selection Assistance Information). After receiving subscribed NSSAI, AMF will compare it to UE's requested NSSAI. If there is a S-NSSAI that has not been subscribed before, AMF will request NSSF for Allowed NSSAI.

+
func handleRequestedNssai(ue *context.AmfUe, anType models.AccessType) error {
+    amfSelf := context.GetSelf()
+
+    if ue.RegistrationRequest.RequestedNSSAI != nil {
+        requestedNssai, err := nasConvert.RequestedNssaiToModels(ue.RegistrationRequest.RequestedNSSAI)
+        if err != nil {
+            return fmt.Errorf("Decode failed at RequestedNSSAI[%s]", err)
+        }
+
+        needSliceSelection := false
+        for _, requestedSnssai := range requestedNssai {
+            ue.GmmLog.Infof("RequestedNssai - ServingSnssai: %+v, HomeSnssai: %+v",
+                requestedSnssai.ServingSnssai, requestedSnssai.HomeSnssai)
+            if ue.InSubscribedNssai(*requestedSnssai.ServingSnssai) {
+                allowedSnssai := models.AllowedSnssai{
+                    AllowedSnssai: &models.Snssai{
+                        Sst: requestedSnssai.ServingSnssai.Sst,
+                        Sd:  requestedSnssai.ServingSnssai.Sd,
+                    },
+                    MappedHomeSnssai: requestedSnssai.HomeSnssai,
+                }
+                if !ue.InAllowedNssai(*allowedSnssai.AllowedSnssai, anType) {
+                    ue.AllowedNssai[anType] = append(ue.AllowedNssai[anType], allowedSnssai)
+                }
+            } else {
+                needSliceSelection = true
+                break
+            }
+        }
+
+        if needSliceSelection {
+            if ue.NssfUri == "" {
+                for {
+                    err := consumer.SearchNssfNSSelectionInstance(ue, amfSelf.NrfUri, models.NfType_NSSF, models.NfType_AMF, nil)
+                    if err != nil {
+                        ue.GmmLog.Errorf("AMF can not select an NSSF Instance by NRF[Error: %+v]", err)
+                        time.Sleep(2 * time.Second)
+                    } else {
+                        break
+                    }
+                }
+            }
+
+            // Step 4
+            problemDetails, err := consumer.NSSelectionGetForRegistration(ue, requestedNssai)
+            if problemDetails != nil {
+                ue.GmmLog.Errorf("NSSelection Get Failed Problem[%+v]", problemDetails)
+                gmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMProtocolErrorUnspecified, "")
+                return fmt.Errorf("Handle Requested Nssai of UE failed")
+            } else if err != nil {
+                ue.GmmLog.Errorf("NSSelection Get Error[%+v]", err)
+                gmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMProtocolErrorUnspecified, "")
+                return fmt.Errorf("Handle Requested Nssai of UE failed")
+            }
+
+//in the amf/internal/gmm/handler.go.
+
+
if param.SliceInfoRequestForRegistration.RequestedNssai != nil &&
+    len(param.SliceInfoRequestForRegistration.RequestedNssai) != 0 {
+    // Requested NSSAI is provided
+    // Verify which S-NSSAI(s) in the Requested NSSAI are permitted based on comparing the Subscribed S-NSSAI(s)
+    if param.Tai != nil &&
+        !util.CheckSupportedNssaiInPlmn(param.SliceInfoRequestForRegistration.RequestedNssai, *param.Tai.PlmnId) {
+        // Return ProblemDetails indicating S-NSSAI is not supported
+        // TODO: Based on TS 23.501 V15.2.0, if the Requested NSSAI includes an S-NSSAI that is not valid in the
+        //       Serving PLMN, the NSSF may derive the Configured NSSAI for Serving PLMN
+        *problemDetails = models.ProblemDetails{
+            Title:  util.UNSUPPORTED_RESOURCE,
+            Status: http.StatusForbidden,
+            Detail: "S-NSSAI in Requested NSSAI is not supported in PLMN",
+            Cause:  "SNSSAI_NOT_SUPPORTED",
+        }
+
+        status = http.StatusForbidden
+        return status
+    }
+
+    // Check if any Requested S-NSSAIs is present in Subscribed S-NSSAIs
+    checkIfRequestAllowed := false
+
+    for _, requestedSnssai := range param.SliceInfoRequestForRegistration.RequestedNssai {
+        if param.Tai != nil && !util.CheckSupportedSnssaiInTa(requestedSnssai, *param.Tai) {
+            // Requested S-NSSAI does not supported in UE's current TA
+            // Add it to Rejected NSSAI in TA
+            authorizedNetworkSliceInfo.RejectedNssaiInTa = append(
+                authorizedNetworkSliceInfo.RejectedNssaiInTa,
+                requestedSnssai)
+            continue
+        }
+
+        var mappingOfRequestedSnssai models.Snssai
+        // TODO: Compared with Restricted S-NSSAI list in configuration under roaming scenario
+        if param.HomePlmnId != nil && !util.CheckStandardSnssai(requestedSnssai) {
+            // Standard S-NSSAIs are supported to be commonly decided by all roaming partners
+            // Only non-standard S-NSSAIs are required to find mappings
+            targetMapping, found := util.FindMappingWithServingSnssai(requestedSnssai,
+                param.SliceInfoRequestForRegistration.MappingOfNssai)
+
+            if !found {
+                // No mapping of Requested S-NSSAI to HPLMN S-NSSAI is provided by UE
+                // TODO: Search for local configuration if there is no provided mapping from UE, and update UE's
+                //       Configured NSSAI
+                checkInvalidRequestedNssai = true
+                authorizedNetworkSliceInfo.RejectedNssaiInPlmn = append(
+                    authorizedNetworkSliceInfo.RejectedNssaiInPlmn,
+                    requestedSnssai)
+                continue
+            } else {
+                // TODO: Check if mappings of S-NSSAIs are correct
+                //       If not, update UE's Configured NSSAI
+                mappingOfRequestedSnssai = *targetMapping.HomeSnssai
+            }
+        } else {
+            mappingOfRequestedSnssai = requestedSnssai
+        }
+
+        hitSubscription := false
+        for _, subscribedSnssai := range param.SliceInfoRequestForRegistration.SubscribedNssai {
+            if mappingOfRequestedSnssai == *subscribedSnssai.SubscribedSnssai {
+                // Requested S-NSSAI matches one of Subscribed S-NSSAI
+                // Add it to Allowed NSSAI list
+                hitSubscription = true
+
+                var allowedSnssaiElement models.AllowedSnssai
+                allowedSnssaiElement.AllowedSnssai = new(models.Snssai)
+                *allowedSnssaiElement.AllowedSnssai = requestedSnssai
+                nsiInformationList := util.GetNsiInformationListFromConfig(requestedSnssai)
+                if nsiInformationList != nil {
+                    // TODO: `NsiInformationList` should be slice in `AllowedSnssai` instead of pointer of slice
+                    allowedSnssaiElement.NsiInformationList = append(
+                        allowedSnssaiElement.NsiInformationList,
+                        nsiInformationList...)
+                }
+                if param.HomePlmnId != nil && !util.CheckStandardSnssai(requestedSnssai) {
+                    allowedSnssaiElement.MappedHomeSnssai = new(models.Snssai)
+                    *allowedSnssaiElement.MappedHomeSnssai = *subscribedSnssai.SubscribedSnssai
+                }
+
+                // Default Access Type is set to 3GPP Access if no TAI is provided
+                // TODO: Depend on operator implementation, it may also return S-NSSAIs in all valid Access Type if
+                //       UE's Access Type could not be identified
+                var accessType models.AccessType = models.AccessType__3_GPP_ACCESS
+                if param.Tai != nil {
+                    accessType = util.GetAccessTypeFromConfig(*param.Tai)
+                }
+
+                util.AddAllowedSnssai(allowedSnssaiElement, accessType, authorizedNetworkSliceInfo)
+
+                checkIfRequestAllowed = true
+                break
+            }
+        }
+
+        if !hitSubscription {
+            // Requested S-NSSAI does not match any Subscribed S-NSSAI
+            // Add it to Rejected NSSAI in PLMN
+            checkInvalidRequestedNssai = true
+            authorizedNetworkSliceInfo.RejectedNssaiInPlmn = append(
+                authorizedNetworkSliceInfo.RejectedNssaiInPlmn,
+                requestedSnssai)
+        }
+    }
+
+    if !checkIfRequestAllowed {
+        // No S-NSSAI from Requested NSSAI is present in Subscribed S-NSSAIs
+        // Subscribed S-NSSAIs marked as default are used
+        useDefaultSubscribedSnssai(param, authorizedNetworkSliceInfo)
+    }
+} else {
+    // No Requested NSSAI is provided
+    // Subscribed S-NSSAIs marked as default are used
+    checkInvalidRequestedNssai = true
+    useDefaultSubscribedSnssai(param, authorizedNetworkSliceInfo)
+}
+
+//in the nssf/internal/sbi/producer/nsselection_for_registration.go, nsselectionForRegistration funcion.
+
+

If NSSF needs to select S-NSSAI, it first finds the mapping of requested NSSAI to configured NSSAI for the HPLMN and converts requested S-NSSAI to S-NSSAI in configured NSSAI for the HPLMN. Then compare these S-NSSAIs with Subscribed S-NSSAIs; if NSSF find one match, set it as AllowedSnssai. If NSSF can't find such a mapping or no S-NSSAI in the mapping matches subscribed S-NSSAIs, it will use default subscribed S-NSSAIs.

+

Reference

+ +

About

+

Hello! My name is 張哲睿, and my current research topic is ATSSS (Access Traffic Steering, Switching and Splitting), I will continue to write articles related to 5G networks in the future. If you find any mistakes in my articles or have any topics you want to know about, please contact me.

+ + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/blog/fuzzing/cve-1.png b/blog/fuzzing/cve-1.png new file mode 100644 index 00000000..56ccbc26 Binary files /dev/null and b/blog/fuzzing/cve-1.png differ diff --git a/blog/fuzzing/cve-2.png b/blog/fuzzing/cve-2.png new file mode 100644 index 00000000..03e3fbe3 Binary files /dev/null and b/blog/fuzzing/cve-2.png differ diff --git a/blog/fuzzing/cve-3.png b/blog/fuzzing/cve-3.png new file mode 100644 index 00000000..b641b337 Binary files /dev/null and b/blog/fuzzing/cve-3.png differ diff --git a/blog/fuzzing/go-fuzzing-1.png b/blog/fuzzing/go-fuzzing-1.png new file mode 100644 index 00000000..b5006035 Binary files /dev/null and b/blog/fuzzing/go-fuzzing-1.png differ diff --git a/blog/fuzzing/go-fuzzing-2.png b/blog/fuzzing/go-fuzzing-2.png new file mode 100644 index 00000000..1f285b33 Binary files /dev/null and b/blog/fuzzing/go-fuzzing-2.png differ diff --git a/blog/fuzzing/main/index.html b/blog/fuzzing/main/index.html new file mode 100644 index 00000000..e49243bf --- /dev/null +++ b/blog/fuzzing/main/index.html @@ -0,0 +1,1154 @@ + + + + + + + + + + + + + + + + + + Fuzz Testing in Go: Discovering Vulnerabilities and Analyzing a Real Case (CVE-2022-43677) - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +

Fuzz Testing in Go: Discovering Vulnerabilities and Analyzing a Real Case (CVE-2022-43677)

+
+

Note

+

Author: Yu-Sheng Liu
+Date: 2023/8/9

+
+
+

Overview

+

In this article, we begin by introducing the concept of fuzz testing and its significance in software testing. Subsequently, we present Go Fuzzing as an illustrative example to demonstrate how to implement fuzz testing in Go. Lastly, we showcase a practical case, CVE-2022-43677, to exemplify how we conduct fuzz testing on the free5GC system.

+
+

Fuzz Testing

+

What is Fuzz Testing (Fuzzing)?

+

Fuzz testing, commonly known as fuzzing, is an automated software testing technique used to uncover vulnerabilities, defects, and unexpected behavior in computer systems, applications, and networks.
+The primary objective of fuzzing is to identify security flaws, crashes, or abnormal program behavior caused by invalid or unexpected inputs.

+

How Fuzz Testing Works

+

Fuzz testing involves subjecting the target software or system to a large number of inputs, including random or malformed data, to see how it handles them.
+The idea is to explore edge cases and input combinations that may not have been adequately tested during traditional software testing.
+Here's how the fuzzing process typically works:

+
    +
  1. +

    Test Input Generation:

    +
      +
    • Fuzzing tools generate test inputs based on various techniques, which can be broadly categorized as:
        +
      • Random Fuzzing: The simplest approach where random data is generated as input.
      • +
      • Mutation-Based Fuzzing: Starting with valid inputs, the tool applies mutations to create variations of the original data.
      • +
      • Grammar-Based Fuzzing: Using a predefined grammar or structure to generate valid and invalid inputs.
      • +
      • Seed Corpus: Using existing inputs (e.g., files, network packets) as the starting set for mutation.
      • +
      +
    • +
    +
  2. +
  3. +

    Test Execution:

    +
      +
    • The generated inputs are provided as input to the target application, component, or system.
    • +
    • The application is executed with each input, and its behavior is monitored during runtime.
    • +
    +
  4. +
  5. +

    Monitoring and Analysis:

    +
      +
    • The fuzzer observes the application's behavior, including any crashes, exceptions, hangs, or memory-related issues.
    • +
    • Code coverage analysis is often performed to determine which parts of the code were exercised during the testing.
    • +
    +
  6. +
  7. +

    Feedback and Iteration:

    +
      +
    • Fuzzing tools use feedback mechanisms to prioritize and select inputs that lead to new code paths or unique behavior.
    • +
    • The process is iterated with refined inputs to continue exploring deeper into the application.
    • +
    +
  8. +
+

Types of Fuzz Testing

+
    +
  1. +

    Black Box Fuzzing:

    +
      +
    • The tester has no access to the application's internal code or design.
    • +
    • Random or mutated inputs are provided to the application to observe its behavior.
    • +
    • Suitable for testing closed-source software or systems where the tester has limited knowledge.
    • +
    +
  2. +
  3. +

    White Box Fuzzing:

    +
      +
    • The tester has access to the application's source code and can leverage this knowledge for targeted testing.
    • +
    • Inputs can be intelligently crafted to explore specific code paths and functions.
    • +
    • Provides more in-depth coverage but requires access to the application's code.
    • +
    +
  4. +
  5. +

    Grey Box Fuzzing:

    +
      +
    • A combination of black box and white box approaches.
    • +
    • The tester has partial knowledge of the application, such as certain APIs or protocols, but not complete access to the source code.
    • +
    • Offers a balance between targeted testing and exploration of unknown behaviors.
    • +
    +
  6. +
+

Advantages of Fuzz Testing

+
    +
  1. +

    Bug and Vulnerability Discovery:

    +
      +
    • Fuzzing can uncover previously unknown security vulnerabilities and software defects, including memory corruption errors and input validation issues.
    • +
    +
  2. +
  3. +

    Automation and Efficiency:

    +
      +
    • Fuzzing is an automated testing process, which allows it to scale and test large codebases quickly and efficiently.
    • +
    +
  4. +
  5. +

    Diverse Test Inputs:

    +
      +
    • Fuzzing generates a wide range of test inputs, exploring various edge cases that might not be covered by manual testing.
    • +
    +
  6. +
  7. +

    Early Vulnerability Detection:

    +
      +
    • Fuzzing can be integrated into the development process, enabling early detection and mitigation of vulnerabilities before deployment.
    • +
    +
  8. +
+

Conclusion for fuzz testing

+

Fuzz testing, or fuzzing, is a powerful and essential technique in the realm of software security testing.
+By providing a diverse set of inputs and exploring uncharted code paths, fuzz testing uncovers vulnerabilities and defects that might otherwise remain hidden.

+

Next, we will use Go fuzzing as an example to introduce how to develop a fuzzing in Go.

+
+

Go Fuzzing

+

Go officially supports fuzzing starting from Go 1.18, and its official figure provides a brief and clear summary of the fuzzing function components.
+

+

Similar to Go's unit test functions, the fuzzing function in Go must follow the naming convention FuzzXxx and take an argument of type *testing.F. This argument has two main functions, Add and Fuzz.

+
    +
  1. +

    Add Function:

    +
      +
    • You can use the Add function to add your own test data to the seed corpus for fuzz testing. The seed corpus is the initial set of inputs that go-fuzz will use to start the fuzzing process.
    • +
    +
  2. +
  3. +

    Fuzz Function:

    +
      +
    • The Fuzz function will be the target function that you want to test using fuzzing. It must have *testing.T as its first argument, similar to regular unit tests.
    • +
    • Additionally, the Fuzz function supports variadic arguments with the following basic data types:
        +
      • string, []byte
      • +
      • int, int8, int16, int32/rune, int64
      • +
      • uint, uint8/byte, uint16, uint32, uint64
      • +
      • float32, float64
      • +
      • bool
      • +
      +
    • +
    +
  4. +
+

These data types represent the different kinds of input data that can be passed to the Fuzz function during the fuzzing process. The fuzzer will generate and mutate inputs of these types to explore different code paths and uncover bugs or unexpected behavior in the target function.

+

In summary, when writing fuzzing functions in Go, remember to use the FuzzXxx naming pattern, accept *testing.F as an argument, utilize the Add function to customize the seed corpus, and use the Fuzz function with supported basic data types to perform fuzz testing on your target functions.

+

You can use the command to execute the fuzz testing:
+

go test -fuzz=<regex> -fuzztime=<duration or times>
+
+# Execute the fuzz testing until it crashs or finding some errors
+go test -fuzz=Fuzz
+
+# Execute the fuzz testing ten iterations
+go test -fuzz=Fuzz -fuzztime=10x
+
+# Execute the fuzz testing twenty seconds
+go test -fuzz=Fuzz -fuzztime=20s
+

+

Simple Example - Division

+

We have developed a very simple function called Division that accepts two arguments, dividend and divisor, and then returns two results: quotient and remainder.

+
func Division(dividend, divisor int32) (
+    quotient, remainder int32,
+) {
+    quotient = dividend / divisor
+    remainder = dividend % divisor
+
+    return
+}
+
+

In the FuzzDivision function, we utilize the data generated by the Go fuzzer to test our Division function.

+
func FuzzDivision(f *testing.F) {
+    f.Fuzz(func(t *testing.T,
+        n1, n2 int32,
+    ) {
+        q, r := Division(n1, n2)
+
+        require.Equal(t, n1, n2*q+r)
+    })
+}
+
+

We expected to see:
+

n1 / n2 = q ... r
+n1 = n2 * q + r
+

+

There should not be any problems with this implementation.

+

Then we can use the following command to start the fuzz testing.

+
go test -fuzz=^FuzzDivision$
+
+

The fuzz testing reports the error "integer divide by zero".

+

+

As a normal user, we understand that the divisor cannot be zero. However, the input data may not always be as expected. This is precisely why we use fuzz testing—to help us find edge cases and uncover unexpected behavior.

+

Go stores the data that caused the fuzz testing to fail. You can check them using the following command.
+ * Note: The file name, 29bf8459dc5d452f64d41eb8a253f6a672939b146b07fcced0b17e99729e9b91, may not be the same.

+
cat testdata/fuzz/FuzzDivision/29bf8459dc5d452f64d41eb8a253f6a672939b146b07fcced0b17e99729e9b91
+
+

The content of the file is as follows:
+

go test fuzz v1
+int32(-7)
+rune('\x00')
+

+

The first line indicates the encoding version, and the subsequent lines represent the argument values that triggered the error during the fuzz testing.

+

Now we can modify our Division function to check the divisor if it is zero.

+
var ErrorDivideByZero = fmt.Errorf("integer divide by zero")
+
+func Division(dividend, divisor int32) (
+    quotient, remainder int32, err error,
+) {
+    if divisor == 0 {
+        err = ErrorDivideByZero
+        return
+    }
+
+    quotient = dividend / divisor
+    remainder = dividend % divisor
+
+    return
+}
+
+

Similarly, the FuzzDivision fuzzing function now checks for the presence of the ErrorDivideByZero error.

+
func FuzzDivision(f *testing.F) {
+    f.Add(int32(67), int32(3))
+
+    f.Fuzz(func(t *testing.T,
+        n1, n2 int32,
+    ) {
+        if q, r, err := Division(n1, n2); err != ErrorDivideByZero {
+            require.Equal(t, n1, n2*q+r)
+        }
+    })
+}
+
+

Now, we can use the following command to re-test the failing case.

+
go test -run=FuzzDivision/29bf8459dc5d452f64d41eb8a253f6a672939b146b07fcced0b17e99729e9b91
+
+

Conclusion for Go Fuzzing

+

We have used a simple example to describe how to develop a fuzzing function in Go and how to leverage the Go command-line tool to execute fuzz testing.

+

Next, we will examine a real case, CVE-2022-43677, and demonstrate the process of developing a fuzzing function to identify edge cases.

+
+

CVE-2022-43677

+

Accroding to the descriptoin:

+
+

In free5GC 3.2.1, a malformed NGAP message can crash the AMF and NGAP decoders via an index-out-of-range panic in aper.GetBitString.

+
+

In response to this vulnerability, we have developed a fuzzing function to test the NGAP decoder.
+The function utilizes two approaches: modifying the NGAP message's content under a valid template or adjusting its format by changing the Information Elements (IEs) with variable lengths.

+
// Put the code under the free5gc/test
+func FuzzNgapDecode(f *testing.F) {
+    f.Fuzz(func(t *testing.T,
+        modifyWhat uint8,
+        changeIe0, changeIe1, changeIe2, changeIe3, changeIe4 bool,
+        valueIe0A uint32,
+        valueIe2ACellId uint64, valueIe2ATac uint32,
+        valueIe3A uint64,
+        valueIe4A uint64,
+        valueIePlmn uint32,
+    ) {
+        var idx, n int
+        var sendMsg []byte
+        var registrationRequest []byte
+        var bs []byte
+        var err error
+        var ngapPdu ngapType.NGAPPDU
+        var mobileIdentity5GS nasType.MobileIdentity5GS
+        var ue *test.RanUeContext
+
+        // New UE
+        ue = test.NewRanUeContext("imsi-2089300007487", 1, security.AlgCiphering128NEA0, security.AlgIntegrity128NIA2,
+            models.AccessType__3_GPP_ACCESS)
+        ue.AmfUeNgapId = 1
+        ue.AuthenticationSubs = test.GetAuthSubscription(TestGenAuthData.MilenageTestSet19.K,
+            TestGenAuthData.MilenageTestSet19.OPC,
+            TestGenAuthData.MilenageTestSet19.OP)
+
+        mobileIdentity5GS = nasType.MobileIdentity5GS{
+            Len:    12, // suci
+            Buffer: []uint8{0x01, 0x02, 0xf8, 0x39, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x47, 0x78},
+        }
+
+        if modifyWhat%2 == DoModifyContent {
+            if changeIe0 {
+                // RAN UE NGAP ID
+                ue.RanUeNgapId = int64(valueIe0A)
+            }
+
+            registrationRequest = nasTestpacket.GetRegistrationRequest(
+                nasMessage.RegistrationType5GSInitialRegistration, mobileIdentity5GS, nil, ue.GetUESecurityCapability(), nil, nil, nil)
+            ngapPdu = ngapTestpacket.BuildInitialUEMessage(ue.RanUeNgapId, registrationRequest, "")
+
+            if changeIe2 {
+                // User Location Information
+                for _, ie := range ngapPdu.InitiatingMessage.Value.InitialUEMessage.ProtocolIEs.List {
+                    if ie.Id.Value == ngapType.ProtocolIEIDUserLocationInformation {
+                        bs = make([]byte, 4)
+                        valueIePlmn &= uint32(PlmnMask)
+                        binary.LittleEndian.PutUint32(bs, valueIePlmn)
+
+                        NgRan := ie.Value.UserLocationInformation.UserLocationInformationNR
+                        NgRan.NRCGI.PLMNIdentity.Value = bs[:PlmnByteLen]
+                        NgRan.TAI.PLMNIdentity.Value = bs[:PlmnByteLen]
+
+                        bs = make([]byte, 8)
+                        valueIe2ACellId &= uint64(CellIdMask)
+                        binary.LittleEndian.PutUint64(bs, valueIe2ACellId)
+                        NgRan.NRCGI.NRCellIdentity.Value.Bytes = bs[:CellIdByteLen]
+
+                        bs = make([]byte, 4)
+                        valueIe2ATac &= uint32(TacMask)
+                        binary.LittleEndian.PutUint32(bs, valueIe2ATac)
+                        NgRan.TAI.TAC.Value = bs[:TacByteLen]
+                    }
+                }
+            }
+            if changeIe3 {
+                // RRC Establishment Cause
+                for _, ie := range ngapPdu.InitiatingMessage.Value.InitialUEMessage.ProtocolIEs.List {
+                    if ie.Id.Value == ngapType.ProtocolIEIDRRCEstablishmentCause {
+                        ie.Value.RRCEstablishmentCause.Value = aper.Enumerated(valueIe3A)
+                    }
+                }
+            }
+            if changeIe4 {
+                // UE Context Request
+                for _, ie := range ngapPdu.InitiatingMessage.Value.InitialUEMessage.ProtocolIEs.List {
+                    if ie.Id.Value == ngapType.ProtocolIEIDUEContextRequest {
+                        ie.Value.UEContextRequest.Value = aper.Enumerated(valueIe4A)
+                    }
+                }
+            }
+            sendMsg, err = ngap.Encoder(ngapPdu)
+        } else if modifyWhat%2 == DoModifyFormat {
+            registrationRequest = nasTestpacket.GetRegistrationRequest(
+                nasMessage.RegistrationType5GSInitialRegistration, mobileIdentity5GS, nil, ue.GetUESecurityCapability(), nil, nil, nil)
+
+            if changeIe1 {
+                registrationRequest[3] += 1
+                registrationRequest = append(registrationRequest, registrationRequest[len(registrationRequest)-1])
+            } else {
+                registrationRequest[3] -= 1
+                registrationRequest = registrationRequest[:len(registrationRequest)-1]
+            }
+
+            ngapPdu = ngapTestpacket.BuildInitialUEMessage(ue.RanUeNgapId, registrationRequest, "")
+            sendMsg, err = ngap.Encoder(ngapPdu)
+            require.Nil(t, err, "Error: %v", err)
+            require.Equal(t, int(sendMsg[3]), len(sendMsg[4:]), "%v", sendMsg)
+
+            idx = bytes.Index(sendMsg, []byte("\x00\x70\x40"))
+            assert.NotEqual(t, idx, -1, "Can not find UE context Request")
+            if idx != -1 {
+                if valueIe4A%8 == 0 || valueIe4A%8 == 1 {
+                    n = 2
+                } else {
+                    n = int(valueIe4A % 8)
+                }
+                sendMsg[idx+3] = uint8(n)
+                sendMsg = sendMsg[:idx+4]
+                bs = make([]byte, 8)
+                binary.LittleEndian.PutUint64(bs, valueIe4A)
+
+                for i := 0; i < n; i++ {
+                    sendMsg = append(sendMsg, bs[i])
+                }
+
+                sendMsg[3] += uint8(n - 1) // total length
+            }
+        }
+        require.Equal(t, int(sendMsg[3]), len(sendMsg[4:]), "%v", sendMsg)
+
+        _, err = ngap.Decoder(sendMsg)
+    })
+}
+
+

We can use the following command to execute the fuzz testing.

+
go test -fuzz=^FuzzNgapDecode$ -run=^FuzzNgapDecode$
+
+

The test resulted in a crash, which confirms the presence of the vulnerability as described in CVE-2022-43677.

+

+

The bug was found in the package aper at version v1.0.4. Fortunately, the latest version of the package has already fixed this issue. To verify the fix, we can update the aper package to the latest commit using the following commands:

+
# Update package aper to the latest commit
+go get github.com/free5gc/aper@main
+
+

After updating the aper package, we can test it again with the fuzzing function:

+

go test -fuzz=^FuzzNgapDecode$ -run=^FuzzNgapDecode$
+

+

+
# Alternatively, re-testing the failing case
+go test -run=FuzzNgapDecode/87af855bbc381c8d510af5ce897fcdd7f9154574e61c0413223f7e31769c2767
+
+

+
+

Conclusion

+

Fuzz testing is a powerful technique for improving the security and reliability of software systems. By subjecting programs to a wide range of inputs, fuzzing can uncover vulnerabilities and defects that might not be found through traditional testing methods. It automates the testing process, making it efficient and scalable for large codebases.

+

In the context of Go programming, Go fuzzing is well-supported and integrates seamlessly with the standard testing framework. Developers can create fuzzing functions to target specific functions and uncover potential issues using random or mutated inputs.

+

To demonstrate the effectiveness of fuzz testing, we presented a real case, CVE-2022-43677, which affected free5GC version 3.2.1. By developing a fuzzing function for the NGAP decoder, we were able to identify a vulnerability that caused a crash.

+

In conclusion, fuzz testing is a critical practice in software development, enabling developers to proactively discover and resolve bugs and vulnerabilities. It empowers them to deliver more secure and robust software systems, providing users with a higher level of confidence in the applications they use. By incorporating fuzz testing as part of the software development lifecycle, developers can significantly enhance the quality and security of their software products.

+
+

Reference

+ +
+

About

+

I'm Yu-Sheng Liu, a master's student at National Yang Ming Chiao Tung University. My research topic focuses on improving the performance of the 5G core network, such as reducing the latency of message propagation in SBI.
+If you have any questions, please don't hesitate to contact me!

+ + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/blog/gPTP_flow.png b/blog/gPTP_flow.png new file mode 100644 index 00000000..fcae2366 Binary files /dev/null and b/blog/gPTP_flow.png differ diff --git a/blog/index.html b/blog/index.html new file mode 100644 index 00000000..01f032ff --- /dev/null +++ b/blog/index.html @@ -0,0 +1,681 @@ + + + + + + + + + + + + + + + + + + Index - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/blog/network_slice/index.html b/blog/network_slice/index.html new file mode 100644 index 00000000..456e3057 --- /dev/null +++ b/blog/network_slice/index.html @@ -0,0 +1,936 @@ + + + + + + + + + + + + + + + + + + How to deploy a free5GC network slice on OpenStack - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +

How to deploy a free5GC network slice on OpenStack

+
+

Note

+

Author: Daniel Hsieh
+Date: 2023/7/26

+
+

What's Network Slicing

+

Network slicing allows for the creation of multiple logical, isolated, and independent virtual networks that can coexist within a shared physical infrastructure. Each network slice provides dedicated and customized network resources to meet the specific requirements of different services
+The main elements of a network slice include:

+
    +
  • +

    Virtualized Network Functions (VNFs): Each network slice can include a set of virtualized network functions that provide specific network capabilities and services. These VNFs can include functions like routing, switching, firewalling, load balancing, or any other network service required by the slice.

    +
  • +
  • +

    Isolation and Resource Allocation: Network slicing ensures the isolation of resources between slices, preventing interference and conflicts. It allows for the allocation of dedicated and optimized resources such as bandwidth, processing power, and storage to each slice based on its specific needs.

    +
  • +
  • +

    Orchestration and Management: Network slice orchestration involves the creation, provisioning, and management of network slices. It involves configuring the appropriate VNFs, assigning resources, and establishing connectivity between the different components of a slice.

    +
  • +
+

+
+

NFV Enabling Network Slicing for 5G

+
+

Take Figure 1 as an example. The first slice is designed for mobile devices such as smartphones. Such slice requires a huge diversity of VNFs, and virtual links with high speed and low latency to support the broadband service of smartphones. In 5G network, Those slices are referred to as eMBB (enhanced mobile broadband) slices.

+

The second slice is designed for autonomous driving. In such scenario, extremely low latency and high reliability are paramount to ensure the vehicles' operability, smoothness and safety. To achieve low latency, some of the NFs should be deployed close to the access node,i.e. on edge cloud. To achieve high reliability, a NF should have multiple instances on available physical resources to make the slice more fault tolerant. Such slice is referred to as URLLC (Ultra-Reliable Low-Latency Communications) slice.

+

The third slice is designed for massive IoT. IoT devices are expected to not move and send very small amount of data intermittently. Due to the nature of such devices, functions that handle mobiltiy and always-on connections are not needed. Such slices are referred to as mIoT (massive IoT) slices.

+

MANO Architecture

+

In this article, we utilize MANO network function virtualization (NFV) architecture to deploy virtual network function (VNF). It plays the role of creating, deploying, and managing VNFs. MANO consists of three main functional components: NFV Orchestrator (NFVO), Virtualized Infrastructure Manager (VIM), and Virtual Network Function Manager (VNFM).

+

+
+

NFV MANO Architecture

+
+
    +
  • +

    NFVO manages the underlying resource by coordinating VIM and VNFM. It handles tasks such as receiving requests, service instantiation, scaling, termination, and monitoring.

    +
  • +
  • +

    VNFM manages the lifecycle of VNF instances. It interacts with the VIM to instantiate, configure, monitor, and terminate VNF instances.

    +
  • +
  • +

    VIM is responsible for managing the underlying virtualized infrastructure that hosts the VNFs. It abstracts the physical resources, such as compute, storage, and networking, and provides a unified view to the NFVO. The VIM handles tasks like resource allocation, performance monitoring, fault management, and virtualization management.

    +
  • +
+

For VIM, we use OpenStack, an open-source software that provides IaaS, to utilize the physical resources. For VNFM and NFVO, we use Tacker, a service component of OpenStack, to manage VNFs.

+

OpenStack

+

OpenStack is an open-source cloud computing platform that provides a set of software tools for building and managing customized clouds. OpenStack offers a infrastructure-as-a-service (IaaS) solution, enabling organizations to create and manage virtualized resources in a cloud environment. It is designed to be modular and consists of various components that work together to deliver a comprehensive cloud computing platform. Some of the key components include:

+
    +
  • +

    Nova: Nova is the computing component of OpenStack and serves as the main compute engine. It manages the creation, scheduling, and management of virtual machines (VMs) and provides APIs for controlling and interacting with the compute resources.

    +
  • +
  • +

    Cinder: Cinder is the block storage component of OpenStack. It provides persistent storage for virtual machines. With Cinder, users can create and manage volumes that can be attached to instances, allowing for flexible and scalable storage options.

    +
  • +
  • +

    Neutron: Neutron is the networking component of OpenStack. It provides a networking-as-a-service (NaaS) solution, allowing users to define and manage network resources. Neutron supports virtual LANs, software-defined networking (SDN), and network function virtualization (NFV), etc.

    +
  • +
  • +

    Keystone: Keystone is the identity service component of OpenStack. It provides authentication and authorization services, enabling users to securely access and manage resources within the cloud. Keystone supports multiple authentication mechanisms, including username/password, token-based, and external identity providers.

    +
  • +
  • +

    Horizon: Horizon is the web-based dashboard for OpenStack. It provides a user-friendly interface for managing and monitoring the cloud infrastructure. With Horizon, users can perform various tasks, such as launching instances, managing storage resources, and configuring networking options.

    +
  • +
+

+
+

OpenStack Architecture

+
+

OpenStack is highly flexible and customizable, allowing organizations to tailor the cloud infrastructure to their specific needs. It supports multiple hypervisors, including KVM, VMware, and Hyper-V.

+

Tacker

+

To enable NFV, we need another service component of OpenStack called Tacker. Tacker is designed to simplify the deployment and lifecycle management of VNFs and network service functions (NSFs) in a cloud infrastructure. It leverages OpenStack's existing components, such as Nova, Neutron, and Heat, to provide a comprehensive solution for network service orchestration.
+Tacker provides several key features and functionalities:

+
    +
  • +

    Service Templates: Tacker uses service templates to define the composition and behavior of network services. These templates describe the VNFs and NSFs involved, their interconnections, resource requirements, etc. Service templates are written using the TOSCA (Topology and Orchestration Specification for Cloud Applications) standard.

    +
  • +
  • +

    Lifecycle Management: Tacker automates the entire lifecycle of network services, including provisioning, scaling, healing, and termination. It leverages Heat, OpenStack's orchestration service, to manage the underlying infrastructure resources required by the services and handle dynamic scaling of VNFs based on traffic demands.

    +
  • +
  • +

    VNF Manager: Tacker includes a VNF Manager component responsible for managing the lifecycle of VNFs. It interacts with OpenStack's compute and networking services, to instantiate and manage VNF instances.

    +
  • +
  • +

    Multi-VIM Support: Tacker supports multiple virtual infrastructure managers to accommodate different cloud platforms and environments. It can interact with OpenStack, VMware vSphere and Kubernetes and so on, enabling operators to deploy network services across heterogeneous infrastructure environments.

    +
  • +
+

+
+

Tacker Architecture

+
+

Deploy a free5GC Network Slice

+
    +
  1. +

    In our implementation, we install OpenStack and Tacker on two different virtual machines for resource utilization reasons, but in fact, they can be installed on the same virtual machine.

    +
  2. +
  3. +

    we need to install OpenStack on a virtual machine. Specific details and corresponding compatibility can be found on OpenStack official website. Using devstack scripts for installation enables operators to customize the environment based on their needs, such as extra plugins (softwares that extends the functionality of OpenStack environment) and overcommit (allows deploying NFs that require more resource than existing physical resourcce) functionality. Upon completion, a web UI enabled by Horizon can be used to access and operate on your own personalized OpenStack cloud.

    +
  4. +
  5. +

    Install Tacker on another virtual machine, which requires four OpenStack service components, Keystone, Mistral, Barbican and Horizon. Once the installation is completed, we can register our OpenStack VIM on Tacker using openstack vim registercommand.

    +
  6. +
  7. +

    Create two instances that will be used as images (one for control plane VNFs, one for UPF) for the VNFs that we will create. Then, ssh into those instances to set up the configurations for the VNFs, such as, installing required packages (go language, mongodb, libtool, etc.) and git clone free5GC source code. Once all the configurations are done, use OpenStack dashboard to take snapshots of these instances, which will be used as the images for VNFs.

    +
  8. +
  9. +

    Import all the VNF descriptors (VNFD) of the VNFs we need by using openstack vnf descriptor create command. VNFDs should be written in accordance with TOSCA format. TOSCA format allows you to define the virtual links (a virtual network VNFs will be running in) and virtual deployment unit (operation unit of a VNF).
    + Below is an example of UPF VNFD:
    +

    tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
    +description: description
    +node_types:
    +  tosca.nodes.nfv.VNF11:
    +    requirements:
    +    - virtualLink1:
    +        type: tosca.nodes.nfv.VL
    +        required: true
    +metadata:
    +  template_name: free5GCSetup
    +topology_template:
    +  substitution_mappings:
    +    node_type: tosca.nodes.nfv.VNF11
    +  node_templates:
    +    VDU1:
    +      type: tosca.nodes.nfv.VDU.Tacker
    +      properties:
    +        name: free5gc-upf1-VNF
    +        image: stage3-up
    +        flavor: free5gc
    +        availability_zone: nova
    +        mgmt_driver: noop
    +        key_name: free5gc
    +        user_data_format: RAW
    +        user_data: |
    +          #!/bin/sh
    +          cd /home/ubuntu/free5gc/src/upf/build 
    +          cat > config/upfcfg.yaml <<- EOM
    +          info:
    +            version: 1.0.0
    +            description: UPF configuration
    +
    +          configuration:
    +            # debugLevel: panic|fatal|error|warn|info|debug|trace
    +            debugLevel: info
    +
    +            pfcp:
    +              - addr: 192.168.2.111
    +
    +            gtpu:
    +              - addr: 192.168.2.111
    +              # [optional] gtpu.name
    +              # - name: upf.5gc.nctu.me
    +              # [optional] gtpu.ifname
    +              # - ifname: gtpif
    +
    +            apn_list:
    +              - apn: internet
    +                cidr: 60.60.0.0/24
    +                # [optional] apn_list[*].natifname
    +                # natifname: eth0
    +          EOM
    +          #sudo ./bin/free5gc-upfd -f config/upfcfg.yaml
    +
    +    CP1:
    +      type: tosca.nodes.nfv.CP.Tacker
    +      properties:
    +        ip_address: 192.168.2.111
    +        management: true
    +      requirements:
    +      - virtualLink:
    +          node: VL1
    +      - virtualBinding:
    +          node: VDU1
    +    VL1:
    +      type: tosca.nodes.nfv.VL
    +      properties:
    +        network_name: 5GC
    +        vendor: Tacker
    +    FIP1:
    +      type: tosca.nodes.network.FloatingIP
    +      properties:
    +        floating_network: public
    +        floating_ip_address: 172.24.4.111
    +      requirements:
    +      - link:
    +          node: CP1
    +

    +
  10. +
  11. Import the network service descriptor (NSD) using openstack ns descriptor create command. The NSD should also be written in accordance with TOSCA format. Once all the VNFDs and NSD are all successfully imported, we can use openstack ns create to deploy the network slice. The VNFs specified in the NSD will also be instantiated along with the network slice. Their instances can be viewed on OpenStack dashboard enabled by Horizon or just use openstack vnf list to check the status of the VNFs.
    + Below is an example of NSD
    +
    tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
    +description: Import Common Slice VNFDs (already on-boarded)
    +imports:
    +  - mongo
    +  - nrf
    +  - amf
    +  - smf
    +  - udr
    +  - pcf
    +  - udm
    +  - nssf
    +  - ausf
    +topology_template:
    +  node_templates:
    +    VNF0:
    +      type: tosca.nodes.nfv.VNF0
    +    VNF1:
    +      type: tosca.nodes.nfv.VNF1
    +    VNF2:
    +      type: tosca.nodes.nfv.VNF2
    +    VNF3:
    +      type: tosca.nodes.nfv.VNF3
    +    VNF4:
    +      type: tosca.nodes.nfv.VNF4
    +    VNF5:
    +      type: tosca.nodes.nfv.VNF5
    +    VNF6:
    +      type: tosca.nodes.nfv.VNF6
    +    VNF7:
    +      type: tosca.nodes.nfv.VNF7
    +    VNF8:
    +      type: tosca.nodes.nfv.VNF8
    +
  12. +
  13. ssh into the VNF instances to make the necessary configuration for each VNF and start the free5GC VNF.
  14. +
  15. Voila! Now we have a fully functional free5GC network slice.
  16. +
+

There are many other ways to set up a network slice. For example, we can deploy VNFs of the same network slice on different VIMs, or we can deploy all the network slices on the same VIM, as long as it is specified in the VNFDs.

+

About

+

Hi, my name is Daniel Hsieh. I am a CS major graduate student. My research field is network slicing. If there are any questions about the article, please feel free to contact.

+
    +
  • email: e657shai@gmail.com
  • +
+

Reference

+
    +
  • +

    https://www.acecloudhosting.com/blog/openstack-the-catalyst-of-the-public-cloud-market/

    +
  • +
  • +

    https://telcocloudbridge.com/blog/a-beginners-guide-to-nfv-management-orchestration-mano/

    +
  • +
  • +

    https://wiki.openstack.org/wiki/Tacker

    +
  • +
  • +

    B. Chatras, U. S. Tsang Kwong and N. Bihannic, "NFV enabling network slicing for 5G," 2017 20th Conference on Innovations in Clouds, Internet and Networks (ICIN), Paris, France, 2017, pp. 219-225, doi: 10.1109/ICIN.2017.7899415.

    +
  • +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/blog/slice-1.png b/blog/slice-1.png new file mode 100644 index 00000000..112620a0 Binary files /dev/null and b/blog/slice-1.png differ diff --git a/blog/slice-2.png b/blog/slice-2.png new file mode 100644 index 00000000..d5e284af Binary files /dev/null and b/blog/slice-2.png differ diff --git a/blog/slice-3.png b/blog/slice-3.png new file mode 100644 index 00000000..251749dd Binary files /dev/null and b/blog/slice-3.png differ diff --git a/blog/slice-4.png b/blog/slice-4.png new file mode 100644 index 00000000..0d164b4c Binary files /dev/null and b/blog/slice-4.png differ diff --git a/blog/slice-5.png b/blog/slice-5.png new file mode 100644 index 00000000..dc0dfeb4 Binary files /dev/null and b/blog/slice-5.png differ diff --git a/blog/time_aware_system.png b/blog/time_aware_system.png new file mode 100644 index 00000000..37c80cf6 Binary files /dev/null and b/blog/time_aware_system.png differ diff --git a/guide/1-1.png b/guide/1-1.png new file mode 100644 index 00000000..20ebd4b5 Binary files /dev/null and b/guide/1-1.png differ diff --git a/guide/1-10.png b/guide/1-10.png new file mode 100644 index 00000000..df39121d Binary files /dev/null and b/guide/1-10.png differ diff --git a/guide/1-11.png b/guide/1-11.png new file mode 100644 index 00000000..3e12c843 Binary files /dev/null and b/guide/1-11.png differ diff --git a/guide/1-12.png b/guide/1-12.png new file mode 100644 index 00000000..ebe8d941 Binary files /dev/null and b/guide/1-12.png differ diff --git a/guide/1-2.png b/guide/1-2.png new file mode 100644 index 00000000..eb2884c6 Binary files /dev/null and b/guide/1-2.png differ diff --git a/guide/1-3.png b/guide/1-3.png new file mode 100644 index 00000000..7847e168 Binary files /dev/null and b/guide/1-3.png differ diff --git a/guide/1-4.png b/guide/1-4.png new file mode 100644 index 00000000..524f703c Binary files /dev/null and b/guide/1-4.png differ diff --git a/guide/1-5.png b/guide/1-5.png new file mode 100644 index 00000000..4054908b Binary files /dev/null and b/guide/1-5.png differ diff --git a/guide/1-6.png b/guide/1-6.png new file mode 100644 index 00000000..8117fa06 Binary files /dev/null and b/guide/1-6.png differ diff --git a/guide/1-7.png b/guide/1-7.png new file mode 100644 index 00000000..ecaba690 Binary files /dev/null and b/guide/1-7.png differ diff --git a/guide/1-8.png b/guide/1-8.png new file mode 100644 index 00000000..a8772f1d Binary files /dev/null and b/guide/1-8.png differ diff --git a/guide/1-9.png b/guide/1-9.png new file mode 100644 index 00000000..9fd9fc6b Binary files /dev/null and b/guide/1-9.png differ diff --git a/guide/1-vm-en/index.html b/guide/1-vm-en/index.html new file mode 100644 index 00000000..b8f34abf --- /dev/null +++ b/guide/1-vm-en/index.html @@ -0,0 +1,785 @@ + + + + + + + + + + + + + + + + + + 1 vm en - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Ubuntu Virtual Machine Installation Demo

+

In this demo, we will

+
    +
  • install VirtualBox
  • +
  • create a Ubuntu Server VM using VirtualBox
  • +
  • use SSH to connect to the Ubuntu VM to install free5GC stage 3
  • +
  • Update and upgrade Ubuntu
  • +
+

1. Install VirtualBox

+

Search virtualbox download, or visit virtualbox.org to download and install VirtualBox (currently 6.1.18) for your operation system.
+

+

Once installed VirtualBox, launch and see if you have something like this:
+

+

2. Download Ubuntu Server

+

Search ubuntu server download on the web and download the latest Ubuntu Server LTS, or visit ubuntu.com, choose Manual Installation Option to download the .iso file (currently 20.04.2 LTS)
+

+

You should have downloaded a .iso image file with name like ubuntu-20.04.1-live-server-amd64.iso, probably in your download directory.
+

+

3. Create a Ubuntu Server VM

+

Launch VirtualBox and create your first Ubuntu VM using the downloaded .iso image file. We use Ubuntu Server instead of Ubuntu Desktop because we only need a basic server machine without too many unnecessary functionalities. The resulting overhead to your host machine is smaller, and the VM starts up faster too.

+
+

Tips

+
    +
  • Name the first VM using a generic name as ubuntu, ubuntu-server, or ubuntu-20.04.
  • +
  • You can pick 1 or 2 (or more) CPUs, and about 2048M memory, although you can change them later.
  • +
  • In addition to the default NAT network interface, also add another “Host-only” network interface.
  • +
+

Refer to the videos Creating VM, Setting up VM.

+
+

3.1 Start Installing Ubuntu

+

Some notes about installing Ubuntu:

+
    +
  • It is recommended that you choose short username and password for ease of typing later
  • +
  • Not choosing LVM will make it a little bit easier later if you want to extend your disk space
  • +
  • Choose to include SSH Server
  • +
  • Let security update complete
  • +
+

Refer to videos Install Ubuntu 1, Install Ubuntu 2.

+

3.2 Log in into Ubuntu

+

Reboot after Ubuntu installation complete; wait a little bit for some initialization steps complete. Then log in with your username and password.
+

+

First try the ifconfig command:
+

ubuntu@ubuntu:~$ ifconfig
+Command 'ifconfig' not found, but can be installed with:
+sudo apt install net-tools
+ubuntu@ubuntu:~$
+

+

If some messages like above show, it means ifconfig has not been installed yet. (ifconfig is no longer installed by defaults in newer Ubuntu, and is replaced by more versatile ip command, but we will use it here for simplicity).

+

Follow its suggestion and install ifconfig:
+

ubuntu@ubuntu:~$ sudo apt install net-tools
+

+Below shows the installation result:
+

+

Run ifconfig again to check the network interfaces:
+

+

Your display may look different, but take notes about the IP address of the Host-only interface card. The example above shows 192.168.56.101. You can SSH from your host machine into this Ubuntu VM using the IP later. (Another IP address, 10.0.2.15 is the IP address of the NAT interface card, the apps in your host machine cannot access it).

+

Finally check if the VM has internet access:
+

ubuntu@ubuntu:~$ ping google.com
+

+

+

Refer to the first part of the video Ping, SSH, and Upgrade.

+

4. Connect to the Ubuntu VM using SSH

+

Launch your favorite SSH client from the host machine.
+Some operation systems (Mac, Ubuntu, some Windows) have pre-installed SSH clients. If you are using Windows, you can also download third-party SSH clients. For example, search “windows ssh download” on the web.

+

The benefit of using SSH is that you can easily copy and paste commands from your machine to Ubuntu VM for execution, and vice versa. You can also create multiple SSH connections with the Ubuntu VM for control and monitoring at the same time.

+

Below shows some examples on a Mac host machine. Suppose the Host-only network IP is 192.168.56.101, and tue username is ubuntu:
+

ssh 192.168.56.101 -l ubuntu
+

+The first time you connect to the VM, your SSH client may show some message asking you for confirmation. Enter yes:
+

+
+

Tips

+

If somehow SSH shows some warning messages telling you the machine has potential security risk, you may have to remove an entry in the file <your home directory>/.ssh/known_hosts related the the IP address.

+
+

If you log in successfully, you will enter a command line interface:
+

+

Repeat the basic commands such as ping, ifconfig to see if the VM is working properly. If so, we can access the Ubuntu VM “remotely” from now on.

+


+

+

5. Update and Upgrade your Ubuntu

+

Let also update and upgrade the Ubuntu VM right now to make sure it is up-to-date with proper security updates.
+

sudo apt update
+sudo apt upgrade
+

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/2-config-vm-en/index.html b/guide/2-config-vm-en/index.html new file mode 100644 index 00000000..b985f7e6 --- /dev/null +++ b/guide/2-config-vm-en/index.html @@ -0,0 +1,807 @@ + + + + + + + + + + + + + + + + + + 2 config vm en - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Creating a free5GC VM and Setting up Network

+

In this demo we will exercise:

+
    +
  • Cloning an existing VM, and install free5GC on it
  • +
  • Setting up the networking for the free5GC VM
  • +
+
+

Tips

+

Refer to video Clone VM and Change IP.

+
+

1. Check up an existing VM for Cloning

+

Launch VirtualBox, and make sure the Ubuntu VM (ubuntu) we created before can boot up, then:

+
    +
  • Log in into the VM using SSH from the host machine, and check if the VM has internet access
  • +
  • Make sure you have done sudo apt update and sudo apt upgrade (or you can do it again)
  • +
  • Shutdown the VM. You can:
  • +
  • use command sudo shutdown -P now, or
  • +
  • click the “Close Window” of the Ubuntu VM terminal and choose the middle option (better not force to turn off the machine power)
  • +
  • later if you just want to reboot, enter sudo shutdown -r now
  • +
+

2. Create a free5GC VM

+

First let’s clone a new VM:

+
    +
  • Select an existing VM (ubuntu) and click the buttons on the right: / Snapshopts / Clone.
  • +
  • Name the new VM free5gc.
  • +
  • The MAC address rule: Create new MAC addresses for all network cards.
  • +
  • Choose the Link cloning option (or you can also choose to complete clone the VM if you like).
  • +
+

After the new VM is created:

+
    +
  • Start up the new free5gc VM, and use the same username and password to log in.
  • +
  • In the Ubuntu terminal, issue ping and ifconfig again to make sure it has internet access, and also make note of the IP address of the Host-only network interface.
      +
    • for example the IP could still be 192.168.56.101, and the interface name is enp0s8.
    • +
    +
  • +
  • Log in into free5gc VM using SSH, and make sure all things working properly.
  • +
+

3. Change hostname

+

The cloned free5gc VM still has host name ubuntu (or the name you gave it in the original VM). Let’s rename the VM to free5gc. You can do this by editing the file /etc/hostname (using vi or nano):
+

sudo nano /etc/hostname
+# or 
+sudo vi /etc/hostname
+

+In the file, change ubuntu into free5gc。If you are using nano ,you can press Ctrl-O to save the file, then Ctrl-X to exit.

+

Let’s also change the file /etc/hosts by replacing the ubuntu inside into free5gc:
+

sudo nano /etc/hosts
+

+

New content of the file /etc/hosts looks like this:
+

127.0.0.1 localhost
+127.0.1.1 free5gc
+...
+

+

The changes will take effect after next reboot.

+

4. Setting Static IP Address

+

The Host-only network interface, by default, gets its IP address through DHCP. The cloned free5gc VM seems to have trouble obtaining new IP address. We can change the host-only interface to use static IP address instead, which can save a lot of trouble later.

+

Here let’s fix the static IP address as 192.168.56.101:
+

$ cd /etc/netplan
+$ ls
+00-installer-config.yaml
+$ cat 00-installer-config.yaml
+

+The original content of the file 00-installer-config.yaml looks like:
+
# This is the network config written by 'subiquity'
+network:
+  ethernets:
+    enp0s3:
+      dhcp4: true
+    enp0s8:
+      dhcp4: true
+  version: 2
+

+meaning the VM has two network interfaces. Using ifconfig we know that enp0s8 is the name of the Host-only network interface. We can edit the file:
+
sudo nano 00-installer-config.yaml
+

+and change it into:
+
# This is the network config written by 'subiquity'
+network:
+  ethernets:
+    enp0s3:
+      dhcp4: true
+    enp0s8:
+      dhcp4: no
+      addresses: [192.168.56.101/24]
+  version: 2
+

+First check if the new content is correct:
+
sudo netplan try
+

+Press enter to exit, if successful. The apply tne new interface setting:
+
sudo netplan apply
+

+Run ifconfig to see if the network setting has been changed correctly:
+
enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
+        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255
+        inet6 fe80::a00:27ff:fec4:254f  prefixlen 64  scopeid 0x20<link>
+        ether 08:00:27:c4:25:4f  txqueuelen 1000  (Ethernet)
+        RX packets 2  bytes 1180 (1.1 KB)
+        RX errors 0  dropped 0  overruns 0  frame 0
+        TX packets 18  bytes 1894 (1.8 KB)
+        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
+        inet 192.168.56.101  netmask 255.255.255.0  broadcast 192.168.56.255
+        inet6 fe80::a00:27ff:fe7e:ada6  prefixlen 64  scopeid 0x20<link>
+        ether 08:00:27:7e:ad:a6  txqueuelen 1000  (Ethernet)
+        RX packets 8420  bytes 531867 (531.8 KB)
+        RX errors 0  dropped 0  overruns 0  frame 0
+        TX packets 10887  bytes 823487 (823.4 KB)
+        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
+        inet 127.0.0.1  netmask 255.0.0.0
+        inet6 ::1  prefixlen 128  scopeid 0x10<host>
+        loop  txqueuelen 1000  (Local Loopback)
+        RX packets 6621  bytes 596035 (596.0 KB)
+        RX errors 0  dropped 0  overruns 0  frame 0
+        TX packets 6621  bytes 596035 (596.0 KB)
+        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+

+We can also check the routing table, just to have a grasp of what is going on regarding the network setting:
+
$ route -n
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
+0.0.0.0         10.0.2.2        0.0.0.0         UG    100    0        0 enp0s3
+10.0.2.0        0.0.0.0         255.255.255.0   U     0      0        0 enp0s3
+10.0.2.2        0.0.0.0         255.255.255.255 UH    100    0        0 enp0s3
+192.168.56.0    0.0.0.0         255.255.255.0   U     0      0        0 enp0s8
+

+

For the display above, we learn that the Host-only network 192.168.56.0/24 does not have internet access by itself (even though we can access it using SSH from the host machine). Internet access is through the NAT network 10.0.2.0/24, with the gateway being 10.0.2.2 (provided by VirtualBox).
+Now we can SSH into free5gc VM using 192.168.56.101:
+

ssh 192.168.56.101 -l ubuntu
+

+This is also how we interact with free5gc VM from now on.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/3-install-free5gc/index.html b/guide/3-install-free5gc/index.html new file mode 100644 index 00000000..2531bf22 --- /dev/null +++ b/guide/3-install-free5gc/index.html @@ -0,0 +1,858 @@ + + + + + + + + + + + + + + + + + + 3 install free5gc - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Installation

+

A. Prerequisites

+
    +
  1. +

    Linux Kernel Version

    +
      +
    • In order to use the UPF element, you must use the 5.0.0-23-generic or 5.4.x version of the Linux kernel. free5gc uses the gtp5g kernel module, which has been tested and compiled against that kernel versions only. If you installed Ubuntu 20.04, the version looks like 5.4.x. To determine the version of the Linux kernel you are using:
    • +
    +
        $ uname -r
    +    5.4.0-65-generic
    +
    +
  2. +
+

You will not be able to run most of the tests in Test section unless you deploy a UPF.

+
    +
  1. +

    Golang Version

    +
      +
    • As noted above, free5gc is built and tested with Go 1.17.8
    • +
    • To check the version of Go on your system, from a command prompt:
    • +
    +
        go version
    +
    +
      +
    • If another version of Go is installed, remove the existing version and install Go 1.17.8:
    • +
    +
        # this assumes your current version of Go is in the default location
    +    sudo rm -rf /usr/local/go
    +    wget https://dl.google.com/go/go1.17.8.linux-amd64.tar.gz
    +    sudo tar -C /usr/local -zxvf go1.17.8.linux-amd64.tar.gz
    +
    +
      +
    • If Go is not installed on your system:
    • +
    +
        wget https://dl.google.com/go/go1.17.8.linux-amd64.tar.gz
    +    sudo tar -C /usr/local -zxvf go1.17.8.linux-amd64.tar.gz
    +    mkdir -p ~/go/{bin,pkg,src}
    +    # The following assume that your shell is bash
    +    echo 'export GOPATH=$HOME/go' >> ~/.bashrc
    +    echo 'export GOROOT=/usr/local/go' >> ~/.bashrc
    +    echo 'export PATH=$PATH:$GOPATH/bin:$GOROOT/bin' >> ~/.bashrc
    +    echo 'export GO111MODULE=auto' >> ~/.bashrc
    +    source ~/.bashrc
    +
    +
      +
    • Further information and installation instructions for golang are available at the official golang site.
    • +
    +
  2. +
  3. +

    Control-plane Supporting Packages

    +
  4. +
+
sudo apt -y update
+sudo apt -y install mongodb wget git
+sudo systemctl start mongodb
+
+
    +
  • +

    WARNING: MongoDB 5.0+ requires a CPU with AVX support. Or downgrade your MongoDB to 4.4

    + +
  • +
  • +

    User-plane Supporting Packages

    +
  • +
+
sudo apt -y update
+sudo apt -y install git gcc g++ cmake autoconf libtool pkg-config libmnl-dev libyaml-dev
+
+
    +
  1. Linux Host Network Settings
  2. +
+
sudo sysctl -w net.ipv4.ip_forward=1
+sudo iptables -t nat -A POSTROUTING -o <dn_interface> -j MASQUERADE
+sudo iptables -A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1400
+sudo systemctl stop ufw
+
+

B. Install Control Plane Elements

+
    +
  1. +

    Clone the free5GC repository

    +
      +
    • To install the latest stable build (v3.3.0):
    • +
    +
        cd ~
    +    git clone --recursive -b v3.3.0 -j `nproc` https://github.com/free5gc/free5gc.git
    +    cd free5gc
    +
    +
      +
    • (Alternatively) to install the latest nightly build:
    • +
    +
        cd ~/free5gc
    +    git checkout main
    +    git submodule sync
    +    git submodule update --init --jobs `nproc`
    +    git submodule foreach git checkout main
    +    git submodule foreach git pull --jobs `nproc`
    +
    +
  2. +
  3. +

    Compile network function services in free5gc

    +
      +
    • To do so individually (e.g., AMF only):
    • +
    +
        cd ~/free5gc
    +    make amf
    +
    +
      +
    • To build all network functions:
    • +
    +
        cd ~/free5gc
    +    make
    +
    +
  4. +
+

C. Install User Plane Function (UPF)

+
    +
  1. As noted above, the GTP kernel module used by the UPF requires that you use Linux kernel version 5.0.0-23-generic or 5.4.x. To verify your version:
  2. +
+
uname -r
+
+
    +
  1. Retrieve the 5G GTP-U kernel module using git and build it
  2. +
+
git clone -b v0.8.1 https://github.com/free5gc/gtp5g.git
+cd gtp5g
+make
+sudo make install
+
+
    +
  1. +

    Build the UPF (you may skip this step if you built all network functions above):

    +
  2. +
  3. +

    to build using make:

    +
  4. +
+
cd ~/free5gc
+make upf
+
+
    +
  1. Customize the UPF as desired. The UPF configuration file in run.sh is free5gc/config/upfcfg.yaml.
  2. +
+

D. Install WebConsole

+
    +
  1. Before building WebConsole, install nodejs and yarn packages first:
  2. +
+
sudo apt remove cmdtest
+sudo apt remove yarn
+curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
+echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
+curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
+sudo apt-get update
+sudo apt-get install -y nodejs yarn
+
+
    +
  1. +

    Build WebConsole

    +
  2. +
  3. +

    to build using make:

    +
  4. +
+
cd ~/free5gc
+make webconsole
+
+
    +
  • (Alternatively) to build manually:
  • +
+
cd ~/free5gc/webconsole/frontend
+yarn install
+yarn build
+rm -rf ../public
+cp -R build ../public
+cd ..
+go build -o bin/webconsole server.go
+
+

Note: 2GB or more of OS memory is recommended. WebConsole may be failed to build if memory is less then 1GB.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/4-test-free5gc/index.html b/guide/4-test-free5gc/index.html new file mode 100644 index 00000000..a3b4e80d --- /dev/null +++ b/guide/4-test-free5gc/index.html @@ -0,0 +1,679 @@ + + + + + + + + + + + + + + + + + + 4 test free5gc - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Test free5GC

+

Start a Wireshark capture on any core-connected interface, applying the filter 'pfcp||icmp||gtp'.

+

In order to run the tests, first do this:

+
cd ~/free5gc
+make upf
+chmod +x ./test.sh
+
+

The tests are all run from within ~/free5gc.

+

a. TestRegistration

+
./test.sh TestRegistration
+
+

b. TestGUTIRegistration

+
./test.sh TestGUTIRegistration
+
+

c. TestServiceRequest

+
./test.sh TestServiceRequest
+
+

d. TestXnHandover

+
./test.sh TestXnHandover
+
+

e. TestDeregistration

+
./test.sh TestDeregistration
+
+

f. TestPDUSessionReleaseRequest

+
./test.sh TestPDUSessionReleaseRequest
+
+

g. TestPaging

+
./test.sh TestPaging
+
+

h. TestN2Handover

+
./test.sh TestN2Handover
+
+

i. TestNon3GPP

+
./test.sh TestNon3GPP
+
+

j. TestReSynchronization

+
./test.sh TestReSynchronization
+
+

k. TestULCL

+
./test_ulcl.sh TestRequestTwoPDUSessions
+
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/5-install-ueransim/index.html b/guide/5-install-ueransim/index.html new file mode 100644 index 00000000..0afd7185 --- /dev/null +++ b/guide/5-install-ueransim/index.html @@ -0,0 +1,949 @@ + + + + + + + + + + + + + + + + + + 5 install ueransim - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Installing UERANSIM - a UE/RAN Simulator

+

In this demo we will practice:

+
    +
  • Installing UERANSIM
  • +
  • Configuring free5GC and UERANSIM
  • +
  • Running UERANSIM against free5GC
  • +
+

1. Install ueramsim VM

+

Repeat the steps of cloning free5gc VM from the base VM, create a new VM for the UERANSIM simulator:

+
    +
  • Name the VM ueransim, and create new MAC addresses for all network cards.
  • +
  • Make sure the VM has internet access and can log in using SSH.
  • +
  • Change the hostname to ueransim.
  • +
  • Make the Host-only network interface have static IP address 192.168.56.102.
  • +
  • Reboot the ueransim VM, as well as the free5gc VM.
  • +
  • You can ping 192.168.56.101 from the ueransim VM, and also ping 192.168.56.102 from the free5gc VM.
  • +
+

2. Install UERANSIM

+

Search “ueransim” on the web, and get the web site.
+On the web site, review what the UERANSIM open-source project is about, then browse into the installation page.

+

To download UERANSIM:
+

cd ~
+git clone https://github.com/aligungr/UERANSIM
+cd UERANSIM
+git checkout 3a96298
+

+

Update and upgrade ueransim VM first:
+

sudo apt update
+sudo apt upgrade
+

+

Install required tools:
+

sudo apt install make
+sudo apt install g++
+sudo apt install libsctp-dev lksctp-tools
+sudo apt install iproute2
+sudo snap install cmake --classic
+

+

Build UERANSIM:
+

cd ~/UERANSIM
+make
+

+

3. Install free5GC WebConsole

+

free5GC provides a simple web tool WebConsole to help creating and managing UE registrations to be used by various 5G network functions (NF). To build WebConsole we need Node.js and Yarn.

+

First SSH into free5gc (192.168.56.101),and remove obsolete tools that may exists:
+

sudo apt remove cmdtest
+sudo apt remove yarn
+

+

Then install Node.js and Yarn:
+

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
+echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
+sudo apt-get update
+sudo apt-get install -y nodejs yarn
+

+

To build WebConsole:
+

cd ~/free5gc
+make webconsole
+

+

4. Use WebConsole to Add an UE

+

First start up the WebConsole server:
+

cd ~/free5gc/webconsole
+go run server.go
+

+

The screen shows the port number :5000 at the end. Open your web browser from your host machine, and enter the URL http://192.168.56.101:5000

+
    +
  • On the login page, enter username admin and password free5gc.
  • +
  • Once logged in, widen the page until you see “Subscribers” on the left-hand side column.
  • +
  • Choose Subscribers and create a new data:
      +
    • Note that other than the “Operator Code Type” field which you should choose “OP” for now, leave other fields unchanged. This registration data is used for ease of testing and actual use later.
    • +
    +
  • +
  • After the data is created successfully, you can press Ctrl-C on the terminal to quit WebConsole.
  • +
+

5. Setting free5GC and UERANSIM Parameters

+

In free5gc VM, we need to edit three files:

+
    +
  • ~/free5gc/config/amfcfg.yaml
  • +
  • ~/free5gc/config/smfcfg.yaml
  • +
  • ~/free5gc/config/upfcfg.yaml
  • +
+

First SSH into free5gc VM, and change ~/free5gc/config/amfcfg.yaml:
+

cd ~/free5gc
+nano config/amfcfg.yaml
+

+

Replace ngapIpList IP from 127.0.0.1 to 192.168.56.101, namely from:
+

...
+  ngapIpList:  # the IP list of N2 interfaces on this AMF
+  - 127.0.0.1
+

+into:
+
...
+  ngapIpList:  # the IP list of N2 interfaces on this AMF
+  - 192.168.56.101  # 127.0.0.1
+

+

Next edit ~/free5gc/config/smfcfg.yaml:
+

nano config/smfcfg.yaml
+

+and in the entry inside userplane_information / up_nodes / UPF / interfaces / endpoints, change the IP from 127.0.0.8 to 192.168.56.101, namely from:
+
...
+  interfaces: # Interface list for this UPF
+   - interfaceType: N3 # the type of the interface (N3 or N9)
+     endpoints: # the IP address of this N3/N9 interface on this UPF
+       - 127.0.0.8
+

+into:
+
...
+  interfaces: # Interface list for this UPF
+   - interfaceType: N3 # the type of the interface (N3 or N9)
+     endpoints: # the IP address of this N3/N9 interface on this UPF
+       - 192.168.56.101  # 127.0.0.8
+

+Finally, edit ~/free5gc/config/upfcfg.yaml,and chage gtpu IP from 127.0.0.8 into 192.168.56.101, namely from:
+
...
+  gtpu:
+    forwarder: gtp5g
+    # The IP list of the N3/N9 interfaces on this UPF
+    # If there are multiple connection, set addr to 0.0.0.0 or list all the addresses
+    ifList:
+      - addr: 127.0.0.8
+        type: N3
+

+into:
+
...
+  gtpu:
+    forwarder: gtp5g
+    # The IP list of the N3/N9 interfaces on this UPF
+    # If there are multiple connection, set addr to 0.0.0.0 or list all the addresses
+    ifList:
+      - addr: 192.168.56.101  # 127.0.0.8
+        type: N3
+

+

6. Setting UERANSIM

+

In the ueransim VM, there are two files related to free5GC:

+
    +
  • ~/UERANSIM/config/free5gc-gnb.yaml
  • +
  • ~/UERANSIM/config/free5gc-ue.yaml
  • +
+

The second file is for UE, which we don’t have to change if the data inside is consistent with the (default) registration data we set using WebConsole previously.

+

First SSH into ueransim, and edit the file ~/UERANSIM/config/free5gc-gnb.yaml, and change the ngapIp IP, as well as the gtpIp IP, from 127.0.0.1 to 192.168.56.102,and also change the IP in amfConfigs into 192.168.56.101, that is, from:
+

...
+  ngapIp: 127.0.0.1   # gNB's local IP address for N2 Interface (Usually same with local IP)
+  gtpIp: 127.0.0.1    # gNB's local IP address for N3 Interface (Usually same with local IP)
+
+  # List of AMF address information
+  amfConfigs:
+    - address: 127.0.0.1
+

+into:
+
...
+  ngapIp: 192.168.56.102  # 127.0.0.1   # gNB's local IP address for N2 Interface (Usually same with local IP)
+  gtpIp: 192.168.56.102  # 127.0.0.1    # gNB's local IP address for N3 Interface (Usually same with local IP)
+
+  # List of AMF address information
+  amfConfigs:
+    - address: 192.168.56.101  # 127.0.0.1
+

+Next we examine the file ~/UERANSIM/config/free5gc-ue.yaml,and see if the settings is consistent with those in free5GC (via WebConsole), for example:
+
# IMSI number of the UE. IMSI = [MCC|MNC|MSISDN] (In total 15 or 16 digits)
+supi: 'imsi-208930000000003'
+# Mobile Country Code value
+mcc: '208'
+# Mobile Network Code value (2 or 3 digits)
+mnc: '93'
+
+# Permanent subscription key
+key: '8baf473f2f8fd09487cccbd7097c6862'
+# Operator code (OP or OPC) of the UE
+op: '8e27b6af0e692e750f32667a3b14605d'
+# This value specifies the OP type and it can be either 'OP' or 'OPC'
+opType: 'OP'
+
+...
+
+# Initial PDU sessions to be established
+sessions:
+  - type: 'IPv4'
+    apn: 'internet'
+    slice:
+      sst: 0x01
+      sd: 0x010203
+
+# List of requested S-NSSAIs by this UE
+slices:
+  - sst: 0x01
+    sd: 0x010203
+
+...
+

+The data appear to be the same as what we set in WebConsole.

+

7. Testing UERANSIM against free5GC

+

SSH into free5gc. If you have rebooted free5gc, remember to do:
+

sudo sysctl -w net.ipv4.ip_forward=1
+sudo iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE
+sudo systemctl stop ufw
+

+

In addition, execute the following command:
+

sudo iptables -I FORWARD 1 -j ACCEPT
+

+

Also, make sure you have make proper changes to the free5GC configuration files, then run ./run.sh:
+

cd ~/free5gc
+./run.sh
+

+

At this time free5GC has been started.

+

Next, prepare three additional SSH terminals from your host machine (if you know how to use tmux, you can use just one).

+

In terminal 1: SSH into ueransim, make sure UERANSIM is built, and configuration files have been changed correctly, then execute nr-gnb:
+

cd ~/UERANSIM
+build/nr-gnb -c config/free5gc-gnb.yaml
+

+

In terminal 2, SSH into ueransim, and execute nr-ue with admin right:
+

cd ~/UERANSIM
+sudo build/nr-ue -c config/free5gc-ue.yaml # for multiple-UEs, use -n and -t for number and delay
+

+

In terminal 3, SSH into ueransim, and ping 192.168.56.101 to see free5gc is alive. Then, use ifconfig to see if the tunnel uesimtun0 has been created (by nr-ue):
+

$ ifconfig
+
+enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
+        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255
+        inet6 fe80::a00:27ff:fe65:1472  prefixlen 64  scopeid 0x20<link>
+        ether 08:00:27:65:14:72  txqueuelen 1000  (Ethernet)
+        RX packets 80  bytes 32423 (32.4 KB)
+        RX errors 0  dropped 0  overruns 0  frame 0
+        TX packets 90  bytes 12860 (12.8 KB)
+        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
+        inet 192.168.56.102  netmask 255.255.255.0  broadcast 192.168.56.255
+        inet6 fe80::a00:27ff:fe5e:be64  prefixlen 64  scopeid 0x20<link>
+        ether 08:00:27:5e:be:64  txqueuelen 1000  (Ethernet)
+        RX packets 1515  bytes 130490 (130.4 KB)
+        RX errors 0  dropped 0  overruns 0  frame 0
+        TX packets 1010  bytes 206670 (206.6 KB)
+        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
+        inet 127.0.0.1  netmask 255.0.0.0
+        inet6 ::1  prefixlen 128  scopeid 0x10<host>
+        loop  txqueuelen 1000  (Local Loopback)
+        RX packets 3445  bytes 174416 (174.4 KB)
+        RX errors 0  dropped 0  overruns 0  frame 0
+        TX packets 3445  bytes 174416 (174.4 KB)
+        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+uesimtun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1500
+        inet 60.60.0.1  netmask 255.255.255.255  destination 60.60.0.1
+        inet6 fe80::2034:d00:a76:84b7  prefixlen 64  scopeid 0x20<link>
+        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)
+        RX packets 3  bytes 252 (252.0 B)
+        RX errors 0  dropped 0  overruns 0  frame 0
+        TX packets 13  bytes 732 (732.0 B)
+        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+

+

Now use ping:
+

ping -I uesimtun0 google.com
+

+If ping gets replies, then free5GC is running properly. Congratulations!

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/6-simple-app/index.html b/guide/6-simple-app/index.html new file mode 100644 index 00000000..f8b59446 --- /dev/null +++ b/guide/6-simple-app/index.html @@ -0,0 +1,823 @@ + + + + + + + + + + + + + + + + + + 6 simple app - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

free5GC Simple Apps

+

In this demo we will use free5GC together with UERANSIM to exercise on some simple network applications:

+
    +
  • ping + tcpdump
  • +
  • wget and curl
  • +
+

ping + tcpdump

+

First start up free5GC and ueransim VMs. This requires one SSH terminal for free5gc, and two for ueransim.

+

Open another SSH terminal and log in into ueransim:
+

ssh 192.168.56.102 -l ubuntu
+

+Use ifconfig to check if uesimtun0 tunnel has been created, and use ping to check if we can ping through it:
+
$ ping google.com
+PING google.com (172.217.27.142) 56(84) bytes of data.
+64 bytes from tsa03s02-in-f14.1e100.net (172.217.27.142): icmp_seq=1 ttl=63 time=3.98 ms
+64 bytes from tsa03s02-in-f14.1e100.net (172.217.27.142): icmp_seq=2 ttl=63 time=3.87 ms
+64 bytes from tsa03s02-in-f14.1e100.net (172.217.27.142): icmp_seq=3 ttl=63 time=4.06 ms
+^C
+--- google.com ping statistics ---
+3 packets transmitted, 3 received, 0% packet loss, time 2003ms
+rtt min/avg/max/mdev = 3.872/3.970/4.060/0.076 ms
+

+
$ ping -I uesimtun0 google.com
+PING google.com (172.217.27.142) from 60.60.0.1 uesimtun0: 56(84) bytes of data.
+64 bytes from tsa03s02-in-f14.1e100.net (172.217.27.142): icmp_seq=1 ttl=61 time=5.85 ms
+64 bytes from tsa03s02-in-f14.1e100.net (172.217.27.142): icmp_seq=2 ttl=61 time=4.87 ms
+64 bytes from tsa03s02-in-f14.1e100.net (172.217.27.142): icmp_seq=3 ttl=61 time=4.76 ms
+^C
+--- google.com ping statistics ---
+3 packets transmitted, 3 received, 0% packet loss, time 2004ms
+rtt min/avg/max/mdev = 4.760/5.160/5.847/0.487 ms
+
+

Also use route -n to observe if current routing table shows some routing rules regarding the two network interfaces enp0s3 and enp0s8:
+

$ route -n
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
+0.0.0.0         10.0.2.2        0.0.0.0         UG    100    0        0 enp0s3
+10.0.2.0        0.0.0.0         255.255.255.0   U     0      0        0 enp0s3
+10.0.2.2        0.0.0.0         255.255.255.255 UH    100    0        0 enp0s3
+192.168.56.0    0.0.0.0         255.255.255.0   U     0      0        0 enp0s8
+

+

The network 10.0.2.0/24 and its enp0s3 interface are related to VirtualBox NAT network card. We can bring down this interface:
+

$ sudo ifconfig enp0s3 down
+$ route -n
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
+192.168.56.0    0.0.0.0         255.255.255.0   U     0      0        0 enp0s8
+

+As shown aboe we have only Host-only network 192.168.56.0/24 left. Run ping again:
+
$ ping 8.8.8.8
+ping: connect: Network is unreachable
+

+

And see that it can not ping through, but runing:
+

$ ping -I uesimtun0 8.8.8.8
+PING 8.8.8.8 (8.8.8.8) from 60.60.0.1 uesimtun0: 56(84) bytes of data.
+64 bytes from 8.8.8.8: icmp_seq=1 ttl=61 time=7.17 ms
+64 bytes from 8.8.8.8: icmp_seq=2 ttl=61 time=5.41 ms
+64 bytes from 8.8.8.8: icmp_seq=3 ttl=61 time=5.15 ms
+^C
+--- 8.8.8.8 ping statistics ---
+3 packets transmitted, 3 received, 0% packet loss, time 2005ms
+rtt min/avg/max/mdev = 5.150/5.907/7.165/0.895 ms
+

+

shows some responses, since we ask ping to go through the free5GC core network. To make ping 8.8.8.8 in addition to ping -I uesimtun0 8.8.8.8 work, we can set the uesimtun0 interface (IP 60.60.0.1) as the new default gateway:
+

$ sudo ip r add default dev uesimtun0
+$ route -n
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
+0.0.0.0         0.0.0.0         0.0.0.0         U     0      0        0 uesimtun0
+192.168.56.0    0.0.0.0         255.255.255.0   U     0      0        0 enp0s8
+

+Now traffic not for the 192.168.56.0/24 network will go to uesimtun0, and ping 8.8.8.8 works this time:
+
$ ping 8.8.8.8
+PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
+64 bytes from 8.8.8.8: icmp_seq=1 ttl=61 time=5.02 ms
+64 bytes from 8.8.8.8: icmp_seq=2 ttl=61 time=6.31 ms
+64 bytes from 8.8.8.8: icmp_seq=3 ttl=61 time=5.41 ms
+^C
+--- 8.8.8.8 ping statistics ---
+3 packets transmitted, 3 received, 0% packet loss, time 2004ms
+rtt min/avg/max/mdev = 5.017/5.581/6.312/0.541 ms
+...
+

+

Note that normally we are using ueransim to simulate “terminal” UE device, not as a network device or proxy, therefore the above two routing rules suffice.

+

Now if we still want to run:
+

$ ping google.com
+ping: google.com: Temporary failure in name resolution
+

+

we will get unresolved domain name. To solve this, we can modify the file /etc/resolv.conf:
+

sudo nano /etc/resolv.conf
+

+

and change the nameserver IP to 8.8.8.8:
+

nameserver 8.8.8.8
+

+

After the change, we can see ping getting responses:
+

$ ping google.com
+PING google.com (216.58.200.46) 56(84) bytes of data.
+64 bytes from tsa01s08-in-f46.1e100.net (216.58.200.46): icmp_seq=1 ttl=61 time=5.19 ms
+64 bytes from tsa01s08-in-f46.1e100.net (216.58.200.46): icmp_seq=2 ttl=61 time=50.4 ms
+64 bytes from tsa01s08-in-f46.1e100.net (216.58.200.46): icmp_seq=3 ttl=61 time=5.66 ms
+^C
+--- google.com ping statistics ---
+3 packets transmitted, 3 received, 0% packet loss, time 2004ms
+rtt min/avg/max/mdev = 5.191/20.423/50.414/21.207 ms
+

+

We can also examine the network traffic happening underneath in the scenario above. First we open another SSH terminal into ueransim, and run the following command:
+

$ sudo tcpdump -n -i any host 60.60.0.1 or 192.168.56.101
+tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
+listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
+

+

then run ping 8.8.8.8 again, wait for a couple seconds, then Ctrl-C to exit. We see the data packets actually going in and out uesimtun0.
+

$ sudo tcpdump -n -i any host 60.60.0.1 or 192.168.56.101
+tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
+listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
+10:24:56.138729 IP 192.168.56.101.38412 > 192.168.56.102.38740: sctp (1) [HB REQ]
+10:24:56.138783 IP 192.168.56.102.38740 > 192.168.56.101.38412: sctp (1) [HB ACK]
+10:24:58.456532 IP 60.60.0.1 > 8.8.8.8: ICMP echo request, id 33, seq 1, length 64
+10:24:58.457416 IP 192.168.56.102.2152 > 192.168.56.101.2152: UDP, length 100
+10:24:58.462136 IP 192.168.56.101.2152 > 192.168.56.102.2152: UDP, length 92
+10:24:58.462324 IP 8.8.8.8 > 60.60.0.1: ICMP echo reply, id 33, seq 1, length 64
+10:24:59.458823 IP 60.60.0.1 > 8.8.8.8: ICMP echo request, id 33, seq 2, length 64
+10:24:59.459031 IP 192.168.56.102.2152 > 192.168.56.101.2152: UDP, length 100
+10:24:59.464214 IP 192.168.56.101.2152 > 192.168.56.102.2152: UDP, length 92
+10:24:59.464396 IP 8.8.8.8 > 60.60.0.1: ICMP echo reply, id 33, seq 2, length 64
+10:25:00.461293 IP 60.60.0.1 > 8.8.8.8: ICMP echo request, id 33, seq 3, length 64
+10:25:00.462178 IP 192.168.56.102.2152 > 192.168.56.101.2152: UDP, length 100
+10:25:00.474941 IP 192.168.56.101.2152 > 192.168.56.102.2152: UDP, length 92
+10:25:00.475561 IP 8.8.8.8 > 60.60.0.1: ICMP echo reply, id 33, seq 3, length 64
+10:25:01.463946 IP 60.60.0.1 > 8.8.8.8: ICMP echo request, id 33, seq 4, length 64
+10:25:01.464523 IP 192.168.56.102.2152 > 192.168.56.101.2152: UDP, length 100
+10:25:01.469297 IP 192.168.56.101.2152 > 192.168.56.102.2152: UDP, length 92
+10:25:01.470314 IP 8.8.8.8 > 60.60.0.1: ICMP echo reply, id 33, seq 4, length 64
+

+

wget

+

Simply look for any web page for file download on the web. For example, if we choose Golang web site as an example, we may find the URL:
+

https://golang.org/dl/go1.15.8.darwin-amd64.pkg
+

+Using the same network settings is the previous exercise, just
+
wget https://golang.org/dl/go1.15.8.darwin-amd64.pkg
+

+And see if you can download a Golang 1.15.8 install file.

+

ptt (ssh bbsu@ptt.cc)

+

You can actually use SSH in the ueransim VM to access remote site. For example, you can SSH to a well-known terminal-based BBS site in Taiwan:
+

ssh bbsu@ppt.cc
+

+

Youtube

+

You can also use Youtube as an example app. To achieve this goal, you can install a desktop VM with graphical UI, such as Ubuntu Desktop, and follow the same procedure to install and start up UERANSIM, then access Youtube through uesimtun0 and free5GC.

+

To reduce resource consumption on your host machine, you may install Lubuntu (at https://lubuntu.me), a more light-weight Ubuntu desktop distro instead. But since viewing free5GC YouTube Channel requires quite sime CPU consumption, you may have to set at least 2 CPUs and 2048 MB memory for the VM.

+

Refer to videos Access Youtube on Lubuntu (1, 2, 3, 4 and 5).

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/Appendix/index.html b/guide/Appendix/index.html new file mode 100644 index 00000000..53c8603a --- /dev/null +++ b/guide/Appendix/index.html @@ -0,0 +1,783 @@ + + + + + + + + + + + + + + + + + + Appendix - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Appendix

+

Appendix A: OAM

+
    +
  1. Run the OAM server
    +
    cd webconsole
    +go run server.go
    +
  2. +
  3. Access the OAM by
    +
    URL: http://localhost:5000
    +Username: admin
    +Password: free5gc
    +
  4. +
  5. Now you can see the information of currently registered UEs (e.g. Supi, connected state, etc.) in the core network at the tab "DASHBOARD" of free5GC webconsole
  6. +
+

Note: You can add the subscribers here too

+

Appendix B: Orchestrator

+

Please refer to free5gmano

+

Appendix C: IPTV

+

Please refer to free5GC/IPTV

+

Appendix D: System Environment Cleaning

+

The below commands may be helpful for development purposes.

+
    +
  1. Remove POSIX message queues
      +
    • ls /dev/mqueue/
    • +
    • rm /dev/mqueue/*
    • +
    +
  2. +
  3. Remove gtp5g tunnels (using tools in libgtp5gnl)
      +
    • cd ./src/upf/lib/libgtp5gnl/tools
    • +
    • ./gtp5g-tunnel list pdr
    • +
    • ./gtp5g-tunnel list far
    • +
    +
  4. +
  5. Remove gtp5g devices (using tools in libgtp5gnl)
      +
    • cd ./src/upf/lib/libgtp5gnl/tools
    • +
    • sudo ./gtp5g-link del {Dev-Name}
    • +
    +
  6. +
+

Appendix E: Change Kernel Version

+
    +
  1. Check the previous kernel version: uname -r
  2. +
  3. Search specific kernel version and install, take 5.0.0-23-generic for example
    +
    sudo apt search 'linux-image-5.0.0-23-generic'
    +sudo apt install 'linux-image-5.0.0-23-generic'
    +sudo apt install 'linux-headers-5.0.0-23-generic'
    +
  4. +
  5. Update initramfs and grub
    +
    sudo update-initramfs -u -k all
    +sudo update-grub
    +
  6. +
  7. Reboot, enter grub and choose kernel version 5.0.0-23-generic
    +
    sudo reboot
    +
  8. +
+

Optional: Remove Kernel Image

+
sudo apt remove 'linux-image-5.0.0-23-generic'
+sudo apt remove 'linux-headers-5.0.0-23-generic'
+
+

Appendix F: Program the SIM Card

+

Install packages:
+

sudo apt-get install pcscd pcsc-tools libccid python-dev swig python-setuptools python-pip libpcsclite-dev
+sudo pip install pycrypto
+

+

Download PySIM
+

git clone git://git.osmocom.org/pysim.git
+

+

Change to pyscard folder and install
+

cd <pyscard-path>
+sudo /usr/bin/python setup.py build_ext install
+

+

Verify your reader is ready

+
sudo pcsc_scan
+
+

Check whether your reader can read the SIM card
+

cd <pysim-path>
+./pySim-read.py –p 0
+

+

Program your SIM card information
+

./pySim-prog.py -p 0 -x 208 -y 93 -t sysmoUSIM-SJS1 -i 208930000000003 --op=8e27b6af0e692e750f32667a3b14605d -k 8baf473f2f8fd09487cccbd7097c6862 -s 8988211000000088313 -a 23605945
+

+

You can get your SIM card from sysmocom. You also need a card reader to write your SIM card. You can get a card reader from here or use other similar devices.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/Configuration/index.html b/guide/Configuration/index.html new file mode 100644 index 00000000..600737c1 --- /dev/null +++ b/guide/Configuration/index.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + + + + + + + Configuration - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Configuration

+

SBI Configuration

+

There are registerIP and bindingIP design on every NF's sbi interface.

+

SBI interface

+

This is due to some orchestration, such as Kubernets or OpenStack, has the design of service IP mapping.

+

Service IP Mapping

+

Use Kubernets as an example. K8S has the service type that enable users to define the service IP outside the pod. But the service IP may be different from the IP assigned inside the pod. Therefore, if we register the binding IP inside the pod to NRF, NRF cannot know which service IP outside the pod has attached. As the result, we need to separate registerIP from bindingIP in this scenario.

+

If you are not sure what IP you should set, just configure it as the same IP address.

+

Sample configuration

+

We provide a sample config to connect to outer ran under /sample/ran_attach_config/. The architecture is as following.

+

free5GC sample config

+

As the result, user's RAN IP must set to 192.168.0.0/24 subnet or let the routing route to this subnet.

+

Notice: If user wants to use the setting, aware to set 192.168.0.1 to your host as well.

+

SMF Configuration

+

A. Configure SMF with S-NSSAI

+
    +
  1. Configure NF Registration SMF S-NSSAI in smfcfg.yaml
  2. +
+

+ +
    +
  1. Configure UE routing path in uerouting.yaml
  2. +
+

+
    +
  • DestinationIP and DestinationPort will be the packet destination.
  • +
  • UPF field will be the packet datapath when it match the destination above.
  • +
+

For more detail of SMF config, please refer to here.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/Environment/index.html b/guide/Environment/index.html new file mode 100644 index 00000000..48916301 --- /dev/null +++ b/guide/Environment/index.html @@ -0,0 +1,671 @@ + + + + + + + + + + + + + + + + + + Environment - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Recommended Environment

+

free5gc has been tested against the following environment:

+
    +
  • Software
      +
    • OS: Ubuntu 20.04.1
    • +
    • gcc 7.3.0
    • +
    • Go 1.14.4 linux/amd64
    • +
    • kernel version 5.4.0-42-generic
    • +
    +
  • +
+

The listed kernel version is required for the UPF element.

+
    +
  • +

    Minimum Hardware

    +
      +
    • CPU: Intel i5 processor
    • +
    • RAM: 4GB
    • +
    • Hard drive: 160GB
    • +
    • NIC: Any 1Gbps Ethernet card supported in the Linux kernel
    • +
    +
  • +
  • +

    Recommended Hardware

    +
      +
    • CPU: Intel i7 processor
    • +
    • RAM: 8GB
    • +
    • Hard drive: 160GB
    • +
    • NIC: Any 10Gbps Ethernet card supported in the Linux kernel
    • +
    +
  • +
+

This guide assumes that you will run all 5GC elements on a single machine.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/New-Subscriber-via-webconsole/index.html b/guide/New-Subscriber-via-webconsole/index.html new file mode 100644 index 00000000..81205728 --- /dev/null +++ b/guide/New-Subscriber-via-webconsole/index.html @@ -0,0 +1,735 @@ + + + + + + + + + + + + + + + + + + New Subscriber via webconsole - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +

New Subscriber via webconsole

+ + + + + +

New Subscriber via webconsole

+

1. Install webconsole

+

2. (Optional)Delete MongoDB

+

If another version of free5GC was ran before, you have to delete MongoDB.

+
$ mongo --eval "db.dropDatabase()" free5gc
+
+

3. Run WebConsole server

+
$ cd ~/free5gc/webconsole
+$ ./bin/webconsole
+
+

4. Use browser to connect to WebConsole

+

Enter :5000 in URL bar.
+

Username: admin
+Password: free5gc
+

+

+

5. Add new subscriber

+
    +
  • Choose SUBSCRIBERS in the left side and press New Subscriber button
  • +
  • Fill the data and press Submit button
  • +
+

+

6. New subscriber is added successfully

+

+

7. Modify the existed subscriber

+

There are some issues for subscriber modification.
+If you want to modify the existed subscriber, please Delete it first and New again for now.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/SMF-Config/index.html b/guide/SMF-Config/index.html new file mode 100644 index 00000000..bde03031 --- /dev/null +++ b/guide/SMF-Config/index.html @@ -0,0 +1,885 @@ + + + + + + + + + + + + + + + + + + SMF Config - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

SMF Config / ULCL Config

+

This document explains the detail of SMF config.
+Also provide some examples about conversion between config file and real userplane topology

+

ULCL limitation:
+The branching UPF now can't connect to the Internet.
+It only serves as a Intranet in the UPF topology.
+(Please refers to the topology of example 2)

+

SBI

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Fieldmeaning
schemeThe protocol for SBI
registerIPv4IP used to register to NRF
bindingIPv4IP used to bind the service
portSMF bind the SBI service to this port
+

PFCP

+ + + + + + + + + + + + + +
Fieldmeaning
addrThe IP address of N4 interface on the SMF (PFCP)
+

Userplane Information

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Fieldmeaning
userplane_informationIncludes topology and information of RAN and UPFs which are controlled by this SMF
up_nodesThe node in the user plane topology. Includes gNodeB, I-UPF and A-UPF
linksThe edge in the user plane topology
typeIndicate it is RAN or specific kind of UPF
node_idThe PFCP IPv4 address for UPF
+

Note:
+up_resource_ip serves as default user plane IP for the UPF.
+In this version, UPF will determine its user plane IP by itself.
+So setting up_resource_ip in SMF config won't affect real config in user plane.

+

AMF Config

+

To understand whole PDU session config, we must take a step forward to understand the AMF config.

+ + + + + + + + + + + + + + + + + +
Fieldmeaning
NGAPIPListThe IP list of N2 interfaces on the AMF
SBISame meaning with SMF/SBI.
+

Example 1

+

SMF Config

+
    +
  • sbi:
      +
    • scheme: http
    • +
    • registerIPv4: 127.0.0.2
    • +
    • bindingIPv4: 127.0.0.2
    • +
    • port: 8000
    • +
    +
  • +
  • pfcp:
      +
    • addr: 10.200.200.1
    • +
    +
  • +
  • userplane_information:
      +
    • up_nodes:
        +
      • gNB1:
          +
        • type: AN
        • +
        +
      • +
      • UPF:
          +
        • type: UPF
        • +
        • node_id: 10.200.200.102
        • +
        +
      • +
      +
    • +
    • links:
        +
      • A: gNB1
      • +
      • B: UPF
      • +
      +
    • +
    +
  • +
+

AMF Config

+
    +
  • ngapIpList:
      +
    • 127.0.0.1
    • +
    +
  • +
  • sbi:
      +
    • scheme: http
    • +
    • registerIPv4: 127.0.0.18
    • +
    • bindingIPv4: 127.0.0.18
    • +
    • port: 8000
    • +
    +
  • +
+

Representing Topology

+

+

Example 2

+

SMF Config

+
    +
  • sbi:
      +
    • scheme: https
    • +
    • registerIPv4: 127.0.0.2
    • +
    • bindingIPv4: 127.0.0.2
    • +
    • port: 29502
    • +
    +
  • +
  • pfcp:
      +
    • addr: 10.200.200.1
    • +
    +
  • +
  • userplane_information:
      +
    • up_nodes:
        +
      • gNB1:
          +
        • type: AN
        • +
        +
      • +
      • BranchingUPF:
          +
        • type: UPF
        • +
        • node_id: 10.200.200.102
        • +
        +
      • +
      • AnchorUPF1:
          +
        • type: UPF
        • +
        • node_id: 10.200.200.101
        • +
        +
      • +
      • AnchorUPF2:
          +
        • type: UPF
        • +
        • node_id: 10.200.200.103
        • +
        +
      • +
      • links:
      • +
      • A: gNB1
        + B: BranchingUPF
      • +
      • A: BranchingUPF
        + B: AnchorUPF1
      • +
      • A: BranchingUPF
        + B: AnchorUPF2
      • +
      +
    • +
    +
  • +
+

AMF Config

+
    +
  • ngapIpList:
      +
    • 127.0.0.1
    • +
    +
  • +
  • sbi:
      +
    • scheme: https
    • +
    • registerIPv4: 127.0.0.18
    • +
    • bindingIPv4: 127.0.0.18
    • +
    • port: 8000
    • +
    +
  • +
+

Representing Topology

+

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/Trouble_Shooting/index.html b/guide/Trouble_Shooting/index.html new file mode 100644 index 00000000..9075844f --- /dev/null +++ b/guide/Trouble_Shooting/index.html @@ -0,0 +1,757 @@ + + + + + + + + + + + + + + + + + + Trouble Shooting - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Trouble Shooting

+

1. ERROR: [SCTP] Failed to connect given AMF N3IWF=NGAP

+

This error occured when N3IWF was started before AMF finishing initialization. This error usually appears when you run the TestNon3GPP in the first time.

+

Rerun the test should be fine. If it still not be solved, larger the sleeping time in line 110 of test.sh.

+

2. TestNon3GPP

+

TestNon3GPP will modify the config/amfcfg.conf. So, if you had killed the TestNon3GPP test before it finished, you might need to copy config/amfcfg.conf.bak back to config/amfcfg.conf to let other tests pass.

+

cp config/amfcfg.conf.bak config/amfcfg.conf

+

3. DB on TLS to H2C

+

If you meet any problems about https or mogodb, it maybe couse our new version from v3.0.1 to v3.0.2 has change http to H2C verion. Try the command below.

+

mongo --eval "db.NfProfile.drop()" free5gc

+

4. MQCreate() Error creating message queue: Too many open files UPF=Util (UPF)

+

Remove POSIX message queues

+
ls /dev/mqueue/
+rm /dev/mqueue/*
+
+

5. Remove gtp devices (using tools in libgtp5gnl) (UPF)

+
cd lib/libgtp5gnl/tools
+sudo ./gtp5g-link del {Dev-Name}
+
+ +
sudo ip link del upfgtp
+
+

7. Decode HTTP/2 packet in Wireshark

+
    +
  1. +

    Run Network Function

    +

    Check has XXFsslkey.log

    +
  2. +
  3. +

    Edit >> Preference >> Protocols >> SSL (TLS)

    +

    +
  4. +
  5. +

    Add keylog

    +

    +
  6. +
  7. +

    Filter http2

    +

    +
  8. +
+

7. Decode H2C (HTTP2 clear text without TLS)

+

The similar reason as NEA0 NAS message. Althrough H2C is clear text, wirshark still considers these packets as the normal TCP packets and does not decode them by HTTP2.

+

To see the details of H2C packets, do the following configuration.

+
    +
  1. +

    Analyze → Decode As…

    +

    +
  2. +
  3. +

    click Add button to add the decode rules

    +

    +

    Decode the packets from the TCP ports listened by each NF as HTTP2 packets.

    +
  4. +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/features/index.html b/guide/features/index.html new file mode 100644 index 00000000..5a92e1c5 --- /dev/null +++ b/guide/features/index.html @@ -0,0 +1,740 @@ + + + + + + + + + + + + + + + + + + Features - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

free5GC Specification

+
    +
  • 3GPP TS 23.501/23.502-Rel-15
  • +
  • 5G Standalone (SA) supported
  • +
  • Serviced-Based Interface (SBI) supported
      +
    • Namf, Nsmf, Nausf, Nudm, Nudr, Nnssf, Nnrf, Npcf
    • +
    +
  • +
  • N1, N2, N3, N4, N6, N9, interfaces supported
  • +
  • 5G SA Network Functions supported:
      +
    • AMF: Access and Mobility Management Function
        +
      • Registration Management, Connection Management, Reachability Management, Mobility Management, and Authentication
      • +
      +
    • +
    • SMF: Session Management Function
        +
      • Session Management, IP Assigning/Management
      • +
      +
    • +
    • UPF: User Plane Function
        +
      • Support multiple UPF and ULCL (uplink classifier)
      • +
      • Session and Service Continuity (SSC) mode 1
      • +
      • Packet Routing/Forwarding
      • +
      +
    • +
    • AUSF: Authentication Server Function
    • +
    • NRF: NF Repository Function
    • +
    • UDM: Unified Data Management
    • +
    • UDR: Unified Data Repository
    • +
    • PCF: Policy and Charging Function
    • +
    • NSSF: Network Slice Selection Function
    • +
    • N3IWF: Non-3GPP Interworking Function
    • +
    +
  • +
+

Supported features

+
    +
  • Registration
      +
    • Initial Registration
    • +
    • Periodic Registration
    • +
    • Mobility Registration
    • +
    +
  • +
  • Authentication
      +
    • 5G-AKA
    • +
    • EAP-AKA'
    • +
    +
  • +
  • NAS Security
      +
    • Ciphering: NEA0, NEA1, NEA2, NEA3
    • +
    • Integrity: NIA0, NIA1, NIA2, NIA3
    • +
    +
  • +
  • Deregistration:
      +
    • UE-initiated Deregistration
    • +
    +
  • +
  • Service Request:
      +
    • UE triggered Service Request
    • +
    • Network Triggered Service Request
    • +
    +
  • +
  • AN Release
  • +
  • PDU Session Establishment
  • +
  • PDU Session Modification (v3.3.0)
  • +
  • PDU Session Release
  • +
  • Handover
      +
    • N2 Handover (Indirect mode not supported)
    • +
    • Xn Handover
    • +
    +
  • +
  • QoS
      +
    • Control Plane only:
        +
      1. 5QI, ARP, GBR, MBR of QoS Flow (v3.3.0)
      2. +
      3. Session-AMBR supported
      4. +
      +
    • +
    +
  • +
  • Collection and reporting of usage data over N4 interface
      +
    • Volume measurement periodically
    • +
    +
  • +
  • UP Security
  • +
  • Multiple UPFs and ULCL (Uplink Classifier)
  • +
  • Multiple Slice and DNN
  • +
  • Dynamic/Static IPv4 address allocation
  • +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/hardware/index.html b/guide/hardware/index.html new file mode 100644 index 00000000..761ed427 --- /dev/null +++ b/guide/hardware/index.html @@ -0,0 +1,668 @@ + + + + + + + + + + + + + + + + + + Hardware - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Hardware Tested

+

Some 5G UE and gNodeB hardware have been tested with free5GC by partners or community members:

+ +

Reports of tested hardware not listed above on Github issue or free5GC forum are welcome.

+

PS: if you don't have any hardware available, we suggest to use UERANSIM to simulate.

+

(Refer to Advanced environment setup section)

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/index.html b/guide/index.html new file mode 100644 index 00000000..25d04a46 --- /dev/null +++ b/guide/index.html @@ -0,0 +1,735 @@ + + + + + + + + + + + + + + + + + + Index - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

User Guide

+

Information

+ +

Roadmap

+

Here are the features on the roadmap. These items are planned to be supported in the near future:

+
    +
  • OAuth on SBA
  • +
  • Charging Function (CHF)
  • +
  • Network Exposure Function (NEF)
  • +
+

free5GC Installation Guide

+

For people who are not familiar with virtual machines and Linux installation, here are some example demonstrations:

+ +

Configuration

+ +

Deployment

+

For Container deployment:

+ +

Others

+ + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..bcda26f3 --- /dev/null +++ b/index.html @@ -0,0 +1,839 @@ + + + + + + + + + + + + + + + + + + + + free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +

Home

+ + + + + + + +

What is free5GC?

+

+

The free5GC is an open-source project for 5th generation (5G) mobile core networks. The ultimate goal of this project is to implement the 5G core network (5GC) defined in 3GPP Release 15 (R15) and beyond.

+

Currently, the major contributors are from National Yang Ming Chiao Tung University (NYCU). Please refer to our roadmap for the features of each release.

+
    +
  • The source code of the latest version of free5GC can be downloaded from here.
  • +
  • Follow our LinkedIn page to get the news about free5GC.
  • +
+
+

Note

+

Thank you very much for your interest in free5GC. The license of free5GC follows Apache 2.0. That is, anyone can use free5GC for commercial purposes for free.

+
+

Sponsors

+

Platinum

+
+ + + + +
+ +

Gold

+
+ +
+ +

Silver

+
+ +
+ +

Hardware Sponsors

+
+ + + + + + +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/membership/index.html b/membership/index.html new file mode 100644 index 00000000..3466c2db --- /dev/null +++ b/membership/index.html @@ -0,0 +1,672 @@ + + + + + + + + + + + + + + + + + + Index - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Sponsorship Info

+

Sponsorship Tiers

+

free5GC is a nonprofit organization dedicated to developing innovative and next-generation features for open-source code of the 5G Core (5GC) Network under Apache 2.0 license. Your generous support and sponsorship will sustain our technology development and the operation of the community. Your company/organization logo will be displayed on the free5GC website and listed as the sponsorship you participate. Here are the sponsorship tiers we offer.

+
    +
  • Sponsor – donation under US $17,000
  • +
  • Bronze Sponsor – donation from US $17,000 to US $34,000
  • +
  • Silver Sponsor – donation from US $34,000 to US $68,000
  • +
  • Gold Sponsor – donation from US $68,000 to US $102,000
  • +
  • Platinum Sponsor – donation for more than US $102,000
  • +
+

Your generosity is appreciated. You can now support free5GC by using your credit cards. Please visit https://fund.nycu.edu.tw/plans/HYnZMprdAGx for donation.

+
+

Tips

+
    +
  • You don’t need to donate to use free5GC. You can download free5GC from https://github.com/free5gc/free5gc.
  • +
  • The license of free5GC follows Apache 2.0. That is, anyone can use free5GC for commercial purposes for free. We will not charge any license fee.
  • +
  • if you have any questions or problems regarding donation and sponsorship, please email us at free5GC.org@gmail.com.
  • +
+
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/publication/index.html b/publication/index.html new file mode 100644 index 00000000..5e431717 --- /dev/null +++ b/publication/index.html @@ -0,0 +1,794 @@ + + + + + + + + + + + + + + + + + + + + + + Relavent Publication - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Publications using free5GC

+

From NYCU

+
    +
  1. V. Jain, H.-T. Chu, S. Qi, C.-A. Lee, H.-C. Chang, C.-Y. Hsieh, K. K. Ramakrishnan, and J.-C. Chen, "L25GC: A Low Latency 5G Core Network based on High-Performance NFV Platforms," full paper, ACM SIGCOMM Conference (SIGCOMM ‘22), (Amsterdam, Netherlands), pp. 143–157, Aug. 2022.
  2. +
  3. C.-Y. Hsieh, Y.-W. Chang, C. Chen, and J.-C. Chen, "Poster: Design and Implementation of a Generic 5G User Plane Function Development Framework," ACM International Conference on Mobile Computing and Networking (MobiCom ‘21), (New Orleans, United States), pp. 846–848, Oct. 2021. (Won second place of the ACM MobiCom 2021 Student Research Competition)
  4. +
  5. Yu-Herng Chai, and Fuchun Joseph Lin, "Evaluating Dedicated Slices of Different Configurations in 5G Core," Computer and Communications, 9(7), p.55-72, 2021.
  6. +
  7. Cheng-Chin Tsai, Fuchun Joseph Lin, and Hiroshige Tanaka, "Evaluation of 5G Core Slicing on User Plane Function," Communications and Network, 13(3), p.79-92, 2021.
  8. +
  9. Wei-Cheng Chang, and Fuchun Joseph Lin, "Coordinated Management of 5G Core Slices by MANO and OSS/BSS," Computer and Communications, 9(6), p.52-72, 2021.
  10. +
  11. Seungjoon Seok, et al, "Towards Service and Networking Intelligence for Humanity: A Report on APNOMS 2020," Network and Systems Management, 29(4), p.1-11, 2021.
  12. +
  13. Yi-Bing Lin, Chien-Chao Tseng, and Ming-Hung Wang, "Effects of Transport Network Slicing on 5G Applications," Future Internet, 13(3), p.69, 2021.
  14. +
  15. Tze-Jie Tan, et al., "A Reliable Intelligent Routing Mechanism in 5G Core Network (5GC)," Annual International Conference on Mobile Computing and Networking, 2020.
  16. +
  17. Chia-Wei Liao, Fuchun Joseph Lin, and Yoichi Sato, "Evaluating NFV-enabled Network Slicing for 5G Core," IEEE Asia-Pacific Network Operations and Management Symposium, 2020.
  18. +
+

Not from NYCU

+
    +
  1. Ralf Kundel, et al., "User plane hardware acceleration in access networks: Experiences in offloading network functions in real 5g deployments," Hawaii International Conference on System Sciences. Computer Society Press, 2022.
  2. +
  3. Taeyun Kim, et al., "An Implementation Study of Network Data Analytic Function in 5G," IEEE International Conference on Consumer Electronics, 2022.
  4. +
  5. Zhou Cong, et al., "CeUPF: Offloading 5G User Plane Function to Programmable Hardware Base on Co-existence Architecture," ACM International Conference on Intelligent Computing and its Emerging Applications, 2021.
  6. +
  7. Gholamreza Ramezan, et al., "EAP-ZKP: A Zero-Knowledge Proof based Authentication Protocol to Prevent DDoS Attacks at the Edge in Beyond 5G," IEEE 4th 5G World Forum, 2021.
  8. +
  9. Ryan Pepito and Ashutosh Dutta, "Open Source 5G Security Testbed for Edge Computing," IEEE 5G World Forum (5GWF), 2021.
  10. +
  11. Robert MacDavid, et al., "A P4-based 5G User Plane Function," 2021.
  12. +
  13. Joe Breen, et al., "Powder: Platform for Open Wireless Data-driven Experimental Research"," Computer Networks, 2021.
  14. +
  15. Endri Goshi, et al,, "Investigating Inter-NF Dependencies in Cloud-Native 5G Core Network," International Conference on Network and Service Management, 2021.
  16. +
  17. Zhi-Li Zhang, et al., "Towards aSoftware-Defined, Fine-Grained QoS Framework for 5G and Beyond Networks," ACM SIGCOMM Workshop on Network-Application Integration, 2021.
  18. +
  19. Zujany Salazar, et al, "5Greplay: a 5G Network Traffic Fuzzer - Application to Attack Injection," International Conference on Availability, Reliability and Security, 2021.
  20. +
  21. M.J. Kim, et al., "Analysis of Current 5G Open-Source Projects," Electronics and Telecommunications Trends, 36(2), p.83-92, 2021.
  22. +
  23. Yang Hu, et al., "Fuzzing Method Based on Selection Mutation of Partition Weight Table for 5G Core Network NGAP Protocol," International Conference on Innovative Mobile and Internet Services in Ubiquitous Computing. Springer, Cham, 2021.
  24. +
  25. Ayoub Bergaoui, et al., "Demonstration of Orchestration of 5G Core Network Functions with a Satellite Emulator," 2021.
  26. +
  27. Dener Kraus, "Computação de borda para indústria utilizando a rede 5G," 2021.
  28. +
  29. Iria Míguez González, "Virtualized cellular networks with native cloud functions," Master Thesis, Telecommunications Engineering School, 2021.
  30. +
  31. Cameron MacLeod, "Kubernetes for the Deployment of Mobile Core Networks," 2020.
  32. +
  33. Alireza Hosseini Vasoukolaei, Danish Sattar, and Ashraf Matrawy, "TLS Performance Evaluation in the Control Plane of a 5G Core Network Slice," 2021.
  34. +
  35. Rui Silva, et al., "A hybrid SDN solution for mobile networks," Computer Networks, 2021.
  36. +
  37. Wei-Lun Lin, Chien-Hsuan Chen, and Huai-Sheng Huang, "Study on the Online Charging System in B5G Era," IEEE Asia-Pacific Network Operations and Management Symposium, 2021.
  38. +
  39. David Lake, et al. ", "Softwarization of 5G Networks – Implications to Open Platforms and Standardizations," IEEE access 9, 2021.
  40. +
  41. Ali Esmaeily, and Katina Kralevska, "Small-Scale 5G Testbeds for Network Slicing Deployment: A Systematic Review," Wireless Communications and Mobile Computing, 2021.
  42. +
  43. Ashok Kumar Murthy, Ranjani Parthasarathi, and V. Vetriselvi, "Security Testbed for Next Generation Mobile Networks," IEEE Third ISEA Conference on Security and Privacy, p.122-129, 2020.
  44. +
  45. Merlin Chlosta, et al., "5G SUCI-Catchers: Still catching them all?" Annual International Conference on Mobile Computing and Networking, 2020.
  46. +
  47. Žiga Berčič, et al., "Raziskava in praktični preizkus odprtokodnih mobilnih jedrnih sistemov 4G in 5G," Diss. Univerza v Ljubljani, Fakulteta za elektrotehniko, 2020.
  48. +
  49. Christian Mailer, "Plataforma de CORE 5G em nuvem para disponibilização de funções de rede como serviço," 2020.
  50. +
  51. Leonardo Bonati, et al., "Open, Programmable, and Virtualized 5G Networks: State-of-the-Art and the Road Ahead," Computer Networks, 2020.
  52. +
  53. Hung-Yen Weng, Ren-Hung Hwang, and Chin-Feng Lai, "Live MPEG-DASH video streaming cache management with cognitive mobile edge computing," Ambient Intelligence and Humanized Computing p.1-18, 2020.
  54. +
  55. Junaid Jalal, "Enabling Edge Computing In 5G Via Local Area Data Network: Implementation and Experiments," Master Thesis, University of Agder, 2019.
  56. +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 00000000..b120b77d --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":""},{"location":"#what-is-free5gc","title":"What is free5GC?","text":"

The free5GC is an open-source project for 5th generation (5G) mobile core networks. The ultimate goal of this project is to implement the 5G core network (5GC) defined in 3GPP Release 15 (R15) and beyond.

Currently, the major contributors are from National Yang Ming Chiao Tung University (NYCU). Please refer to our roadmap for the features of each release.

  • The source code of the latest version of free5GC can be downloaded from here.
  • Follow our LinkedIn page to get the news about free5GC.

Note

Thank you very much for your interest in free5GC. The license of free5GC follows Apache 2.0. That is, anyone can use free5GC for commercial purposes for free.

"},{"location":"#sponsors","title":"Sponsors","text":""},{"location":"#platinum","title":"Platinum","text":""},{"location":"#gold","title":"Gold","text":""},{"location":"#silver","title":"Silver","text":""},{"location":"#hardware-sponsors","title":"Hardware Sponsors","text":""},{"location":"publication/","title":"Relavent Publication","text":""},{"location":"publication/#publications-using-free5gc","title":"Publications using free5GC","text":""},{"location":"publication/#from-nycu","title":"From NYCU","text":"
  1. V. Jain, H.-T. Chu, S. Qi, C.-A. Lee, H.-C. Chang, C.-Y. Hsieh, K. K. Ramakrishnan, and J.-C. Chen, \"L25GC: A Low Latency 5G Core Network based on High-Performance NFV Platforms,\" full paper, ACM SIGCOMM Conference (SIGCOMM \u201822), (Amsterdam, Netherlands), pp. 143\u2013157, Aug. 2022.
  2. C.-Y. Hsieh, Y.-W. Chang, C. Chen, and J.-C. Chen, \"Poster: Design and Implementation of a Generic 5G User Plane Function Development Framework,\" ACM International Conference on Mobile Computing and Networking (MobiCom \u201821), (New Orleans, United States), pp. 846\u2013848, Oct. 2021. (Won second place of the ACM MobiCom 2021 Student Research Competition)
  3. Yu-Herng Chai, and Fuchun Joseph Lin, \"Evaluating Dedicated Slices of Different Configurations in 5G Core,\" Computer and Communications, 9(7), p.55-72, 2021.
  4. Cheng-Chin Tsai, Fuchun Joseph Lin, and Hiroshige Tanaka, \"Evaluation of 5G Core Slicing on User Plane Function,\" Communications and Network, 13(3), p.79-92, 2021.
  5. Wei-Cheng Chang, and Fuchun Joseph Lin, \"Coordinated Management of 5G Core Slices by MANO and OSS/BSS,\" Computer and Communications, 9(6), p.52-72, 2021.
  6. Seungjoon Seok, et al, \"Towards Service and Networking Intelligence for Humanity: A Report on APNOMS 2020,\" Network and Systems Management, 29(4), p.1-11, 2021.
  7. Yi-Bing Lin, Chien-Chao Tseng, and Ming-Hung Wang, \"Effects of Transport Network Slicing on 5G Applications,\" Future Internet, 13(3), p.69, 2021.
  8. Tze-Jie Tan, et al., \"A Reliable Intelligent Routing Mechanism in 5G Core Network (5GC),\" Annual International Conference on Mobile Computing and Networking, 2020.
  9. Chia-Wei Liao, Fuchun Joseph Lin, and Yoichi Sato, \"Evaluating NFV-enabled Network Slicing for 5G Core,\" IEEE Asia-Pacific Network Operations and Management Symposium, 2020.
"},{"location":"publication/#not-from-nycu","title":"Not from NYCU","text":"
  1. Ralf Kundel, et al., \"User plane hardware acceleration in access networks: Experiences in offloading network functions in real 5g deployments,\" Hawaii International Conference on System Sciences. Computer Society Press, 2022.
  2. Taeyun Kim, et al., \"An Implementation Study of Network Data Analytic Function in 5G,\" IEEE International Conference on Consumer Electronics, 2022.
  3. Zhou Cong, et al., \"CeUPF: Offloading 5G User Plane Function to Programmable Hardware Base on Co-existence Architecture,\" ACM International Conference on Intelligent Computing and its Emerging Applications, 2021.
  4. Gholamreza Ramezan, et al., \"EAP-ZKP: A Zero-Knowledge Proof based Authentication Protocol to Prevent DDoS Attacks at the Edge in Beyond 5G,\" IEEE 4th 5G World Forum, 2021.
  5. Ryan Pepito and Ashutosh Dutta, \"Open Source 5G Security Testbed for Edge Computing,\" IEEE 5G World Forum (5GWF), 2021.
  6. Robert MacDavid, et al., \"A P4-based 5G User Plane Function,\" 2021.
  7. Joe Breen, et al., \"Powder: Platform for Open Wireless Data-driven Experimental Research\",\" Computer Networks, 2021.
  8. Endri Goshi, et al,, \"Investigating Inter-NF Dependencies in Cloud-Native 5G Core Network,\" International Conference on Network and Service Management, 2021.
  9. Zhi-Li Zhang, et al., \"Towards aSoftware-Defined, Fine-Grained QoS Framework for 5G and Beyond Networks,\" ACM SIGCOMM Workshop on Network-Application Integration, 2021.
  10. Zujany Salazar, et al, \"5Greplay: a 5G Network Traffic Fuzzer - Application to Attack Injection,\" International Conference on Availability, Reliability and Security, 2021.
  11. M.J. Kim, et al., \"Analysis of Current 5G Open-Source Projects,\" Electronics and Telecommunications Trends, 36(2), p.83-92, 2021.
  12. Yang Hu, et al., \"Fuzzing Method Based on Selection Mutation of Partition Weight Table for 5G Core Network NGAP Protocol,\" International Conference on Innovative Mobile and Internet Services in Ubiquitous Computing. Springer, Cham, 2021.
  13. Ayoub Bergaoui, et al., \"Demonstration of Orchestration of 5G Core Network Functions with a Satellite Emulator,\" 2021.
  14. Dener Kraus, \"Computa\u00e7\u00e3o de borda para ind\u00fastria utilizando a rede 5G,\" 2021.
  15. Iria M\u00edguez Gonz\u00e1lez, \"Virtualized cellular networks with native cloud functions,\" Master Thesis, Telecommunications Engineering School, 2021.
  16. Cameron MacLeod, \"Kubernetes for the Deployment of Mobile Core Networks,\" 2020.
  17. Alireza Hosseini Vasoukolaei, Danish Sattar, and Ashraf Matrawy, \"TLS Performance Evaluation in the Control Plane of a 5G Core Network Slice,\" 2021.
  18. Rui Silva, et al., \"A hybrid SDN solution for mobile networks,\" Computer Networks, 2021.
  19. Wei-Lun Lin, Chien-Hsuan Chen, and Huai-Sheng Huang, \"Study on the Online Charging System in B5G Era,\" IEEE Asia-Pacific Network Operations and Management Symposium, 2021.
  20. David Lake, et al. \", \"Softwarization of 5G Networks \u2013 Implications to Open Platforms and Standardizations,\" IEEE access 9, 2021.
  21. Ali Esmaeily, and Katina Kralevska, \"Small-Scale 5G Testbeds for Network Slicing Deployment: A Systematic Review,\" Wireless Communications and Mobile Computing, 2021.
  22. Ashok Kumar Murthy, Ranjani Parthasarathi, and V. Vetriselvi, \"Security Testbed for Next Generation Mobile Networks,\" IEEE Third ISEA Conference on Security and Privacy, p.122-129, 2020.
  23. Merlin Chlosta, et al., \"5G SUCI-Catchers: Still catching them all?\" Annual International Conference on Mobile Computing and Networking, 2020.
  24. \u017diga Ber\u010di\u010d, et al., \"Raziskava in prakti\u010dni preizkus odprtokodnih mobilnih jedrnih sistemov 4G in 5G,\" Diss. Univerza v Ljubljani, Fakulteta za elektrotehniko, 2020.
  25. Christian Mailer, \"Plataforma de CORE 5G em nuvem para disponibiliza\u00e7\u00e3o de fun\u00e7\u00f5es de rede como servi\u00e7o,\" 2020.
  26. Leonardo Bonati, et al., \"Open, Programmable, and Virtualized 5G Networks: State-of-the-Art and the Road Ahead,\" Computer Networks, 2020.
  27. Hung-Yen Weng, Ren-Hung Hwang, and Chin-Feng Lai, \"Live MPEG-DASH video streaming cache management with cognitive mobile edge computing,\" Ambient Intelligence and Humanized Computing p.1-18, 2020.
  28. Junaid Jalal, \"Enabling Edge Computing In 5G Via Local Area Data Network: Implementation and Experiments,\" Master Thesis, University of Agder, 2019.
"},{"location":"videos/","title":"Other Videos","text":""},{"location":"videos/#other-videos-showing-free5gc","title":"Other videos showing free5GC","text":"
  1. Akraino Blueprints: Integrated Cloud Native Private Wireless, The Linux Foundation, October 11, 2021

  2. SD Core Techinar July 7 2021, Open Networking Foundation, July 13, 2021

  3. Aarna Networks MWC 2021 Demo, Aarna Networks Channel, June 27, 2021

  4. OpenStack Tacker Demo, Open Infrastructure Foundation, April 26, 2021

  5. OpenNess Tungsten Fabric free5GC demo, Aarna Networks Channel, February 16, 2021

  6. 5G Core on Diamanti, Diamanti, Inc., February 3, 2021

  7. free5GC (5G Core) Orchestration on Kubernetes with Tungsten Fabric CNI and Testing, Aarna Networks Channel, December 2, 2020

  8. IoT LoRa (sensors and gateway in hardware), RAN in hardware (SDR) and software, and the free5GC, LABORA Research Group, July 3, 2020

  9. UE and eNodeB in Hardware (conventional cell phone + SDR) and free5GC: a pratical approach in 5G, LABORA Research Group, July 3, 2020

  10. OpenAirInterface and free5GC: a pratical approach in 5G networks, LABORA Research Group, June 29, 2020

"},{"location":"blog/","title":"Index","text":""},{"location":"blog/#blogs","title":"Blogs","text":""},{"location":"blog/#official","title":"Official","text":"
  • 2023/8/23: Web security: CSRF vulnerability in webconsole
  • 2023/8/16: Introduce Kubernetes and Deployment free5GC on Kubernetes with helm
  • 2023/8/9: Fuzz Testing in Go: Discovering Vulnerabilities and Analyzing a Real Case (CVE-2022-43677)
  • 2023/8/2: Authentication Mechanism in NRF: What Is OAuth?
  • 2023/7/26: How to deploy free5GC network slice on OpenStack
  • 2023/7/19: Network function UDM introduction
  • 2023/7/12: Time-Sensitive Networking over 5G system - Introduction (Rel-16)
  • 2023/7/5: Use network namespace to separate the 5GC and RAN simulator
  • 2023/6/21: 5G SCTP LoadBalancer Using LoxiLB Applying on free5GC
"},{"location":"blog/#external","title":"External","text":"
  • free5GC 5GC & UERANSIM UE / RAN Sample Configuration - VPP-UPF with DPDK
  • Deploy eBPF-based UPF with free5GC
  • Introduce to 5GC (written in traditional chinese)
  • Deploying 5G core network with Free5GC, Kubernetes and Helm
  • Running Free5GC on Platform9 Managed Kubernetes
"},{"location":"blog/1-free5gc-with-namespace/","title":"1 free5gc with namespace","text":""},{"location":"blog/1-free5gc-with-namespace/#use-network-namespace-to-separate-the-5g-core-5gc-and-ran-simulator","title":"Use network namespace to separate the 5G core (5GC) and RAN simulator","text":"

Note

Author: Jimmy Chang Date: 2023/7/5

"},{"location":"blog/1-free5gc-with-namespace/#overview","title":"Overview","text":"

This technique leverages namespace to run UERANSIM, an opensource 5G-UE and RAN(gNodeB) simulator, and connect to free5GC. UERANSIM follows the 3GPP specification for developing and can support multiple 5G core (5GC) including free5GC.

Why are we using namespace? Well, you can follow ULCL and free5GC compose to set up the environment with VM and docker, but there are limitations for hardware\u2019s capability. With network namespace, you can have different and separate network instances of network interfaces and routing tables that operate independently.

So, what is network namespace? Network namespace makes a copy of network stack with its own routing table, firewall and devices. A named network namespace is an object at /var/run/netns/. The file descriptor resulting from opening /var/run/netns/ refers to the specified network namespace. Holding that file descriptor open keeps the network namespace alive.

And how to make both namespaces communicating? A virtual Ethernet device (veth) pair provides the abstraction that can be used to create tunnels between network namespaces, and can be used to create bridge to a physical network device in another namespace. Veth pair also be used as standalone network devices. When the namespace freed, veth device which attatch to would be destroyed.

The environment is as follow. Suppose you have already installed as well as set up free5GC and UERANSIM properly.

  • free5GC v3.3.0
  • UERANSIM v3.1.0

Note

Namespace free5GC represents host network namespace. And enp0s5 is an ethernet interface connectting to external.

Each devices as follow\n| Device        | IP             |\n| ------------- | -------------  |\n| veth0         | 10.200.200.1   |\n| veth1         | 10.200.200.2   |\n| br-veth0      | none           |\n| br-veth1      | none           |\n| enp0s5        | 10.211.55.23   |\n\n\nUE information in UERANSIM as follow. Already \n| IMSI             | DNN           |\n| ---------------- | ------------- |\n| 208930000000003  | internet      |\n
"},{"location":"blog/1-free5gc-with-namespace/#configuration-file-of-free5gc-and-ueransim","title":"Configuration file of free5GC and UERANSIM","text":""},{"location":"blog/1-free5gc-with-namespace/#free5gc","title":"free5GC","text":"
  • free5gc/config/amfcfg.yaml

Replace ngapIpList IP from 127.0.0.18 to 10.200.200.2:

info:\nversion: 1.0.9\ndescription: AMF initial local configuration\n\nconfiguration:\namfName: AMF # the name of this AMF\nngapIpList:  # the IP list of N2 interfaces on this AMF\n- 10.200.200.2 # 127.0.0.18\nngapPort: 38412 # the SCTP port listened by NGAP\nsbi: # Service-based interface information\nscheme: http # the protocol for sbi (http or https)\nregisterIPv4: 127.0.0.18 # IP used to register to NRF\nbindingIPv4: 127.0.0.18  # IP used to bind the service\nport: 8000 # port used to bind the service\ntls: # the local path of TLS key\npem: cert/amf.pem # AMF TLS Certificate\nkey: cert/amf.key # AMF TLS Private key\nserviceNameList: # the SBI services provided by this AMF, refer to TS 29.518\n- namf-comm # Namf_Communication service\n- namf-evts # Namf_EventExposure service\n- namf-mt   # Namf_MT service\n- namf-loc  # Namf_Location service\n- namf-oam  # OAM service\nservedGuamiList: # Guami (Globally Unique AMF ID) list supported by this AMF\n# <GUAMI> = <MCC><MNC><AMF ID>\n- plmnId: # Public Land Mobile Network ID, <PLMN ID> = <MCC><MNC>\nmcc: 208 # Mobile Country Code (3 digits string, digit: 0~9)\nmnc: 93 # Mobile Network Code (2 or 3 digits string, digit: 0~9)\namfId: cafe00 # AMF identifier (3 bytes hex string, range: 000000~FFFFFF)\nsupportTaiList:  # the TAI (Tracking Area Identifier) list supported by this AMF\n- plmnId: # Public Land Mobile Network ID, <PLMN ID> = <MCC><MNC>\nmcc: 208 # Mobile Country Code (3 digits string, digit: 0~9)\nmnc: 93 # Mobile Network Code (2 or 3 digits string, digit: 0~9)\ntac: 000001 # Tracking Area Code (3 bytes hex string, range: 000000~FFFFFF)\nplmnSupportList: # the PLMNs (Public land mobile network) list supported by this AMF\n- plmnId: # Public Land Mobile Network ID, <PLMN ID> = <MCC><MNC>\nmcc: 208 # Mobile Country Code (3 digits string, digit: 0~9)\nmnc: 93 # Mobile Network Code (2 or 3 digits string, digit: 0~9)\nsnssaiList: # the S-NSSAI (Single Network Slice Selection Assistance Information) list supported by this AMF\n- sst: 1 # Slice/Service Type (uinteger, range: 0~255)\nsd: 010203 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)\n- sst: 1 # Slice/Service Type (uinteger, range: 0~255)\nsd: 112233 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)\nsupportDnnList:  # the DNN (Data Network Name) list supported by this AMF\n- internet\nnrfUri: http://127.0.0.10:8000 # a valid URI of NRF\nsecurity:  # NAS security parameters\nintegrityOrder: # the priority of integrity algorithms\n- NIA2\n# - NIA0\ncipheringOrder: # the priority of ciphering algorithms\n- NEA0\n# - NEA2\nnetworkName:  # the name of this core network\nfull: free5GC\nshort: free\nngapIE: # Optional NGAP IEs\nmobilityRestrictionList: # Mobility Restriction List IE, refer to TS 38.413\nenable: true # append this IE in related message or not\nmaskedIMEISV: # Masked IMEISV IE, refer to TS 38.413\nenable: true # append this IE in related message or not\nredirectionVoiceFallback: # Redirection Voice Fallback IE, refer to TS 38.413\nenable: false # append this IE in related message or not\nnasIE: # Optional NAS IEs\nnetworkFeatureSupport5GS: # 5gs Network Feature Support IE, refer to TS 24.501\nenable: true # append this IE in Registration accept or not\nlength: 1 # IE content length (uinteger, range: 1~3)\nimsVoPS: 0 # IMS voice over PS session indicator (uinteger, range: 0~1)\nemc: 0 # Emergency service support indicator for 3GPP access (uinteger, range: 0~3)\nemf: 0 # Emergency service fallback indicator for 3GPP access (uinteger, range: 0~3)\niwkN26: 0 # Interworking without N26 interface indicator (uinteger, range: 0~1)\nmpsi: 0 # MPS indicator (uinteger, range: 0~1)\nemcN3: 0 # Emergency service support indicator for Non-3GPP access (uinteger, range: 0~1)\nmcsi: 0 # MCS indicator (uinteger, range: 0~1)\nt3502Value: 720  # timer value (seconds) at UE side\nt3512Value: 3600 # timer value (seconds) at UE side\nnon3gppDeregTimerValue: 3240 # timer value (seconds) at UE side\n# retransmission timer for paging message\nt3513:\nenable: true     # true or false\nexpireTime: 6s   # default is 6 seconds\nmaxRetryTimes: 4 # the max number of retransmission\n# retransmission timer for NAS Deregistration Request message\nt3522:\nenable: true     # true or false\nexpireTime: 6s   # default is 6 seconds\nmaxRetryTimes: 4 # the max number of retransmission\n# retransmission timer for NAS Registration Accept message\nt3550:\nenable: true     # true or false\nexpireTime: 6s   # default is 6 seconds\nmaxRetryTimes: 4 # the max number of retransmission\n# retransmission timer for NAS Authentication Request/Security Mode Command message\nt3560:\nenable: true     # true or false\nexpireTime: 6s   # default is 6 seconds\nmaxRetryTimes: 4 # the max number of retransmission\n# retransmission timer for NAS Notification message\nt3565:\nenable: true     # true or false\nexpireTime: 6s   # default is 6 seconds\nmaxRetryTimes: 4 # the max number of retransmission\n# retransmission timer for NAS Identity Request message\nt3570:\nenable: true     # true or false\nexpireTime: 6s   # default is 6 seconds\nmaxRetryTimes: 4 # the max number of retransmission\nlocality: area1 # Name of the location where a set of AMF, SMF, PCF and UPFs are located\nsctp: # set the sctp server setting <optinal>, once this field is set, please also add maxInputStream, maxOsStream, maxAttempts, maxInitTimeOut\nnumOstreams: 3 # the maximum out streams of each sctp connection\nmaxInstreams: 5 # the maximum in streams of each sctp connection\nmaxAttempts: 2 # the maximum attempts of each sctp connection\nmaxInitTimeout: 2 # the maximum init timeout of each sctp connection\ndefaultUECtxReq: false # the default value of UE Context Request to decide when triggering Initial Context Setup procedure\n\nlogger: # log output setting\nenable: true # true or false\nlevel: info # how detailed to output, value: trace, debug, info, warn, error, fatal, panic\nreportCaller: false # enable the caller report or not, value: true or false\n
- free5gc/config/smfcfg.yaml

Replace userplaneInformation / upNodes / UPF / interfaces / endpoints from 127.0.0.8 to 10.200.200.2:

info:\nversion: 1.0.7\ndescription: SMF initial local configuration\n\nconfiguration:\nsmfName: SMF # the name of this SMF\nsbi: # Service-based interface information\nscheme: http # the protocol for sbi (http or https)\nregisterIPv4: 127.0.0.2 # IP used to register to NRF\nbindingIPv4: 127.0.0.2 # IP used to bind the service\nport: 8000 # Port used to bind the service\ntls: # the local path of TLS key\nkey: cert/smf.key # SMF TLS Certificate\npem: cert/smf.pem # SMF TLS Private key\nserviceNameList: # the SBI services provided by this SMF, refer to TS 29.502\n- nsmf-pdusession # Nsmf_PDUSession service\n- nsmf-event-exposure # Nsmf_EventExposure service\n- nsmf-oam # OAM service\nsnssaiInfos: # the S-NSSAI (Single Network Slice Selection Assistance Information) list supported by this AMF\n- sNssai: # S-NSSAI (Single Network Slice Selection Assistance Information)\nsst: 1 # Slice/Service Type (uinteger, range: 0~255)\nsd: 010203 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)\ndnnInfos: # DNN information list\n- dnn: internet # Data Network Name\ndns: # the IP address of DNS\nipv4: 8.8.8.8\nipv6: 2001:4860:4860::8888\n- sNssai: # S-NSSAI (Single Network Slice Selection Assistance Information)\nsst: 1 # Slice/Service Type (uinteger, range: 0~255)\nsd: 112233 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)\ndnnInfos: # DNN information list\n- dnn: internet # Data Network Name\ndns: # the IP address of DNS\nipv4: 8.8.8.8\nipv6: 2001:4860:4860::8888\nplmnList: # the list of PLMN IDs that this SMF belongs to (optional, remove this key when unnecessary)\n- mcc: 208 # Mobile Country Code (3 digits string, digit: 0~9)\nmnc: 93 # Mobile Network Code (2 or 3 digits string, digit: 0~9)\nlocality: area1 # Name of the location where a set of AMF, SMF, PCF and UPFs are located\npfcp: # the IP address of N4 interface on this SMF (PFCP)\n# addr config is deprecated in smf config v1.0.3, please use the following config\nnodeID: 127.0.0.1 # the Node ID of this SMF\nlistenAddr: 127.0.0.1 # the IP/FQDN of N4 interface on this SMF (PFCP)\nexternalAddr: 127.0.0.1 # the IP/FQDN of N4 interface on this SMF (PFCP)\nuserplaneInformation: # list of userplane information\nupNodes: # information of userplane node (AN or UPF)\ngNB1: # the name of the node\ntype: AN # the type of the node (AN or UPF)\nUPF: # the name of the node\ntype: UPF # the type of the node (AN or UPF)\nnodeID: 127.0.0.8 # the Node ID of this UPF\naddr: 127.0.0.8 # the IP/FQDN of N4 interface on this UPF (PFCP)\nsNssaiUpfInfos: # S-NSSAI information list for this UPF\n- sNssai: # S-NSSAI (Single Network Slice Selection Assistance Information)\nsst: 1 # Slice/Service Type (uinteger, range: 0~255)\nsd: 010203 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)\ndnnUpfInfoList: # DNN information list for this S-NSSAI\n- dnn: internet\npools:\n- cidr: 10.60.0.0/16\nstaticPools:\n- cidr: 10.60.100.0/24\n- sNssai: # S-NSSAI (Single Network Slice Selection Assistance Information)\nsst: 1 # Slice/Service Type (uinteger, range: 0~255)\nsd: 112233 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)\ndnnUpfInfoList: # DNN information list for this S-NSSAI\n- dnn: internet\npools:\n- cidr: 10.61.0.0/16\nstaticPools:\n- cidr: 10.61.100.0/24\ninterfaces: # Interface list for this UPF\n- interfaceType: N3 # the type of the interface (N3 or N9)\nendpoints: # the IP address of this N3/N9 interface on this UPF\n- 10.200.200.2 # 127.0.0.8\nnetworkInstances:  # Data Network Name (DNN)\n- internet\nlinks: # the topology graph of userplane, A and B represent the two nodes of each link\n- A: gNB1\nB: UPF\n# retransmission timer for pdu session modification command\nt3591:\nenable: true     # true or false\nexpireTime: 16s   # default is 6 seconds\nmaxRetryTimes: 3 # the max number of retransmission\n# retransmission timer for pdu session release command\nt3592:\nenable: true     # true or false\nexpireTime: 16s   # default is 6 seconds\nmaxRetryTimes: 3 # the max number of retransmission\nnrfUri: http://127.0.0.10:8000 # a valid URI of NRF\n#urrPeriod: 10 # default usage report period in seconds\n#urrThreshold: 1000 # default usage report threshold in bytes\n\nlogger: # log output setting\nenable: true # true or false\nlevel: info # how detailed to output, value: trace, debug, info, warn, error, fatal, panic\nreportCaller: false # enable the caller report or not, value: true or false\n
- free5gc/config/upfcfg.yaml

Replace gtpu from 127.0.0.8to 10.200.200.2:

version: 1.0.3\ndescription: UPF initial local configuration\n\n# The listen IP and nodeID of the N4 interface on this UPF (Can't set to 0.0.0.0)\npfcp:\naddr: 127.0.0.8   # IP addr for listening\nnodeID: 127.0.0.8 # External IP or FQDN can be reached\nretransTimeout: 1s # retransmission timeout\nmaxRetrans: 3 # the max number of retransmission\n\ngtpu:\nforwarder: gtp5g\n# The IP list of the N3/N9 interfaces on this UPF\n# If there are multiple connection, set addr to 0.0.0.0 or list all the addresses\nifList:\n- addr: 10.200.200.2 # 127.0.0.8\ntype: N3\n# name: upf.5gc.nctu.me\n# ifname: gtpif\n# mtu: 1400\n\n# The DNN list supported by UPF\ndnnList:\n- dnn: internet # Data Network Name\ncidr: 10.60.0.0/24 # Classless Inter-Domain Routing for assigned IPv4 pool of UE\n# natifname: eth0\n\nlogger: # log output setting\nenable: true # true or false\nlevel: info # how detailed to output, value: trace, debug, info, warn, error, fatal, panic\nreportCaller: false # enable the caller report or not, value: true or false\n
"},{"location":"blog/1-free5gc-with-namespace/#ueransim","title":"UERANSIM","text":"
  • UERANSIM/config/free5gc-gnb.yaml

  • Replace ngapIp from 127.0.0.1to 10.200.200.1

  • Replace gtpIp from 127.0.0.1to 10.200.200.1

  • Replace amfConfigs / address from 127.0.0.1to 10.200.200.2

mcc: '208'          # Mobile Country Code value\nmnc: '93'           # Mobile Network Code value (2 or 3 digits)\n\nnci: '0x000000010'  # NR Cell Identity (36-bit)\nidLength: 32        # NR gNB ID length in bits [22...32]\ntac: 1              # Tracking Area Code\n\nlinkIp: 127.0.0.1   # gNB's local IP address for Radio Link Simulation (Usually same with local IP)\nngapIp: 10.200.200.1 # 127.0.0.1   # gNB's local IP address for N2 Interface (Usually same with local IP)\ngtpIp: 10.200.200.1 # 127.0.0.1    # gNB's local IP address for N3 Interface (Usually same with local IP)\n\n# List of AMF address information\namfConfigs:\n- address: 10.200.200.2 # 127.0.0.1\nport: 38412\n\n# List of supported S-NSSAIs by this gNB\nslices:\n- sst: 0x1\nsd: 0x010203\n\n# Indicates whether or not SCTP stream number errors should be ignored.\nignoreStreamIds: true\n
- UERANSIM/config/free5gc-ue.yaml
# IMSI number of the UE. IMSI = [MCC|MNC|MSISDN] (In total 15 or 16 digits)\nsupi: 'imsi-208930000000003'\n# Mobile Country Code value\nmcc: '208'\n# Mobile Network Code value (2 or 3 digits)\nmnc: '93'\n\n# Permanent subscription key\nkey: '8baf473f2f8fd09487cccbd7097c6862'\n# Operator code (OP or OPC) of the UE\nop: '8e27b6af0e692e750f32667a3b14605d'\n# This value specifies the OP type and it can be either 'OP' or 'OPC'\nopType: 'OP'\n# Authentication Management Field (AMF) value\namf: '8000'\n# IMEI number of the device. It is used if no SUPI is provided\nimei: '356938035643803'\n# IMEISV number of the device. It is used if no SUPI and IMEI is provided\nimeiSv: '4370816125816151'\n\n# List of gNB IP addresses for Radio Link Simulation\ngnbSearchList:\n- 127.0.0.1\n\n# Initial PDU sessions to be established\nsessions:\n- type: 'IPv4'\napn: 'internet'\nslice:\nsst: 0x01\nsd: 0x010203\n\n# List of requested S-NSSAIs by this UE\nslices:\n- sst: 0x01\nsd: 0x010203\n\n# Supported encryption and integrity algorithms by this UE\nintegrity:\nIA1: true\nIA2: true\nIA3: true\nciphering:\nEA1: true\nEA2: true\nEA3: true\n

"},{"location":"blog/1-free5gc-with-namespace/#environment-set-up-of-free5gc-and-ueransim","title":"Environment set up of free5GC and UERANSIM","text":"

First, create a namespace:

Note

Assume that you are either running as root, or it behoves you to prepend sudo to commands as necessary.

ip netns add ueransim\n
Next, add the bridge:
ip link add free5gc-br type bridge\n
Add two pairs of veth:
ip link add veth0 type veth peer name br-veth0\nip link add veth1 type veth peer name br-veth1\n
Now, it could be like:
root@free5gc:~# ip a\n1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000\n    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n    inet 127.0.0.1/8 scope host lo\n       valid_lft forever preferred_lft forever\n    inet6 ::1/128 scope host\n       valid_lft forever preferred_lft forever\n2: enp0s5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000\n    link/ether 00:1c:42:b1:ba:f4 brd ff:ff:ff:ff:ff:ff\n    inet 10.211.55.23/24 brd 10.211.55.255 scope global dynamic enp0s5\n       valid_lft 1714sec preferred_lft 1714sec\n    inet6 fdb2:2c26:f4e4:0:21c:42ff:feb1:baf4/64 scope global dynamic mngtmpaddr noprefixroute\n       valid_lft 2591750sec preferred_lft 604550sec\n    inet6 fe80::21c:42ff:feb1:baf4/64 scope link\n       valid_lft forever preferred_lft forever\n3: enp0s6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000\n    link/ether 00:1c:42:f1:11:c6 brd ff:ff:ff:ff:ff:ff\n    inet 10.37.129.20/24 brd 10.37.129.255 scope global enp0s6\n       valid_lft forever preferred_lft forever\n    inet6 fdb2:2c26:f4e4:1:21c:42ff:fef1:11c6/64 scope global dynamic mngtmpaddr noprefixroute\n       valid_lft 2591750sec preferred_lft 604550sec\n    inet6 fe80::21c:42ff:fef1:11c6/64 scope link\n       valid_lft forever preferred_lft forever\n4: free5gc-br: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000\n    link/ether 4e:f6:d7:9c:50:de brd ff:ff:ff:ff:ff:ff\n5: br-veth0@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000\n    link/ether c2:31:0c:5f:45:81 brd ff:ff:ff:ff:ff:ff\n6: veth0@br-veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000\n    link/ether 4a:0f:1e:80:9b:be brd ff:ff:ff:ff:ff:ff\n7: br-veth1@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000\n    link/ether 56:99:b0:82:78:0d brd ff:ff:ff:ff:ff:ff\n8: veth1@br-veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000\n    link/ether 12:5a:56:00:5b:be brd ff:ff:ff:ff:ff:ff\n

Next, assign interface to namespace:

ip link set dev veth0 netns ueransim\n
Set ip address:
ip netns exec ueransim ip a add 10.200.200.1/24 dev veth0\n
Enable both interface. Don't forget lo:
ip netns exec ueransim ip link set lo up\nip netns exec ueransim ip link set veth0 up\n
Check with ip a:
root@free5gc:~# ip netns exec ueransim ip a\n1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000\n    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n    inet 127.0.0.1/8 scope host lo\n       valid_lft forever preferred_lft forever\n    inet6 ::1/128 scope host\n       valid_lft forever preferred_lft forever\n6: veth0@if5: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN group default qlen 1000\n    link/ether 4a:0f:1e:80:9b:be brd ff:ff:ff:ff:ff:ff link-netnsid 0\n    inet 10.200.200.1/24 scope global veth0\n       valid_lft forever preferred_lft forever\n
Set for veth1 as well:
ip a add 10.200.200.2/24 dev veth1\nip link set veth1 up\n
Let two interfaces attatch to bridge:
ip link set dev br-veth0 master free5gc-br\nip link set dev br-veth1 master free5gc-br\nip link set br-veth0 up\nip link set br-veth1 up\nip link set free5gc-br up\n
Using bridge link to check:
root@free5gc:~# bridge link\n5: br-veth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master free5gc-br state forwarding priority 32 cost 2\n7: br-veth1@veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master free5gc-br state forwarding priority 32 cost 2\n
Now it looks like:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000\n    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n    inet 127.0.0.1/8 scope host lo\n       valid_lft forever preferred_lft forever\n    inet6 ::1/128 scope host\n       valid_lft forever preferred_lft forever\n2: enp0s5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000\n    link/ether 00:1c:42:b1:ba:f4 brd ff:ff:ff:ff:ff:ff\n    inet 10.211.55.23/24 brd 10.211.55.255 scope global dynamic enp0s5\n       valid_lft 1000sec preferred_lft 1000sec\n    inet6 fdb2:2c26:f4e4:0:21c:42ff:feb1:baf4/64 scope global dynamic mngtmpaddr noprefixroute\n       valid_lft 2591870sec preferred_lft 604670sec\n    inet6 fe80::21c:42ff:feb1:baf4/64 scope link\n       valid_lft forever preferred_lft forever\n3: enp0s6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000\n    link/ether 00:1c:42:f1:11:c6 brd ff:ff:ff:ff:ff:ff\n    inet 10.37.129.20/24 brd 10.37.129.255 scope global enp0s6\n       valid_lft forever preferred_lft forever\n    inet6 fdb2:2c26:f4e4:1:21c:42ff:fef1:11c6/64 scope global dynamic mngtmpaddr noprefixroute\n       valid_lft 2591870sec preferred_lft 604670sec\n    inet6 fe80::21c:42ff:fef1:11c6/64 scope link\n       valid_lft forever preferred_lft forever\n4: free5gc-br: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000\n    link/ether 56:99:b0:82:78:0d brd ff:ff:ff:ff:ff:ff\n    inet6 fe80::5499:b0ff:fe82:780d/64 scope link\n       valid_lft forever preferred_lft forever\n5: br-veth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master free5gc-br state UP group default qlen 1000\n    link/ether c2:31:0c:5f:45:81 brd ff:ff:ff:ff:ff:ff link-netns ueransim\n    inet6 fe80::c031:cff:fe5f:4581/64 scope link\n       valid_lft forever preferred_lft forever\n7: br-veth1@veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master free5gc-br state UP group default qlen 1000\n    link/ether 56:99:b0:82:78:0d brd ff:ff:ff:ff:ff:ff\n    inet6 fe80::5499:b0ff:fe82:780d/64 scope link\n       valid_lft forever preferred_lft forever\n8: veth1@br-veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000\n    link/ether 12:5a:56:00:5b:be brd ff:ff:ff:ff:ff:ff\n    inet 10.200.200.2/24 scope global veth1\n       valid_lft forever preferred_lft forever\n    inet6 fe80::105a:56ff:fe00:5bbe/64 scope link\n       valid_lft forever preferred_lft forever\n
Let's test it:

Note

You can perform ip netns exec ueransim /bin/bash --rcfile <(echo \"PS1=\\\"ueransim> \\\"\") to enter namespace and modify shell prefix.

root@free5gc:~# ip netns exec ueransim /bin/bash --rcfile <(echo \"PS1=\\\"ueransim> \\\"\")\nueransim> ping -c2 10.200.200.2\nPING 10.200.200.2 (10.200.200.2) 56(84) bytes of data.\n64 bytes from 10.200.200.2: icmp_seq=1 ttl=64 time=0.089 ms\n64 bytes from 10.200.200.2: icmp_seq=2 ttl=64 time=0.226 ms\n\n--- 10.200.200.2 ping statistics ---\n2 packets transmitted, 2 received, 0% packet loss, time 1020ms\nrtt min/avg/max/mdev = 0.089/0.157/0.226/0.068 ms\n
Insert default routing rule:
ueransim> ip route add default via 10.200.200.2\nueransim> netstat -rn\nKernel IP routing table\nDestination     Gateway         Genmask         Flags   MSS Window  irtt Iface\n0.0.0.0         10.200.200.2    0.0.0.0         UG        0 0          0 veth0\n10.200.200.0    0.0.0.0         255.255.255.0   U         0 0          0 veth0\n
Try to ping 8.8.8.8:
ueransim> ping -c2 8.8.8.8\nPING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.\n\n--- 8.8.8.8 ping statistics ---\n2 packets transmitted, 0 received, 100% packet loss, time 1028ms\n
It is because the main host must translate the source addresses. Besides, the main host need to forward packet:
root@free5gc:~# iptables -t nat -A POSTROUTING -o enp0s5 -j MASQUERADE\nroot@free5gc:~# sysctl -w net.ipv4.ip_forward=1\nroot@free5gc:~# sudo iptables -I FORWARD 1 -j ACCEPT\n
And then:
ueransim> ping -c2 8.8.8.8\nPING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.\n64 bytes from 8.8.8.8: icmp_seq=1 ttl=127 time=13.9 ms\n64 bytes from 8.8.8.8: icmp_seq=2 ttl=127 time=28.0 ms\n\n--- 8.8.8.8 ping statistics ---\n2 packets transmitted, 2 received, 0% packet loss, time 1002ms\nrtt min/avg/max/mdev = 13.866/20.939/28.012/7.073 ms\n

After free5GC execute run.sh, it's time for UERANSIM:

In terminal 1:

ueransim> build/nr-gnb -c config/free5gc-gnb.yaml\nUERANSIM v3.1.0\n[2023-07-05 19:58:26.368] [sctp] [info] Trying to establish SCTP connection... (10.200.200.2:38412)\n[2023-07-05 19:58:26.373] [sctp] [info] SCTP connection established (10.200.200.2:38412)\n[2023-07-05 19:58:26.374] [sctp] [debug] SCTP association setup ascId[3]\n[2023-07-05 19:58:26.375] [ngap] [debug] Sending NG Setup Request\n[2023-07-05 19:58:26.380] [ngap] [debug] NG Setup Response received\n[2023-07-05 19:58:26.380] [ngap] [info] NG Setup procedure is successful\n[2023-07-05 19:58:35.804] [mr] [info] New UE connected to gNB. Total number of UEs is now: 1\n[2023-07-05 19:58:35.806] [rrc] [debug] Sending RRC Setup for UE[3]\n[2023-07-05 19:58:35.807] [ngap] [debug] Initial NAS message received from UE 3\n[2023-07-05 19:58:35.869] [ngap] [debug] Initial Context Setup Request received\n[2023-07-05 19:58:36.108] [ngap] [info] PDU session resource is established for UE[3] count[1]\n
In terminal 2:
ueransim> sudo build/nr-ue -c config/free5gc-ue.yaml\nUERANSIM v3.1.0\n[2023-07-05 19:58:35.803] [nas] [debug] NAS layer started\n[2023-07-05 19:58:35.803] [rrc] [debug] RRC layer started\n[2023-07-05 19:58:35.804] [nas] [info] UE switches to state: MM-DEREGISTERED/PLMN-SEARCH\n[2023-07-05 19:58:35.804] [nas] [info] UE connected to gNB\n[2023-07-05 19:58:35.804] [nas] [info] UE switches to state: MM-DEREGISTERED/NORMAL-SERVICE\n[2023-07-05 19:58:35.804] [nas] [info] UE switches to state: MM-REGISTERED-INITIATED/NA\n[2023-07-05 19:58:35.805] [rrc] [debug] Sending RRC Setup Request\n[2023-07-05 19:58:35.806] [rrc] [info] RRC connection established\n[2023-07-05 19:58:35.806] [nas] [info] UE switches to state: CM-CONNECTED\n[2023-07-05 19:58:35.838] [nas] [debug] Received rand[61262F32A617D0BAD716603B1CBDA477] autn[44778026F4238000FC14B59D68855328]\n[2023-07-05 19:58:35.838] [nas] [debug] Calculated res[47759045F5ACEA59] ck[1C559301F29EF49572F5D150B3B99288] ik[D223317F752F233CE4C7AA253644D882] ak[528433D1FBE6] mac_a[FC14B59D68855328]\n[2023-07-05 19:58:35.838] [nas] [debug] Used snn[5G:mnc093.mcc208.3gppnetwork.org] sqn[16F3B3F70FC5]\n[2023-07-05 19:58:35.838] [nas] [debug] Derived kSeaf[7FC8B7FB1B141B6579B9C0FAEB9CCF1312FE9F9634868E234756DE49FD67C5F1] kAusf[FA0402A892E6046D52F4DECACA40B2A75B698FCEAD5EB320139FC69B77BD4C46] kAmf[3D4AD68E153B9642ACBECC67AD399015F7CB578F9DF4C88A35EED99C72C9B95B]\n[2023-07-05 19:58:35.843] [nas] [debug] Derived kNasEnc[1F829EB2BA238DD0226C3484E6A79D1F] kNasInt[251C0412B1BAD88A9DD0008F32D6F216]\n[2023-07-05 19:58:35.843] [nas] [debug] Selected integrity[2] ciphering[0]\n[2023-07-05 19:58:35.869] [nas] [debug] T3512 started with int[3600]\n[2023-07-05 19:58:35.869] [nas] [info] UE switches to state: MM-REGISTERED/NORMAL-SERVICE\n[2023-07-05 19:58:35.869] [nas] [info] Initial Registration is successful\n[2023-07-05 19:58:35.869] [nas] [info] Initial PDU sessions are establishing [1#]\n[2023-07-05 19:58:35.869] [nas] [debug] Sending PDU session establishment request\n[2023-07-05 19:58:36.108] [nas] [info] PDU Session establishment is successful PSI[1]\n[2023-07-05 19:58:36.113] [app] [info] Connection setup for PDU session[1] is successful, TUN interface[uesimtun0, 10.60.0.1] is up.\n
In terminal 3:
ueransim> ip a\n1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000\n    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n    inet 127.0.0.1/8 scope host lo\n       valid_lft forever preferred_lft forever\n    inet6 ::1/128 scope host\n       valid_lft forever preferred_lft forever\n2: uesimtun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500\n    link/none\n    inet 10.60.0.1/32 scope global uesimtun0\n       valid_lft forever preferred_lft forever\n    inet6 fe80::b5ef:5b4:e3f6:af64/64 scope link stable-privacy\n       valid_lft forever preferred_lft forever\n6: veth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000\n    link/ether 4a:0f:1e:80:9b:be brd ff:ff:ff:ff:ff:ff link-netnsid 0\n    inet 10.200.200.1/24 scope global veth0\n       valid_lft forever preferred_lft forever\n    inet6 fe80::480f:1eff:fe80:9bbe/64 scope link\n       valid_lft forever preferred_lft forever\nueransim> ping -c2 -I uesimtun0 8.8.8.8\nPING 8.8.8.8 (8.8.8.8) from 10.60.0.1 uesimtun0: 56(84) bytes of data.\n64 bytes from 8.8.8.8: icmp_seq=1 ttl=127 time=19.5 ms\n64 bytes from 8.8.8.8: icmp_seq=2 ttl=127 time=33.2 ms\n\n--- 8.8.8.8 ping statistics ---\n2 packets transmitted, 2 received, 0% packet loss, time 1006ms\nrtt min/avg/max/mdev = 19.478/26.348/33.219/6.870 ms\n
Also ping to google.com:
ueransim> ping -c2 -I uesimtun0 google.com\nPING google.com (172.217.160.110) from 10.60.0.1 uesimtun0: 56(84) bytes of data.\n64 bytes from tsa03s06-in-f14.1e100.net (172.217.160.110): icmp_seq=1 ttl=127 time=17.3 ms\n64 bytes from tsa03s06-in-f14.1e100.net (172.217.160.110): icmp_seq=2 ttl=127 time=29.5 ms\n\n--- google.com ping statistics ---\n2 packets transmitted, 2 received, 0% packet loss, time 1005ms\nrtt min/avg/max/mdev = 17.295/23.385/29.476/6.090 ms\n

"},{"location":"blog/1-free5gc-with-namespace/#what-if-two-ueransims-with-two-namespaces","title":"What if two UERANSIMs with two namespaces?","text":"

Same as before, you should create another namespace for UERANSIM, called it ueransim2:

root@free5gc:~# ip netns ls\nueransim2 (id: 1)\nueransim (id: 0)\n
And then:
ip link add veth2 type veth peer name br-veth2\nip link set dev veth2 netns ueransim2\nip link set br-veth2 master free5gc-br\nip link set br-veth2 up\nip netns exec ueransim2 ip a add 10.200.200.3/24 dev veth2\nip netns exec ueransim2 ip link set lo up\nip netns exec ueransim2 ip link set veth2 up\nip netns exec ueransim2 ip route add default via 10.200.200.2\n

Copy UERANSIM/config/free5gc-gnb.yaml and UERANSIM/config/free5gc-ue.yaml to free5gc-gnb2.yaml and free5gc-ue2.yaml, modify:

free5gc-gnb2.yaml

  • Replace ngapIp from 127.0.0.1 to 10.200.200.3
  • Replace gtpIp from 127.0.0.1 to 10.200.200.3

...\nngapIp: 10.200.200.3 # 127.0.0.1   # gNB's local IP address for N2 Interface (Usually same with local IP)\ngtpIp: 10.200.200.3 # 127.0.0.1    # gNB's local IP address for N3 Interface (Usually same with local IP)\n\n# List of AMF address information\namfConfigs:\n- address: 10.200.200.2 # 127.0.0.1\nport: 38412\n...\n
free5gc-ue2.yaml

supi change to imsi-208930000000004

...\n# IMSI number of the UE. IMSI = [MCC|MNC|MSISDN] (In total 15 or 16 digits)\nsupi: 'imsi-208930000000004'\n...\n

Note

Should register ue to webconsole first.

The result:

ueransim> ip a\n1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000\n    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n    inet 127.0.0.1/8 scope host lo\n       valid_lft forever preferred_lft forever\n    inet6 ::1/128 scope host\n       valid_lft forever preferred_lft forever\n6: veth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000\n    link/ether 4a:0f:1e:80:9b:be brd ff:ff:ff:ff:ff:ff link-netnsid 0\n    inet 10.200.200.1/24 scope global veth0\n       valid_lft forever preferred_lft forever\n    inet6 fe80::480f:1eff:fe80:9bbe/64 scope link\n       valid_lft forever preferred_lft forever\n7: uesimtun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500\n    link/none\n    inet 10.60.0.1/32 scope global uesimtun0\n       valid_lft forever preferred_lft forever\n    inet6 fe80::f6d7:dd81:fe7f:496a/64 scope link stable-privacy\n       valid_lft forever preferred_lft forever\nueransim> ping -c2 -I uesimtun0 google.com\nPING google.com (172.217.160.110) from 10.60.0.1 uesimtun0: 56(84) bytes of data.\n64 bytes from tsa03s06-in-f14.1e100.net (172.217.160.110): icmp_seq=1 ttl=127 time=17.2 ms\n64 bytes from tsa03s06-in-f14.1e100.net (172.217.160.110): icmp_seq=2 ttl=127 time=28.5 ms\n\n--- google.com ping statistics ---\n2 packets transmitted, 2 received, 0% packet loss, time 1003ms\nrtt min/avg/max/mdev = 17.200/22.863/28.527/5.663 ms\n

ueransim2> ip a\n1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000\n    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n    inet 127.0.0.1/8 scope host lo\n       valid_lft forever preferred_lft forever\n    inet6 ::1/128 scope host \n       valid_lft forever preferred_lft forever\n5: uesimtun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500\n    link/none \n    inet 10.60.0.2/32 scope global uesimtun0\n       valid_lft forever preferred_lft forever\n    inet6 fe80::16a4:523a:a86:bf83/64 scope link stable-privacy \n       valid_lft forever preferred_lft forever\n12: veth2@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000\n    link/ether fa:12:bb:9c:fa:40 brd ff:ff:ff:ff:ff:ff link-netnsid 0\n    inet 10.200.200.3/24 scope global veth2\n       valid_lft forever preferred_lft forever\n    inet6 fe80::f812:bbff:fe9c:fa40/64 scope link \n       valid_lft forever preferred_lft forever\nueransim2> ping -c2 -I uesimtun0 google.com\nPING google.com (172.217.160.110) from 10.60.0.2 uesimtun0: 56(84) bytes of data.\n64 bytes from tsa03s06-in-f14.1e100.net (172.217.160.110): icmp_seq=1 ttl=127 time=18.9 ms\n64 bytes from tsa03s06-in-f14.1e100.net (172.217.160.110): icmp_seq=2 ttl=127 time=15.8 ms\n\n--- google.com ping statistics ---\n2 packets transmitted, 2 received, 0% packet loss, time 1002ms\nrtt min/avg/max/mdev = 15.786/17.353/18.921/1.567 ms\n
"},{"location":"blog/1-free5gc-with-namespace/#about","title":"About","text":"

Hi, my name is Jimmy Chang. The current research topic is 5G LAN with a focus on the 5G Data Plane. Any questions or errors in the article are welcome for correction. Please feel free to send an email to provide feedback.

  • Graduate student major in 5GC Research
  • LinkedIn
"},{"location":"blog/1-free5gc-with-namespace/#reference","title":"Reference","text":"
  • https://github.com/s5uishida/free5gc_ueransim_ulcl_sample_config
  • https://github.com/free5gc/free5gc/blob/main/test_ulcl.sh
  • https://blog.scottlowe.org/2013/09/04/introducing-linux-network-namespaces/
  • https://man7.org/linux/man-pages/man7/namespaces.7.html
  • https://linux.die.net/man/8/iptables
"},{"location":"blog/20230802/","title":"Authentication Mechanism in NRF: What Is OAuth?","text":"

Note

Author: Wilson Date: 2023/8/2

"},{"location":"blog/20230802/#abstract","title":"Abstract","text":"

Regarding the theme this time, I will briefly introduce OAuth. OAuth 2.0 defines four types of authorization flows. I choose the Client Credentials Flow to explain because the authentication mechanism in NRF is closely related to the Client Credentials Flow.

Next, I will explain how to apply the concept of the Client Credentials Flow to NRF and introduce Nnrf_AccessToken Service, because Nnrf_AccessToken Service is closely related to the Client Credentials Flow.

Finally, I will make a simple experiment of the authentication mechanism in NRF and share the environment settings and methods of operation.

"},{"location":"blog/20230802/#oauth","title":"OAuth","text":"

Before explaining the authentication mechanism in NRF, I will introduce OAuth. Regarding the OAuth flow, we can log in to the account through the platform before accessing an application. After logging in, we agree that an application can limitedly obtain the information of the user on the platform. The application can be LinkedIn, YouTube, etc. The platform can be Google, Facebook, etc.

The full English name of OAuth is Open standard Authorization. OAuth is an open standard, and it's used to deal with authorization-related behaviors. OAuth 2.0 defines four types of authorization flows. The four types of the authorization flows are:

  • Authorization Code
  • Implicit
  • Resource Owner Password Credentials
  • Client Credentials

This article explains the entire authorization of the Client Credentials Flow only, because the authentication mechanism in NRF adopts the Client Credentials.

If you're interested in how authorization mechanism works, please refer to this article for more details.

"},{"location":"blog/20230802/#client-credentials-flow","title":"Client Credentials Flow","text":"

Figure 1. Client Credentials Flow

Referring to the Figure 1, the Client Credentials Flow is mainly composed of:

  • Client
  • Authorization Server
  • Resource Server

The entire authorization of the Client Credentials Flow can be devided into 3 steps:

  • First, the Client provdies Client ID, Client Secret Token, Scope, and Grant Type to the Authorization Server.
  • Second, the Authorization Server verifies the information provided by the Client. After the Authorization Server verifies the information, it signs with the private key and sends the Access Token to the Client.
  • Third, the Client obtains resources from the Resource Server with the Access Token.

In addition, the Client and the Authorization Server have their own Scope list. The Scope list records a series of the actions. The Client or the Authorization Server is permitted to do the actions for obtaining the user\u2019s name, deleting posts, etc.

Below I will explain how to apply the Client Credentials Flow to NRF after talking about the Client Credentials Flow.

"},{"location":"blog/20230802/#client-credentials-flow-in-nrf","title":"Client Credentials Flow in NRF","text":"

The Figure 2 and the Figure 3 originate from the Figure 13.4.1.1-1 and the Figure 13.4.1.1-2 of the TS 33.501.

Figure 2. NF Service Consumer Obtaining Access Token before NF Service Access

The entire flow in Figure 2 is the same as Step 1 and Step 2 in the Figure 1. The role of the Client is played by the NF Service Consumer, and the role of the Authorization Server is played by the NRF.

First, the NF Service Consumer registers with NRF. Then the NF Service Consumer sends the Nnrf_AccessToken_Get Request to NRF. The Nnrf_AccessToken_Get Request includes:

  • Consumer NF Type
  • Expected NF Type
  • Expected NF Service Name
  • Client ID

The NF Type can be AMF, SMF, etc. , and the NF Service Name can be namf-comm, nsmf-pdusession, etc.

NRF verifies the information provided by the NF Service Consumer after it receives the Nnrf_AccessToken_Get Request. NRF generates an Access Token and uses the NRF private key to sign on the Access Token after the verification is successful.

Finally, NRF returns the Nnrf_AccessToken_Get Response to the NF Service Consumer. The NF Service Consumer stores the Access Token within the validity period after it gets the Access Token. The services provided by the NF Service Producer are in the Expected NF Service Name. The NF Service Consumer doesn\u2019t need to verify again when it wants to use the services provided by the NF Service Producer.

Figure 3. NF Service Consumer Requesting Service Access with an Access Token

The entire flow in Figure 3 is the same as Step 3 in the Figure 1. The role of the Client is played by the NF Service Consumer, and the role of the Resource Server is played by the NF Service Producer.

First, the NF Service Consumer sends the NF Service Request to the NF Service Producer with the Access Token. Simply put, the NF Service Consumer wants to consume the service provided by the NF Service Producer.

The NF Service Producer uses the NRF public key to verify the signed Access Token after it receives the NF Service Request. If the verification is successful, the NF Service Producer will send the NF Service Response to the NF Service Consumer.

Now I will talk about the Nnrf_AccessToken Service after explaining how to apply the Client Credentials Flow to NRF.

"},{"location":"blog/20230802/#nnrf_accesstoken-service","title":"Nnrf_AccessToken Service","text":"

Figure 4. Access Token Request

The Figure 4 originates from the Figure 5.4.2.2.1-1 of the TS 29.510.

First, the NF Service Consumer sends the POST /oauth2/token to NRF, and the data is stored in the AccessTokenReq. The attribute name, the data type, and the formulation rule of the AccessTokenReq are shown in the Table 1. The Table 1 originates from the Table 6.3.5.2.2-1 of the TS 29.510.

Table 1. Definition of Type AccessTokenReq

Definition of type AccessTokenReq:

  • grant_type: The value must be set to the client_credentials, and it is checked in the Snippet 1.
  • nfInstanceId: The value stores the ID of the NF Service Consumer.
  • targetNfInstanceId: The value stores the ID of the NF Service Producer.
  • nfType: The value stores the network function name of the NF Service Consumer. The network function name can be the AMF, SMF, etc.
  • targetNfType: The value stores the network function name of the NF Service Producer.
  • scope: It stores the services. The services can be the namf-comm, nsmf-pdusession, etc. When the NF Service Consumer requests the services. The services will be provided by the NF Service Producer.
  • requesterPlmn: It is mainly used in the roaming.
  • targetPlmn: It is mainly used in the roaming.

if reqGrantType != \"client_credentials\" {\nreturn &models.AccessTokenErr{\nError: \"unsupported_grant_type\",\n}\n}\n
Snippet 1. Grant Type Value Checking

NRF sends AccessTokenRsp to the NF Service Consumer in the Step 2a of the Figure 4. The attribute name, the data type, and the formulation rule of the AccessTokenRsp are shown in the Table 2. The Table 2 originates from the Table 6.3.5.2.3-1 of the TS 29.510.

Table 2. Definition of Type AccessTokenRsp

The AccessTokenRsp contains four attribute names. The four attribute names are:

  • access_token: It stores all the attribute names and values of the AccessTokenClaims in the Table 3. The Table 3 originates form the Table 6.3.5.2.4-1 of the TS 29.510.
  • token_type: It must be set to the Bearer and can be seen in the Snippet 2.
  • expires_in: It stores information related to the expiration date.
  • scope: The NF Service Consumer and the NF Service Producer have their own scope list. The scope in the AccessTokenRsp has a series of these services, and the NF Service Producer is permitted to consume these services.

Table 3. Definition of Type AccessTokenClaims

Definition of Type AccessTokenClaims:

  • iss: It is called issuer, and the content usually stores the ID of NRF.
  • sub: It is called subject, and the content stores the ID of the NF Service Consumer.
  • aud: It is called audience, and the content stores the ID of the NF Service Producer.
  • scope: The scope in the AccessTokenClaims has a series of these services, and the NF Service Consumer is authorized by the NF Service Producer and permitted to consume these services.
  • exp: It stores information related to the validity period.

func AccessTokenProcedure(request models.AccessTokenReq) (\n*models.AccessTokenRsp, *models.AccessTokenErr,\n) {\nlogger.AccTokenLog.Infoln(\"In AccessTokenProcedure\")\n\nvar expiration int32 = 1000\nscope := request.Scope\ntokenType := \"Bearer\"\nnow := int32(time.Now().Unix())\n\nerrResponse := AccessTokenScopeCheck(request)\nif errResponse != nil {\nreturn nil, errResponse\n}\n\n// Create AccessToken\nnrfCtx := nrf_context.GetSelf()\naccessTokenClaims := models.AccessTokenClaims{\nIss:            nrfCtx.Nrf_NfInstanceID,    // NF instance id of the NRF\nSub:            request.NfInstanceId,       // nfInstanceId of service consumer\nAud:            request.TargetNfInstanceId, // nfInstanceId of service producer\nScope:          request.Scope,              // TODO: the name of the NF services for which the\nExp:            now + expiration,           // access_token is authorized for use\nStandardClaims: jwt.StandardClaims{},\n}\naccessTokenClaims.IssuedAt = int64(now)\n\n// Use NRF private key to sign AccessToken\ntoken := jwt.NewWithClaims(jwt.GetSigningMethod(\"RS512\"), accessTokenClaims)\naccessToken, err := token.SignedString(nrfCtx.NrfPrivKey)\nif err != nil {\nlogger.AccTokenLog.Warnln(\"Signed string error: \", err)\nreturn nil, &models.AccessTokenErr{\nError: \"invalid_request\",\n}\n}\n\nresponse := &models.AccessTokenRsp{\nAccessToken: accessToken,\nTokenType:   tokenType,\nExpiresIn:   expiration,\nScope:       scope,\n}\nreturn response, nil\n}\n
Snippet 2. AccessTokenProcedure Function

The Snippet 2 is the AccessTokenProcedure() function. The function is executed in NRF.

The function mainly processes:

  1. The NRF receives the AccessTokenReq sent by the NF Service Customer.
  2. The function calls the AccessTokenScopeCheck() function. The AccessTokenScopeCheck() function checks whether the content of the attribute name in the AccessTokenReq complies with the requirements of the TS 29.510. If not, the AccessTokenProcedure() function immediately returns the AccessTokenErr to the NF Service Customer.
  3. The function starts to create the Access Token. The Access Token is stored in the AccessTokenRsp. The AccessTokenRsp is sent back to the NF Service Customer. The Iss in the AccessToken obtains its own ID in NRF. The Sub and Aud are obtained from the NfInstancedId and the TargetNfInstanceId in the AccessTokenReq respectively. The Scope is obtained from the scope in the AccessTokenReq. The expiration is set to the 1000 in the Snippet 2. Therefore, the value of the exp is the current time + 1000.
  4. After the Access Token is created, the function uses the NRF private key to sign on the Access Token. After signing, the function checks whether there is an error. If so, the function immediately sends the AccessTokenErr to the NF Service Customer.
  5. The function puts the signed Access Token into the AccessTokenRsp. The value of the TokenType is set to the Bearer by the function. The function sets the ExprieIn and the Scope in the Snippet 2.

Finally, I make a simple experiment about the Access Token and share the environment setting and method of operation with you.

"},{"location":"blog/20230802/#experiment","title":"Experiment","text":"

The Table 4 is my environment setting. I provide the Table 4 for you. You can refer it.

Table 4. Environment

Remove the part of the tls and add the content of the cert, rootcert and oauth under sbi in the nrfcfg.yaml before implementing about the Access Token.

info:\nversion: 1.0.2\ndescription: NRF initial local configuration\n\nconfiguration:\nMongoDBName: free5gc # database name in MongoDB\nMongoDBUrl: mongodb://127.0.0.1:27017 # a valid URL of the mongodb\nsbi: # Service-based interface information\nscheme: http # the protocol for sbi (http or https)\nregisterIPv4: 127.0.0.10 # IP used to serve NFs or register to another NRF\nbindingIPv4: 127.0.0.10  # IP used to bind the service\nport: 8000 # port used to bind the service\ncert:\npem: cert/nrf.pem\nkey: cert/nrf.key\nrootcert:\npem: cert/nrf.pem\nkey: cert/nrf.key\noauth: true\nDefaultPlmnId:\nmcc: 208 # Mobile Country Code (3 digits string, digit: 0~9)\nmnc: 93 # Mobile Network Code (2 or 3 digits string, digit: 0~9)\nserviceNameList: # the SBI services provided by this NRF, refer to TS 29.510\n- nnrf-nfm # Nnrf_NFManagement service\n- nnrf-disc # Nnrf_NFDiscovery service\n\nlogger: # log output setting\nenable: true # true or false\nlevel: info # how detailed to output, value: trace, debug, info, warn, error, fatal, panic\nreportCaller: false # enable the caller report or not, value: true or false\n
nrfcfg.yaml

Find the http://127.0.0.10:8000/nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531 in the NRF log, and you will get the 8f7891b4-b127-4f59-9ec2-b5e6aade5531. The 8f7891b4-b127-4f59-9ec2-b5e6aade5531 is the nfInstanceID.

2023-08-02T20:07:43.300826205Z [INFO][NRF][NFM] Handle NFRegisterRequest\n2023-08-02T20:07:43.308259291Z [INFO][NRF][NFM] urilist create\n2023-08-02T20:07:43.311674255Z [INFO][NRF][NFM] Create NF Profile\n2023-08-02T20:07:43.318192771Z [INFO][NRF][NFM] Location header:  http://127.0.0.10:8000/nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531\n2023-08-02T20:07:43.325073275Z [INFO][NRF][GIN] | 201 |       127.0.0.1 | PUT     | /nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531 |\n

Execute $curl -X GET {apiRoot}/nnrf-nfm/v1/nf-instances/{nfInstanceID}, and you will obtain the detail information about the nfInstanceID. You can see the nfType of the nfInstanceID is NSSF, and the information about the nfInstanceID is used when you implement the Access Token.

ubuntu@free5GC:~/free5gc/NFs/nrf$ curl -X GET http://127.0.0.10:8000/nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531\n{\"ipv4Addresses\":[\"127.0.0.31\"],\"nfInstanceId\":\"8f7891b4-b127-4f59-9ec2-b5e6aade5531\",\"nfServices\":[{\"apiPrefix\":\"http://127.0.0.31:8000\",\"ipEndPoints\":[{\"ipv4Address\":\"127.0.0.31\",\"port\":8000,\"transport\":\"TCP\"}],\"nfServiceStatus\":\"REGISTERED\",\"scheme\":\"http\",\"serviceInstanceId\":\"0\",\"serviceName\":\"nnssf-nsselection\",\"versions\":[{\"apiFullVersion\":\"1.0.2\",\"apiVersionInUri\":\"v1\"}]},{\"apiPrefix\":\"http://127.0.0.31:8000\",\"ipEndPoints\":[{\"ipv4Address\":\"127.0.0.31\",\"port\":8000,\"transport\":\"TCP\"}],\"nfServiceStatus\":\"REGISTERED\",\"scheme\":\"http\",\"serviceInstanceId\":\"1\",\"serviceName\":\"nnssf-nssaiavailability\",\"versions\":[{\"apiFullVersion\":\"1.0.2\",\"apiVersionInUri\":\"v1\"}]}],\"nfStatus\":\"REGISTERED\",\"nfType\":\"NSSF\",\"plmnList\":[{\"mcc\":\"208\",\"mnc\":\"93\"}]}\n

Then you execute this command, see below.

$curl -X POST -H \"Content-Type: application/json\" -d '{\"nfInstanceId\": {nfInstanceID}, \"grant_type\": \"client_credentials\", \"nfType\": {nfType}, \"targetNfType\": \"UDR\", \"scope\": \"nudr-dr\"}' {apiRoot}/oauth2/token\n
You will get the long symbols. The long symbols is that the Access Token is encrypted by the private key of NRF and stored in the AccessTokenRsp.

ubuntu@free5GC:~/free5gc/NFs/nrf$ curl -X POST -H \"Content-Type: application/json\" -d '{\"nfInstanceId\": \"8f7891b4-b127-4f59-9ec2-b5e6aade5531\", \"grant_type\": \"client_credentials\", \"nfType\": \"NSSF\", \"targetNfType\": \"UDR\", \"scope\": \"nudr-dr\"}' http://127.0.0.10:8000/oauth2/token\n\"eyJhY2Nlc3NfdG9rZW4iOiJleUpoYkdjaU9pSlNVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKcGMzTWlPaUlpTENKemRXSWlPaUk0WmpjNE9URmlOQzFpTVRJM0xUUm1OVGt0T1dWak1pMWlOV1UyWVdGa1pUVTFNekVpTENKaGRXUWlPaUlpTENKelkyOXdaU0k2SW01MVpISXRaSElpTENKbGVIQWlPakUyT1RFd01EZzBPRGdzSW1saGRDSTZNVFk1TVRBd056UTRPSDAuY3VHSkkwTndfV280S2lQbS1fZEZVdnVTQWM1WVEwMmRKYk5PTUhmMV9IOHdIZ2JKWFhUam9xU1Y2OTNYSmFKemkweGIxdC1DMW14TWhVZkZjbXpNMC1Nd2oxTXZYaWhyTTktdDFRUFItSFcxQlBlN0tHMUxBV3d5MEJfcXpIalltRlR6eGhONVlyNkpURDhBbkMxaFJFeEh4WHBjV1NqbV9vZnV0NVhfUFRFRkZtaHZrbmtVbU8waWFrTmdRWElRVTc1NnlvZ29ZTlFDRnJvSmRWamJMdnpFdkJLYTVFN0hQeXc3RkRDRHpTZU5WT2t2WTlobU11eldYZ3dOVmRIT3c1c2lNbmppbTlmTVZ0RTFxS1hjWDlScXlUdXlsWjM2ZlJ1QjdVZ2hkLU15Q19xd2VJRE41ZFdYOWZqdnA3VUNZZ01mVHhSLUI2M3d5OWFjQ183eThRIiwidG9rZW5fdHlwZSI6IkJlYXJlciIsImV4cGlyZXNfaW4iOjEwMDAsInNjb3BlIjoibnVkci1kciJ9\"\n

NSSF sends the AccessTokenReq to NRF after you execute the above command. In the AccessTokenReq, the nfInstanceId is set to 8f7891b4-b127-4f59-9ec2-b5e6aade5531. The grant_type is set to the client_credentials. The nfType is set to NSSF. The targetNfType is set to UDR. The scope is set to nudr-dr. The information is shown in the NRF log. The value of the targetNfInstanceId, requesterPlmn, and targetPlmn is empty because they are not set.

2023-08-02T20:18:08.127557565Z [INFO][NRF][Token] In AccessTokenProcedure\n2023-08-02T20:18:08.127586736Z [INFO][NRF][Token] Access Token Request\n2023-08-02T20:18:08.127611885Z [INFO][NRF][Token] Grant Type: client_credentials\n2023-08-02T20:18:08.127637480Z [INFO][NRF][Token] NF Instance ID: 8f7891b4-b127-4f59-9ec2-b5e6aade5531\n2023-08-02T20:18:08.127664415Z [INFO][NRF][Token] Target NF Instance ID:\n2023-08-02T20:18:08.127689792Z [INFO][NRF][Token] NF Type: NSSF\n2023-08-02T20:18:08.127712916Z [INFO][NRF][Token] Target NF Type: UDR\n2023-08-02T20:18:08.127734827Z [INFO][NRF][Token] Scope: nudr-dr\n2023-08-02T20:18:08.127758317Z [INFO][NRF][Token] Requester PLMN: <nil>\n2023-08-02T20:18:08.127781052Z [INFO][NRF][Token] Target PLMN: <nil>\n

Next, you can see the Access Token in the NRF log. The value of the Sub is 8f7891b4-b127-4f59-9ec2-b5e6aade5531. The Sub represents NSSF, and NSSF belongs to the NF Service Customer. The value of the Scope is the nudr-dr. The value of the Exp is 1691008488.

2023-08-02T20:18:08.134096785Z [INFO][NRF][Token] Access Token Claims\n2023-08-02T20:18:08.138100978Z [INFO][NRF][Token] Iss:\n2023-08-02T20:18:08.138185972Z [INFO][NRF][Token] Sub: 8f7891b4-b127-4f59-9ec2-b5e6aade5531\n2023-08-02T20:18:08.138228925Z [INFO][NRF][Token] Aud:\n2023-08-02T20:18:08.138264519Z [INFO][NRF][Token] Scope: nudr-dr\n2023-08-02T20:18:08.138298628Z [INFO][NRF][Token] Exp: 1691008488\n

Next, you can see the AccessTokenRsp. You can see that the Access Token has become the long symbols. The value of the Token Type is set to the Bearer. The value of the ExpiresIn is set to 1000. The value of the Scope is set to nudr-dr.

2023-08-02T20:18:08.149587382Z [INFO][NRF][Token] Access Token Response\n2023-08-02T20:18:08.150006665Z [INFO][NRF][Token] Access Token: eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIiLCJzdWIiOiI4Zjc4OTFiNC1iMTI3LTRmNTktOWVjMi1iNWU2YWFkZTU1MzEiLCJhdWQiOiIiLCJzY29wZSI6Im51ZHItZHIiLCJleHAiOjE2OTEwMDg0ODgsImlhdCI6MTY5MTAwNzQ4OH0.cuGJI0Nw_Wo4KiPm-_dFUvuSAc5YQ02dJbNOMHf1_H8wHgbJXXTjoqSV693XJaJzi0xb1t-C1mxMhUfFcmzM0-Mwj1MvXihrM9-t1QPR-HW1BPe7KG1LAWwy0B_qzHjYmFTzxhN5Yr6JTD8AnC1hRExHxXpcWSjm_ofut5X_PTEFFmhvknkUmO0iakNgQXIQU756yogoYNQCFroJdVjbLvzEvBKa5E7HPyw7FDCDzSeNVOkvY9hmMuzWXgwNVdHOw5siMnjim9fMVtE1qKXcX9RqyTuylZ36fRuB7Ughd-MyC_qweIDN5dWX9fjvp7UCYgMfTxR-B63wy9acC_7y8Q\n2023-08-02T20:18:08.150094277Z [INFO][NRF][Token] Token Type: Bearer\n2023-08-02T20:18:08.150133189Z [INFO][NRF][Token] Expires In: 1000\n2023-08-02T20:18:08.150167371Z [INFO][NRF][Token] Scope: nudr-dr\n

Finally, you can see 200. 200 means that AUSF sends the AccessTokenReq to NRF. NRF successfully sends to AUSF after verification.

2023-08-02T20:18:08.150302345Z [INFO][NRF][GIN] | 200 |       127.0.0.1 | POST    | /oauth2/token |\n
"},{"location":"blog/20230802/#reference","title":"Reference","text":"
  • TS 29.510
  • TS 33.501
  • [Notes] Understanding OAuth 2.0: Understand the differences of each role and each type of process at one time
  • https://blog.techbridge.cc/2019/02/01/linux-curl-command-tutorial/
  • https://github.com/free5gc/free5gc/issues/434
"},{"location":"blog/20230802/#about","title":"About","text":"

Hi, my name is Wilson. I am a master\u2019s student. My main area of research is network slicing. In the future, I will introduce more information about 5G. Hope you enjoy it.

"},{"location":"blog/TSN/","title":"TSN","text":""},{"location":"blog/TSN/#time-sensitive-networking-over-5g-system-introduction-rel-16","title":"Time-Sensitive Networking over 5G system - Introduction (Rel-16)","text":"

Note

Author: Ya-shih Tseng Date: 2023/7/12

This blog focuses on the role of the 5G system in 3GPP Release 16 TSN (Time-Sensitive Networking).

"},{"location":"blog/TSN/#what-is-time-sensitive-network-tsn","title":"What is Time-Sensitive Network (TSN)","text":"

Traditional Ethernet technology can only achieve \"best-effort\" communication and cannot meet the high reliability and low latency requirements of industrial manufacturing applications. Therefore, in the context of industrial automation, there is a need to upgrade the traditional \"best-effort\" Ethernet to provide \"deterministic\" services.

Time Sensitive Networking (TSN) brings determinism and real-time communication to standard Ethernet through mechanisms and protocols defined by the IEEE 802.1 standard, which is used by Audio Video Bridging (AVB) and TSN. It offers reliable message delivery, minimized jitter, and guaranteed delivery through central management, time scheduling, and other key features. The introduction of TSN technology holds great potential and benefits for real-time applications in industrial control, automation, and other fields.

TSN_OSI_layer

"},{"location":"blog/TSN/#tsn-standard","title":"TSN Standard","text":"

There are a lot of standards that TSN task group has completed or ongoing projects. Here are some base standards.

Standard Title IEEE 1588 V2 Precision Clock Synchronization Protocol for Networked Measurement and Control Systems IEEE 802.1Q-2022 Bridges and Bridged Networks IEEE 802.1AB-2016 Station and Media Access Control Connectivity Discovery (specifies the Link Layer Discovery Protocol (LLDP)) IEEE 802.1AS-2020 Timing and Synchronization for Time-Sensitive Applications IEEE 802.1AX-2020 Link Aggregation IEEE 802.1CB-2017 Frame Replication and Elimination for Reliability IEEE 802.1CS-2020 Link-local Registration Protocol"},{"location":"blog/TSN/#the-role-of-5g-system-in-tsn","title":"The role of 5G system in TSN","text":"

With the increasing demands for wireless control in applications such as industrial automation, remote surgical operations, smart grid distribution automation, transportation safety, autonomous driving, and more, there is a growing need to meet the low-latency requirements of these applications while achieving management, scheduling, and traffic planning. Time synchronization becomes a critical aspect. The following will explain how the interaction between TSN and 5G systems enables time synchronization.

"},{"location":"blog/TSN/#time-synchronization","title":"Time Synchronization","text":"

To achieve time synchronization between TSN and 5G systems, TSN utilizes the time synchronization method defined in IEEE 802.1AS, which is the generalized Precision Time Protocol (gPTP). gPTP supports time synchronization for Time-aware end stations and Time-aware Bridges in Layer 2. In the 3GPP TS23.501 release 16 specification, the 5G system plays the role of a \"Time-aware system\" as defined in IEEE 802.1AS and is designated as a Logical bridge, connecting TSN system end stations.

Note

gPTP is an extended version of PTP (Precision Time Protocol) that primarily expands support for second-layer network devices.

How can we synchronize the time of two end stations into the same time domain?

First, the time synchronization architecture includes Master clocks and Slave clocks. The Master regularly sends sync messages to allow the Slave to obtain the Master's time. The Slave, in turn, periodically sends peer delay requests to exchange messages with the Master, obtaining the delay time between the two devices for time correction. Additionally, the resident time, which is the message propagation delay introduced by bridges, should also be taken into account. By considering all these factors, the time synchronization of both sides can be achieved within the TSN time domain.

Time Synchronization process of gPTP

Check the link for more detail about how PTP works.

"},{"location":"blog/TSN/#intergration-of-tsn-and-5g","title":"Intergration of TSN and 5G","text":"

By now, I believe you have gained an understanding of the time synchronization mechanism in TSN. Let's briefly explain how the 5G system supports TSN as a logical TSN bridge. The 3GPP has defined new functionalities such as NW-TT, DS-TT, and TSN-AF, as well as TSN control nodes like CUC and CNC. Please check TS 23.501 Release 16 for more details.

System architecture of 5G support TSN

"},{"location":"blog/TSN/#support-ethernet-type-pdu-session","title":"Support Ethernet type PDU session","text":"

To archive the intergration, 5G system should support ingress port and egress port pair via an Ethernet Type PDU session between the corresponding UE and UPF. As mentioned above, gPTP supports layer 2 (Ethernet) only.

"},{"location":"blog/TSN/#ds-tt-and-nw-tt","title":"DS-TT and NW-TT","text":"

In the 5G system, DS-TT (Device-side TSN translator) and NW-TT (Network-side TSN translator) serve as TSN translators. DS-TT is responsible for connecting TSN Slave endpoints with the UE, while NW-TT connects TSN Master endpoints with the UPF.

When the sync message generated by the Master clock reaches the bridge, NW-TT captures its Ingress Timestamp and measures the delay between NW-TT and the Master clock. These timestamps are then embedded within the sync message and transmitted to the UE. Once the UE receives the sync message, DS-TT calculates the resident time by subtracting the Ingress Timestamp provided in the sync message, from the Egress Timestamp which represents the time of sync message reception. The resident time is added to the delay time mentioned in the sync message to determine the corrected time. Through the assistance of the TSN translators, the Slave endpoint receives the message and obtains information about time deviation and other relevant data for further adjustment.

Note

DS-TT and NW-TT enable the 5G system to function as a virtual bridge. The bridge is also called \"Transparent clock\" which is definded in IEEE 1588 and required in IEEE 802.1AS. You can say that Master and Slaver don't know the exist of the 5G TSN bridge, since it's logical transparent.

\"Transparent clocks are used to route timing messages within a network. Used when: Ethernet timing must pass through switches.\" - different type of clocks

"},{"location":"blog/TSN/#tsn-af","title":"TSN-AF","text":"

With TSN-AF, CNC can manage the 5G system functioning as a logical bridge and achieve the integration of the 5G TSN bridge with the TSN network in collaboration with NW-TT and DS-TT. Additionally, TSN-AF gathers information and capability lists of the 5G TSN Bridge and transmits them to CNC.

"},{"location":"blog/TSN/#tsn-control-nodes","title":"TSN control nodes","text":"

To meet the requirements of application services and control TSN, there are two key functions utilized in the TSN system. CNC (Centralized Network Controller), as the central controller in the TSN system, receives the information from CUC (Centralized User Configuration) and performs scheduling and planning tasks. It calculates the optimal transmission schedule for the TSN traffic based on factors such as bandwidth requirements, latency constraints, and network conditions. Once the transmission schedule is computed and confirmed, CNC proceeds to deploy the necessary network resource configuration on the TSN switches. This ensures that the TSN network operates efficiently and effectively in delivering the required QoS (Quality of Service) for the application services.

"},{"location":"blog/TSN/#reference","title":"Reference","text":"
  • IEEE Std 802.1AS-2020: \u201cIEEE Standard for Local and metropolitan area networks--Timing and Synchronization for Time-Sensitive Applications\u201d.
  • IEEE Std 1588: \u201cIEEE Standard for a Precision Clock Synchronization Protocol for Networked Measurement and Control Systems\u201d, Edition 2019.
  • 3GPP TS 23.501 Release 16
  • Time-Sensitive Networking - Wikipedia
  • Time-Sensitive Networking (TSN) Task Group | - IEEE 802.1
"},{"location":"blog/TSN/#about","title":"About","text":"

Hi, This is Ya-shih Tseng. I am currently researching the implementation of 5G TSN (Time-Sensitive Networking) as part of my master's studies. In the future, I will introduce more information about TSN. Hope you enjoy it.

"},{"location":"blog/UDM_introduce/","title":"Network function UDM introduction","text":"

Note

Author: \u5f35\u54f2\u777f Date: 2023/7/19

"},{"location":"blog/UDM_introduce/#overview","title":"Overview","text":"

In this article, I will introduce UDM and its three services that will be used in the general UE registration procedure (Nudm_UECM service, Nudm_SubscriberDataManagement Service, and Nudm_UEAuthentication service) to let everyone understand UDM more clearly.

"},{"location":"blog/UDM_introduce/#udm","title":"UDM","text":"

Unified Data Management is responsible for managing information related to UE. When other NFs need to use the UE subscription information, they will obtain it from UDM through the SBI of UDM.

"},{"location":"blog/UDM_introduce/#nudm_ueauthentication-service","title":"Nudm_UEAuthentication Service","text":"

This service is used by AUSF to retrieve authentication-related information and, after authentication, confirm the result.

3GPP TS33.501 v15.2.0

In Authentication, AUSF uses the GET operation to retrieve authentication information for the UE. The request contains the UE\u2019s identity (supi or suci) and the serving network name. The serving network name is used in the derivation of the anchor key, which is used by subsensual authentication. UE\u2019s identity will be contained in the URI, and the serving network name will be contained in the request body.

Upon reception of the Nudm_UEAuthentication_Get Request, the UDM shall de-conceal SUCI to gain SUPI if SUCI is received. At this time, UDM will query the authentication subscription data from UDR. Then, UDM shall select the authentication method based on SUPI, and if required (e.g., 5G-AKA), UDM will calculate the authentication vector and pass it to AUSF.

  • SUPI: A globally unique 5G Subscription Permanent Identifier, used to identify UE.
  • SUCI: Subscription concealed identifier, obtained by encrypting supi through the Home Network Public Key so that supi will not be obtained by a third party on the network.
logger.UeauLog.Traceln(\"In GenerateAuthDataProcedure\")\n\nresponse = &models.AuthenticationInfoResult{}\nrand.Seed(time.Now().UnixNano())\nsupi, err := suci.ToSupi(supiOrSuci, udm_context.Getself().SuciProfiles)\nif err != nil {\nproblemDetails = &models.ProblemDetails{\nStatus: http.StatusForbidden,\nCause:  authenticationRejected,\nDetail: err.Error(),\n}\n\nlogger.UeauLog.Errorln(\"suciToSupi error: \", err.Error())\nreturn nil, problemDetails\n}\n\nlogger.UeauLog.Tracef(\"supi conversion => [%s]\", supi)\n\nclient, err := createUDMClientToUDR(supi)\nif err != nil {\nreturn nil, openapi.ProblemDetailsSystemFailure(err.Error())\n}\nauthSubs, res, err := client.AuthenticationDataDocumentApi.QueryAuthSubsData(context.Background(), supi, nil)\n\n//in the udm/internal/sbi/producer/generate_auth_data.go, GenerateAuthDataProcedure function.\n

From the code, we can see UDM first de-conceal SUCI (line 5), then use QueryAuthSubsData to get authSub from UDR. After that, UDM uses this information to create the authentication vector.

Then we record the packet sent in the registration process and find the packet according to the URI specified by the specification. We can find the packet corresponding to this service.

Open the response packet, and we can see the response body matches the AuthenticationInfoResult data type.

3GPP TS29.503 v15.2.1

After AUSF authenticates the UE, it will confirm the result with UDM. These details will be used in linking authentication confirmation to the Nudm_UECM_Registration procedure from AMF.

func communicateWithUDM(ue *context.AmfUe, accessType models.AccessType) error {\nue.GmmLog.Debugln(\"communicateWithUDM\")\namfSelf := context.GetSelf()\n\n// UDM selection described in TS 23.501 6.3.8\n// TODO: consider udm group id, Routing ID part of SUCI, GPSI or External Group ID (e.g., by the NEF)\nparam := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{\nSupi: optional.NewString(ue.Supi),\n}\nresp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_UDM, models.NfType_AMF, &param)\nif err != nil {\nreturn errors.Errorf(\"AMF can not select an UDM by NRF: SendSearchNFInstances failed\")\n}\n\nvar uecmUri, sdmUri string\nfor _, nfProfile := range resp.NfInstances {\nue.UdmId = nfProfile.NfInstanceId\nuecmUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NUDM_UECM, models.NfServiceStatus_REGISTERED)\nsdmUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NUDM_SDM, models.NfServiceStatus_REGISTERED)\nif uecmUri != \"\" && sdmUri != \"\" {\nbreak\n}\n}\nue.NudmUECMUri = uecmUri\nue.NudmSDMUri = sdmUri\nif ue.NudmUECMUri == \"\" || ue.NudmSDMUri == \"\" {\nreturn errors.Errorf(\"AMF can not select an UDM by NRF: SearchNFServiceUri failed\")\n}\n\nproblemDetails, err := consumer.UeCmRegistration(ue, accessType, true)\nif problemDetails != nil {\nreturn errors.Errorf(problemDetails.Cause)\n} else if err != nil {\nreturn errors.Wrap(err, \"UECM_Registration Error\")\n}\n\n// TS 23.502 4.2.2.2.1 14a-c.\n// \"After a successful response is received, the AMF subscribes to be notified\n//      using Nudm_SDM_Subscribe when the data requested is modified\"\nproblemDetails, err = consumer.SDMGetAmData(ue)\nif problemDetails != nil {\nreturn errors.Errorf(problemDetails.Cause)\n} else if err != nil {\nreturn errors.Wrap(err, \"SDM_Get AmData Error\")\n}\n\nproblemDetails, err = consumer.SDMGetSmfSelectData(ue)\nif problemDetails != nil {\nreturn errors.Errorf(problemDetails.Cause)\n} else if err != nil {\nreturn errors.Wrap(err, \"SDM_Get SmfSelectData Error\")\n}\n\nproblemDetails, err = consumer.SDMGetUeContextInSmfData(ue)\nif problemDetails != nil {\nreturn errors.Errorf(problemDetails.Cause)\n} else if err != nil {\nreturn errors.Wrap(err, \"SDM_Get UeContextInSmfData Error\")\n}\n\nproblemDetails, err = consumer.SDMSubscribe(ue)\nif problemDetails != nil {\nreturn errors.Errorf(problemDetails.Cause)\n} else if err != nil {\nreturn errors.Wrap(err, \"SDM Subscribe Error\")\n}\nue.ContextValid = true\nreturn nil\n}\n\n\n//in the amf/internal/gmm/handler.go.\n

Next, let's take a look at this function. It is called in HandleInitialRegistration, which handles UE's initial registration. UeCmRegistration will use the Nudm_UECM (UECM) service to store related UE Context Management information in UDM. In lines 40, 47, and 54, AMF uses the Nudm_SubscriberDataManagement (SDM) Service to get some subscribe data.

"},{"location":"blog/UDM_introduce/#nudm_uecontextmanagement-service","title":"Nudm_UEContextManagement Service","text":"

In the UeCmRegistration function, AMF registers as UE's serving NF on UDM and stores related UE Context Management information in UDM. Looking at the packet, you can see that the request body contains amfInstanceId and guami, representing the amf identity, and ratType, representing the radio access technology type used by UE.

// TS 29.503 5.3.2.2.2\nfunc RegistrationAmf3gppAccessProcedure(registerRequest models.Amf3GppAccessRegistration, ueID string) (\nheader http.Header, response *models.Amf3GppAccessRegistration, problemDetails *models.ProblemDetails,\n) {\n// TODO: EPS interworking with N26 is not supported yet in this stage\nvar oldAmf3GppAccessRegContext *models.Amf3GppAccessRegistration\nif udm_context.Getself().UdmAmf3gppRegContextExists(ueID) {\nue, _ := udm_context.Getself().UdmUeFindBySupi(ueID)\noldAmf3GppAccessRegContext = ue.Amf3GppAccessRegistration\n}\n\nudm_context.Getself().CreateAmf3gppRegContext(ueID, registerRequest)\n\nclientAPI, err := createUDMClientToUDR(ueID)\nif err != nil {\nreturn nil, nil, openapi.ProblemDetailsSystemFailure(err.Error())\n}\n\nvar createAmfContext3gppParamOpts Nudr_DataRepository.CreateAmfContext3gppParamOpts\noptInterface := optional.NewInterface(registerRequest)\ncreateAmfContext3gppParamOpts.Amf3GppAccessRegistration = optInterface\nresp, err := clientAPI.AMF3GPPAccessRegistrationDocumentApi.CreateAmfContext3gpp(context.Background(),\nueID, &createAmfContext3gppParamOpts)\nif err != nil {\nlogger.UecmLog.Errorln(\"CreateAmfContext3gpp error : \", err)\nproblemDetails = &models.ProblemDetails{\nStatus: int32(resp.StatusCode),\nCause:  err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails).Cause,\nDetail: err.Error(),\n}\nreturn nil, nil, problemDetails\n}\ndefer func() {\nif rspCloseErr := resp.Body.Close(); rspCloseErr != nil {\nlogger.UecmLog.Errorf(\"CreateAmfContext3gpp response body cannot close: %+v\", rspCloseErr)\n}\n}()\n\n// TS 23.502 4.2.2.2.2 14d: UDM initiate a Nudm_UECM_DeregistrationNotification to the old AMF\n// corresponding to the same (e.g. 3GPP) access, if one exists\nif oldAmf3GppAccessRegContext != nil {\nderegistData := models.DeregistrationData{\nDeregReason: models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN,\nAccessType:  models.AccessType__3_GPP_ACCESS,\n}\ncallback.SendOnDeregistrationNotification(ueID, oldAmf3GppAccessRegContext.DeregCallbackUri,\nderegistData) // Deregistration Notify Triggered\n\nreturn nil, nil, nil\n} else {\nheader = make(http.Header)\nudmUe, _ := udm_context.Getself().UdmUeFindBySupi(ueID)\nheader.Set(\"Location\", udmUe.GetLocationURI(udm_context.LocationUriAmf3GppAccessRegistration))\nreturn header, &registerRequest, nil\n}\n}\n\n//in the udm/internal/sbi/producer/ue_context_management.go\n

In the RegistrationAmf3gppAccessProcedure function, UDM first checks whether the context has been established for that UE; if UDM has such a context, it initiates a Nudm_UECM_DeregistrationNotification to the old AMF later. UDM used the received information to create context and stored it in UDR.

"},{"location":"blog/UDM_introduce/#nudm_subscriberdatamanagement-sdm-service","title":"Nudm_SubscriberDataManagement (SDM) Service","text":"

The SDM service is used to retrieve the UE's individual subscription data relevant to the consumer's NF from the UDM. In the SDMGetAmData function, AMF gets subscription data used in registration and mobility management. In the response packet, AMF got gpsis, subscribedUeAmbr, and nssai.

The GPSI (Generic Public Subscription Identifier) is used to address a 3GPP subscription in data networks outside the realms of a 3GPP system. It contains either an External ID or an MSISDN \uff08Mobile Subscriber ISDN Number\uff09.The subscribedUeAmbr is The Maximum Aggregated uplink and downlink MBRs (max. bit rate) to be shared across all Non-GBR (non-guaranteed Bit Rate) QoS Flows according to the subscription of the user.

In the SDMGetSmfSelectData function, AMF gets subscribed S-NSSAIs (Single Network Slice Selection Assistance Information) and Data Network Names for these S-NSSAIs. AMF will use this information to select an SMF that manages the PDU Session.

func HandleInitialRegistration(ue *context.AmfUe, anType models.AccessType) error {\nue.GmmLog.Infoln(\"Handle InitialRegistration\")\n\namfSelf := context.GetSelf()\n\n// update Kgnb/Kn3iwf\nue.UpdateSecurityContext(anType)\n\n// Registration with AMF re-allocation (TS 23.502 4.2.2.2.3)\nif len(ue.SubscribedNssai) == 0 {\ngetSubscribedNssai(ue)\n}\n\nif err := handleRequestedNssai(ue, anType); err != nil {\nreturn err\n}\n\n//in the amf/internal/gmm/handler.go.\n

In the initialization of HandleInitialRegistration, AMF sends a request to the UDM to receive the UE's NSSAI (Network Slice Selection Assistance Information). After receiving subscribed NSSAI, AMF will compare it to UE's requested NSSAI. If there is a S-NSSAI that has not been subscribed before, AMF will request NSSF for Allowed NSSAI.

func handleRequestedNssai(ue *context.AmfUe, anType models.AccessType) error {\namfSelf := context.GetSelf()\n\nif ue.RegistrationRequest.RequestedNSSAI != nil {\nrequestedNssai, err := nasConvert.RequestedNssaiToModels(ue.RegistrationRequest.RequestedNSSAI)\nif err != nil {\nreturn fmt.Errorf(\"Decode failed at RequestedNSSAI[%s]\", err)\n}\n\nneedSliceSelection := false\nfor _, requestedSnssai := range requestedNssai {\nue.GmmLog.Infof(\"RequestedNssai - ServingSnssai: %+v, HomeSnssai: %+v\",\nrequestedSnssai.ServingSnssai, requestedSnssai.HomeSnssai)\nif ue.InSubscribedNssai(*requestedSnssai.ServingSnssai) {\nallowedSnssai := models.AllowedSnssai{\nAllowedSnssai: &models.Snssai{\nSst: requestedSnssai.ServingSnssai.Sst,\nSd:  requestedSnssai.ServingSnssai.Sd,\n},\nMappedHomeSnssai: requestedSnssai.HomeSnssai,\n}\nif !ue.InAllowedNssai(*allowedSnssai.AllowedSnssai, anType) {\nue.AllowedNssai[anType] = append(ue.AllowedNssai[anType], allowedSnssai)\n}\n} else {\nneedSliceSelection = true\nbreak\n}\n}\n\nif needSliceSelection {\nif ue.NssfUri == \"\" {\nfor {\nerr := consumer.SearchNssfNSSelectionInstance(ue, amfSelf.NrfUri, models.NfType_NSSF, models.NfType_AMF, nil)\nif err != nil {\nue.GmmLog.Errorf(\"AMF can not select an NSSF Instance by NRF[Error: %+v]\", err)\ntime.Sleep(2 * time.Second)\n} else {\nbreak\n}\n}\n}\n\n// Step 4\nproblemDetails, err := consumer.NSSelectionGetForRegistration(ue, requestedNssai)\nif problemDetails != nil {\nue.GmmLog.Errorf(\"NSSelection Get Failed Problem[%+v]\", problemDetails)\ngmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMProtocolErrorUnspecified, \"\")\nreturn fmt.Errorf(\"Handle Requested Nssai of UE failed\")\n} else if err != nil {\nue.GmmLog.Errorf(\"NSSelection Get Error[%+v]\", err)\ngmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMProtocolErrorUnspecified, \"\")\nreturn fmt.Errorf(\"Handle Requested Nssai of UE failed\")\n}\n\n//in the amf/internal/gmm/handler.go.\n
if param.SliceInfoRequestForRegistration.RequestedNssai != nil &&\nlen(param.SliceInfoRequestForRegistration.RequestedNssai) != 0 {\n// Requested NSSAI is provided\n// Verify which S-NSSAI(s) in the Requested NSSAI are permitted based on comparing the Subscribed S-NSSAI(s)\nif param.Tai != nil &&\n!util.CheckSupportedNssaiInPlmn(param.SliceInfoRequestForRegistration.RequestedNssai, *param.Tai.PlmnId) {\n// Return ProblemDetails indicating S-NSSAI is not supported\n// TODO: Based on TS 23.501 V15.2.0, if the Requested NSSAI includes an S-NSSAI that is not valid in the\n//       Serving PLMN, the NSSF may derive the Configured NSSAI for Serving PLMN\n*problemDetails = models.ProblemDetails{\nTitle:  util.UNSUPPORTED_RESOURCE,\nStatus: http.StatusForbidden,\nDetail: \"S-NSSAI in Requested NSSAI is not supported in PLMN\",\nCause:  \"SNSSAI_NOT_SUPPORTED\",\n}\n\nstatus = http.StatusForbidden\nreturn status\n}\n\n// Check if any Requested S-NSSAIs is present in Subscribed S-NSSAIs\ncheckIfRequestAllowed := false\n\nfor _, requestedSnssai := range param.SliceInfoRequestForRegistration.RequestedNssai {\nif param.Tai != nil && !util.CheckSupportedSnssaiInTa(requestedSnssai, *param.Tai) {\n// Requested S-NSSAI does not supported in UE's current TA\n// Add it to Rejected NSSAI in TA\nauthorizedNetworkSliceInfo.RejectedNssaiInTa = append(\nauthorizedNetworkSliceInfo.RejectedNssaiInTa,\nrequestedSnssai)\ncontinue\n}\n\nvar mappingOfRequestedSnssai models.Snssai\n// TODO: Compared with Restricted S-NSSAI list in configuration under roaming scenario\nif param.HomePlmnId != nil && !util.CheckStandardSnssai(requestedSnssai) {\n// Standard S-NSSAIs are supported to be commonly decided by all roaming partners\n// Only non-standard S-NSSAIs are required to find mappings\ntargetMapping, found := util.FindMappingWithServingSnssai(requestedSnssai,\nparam.SliceInfoRequestForRegistration.MappingOfNssai)\n\nif !found {\n// No mapping of Requested S-NSSAI to HPLMN S-NSSAI is provided by UE\n// TODO: Search for local configuration if there is no provided mapping from UE, and update UE's\n//       Configured NSSAI\ncheckInvalidRequestedNssai = true\nauthorizedNetworkSliceInfo.RejectedNssaiInPlmn = append(\nauthorizedNetworkSliceInfo.RejectedNssaiInPlmn,\nrequestedSnssai)\ncontinue\n} else {\n// TODO: Check if mappings of S-NSSAIs are correct\n//       If not, update UE's Configured NSSAI\nmappingOfRequestedSnssai = *targetMapping.HomeSnssai\n}\n} else {\nmappingOfRequestedSnssai = requestedSnssai\n}\n\nhitSubscription := false\nfor _, subscribedSnssai := range param.SliceInfoRequestForRegistration.SubscribedNssai {\nif mappingOfRequestedSnssai == *subscribedSnssai.SubscribedSnssai {\n// Requested S-NSSAI matches one of Subscribed S-NSSAI\n// Add it to Allowed NSSAI list\nhitSubscription = true\n\nvar allowedSnssaiElement models.AllowedSnssai\nallowedSnssaiElement.AllowedSnssai = new(models.Snssai)\n*allowedSnssaiElement.AllowedSnssai = requestedSnssai\nnsiInformationList := util.GetNsiInformationListFromConfig(requestedSnssai)\nif nsiInformationList != nil {\n// TODO: `NsiInformationList` should be slice in `AllowedSnssai` instead of pointer of slice\nallowedSnssaiElement.NsiInformationList = append(\nallowedSnssaiElement.NsiInformationList,\nnsiInformationList...)\n}\nif param.HomePlmnId != nil && !util.CheckStandardSnssai(requestedSnssai) {\nallowedSnssaiElement.MappedHomeSnssai = new(models.Snssai)\n*allowedSnssaiElement.MappedHomeSnssai = *subscribedSnssai.SubscribedSnssai\n}\n\n// Default Access Type is set to 3GPP Access if no TAI is provided\n// TODO: Depend on operator implementation, it may also return S-NSSAIs in all valid Access Type if\n//       UE's Access Type could not be identified\nvar accessType models.AccessType = models.AccessType__3_GPP_ACCESS\nif param.Tai != nil {\naccessType = util.GetAccessTypeFromConfig(*param.Tai)\n}\n\nutil.AddAllowedSnssai(allowedSnssaiElement, accessType, authorizedNetworkSliceInfo)\n\ncheckIfRequestAllowed = true\nbreak\n}\n}\n\nif !hitSubscription {\n// Requested S-NSSAI does not match any Subscribed S-NSSAI\n// Add it to Rejected NSSAI in PLMN\ncheckInvalidRequestedNssai = true\nauthorizedNetworkSliceInfo.RejectedNssaiInPlmn = append(\nauthorizedNetworkSliceInfo.RejectedNssaiInPlmn,\nrequestedSnssai)\n}\n}\n\nif !checkIfRequestAllowed {\n// No S-NSSAI from Requested NSSAI is present in Subscribed S-NSSAIs\n// Subscribed S-NSSAIs marked as default are used\nuseDefaultSubscribedSnssai(param, authorizedNetworkSliceInfo)\n}\n} else {\n// No Requested NSSAI is provided\n// Subscribed S-NSSAIs marked as default are used\ncheckInvalidRequestedNssai = true\nuseDefaultSubscribedSnssai(param, authorizedNetworkSliceInfo)\n}\n\n//in the nssf/internal/sbi/producer/nsselection_for_registration.go, nsselectionForRegistration funcion.\n

If NSSF needs to select S-NSSAI, it first finds the mapping of requested NSSAI to configured NSSAI for the HPLMN and converts requested S-NSSAI to S-NSSAI in configured NSSAI for the HPLMN. Then compare these S-NSSAIs with Subscribed S-NSSAIs; if NSSF find one match, set it as AllowedSnssai. If NSSF can't find such a mapping or no S-NSSAI in the mapping matches subscribed S-NSSAIs, it will use default subscribed S-NSSAIs.

"},{"location":"blog/UDM_introduce/#reference","title":"Reference","text":"
  • 3GPP TS29.503 v15.2.1
  • 3GPP TS23.502 v15.2.0
  • 3GPP TS23.501 v15.2.0
  • 3GPP TS33.501 v15.2.0
  • free5GC v3.3.0
"},{"location":"blog/UDM_introduce/#about","title":"About","text":"

Hello! My name is \u5f35\u54f2\u777f, and my current research topic is ATSSS (Access Traffic Steering, Switching and Splitting), I will continue to write articles related to 5G networks in the future. If you find any mistakes in my articles or have any topics you want to know about, please contact me.

  • Linkedln
"},{"location":"blog/network_slice/","title":"How to deploy a free5GC network slice on OpenStack","text":"

Note

Author: Daniel Hsieh Date: 2023/7/26

"},{"location":"blog/network_slice/#whats-network-slicing","title":"What's Network Slicing","text":"

Network slicing allows for the creation of multiple logical, isolated, and independent virtual networks that can coexist within a shared physical infrastructure. Each network slice provides dedicated and customized network resources to meet the specific requirements of different services The main elements of a network slice include:

  • Virtualized Network Functions (VNFs): Each network slice can include a set of virtualized network functions that provide specific network capabilities and services. These VNFs can include functions like routing, switching, firewalling, load balancing, or any other network service required by the slice.

  • Isolation and Resource Allocation: Network slicing ensures the isolation of resources between slices, preventing interference and conflicts. It allows for the allocation of dedicated and optimized resources such as bandwidth, processing power, and storage to each slice based on its specific needs.

  • Orchestration and Management: Network slice orchestration involves the creation, provisioning, and management of network slices. It involves configuring the appropriate VNFs, assigning resources, and establishing connectivity between the different components of a slice.

NFV Enabling Network Slicing for 5G

Take Figure 1 as an example. The first slice is designed for mobile devices such as smartphones. Such slice requires a huge diversity of VNFs, and virtual links with high speed and low latency to support the broadband service of smartphones. In 5G network, Those slices are referred to as eMBB (enhanced mobile broadband) slices.

The second slice is designed for autonomous driving. In such scenario, extremely low latency and high reliability are paramount to ensure the vehicles' operability, smoothness and safety. To achieve low latency, some of the NFs should be deployed close to the access node,i.e. on edge cloud. To achieve high reliability, a NF should have multiple instances on available physical resources to make the slice more fault tolerant. Such slice is referred to as URLLC (Ultra-Reliable Low-Latency Communications) slice.

The third slice is designed for massive IoT. IoT devices are expected to not move and send very small amount of data intermittently. Due to the nature of such devices, functions that handle mobiltiy and always-on connections are not needed. Such slices are referred to as mIoT (massive IoT) slices.

"},{"location":"blog/network_slice/#mano-architecture","title":"MANO Architecture","text":"

In this article, we utilize MANO network function virtualization (NFV) architecture to deploy virtual network function (VNF). It plays the role of creating, deploying, and managing VNFs. MANO consists of three main functional components: NFV Orchestrator (NFVO), Virtualized Infrastructure Manager (VIM), and Virtual Network Function Manager (VNFM).

NFV MANO Architecture

  • NFVO manages the underlying resource by coordinating VIM and VNFM. It handles tasks such as receiving requests, service instantiation, scaling, termination, and monitoring.

  • VNFM manages the lifecycle of VNF instances. It interacts with the VIM to instantiate, configure, monitor, and terminate VNF instances.

  • VIM is responsible for managing the underlying virtualized infrastructure that hosts the VNFs. It abstracts the physical resources, such as compute, storage, and networking, and provides a unified view to the NFVO. The VIM handles tasks like resource allocation, performance monitoring, fault management, and virtualization management.

For VIM, we use OpenStack, an open-source software that provides IaaS, to utilize the physical resources. For VNFM and NFVO, we use Tacker, a service component of OpenStack, to manage VNFs.

"},{"location":"blog/network_slice/#openstack","title":"OpenStack","text":"

OpenStack is an open-source cloud computing platform that provides a set of software tools for building and managing customized clouds. OpenStack offers a infrastructure-as-a-service (IaaS) solution, enabling organizations to create and manage virtualized resources in a cloud environment. It is designed to be modular and consists of various components that work together to deliver a comprehensive cloud computing platform. Some of the key components include:

  • Nova: Nova is the computing component of OpenStack and serves as the main compute engine. It manages the creation, scheduling, and management of virtual machines (VMs) and provides APIs for controlling and interacting with the compute resources.

  • Cinder: Cinder is the block storage component of OpenStack. It provides persistent storage for virtual machines. With Cinder, users can create and manage volumes that can be attached to instances, allowing for flexible and scalable storage options.

  • Neutron: Neutron is the networking component of OpenStack. It provides a networking-as-a-service (NaaS) solution, allowing users to define and manage network resources. Neutron supports virtual LANs, software-defined networking (SDN), and network function virtualization (NFV), etc.

  • Keystone: Keystone is the identity service component of OpenStack. It provides authentication and authorization services, enabling users to securely access and manage resources within the cloud. Keystone supports multiple authentication mechanisms, including username/password, token-based, and external identity providers.

  • Horizon: Horizon is the web-based dashboard for OpenStack. It provides a user-friendly interface for managing and monitoring the cloud infrastructure. With Horizon, users can perform various tasks, such as launching instances, managing storage resources, and configuring networking options.

OpenStack Architecture

OpenStack is highly flexible and customizable, allowing organizations to tailor the cloud infrastructure to their specific needs. It supports multiple hypervisors, including KVM, VMware, and Hyper-V.

"},{"location":"blog/network_slice/#tacker","title":"Tacker","text":"

To enable NFV, we need another service component of OpenStack called Tacker. Tacker is designed to simplify the deployment and lifecycle management of VNFs and network service functions (NSFs) in a cloud infrastructure. It leverages OpenStack's existing components, such as Nova, Neutron, and Heat, to provide a comprehensive solution for network service orchestration. Tacker provides several key features and functionalities:

  • Service Templates: Tacker uses service templates to define the composition and behavior of network services. These templates describe the VNFs and NSFs involved, their interconnections, resource requirements, etc. Service templates are written using the TOSCA (Topology and Orchestration Specification for Cloud Applications) standard.

  • Lifecycle Management: Tacker automates the entire lifecycle of network services, including provisioning, scaling, healing, and termination. It leverages Heat, OpenStack's orchestration service, to manage the underlying infrastructure resources required by the services and handle dynamic scaling of VNFs based on traffic demands.

  • VNF Manager: Tacker includes a VNF Manager component responsible for managing the lifecycle of VNFs. It interacts with OpenStack's compute and networking services, to instantiate and manage VNF instances.

  • Multi-VIM Support: Tacker supports multiple virtual infrastructure managers to accommodate different cloud platforms and environments. It can interact with OpenStack, VMware vSphere and Kubernetes and so on, enabling operators to deploy network services across heterogeneous infrastructure environments.

Tacker Architecture

"},{"location":"blog/network_slice/#deploy-a-free5gc-network-slice","title":"Deploy a free5GC Network Slice","text":"
  1. In our implementation, we install OpenStack and Tacker on two different virtual machines for resource utilization reasons, but in fact, they can be installed on the same virtual machine.

  2. we need to install OpenStack on a virtual machine. Specific details and corresponding compatibility can be found on OpenStack official website. Using devstack scripts for installation enables operators to customize the environment based on their needs, such as extra plugins (softwares that extends the functionality of OpenStack environment) and overcommit (allows deploying NFs that require more resource than existing physical resourcce) functionality. Upon completion, a web UI enabled by Horizon can be used to access and operate on your own personalized OpenStack cloud.

  3. Install Tacker on another virtual machine, which requires four OpenStack service components, Keystone, Mistral, Barbican and Horizon. Once the installation is completed, we can register our OpenStack VIM on Tacker using openstack vim registercommand.

  4. Create two instances that will be used as images (one for control plane VNFs, one for UPF) for the VNFs that we will create. Then, ssh into those instances to set up the configurations for the VNFs, such as, installing required packages (go language, mongodb, libtool, etc.) and git clone free5GC source code. Once all the configurations are done, use OpenStack dashboard to take snapshots of these instances, which will be used as the images for VNFs.

  5. Import all the VNF descriptors (VNFD) of the VNFs we need by using openstack vnf descriptor create command. VNFDs should be written in accordance with TOSCA format. TOSCA format allows you to define the virtual links (a virtual network VNFs will be running in) and virtual deployment unit (operation unit of a VNF). Below is an example of UPF VNFD:

    tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0\ndescription: description\nnode_types:\ntosca.nodes.nfv.VNF11:\nrequirements:\n- virtualLink1:\ntype: tosca.nodes.nfv.VL\nrequired: true\nmetadata:\ntemplate_name: free5GCSetup\ntopology_template:\nsubstitution_mappings:\nnode_type: tosca.nodes.nfv.VNF11\nnode_templates:\nVDU1:\ntype: tosca.nodes.nfv.VDU.Tacker\nproperties:\nname: free5gc-upf1-VNF\nimage: stage3-up\nflavor: free5gc\navailability_zone: nova\nmgmt_driver: noop\nkey_name: free5gc\nuser_data_format: RAW\nuser_data: |\n#!/bin/sh\ncd /home/ubuntu/free5gc/src/upf/build \ncat > config/upfcfg.yaml <<- EOM\ninfo:\nversion: 1.0.0\ndescription: UPF configuration\n\nconfiguration:\n# debugLevel: panic|fatal|error|warn|info|debug|trace\ndebugLevel: info\n\npfcp:\n- addr: 192.168.2.111\n\ngtpu:\n- addr: 192.168.2.111\n# [optional] gtpu.name\n# - name: upf.5gc.nctu.me\n# [optional] gtpu.ifname\n# - ifname: gtpif\n\napn_list:\n- apn: internet\ncidr: 60.60.0.0/24\n# [optional] apn_list[*].natifname\n# natifname: eth0\nEOM\n#sudo ./bin/free5gc-upfd -f config/upfcfg.yaml\n\nCP1:\ntype: tosca.nodes.nfv.CP.Tacker\nproperties:\nip_address: 192.168.2.111\nmanagement: true\nrequirements:\n- virtualLink:\nnode: VL1\n- virtualBinding:\nnode: VDU1\nVL1:\ntype: tosca.nodes.nfv.VL\nproperties:\nnetwork_name: 5GC\nvendor: Tacker\nFIP1:\ntype: tosca.nodes.network.FloatingIP\nproperties:\nfloating_network: public\nfloating_ip_address: 172.24.4.111\nrequirements:\n- link:\nnode: CP1\n

  6. Import the network service descriptor (NSD) using openstack ns descriptor create command. The NSD should also be written in accordance with TOSCA format. Once all the VNFDs and NSD are all successfully imported, we can use openstack ns create to deploy the network slice. The VNFs specified in the NSD will also be instantiated along with the network slice. Their instances can be viewed on OpenStack dashboard enabled by Horizon or just use openstack vnf list to check the status of the VNFs. Below is an example of NSD
    tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0\ndescription: Import Common Slice VNFDs (already on-boarded)\nimports:\n- mongo\n- nrf\n- amf\n- smf\n- udr\n- pcf\n- udm\n- nssf\n- ausf\ntopology_template:\nnode_templates:\nVNF0:\ntype: tosca.nodes.nfv.VNF0\nVNF1:\ntype: tosca.nodes.nfv.VNF1\nVNF2:\ntype: tosca.nodes.nfv.VNF2\nVNF3:\ntype: tosca.nodes.nfv.VNF3\nVNF4:\ntype: tosca.nodes.nfv.VNF4\nVNF5:\ntype: tosca.nodes.nfv.VNF5\nVNF6:\ntype: tosca.nodes.nfv.VNF6\nVNF7:\ntype: tosca.nodes.nfv.VNF7\nVNF8:\ntype: tosca.nodes.nfv.VNF8\n
  7. ssh into the VNF instances to make the necessary configuration for each VNF and start the free5GC VNF.
  8. Voila! Now we have a fully functional free5GC network slice.

There are many other ways to set up a network slice. For example, we can deploy VNFs of the same network slice on different VIMs, or we can deploy all the network slices on the same VIM, as long as it is specified in the VNFDs.

"},{"location":"blog/network_slice/#about","title":"About","text":"

Hi, my name is Daniel Hsieh. I am a CS major graduate student. My research field is network slicing. If there are any questions about the article, please feel free to contact.

  • email: e657shai@gmail.com
"},{"location":"blog/network_slice/#reference","title":"Reference","text":"
  • https://www.acecloudhosting.com/blog/openstack-the-catalyst-of-the-public-cloud-market/

  • https://telcocloudbridge.com/blog/a-beginners-guide-to-nfv-management-orchestration-mano/

  • https://wiki.openstack.org/wiki/Tacker

  • B. Chatras, U. S. Tsang Kwong and N. Bihannic, \"NFV enabling network slicing for 5G,\" 2017 20th Conference on Innovations in Clouds, Internet and Networks (ICIN), Paris, France, 2017, pp. 219-225, doi: 10.1109/ICIN.2017.7899415.

"},{"location":"blog/CSRF/20230823/","title":"Web security: CSRF vulnerability in webconsole","text":""},{"location":"blog/CSRF/20230823/#abstract","title":"Abstract","text":"

This article is intended for individuals who possess an interest in free5gc/webconsole and hold concerns regarding security matters. It aims to provide a concise introduction to the webconsole, followed by an exposition of a significant security concern along with our corresponding solution. Within webconsole v1.2.0, aligning with the most recent iteration of free5gc v3.3.0, certain vulnerabilities have been identified that could potentially lead to the exposure of subscriber data. It is my responsibility to address and rectify these vulnerabilities, enhancing the webconsole's resilience against cyber attacks.

"},{"location":"blog/CSRF/20230823/#webconsole-overview","title":"Webconsole Overview","text":"

The Webconsole serves as a web-based tool designed to manage User Equipment (UE) subscription data. It plays a crucial role in aiding the free5GC Core Network manager by facilitating the configuration of UEs and providing the ability to monitor the status of activated UEs.

"},{"location":"blog/CSRF/20230823/#environment","title":"Environment","text":"
  • Frontend
    • React v17.0.2
    • node.js v20.2.0
    • yarn v1.22.19
  • Backend
    • Golang v1.17
    • Gin v1.9.0
    • MongoDB v3.6.8
"},{"location":"blog/CSRF/20230823/#install-run-webconsole","title":"Install & Run webconsole","text":"

Prior to building webconsole, install nodejs and yarn package first:

sudo apt remove cmdtest\nsudo apt remove yarn\ncurl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -\necho \"deb https://dl.yarnpkg.com/debian/ stable main\" | sudo tee /etc/apt/sources.list.d/yarn.list\nsudo apt-get update\nsudo apt-get install -y nodejs yarn\n

To run free5GC webconsole server. The following steps are to be considered.

git clone https://github.com/free5gc/webconsole.git\ncd frontend\nyarn install\nyarn build\nrm -rf ../public\ncp -R build ../public\ncd ..\ngo run server.go\n

Default account and password is admin/free5gc

"},{"location":"blog/CSRF/20230823/#pages","title":"Pages","text":""},{"location":"blog/CSRF/20230823/#subscribers","title":"SUBSCRIBERS","text":"

Creation/deletion/editing the subscriber's data:

A Subscriber data contains these informations: - PLMN ID - SUPI (UE ID) - AKA parameters - S-NSSAI Configurations - Sst/Sd - DNN - Name - AMBR - Flow Rules - IP Filter - Precedence - 5QI - GBR - MBR

"},{"location":"blog/CSRF/20230823/#tenant-and-user","title":"TENANT AND USER","text":"

The Webconsole also allows for the creation, deletion, and editing of tenants. A tenant functions as an access control group, delineating specific permissions and boundaries. In this setup, if you do not possess admin privileges, you are unable to access subscriber data generated by other tenants, ensuring data privacy and security.

Furthermore, the capability to incorporate users within a tenant is available. To illustrate, by selecting the brian1 tenant and clicking on the New User option, it becomes possible to introduce a new user. As an example, a user with the email address aaabbb@gmail.com can be added through this process.

The data within MongoDB can be accessed and reviewed using the MongoDBCompass tool.

"},{"location":"blog/CSRF/20230823/#csrf-cross-site-request-forgery-vulnerability","title":"CSRF (Cross-Site Request Forgery) Vulnerability","text":"

The vulnerability was discovered by INCIBE, and they promptly notified the free5GC team via email.

The corresponding issue related to this vulnerability is also documented in the free5gc repository. Despite the typical deployment of the webconsole within LAN or Docker environments, it's essential to exercise caution regarding users who operate this service on a public IP or within an insecure network environment.

In a nutshell, an attacker can gain unauthorized access to the database by merely setting the token to the term 'admin'.

$ curl '<webconsole's IP>:5000/api/subscriber' -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.0' -H 'Accept: application/json' -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate' -H 'Referer: http://<webconsole's IP>:5000/' -H 'Connection: keep-alive' -H 'X-Requested-With: XMLHttpRequest' -H 'Token: admin' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache'\n

Subsequently, they can directly retrieve subscriber information from the server's MongoDB.

[{\"plmnID\":\"20893\",\"ueId\":\"imsi-208930000000003\"}]\n

Undoubtedly, this vulnerability is of significant concern since the intended safeguard, allowing access solely to admin, has been compromised, thereby enabling easy access for anyone.

"},{"location":"blog/CSRF/20230823/#trace-code","title":"Trace Code","text":""},{"location":"blog/CSRF/20230823/#frontend","title":"Frontend","text":"

In webconsole/frontend/src/util/AuthHelper.js - In scenarios where the default username and password (admin/free5gc) are employed, the ApiHelper.login() function remains untouched. This practice might expedite agile development, but it comes at the cost of compromising security.

"},{"location":"blog/CSRF/20230823/#backend","title":"Backend","text":"

In webconsole/frontend/WebUI/api_webui.go - In situations where a webconsole client configures the tokenStr as 'admin', the backend process will omit the execution of ParseJWT().

"},{"location":"blog/CSRF/20230823/#json-web-token-jwt","title":"JSON Web Token (JWT)","text":"

The Webconsole relies on JSON Web Token (JWT) as its authentication mechanism, a specification outlined in RFC 7519.

JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.

When a client employs a web browser to initiate a login via the HTTP(s) protocol, the Web server is expected to furnish the client with a JWT token in response. Subsequently, the client employs this JWT token to interact with resources by sending requests through the RESTful API (such as GET, POST, PUT, etc.).

A JSON Web Token (JWT) consists of three distinct parts. In the context of the webconsole backend, the following fields are relevant: - Header: This section contains information about the type of token and the signing algorithm used. It often includes the \"alg\" (algorithm) and \"typ\" (type) fields. - Payload: The payload holds the actual claims or data that are being conveyed by the token. For the webconsole backend, specific fields within this section could include: - Claim (JSON object) - sub: identifies the principal that is the subject of the JWT. - iat: identifies the time at which the JWT was issued. - exp: identifies the expiration time onor after which the JWT MUST NOT be accepted for processing. - email - tenantId - ...(you can design the attribute yourself) - Signature: This component is created by combining the encoded header and payload with a secret key (or a public/private key pair) to ensure the token's integrity and authenticity. The signature allows the recipient to verify that the token hasn't been tampered with.

The JWT Claims Set represents a JSON object whose members are the claims conveyed by the JWT. The Claim Names within a JWT Claims Set MUST be unique; JWT parsers MUST either reject JWTs with duplicate Claim Names or use a JSON parser that returns only the lexically last duplicate member name

The image depicted below illustrates the process of using jwt.io to both encode and decode JWT tokens. These tokens are segmented into distinct sections denoted by the red, purple and blue divisions, separated by periods dots.

Given that the Payload can be decoded using the algorithm specified in the Header, it's essential to refrain from including sensitive details like passwords or credit card numbers within it. Instead, the Payload typically holds claims and application-specific metadata.

To maintain the security of the process, the server retains a confidential key used to validate the signature. In situations where a client endeavors to access a resource using a JWT token that possesses an incorrect Verify Signature, an error response will be generated. This stringent signature verification mechanism ensures that the authenticity and integrity of both the token and its enclosed data are upheld.

"},{"location":"blog/CSRF/20230823/#trace-code-cont","title":"Trace Code (Cont.)","text":"

In webconsole/frontend/WebUI/api_webui.go, we can find the implementation of JWT. - JWT() is for encoding: ```go=394 func JWT(email, userId, tenantId string) string { token := jwt.New(jwt.SigningMethodHS256)

claims := token.Claims.(jwt.MapClaims)\nclaims[\"sub\"] = userId\nclaims[\"iat\"] = time.Now()\nclaims[\"exp\"] = time.Now().Add(time.Hour * 24).Unix()\nclaims[\"email\"] = email\nclaims[\"tenantId\"] = tenantId\n\nif jwtKey == \"\" {\n    return \"\"\n}\n\ntokenString, err := token.SignedString([]byte(jwtKey))\nif err != nil {\n    logger.ProcLog.Errorf(\"JWT err: %+v\", err)\n    return \"\"\n}\n\nreturn tokenString\n

} - `ParseJWT()` is for decoding:go=491 func ParseJWT(tokenStr string) (jwt.MapClaims, error) { token, err := jwt.Parse(tokenStr, func(token jwt.Token) (interface{}, error) { return []byte(jwtKey), nil }) if err != nil { return nil, errors.Wrap(err, \"ParseJWT error\") } claims, _ := token.Claims.(jwt.MapClaims) return claims, nil } - The function `CheckAuth()` serves the purpose of determining whether a user possesses the authorization to access a particular resource.go=505 func CheckAuth(c gin.Context) bool { tokenStr := c.GetHeader(\"Token\") if tokenStr == \"admin\" { return true } else { return false } } `` ::: - The secret key utilized for signature verification is obtained throughos.Getenv(\"SIGNINGKEY\"). However, there's a possibility thatSIGNINGKEYmight not be exported as an environment variable, leading to a potential return of an empty value. Under such circumstances, an implication arises: an admin in Webconsole A could potentially gain access to subscriber data within Webconsole B. - Within theCheckAuth()` function, if the client sets the JWT token to 'admin', the function will evaluate to true, effectively allowing the check to be passed. :::

"},{"location":"blog/CSRF/20230823/#implementation","title":"Implementation","text":""},{"location":"blog/CSRF/20230823/#check-authentication","title":"Check Authentication","text":"

Initially, I have revised the design of the CheckAuth() function to ensure the mandatory execution of ParseJWT(). go= func CheckAuth(c *gin.Context) bool { tokenStr := c.GetHeader(\"Token\") claims, err := ParseJWT(tokenStr) if err == nil && claims[\"email\"] == \"admin\" { return true } else { return false } } Furthermore, I've implemented a second change where, considering that the webconsole v1.2.0 doesn't inherently establish a tenant named 'admin' or a user named 'admin', I propose a more effective approach. During the initialization of the webconsole backend, it is recommended to generate an 'admin' tenant and user. This means that executing go run server.go within the webconsole/ directory should consistently generate an admin user, thereby fulfilling the initial login requirement.

Certainly, in the backend/WebUI/api_webui.go file, I propose the addition of a function named SetAdmin(). To streamline the process and maintain consistency with the rest of the free5GC project, it is recommended to leverage the mongoapi module established within the free5gc/util repository. Given the project's heavy reliance on MongoDB, employing mongoapi over frequent calls to mongo-driver is essential to ensure efficiency and coherence.

```go= func SetAdmin() { err := mongoapi.RestfulAPIDeleteOne(\"tenantData\", bson.M{\"tenantName\": \"admin\"}) if err != nil { logger.InitLog.Errorf(\"RestfulAPIDeleteOne err: %+v\", err) } err = mongoapi.RestfulAPIDeleteOne(\"userData\", bson.M{\"email\": \"admin\"}) if err != nil { logger.InitLog.Errorf(\"RestfulAPIDeleteOne err: %+v\", err) }

// Create Admin tenant\nlogger.InitLog.Infoln(\"Create tenant: admin\")\n\nadminTenantData := bson.M{\n    \"tenantId\":   uuid.Must(uuid.NewRandom()).String(),\n    \"tenantName\": \"admin\",\n}\n\n_, err = mongoapi.RestfulAPIPutOne(\"tenantData\", bson.M{\"tenantName\": \"admin\"}, adminTenantData)\nif err != nil {\n    logger.InitLog.Errorf(\"RestfulAPIPutOne err: %+v\", err)\n}\n\nAmdinTenant, err := mongoapi.RestfulAPIGetOne(\"tenantData\", bson.M{\"tenantName\": \"admin\"})\nif err != nil {\n    logger.InitLog.Errorf(\"RestfulAPIGetOne err: %+v\", err)\n}\n\n// Create Admin user\nlogger.InitLog.Infoln(\"Create user: admin\")\n\nhash, err := bcrypt.GenerateFromPassword([]byte(\"free5gc\"), 12)\nif err != nil {\n    logger.InitLog.Errorf(\"GenerateFromPassword err: %+v\", err)\n}\n\nadminUserData := bson.M{\n    \"userId\":            uuid.Must(uuid.NewRandom()).String(),\n    \"tenantId\":          AmdinTenant[\"tenantId\"],\n    \"email\":             \"admin\",\n    \"encryptedPassword\": string(hash),\n}\n\n_, err = mongoapi.RestfulAPIPutOne(\"userData\", bson.M{\"email\": \"admin\"}, adminUserData)\nif err != nil {\n    logger.InitLog.Errorf(\"RestfulAPIPutOne err: %+v\", err)\n}\n

} ```

"},{"location":"blog/CSRF/20230823/#jwt-verify-signature","title":"JWT Verify Signature","text":"

Certainly, within the backend/WebUI/api_webui.go file, I recommend introducing a string variable named jwtKey to serve as the private key for JWT Verify Signature. Although the length of jwtKey is specified as 256 bytes, it's worth noting that the distinction between 256 bytes and 256 bits is inconsequential in this context. The jwt module will adeptly transform the key to a 256-bit form. For further insights, you can refer to issue 28. go= var jwtKey = \"\" // for generating JWT /* ... */ func InitJwtKey() error { randomBytes := make([]byte, 256) _, err := rand.Read(randomBytes) if err != nil { return errors.Wrap(err, \"Init JWT key error\") } else { jwtKey = string(randomBytes) } return nil }

"},{"location":"blog/CSRF/20230823/#backend-initialization","title":"Backend Initialization","text":"

In backend/webui_service/webui_init.go:

```go= func (a WebuiApp) Start(tlsKeyLogPath string) { / ... / WebUI.SetAdmin() if err := WebUI.InitJwtKey(); err != nil { logger.InitLog.Errorln(err) return } / ... */ }

### Frontend Login\n\nCertainly, in the `frontend/src/util/AuthHelper.js` file, it is advised to remove the section of code that could be considered a \"cheating snippet.\" To ensure a robust authentication process, all users should be required to successfully pass through the `ApiHelper.login` function and receive a response code of 200. This approach ensures a consistent and legitimate authentication mechanism.\n\n```javascript\nstatic async login(username, password) {\n    let response = await ApiHelper.login({username: username, password: password});\n\n    if (response !== undefined && response.status === 200) {\n      var user = null\n      if (username == \"admin\") {\n        user = new User(username, \"System Administrator\", response.data.access_token);\n      } else {\n        user = new User(username, \"User\", response.data.access_token);\n      }\n      LocalStorageHelper.setUserInfo(user);\n      store.dispatch(authActions.setUser(user));\n      return true;\n    } else {\n      return false;\n    }\n  }\n

"},{"location":"blog/CSRF/20230823/#conclusion","title":"Conclusion","text":"

In this endeavor, we've successfully addressed the CSRF vulnerability issue, as highlighted in issue #387 and acknowledged by INCIBE. Furthermore, I've introduced the concept of JWT tokens in this article, detailing their implementation and the corresponding adjustments made within the webconsole. You can locate the detailed implementation in the merged PR #44 of the webconsole repository. I'd like to extend my gratitude to the contributors kishiguro and LaumiH for their significant role in refactoring the webconsole. As a result of their efforts, the webconsole UI has been notably enhanced. Our upcoming focus involves the integration of the charging function, which we are actively pursuing.

"},{"location":"blog/CSRF/20230823/#reference","title":"Reference","text":"

free5gc/webconsole merged PR #44 free5gc issue #387 free5gc issue #28 JSON Token RFC 7519 MongoDBCompass

"},{"location":"blog/CSRF/20230823/#about","title":"About","text":"

Hello everyone,

I'm Brian Chen (\u9673\u715c\u76db), and I've been immersed in the realm of 5G Core Network technologies. Over the course of seven months, I've had the privilege of serving as an intern at Saviah. In this role, my responsibilities encompass a spectrum of tasks including maintenance, development, and rigorous testing of the free5GC project.

Should any inquiries, questions, or bug reports regarding free5GC arise, I encourage you to reach out by creating an issue in the free5gc repository or by participating in discussions on the forum. I'm here to assist and collaborate with the community as we navigate the intricacies of this project.

Warm regards, Brian Chen (\u9673\u715c\u76db) - Github - LinkedIn

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/","title":"Introduce Kubernetes and Deploy free5GC on Kubernetes with helm","text":"

Note

Author: Elisa Lee Date: 2023/8/16

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#abstract","title":"Abstract","text":"

In the initial section of the article, I will provide an introduction to Kubernetes. Moving on to the subsequent part, I will delve into the utilization of Kubernetes for facilitating the deployment of free5GC. Lastly, in the final segment of the article, I will elaborate on the effective utilization of Kubernetes for monitoring services.

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#introduce-kubernetes","title":"Introduce Kubernetes","text":"

Do you know why Kubernetes is called k8s?

It's due to a shorthand notation that uses the first letter \"k,\" followed by the number \"8,\" and ending with the last letter \"s\" to represent the full name. Kubernetes,stands as an open-source container orchestration platform that bestows organizations with the capacity to adeptly govern, deploy, and expand containerized applications. Initially conceived by Google and presently overseen by the Cloud Native Computing Foundation (CNCF), Kubernetes has ascended to become a pivotal technological underpinning within the realm of contemporary cloud-native computing.

For those who find themselves unacquainted with the intricacies of Kubernetes, let us embark on an exploration of its architectural framework.

I understand that the image presented above might appear intricate at first glance. However, there's no need for concern. Allow me to guide you through each component step by step.

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#pods","title":"Pods","text":"

A \"Pod\" stands as the most diminutive executable entity within the Kubernetes ecosystem. It possesses the capability to encompass either an individual container or a collective assembly of containers. The subsequent enumeration outlines several salient distinctions that set it apart from the act of directly launching a standalone container.

Notably, a Pod possesses its dedicated network interface, affording all enclosed containers the ability to intercommunicate seamlessly by interfacing with the \"localhost.\" Furthermore, connectivity to other Pods is conveniently established through direct usage of their respective IP addresses within the Kubernetes environment.

The Pod's inherent duplicability and capacity for effortless restarts, even from the point of its most recent execution, distinguish it. Additionally, the versatility of including a functioning container within its initial state further characterizes its nature.

Collectively, these attributes contribute to the refinement and streamlined nature of networking within the Kubernetes ecosystem. Such qualities not only facilitate smoother scalability but also offer enhanced capabilities for restarting services with utmost ease.

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#nodes","title":"Nodes","text":"

Consider a \"node\" as a tangible computing entity akin to a physical machine. Analogous to our personal machines, these nodes possess the capacity to concurrently execute multiple tasks, akin to the pods referenced earlier. The orchestration of nodes is overseen by a pivotal component known as the Kubernetes control plane, which, in an automated fashion, allocates pods across the available nodes. Within each node, a minimum of two services operate in tandem.

  1. Kubelet: This crucial service undertakes the responsibility of facilitating seamless communication between the Kubernetes control plane and the individual node. It serves as the intermediary that relays instructions and status updates, ensuring synchronization and cooperation.

  2. Container Runtime: Operating in tandem with Kubelet, the container runtime undertakes pivotal functions. These encompass retrieving container images from registries, the unpacking of containers, and the actual execution of applications. A prime example of such a container runtime is Docker, renowned for its role in enabling containerization.

In essence, this intricate interplay of nodes, services, and orchestration elements underscores the dynamism and efficiency inherent to the Kubernetes ecosystem. Through these interlocking mechanisms, the platform optimizes resource utilization, ensures effective communication, and enables the seamless execution of applications across a distributed infrastructure.

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#master-nodes","title":"Master Nodes","text":"

We've now explored all the scalable components and the task runner. Undoubtedly, to orchestrate and oversee everything, a central command hub is necessary \u2013 this is referred to as the master node. Although direct intervention within these nodes isn't typically required to ensure the seamless operation of the entire system, it's still beneficial for you to grasp a basic understanding of its functionality.

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#api-server","title":"API server","text":"

It determines which interface among all nodes can be externally accessed. Any subsequent commands you execute will be channeled through this service to the designated node or pod. Furthermore, essential cluster information can also be obtained from this service.

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#scheduler","title":"Scheduler","text":"

Similar to an airport's control tower, its function is akin to orchestrating the deployment of pods on specific nodes based on the rules you've established and the data obtained from the API server. The effectiveness of these rules is pivotal, as they often determine the system's overall efficiency.

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#controller-manager","title":"Controller Manager","text":"

When the need arises to enact concrete modifications on a pod, such as terminating or pausing its operation, a fundamental prerequisite is pinpointing the pod's process location and establishing the means to interact with it. This is precisely the role fulfilled by the controller manager. Additionally, this manager oversees vital components, including accounts, services, and more.

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#etcd","title":"Etcd","text":"

For a simplified understanding, we can view this as essentially a comprehensive backup of the entire cluster.

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#service","title":"Service","text":"

In Kubernetes, a \"service\" is an abstraction that enables communication between different sets of pods, usually to provide a stable network endpoint for accessing a specific group of pods. Pods in Kubernetes are ephemeral and can be created, terminated, or scaled dynamically, which makes their IP addresses and lifecycles unpredictable. Services provide a way to decouple the frontend of an application from the backend pods, making it easier for other components or users to access the application without having to know the exact locations or IP addresses of the pods.

A service can be defined in Kubernetes using a YAML or JSON configuration file, and it is associated with a set of pods based on a label selector. The service acts as a load balancer, distributing incoming network traffic among the pods that match the specified selector. This distribution ensures that even if pods are scaled up or down, the service remains available and reachable.

There are different types of services in Kubernetes:

  1. ClusterIP: This is the default service type, and it exposes the service on a cluster-internal IP address. It is accessible only within the cluster.

  2. NodePort: This type exposes the service on each node's IP address at a static port. It allows external access to the service using the node's IP and the specified static port.

  3. LoadBalancer: This type automatically provisions a cloud provider load balancer to expose the service externally. It works in environments that support external load balancers.

  4. ExternalName: This type provides an alias for an external service by returning a CNAME record with the configured DNS name.

Services are a fundamental concept in Kubernetes and play a crucial role in enabling communication and load balancing between pods and external clients. They provide a stable and abstracted network endpoint that allows applications to scale and be more resilient without disrupting access from users or other components.

In the upcoming section, I will delve into the process of deploying free5GC on Kubernetes.

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#deploying-5g-core-network-with-free5gc","title":"Deploying 5G core network with free5GC","text":"

Now I'm going to introduce how to implement free5GC on Kubernetes with helm

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#install-require-packages","title":"Install require packages","text":"
sudo apt update -y\nsudo apt upgrade -y\n
"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#install-apt-transport-https","title":"Install apt-transport-https","text":"

\"apt-transport-https\" is a crucial package that equips your system with the essential tools and libraries required to seamlessly integrate the HTTPS protocol. This integration ensures secure and encrypted communication when connecting to package repositories while utilizing the Advanced Package Tool (APT) for effective package management.

sudo apt install -y curl wget apt-transport-https\n

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#install-gtp5g","title":"Install gtp5g","text":"

\"gtp5g\" refers to a customized Linux kernel module specifically designed to handle packets by PFCP (Packet Forwarding Control Protocol) Information Elements (IEs) such as PDR (Packet Detection Rule) and FAR (Forwarding Action Rule). For comprehensive insights, you can delve into the 3GPP specifications TS 29.281 and TS 29.244. To employ the UPF (User Plane Function) component effectively, it's imperative to operate on either the 5.0.0-23-generic or 5.4.x version of the Linux kernel. This ensures optimal compatibility and seamless integration with the necessary functionalities.

sudo apt install gcc\nsudo apt install make\ngit clone -b v0.8.1 https://github.com/free5gc/gtp5g.git\ncd gtp5g\nmake\nsudo make install\n

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#install-docker","title":"Install docker","text":"

\"docker\" is a platform that enables developers to build, package, and distribute applications as containers. Containers are lightweight, portable, and self-sufficient units that encapsulate everything an application needs to run, including the code, runtime, system tools, system libraries, and settings. Docker provides a consistent environment across different development and deployment stages, from local development to testing and production.

for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done\nsudo apt-get update\nsudo apt-get install ca-certificates curl gnupg\nsudo install -m 0755 -d /etc/apt/keyrings\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg\nsudo chmod a+r /etc/apt/keyrings/docker.gpg\necho \\\n  \"deb [arch=\"$(dpkg --print-architecture)\" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \\\n  \"$(. /etc/os-release && echo \"$VERSION_CODENAME\")\" stable\" | \\\n  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null\n  sudo apt-get update\n  sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#install-minikube","title":"Install minikube","text":"

\"minikube\" is an open-source tool that enables developers to set up and run a single-node Kubernetes cluster locally on their own computer. It's particularly useful for learning, development, and testing purposes. Minikube provides an easy way to experience Kubernetes without needing access to a full-scale cluster, making it a great tool for getting familiar with Kubernetes concepts and features.

wget https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64\nsudo cp minikube-linux-amd64 /usr/local/bin/minikube\nsudo chmod +x /usr/local/bin/minikube\n

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#install-kubectl","title":"Install kubectl","text":"

\"kubectl\" is the command-line tool used to interact with and manage Kubernetes clusters. It is an essential component for working with Kubernetes, allowing users to perform various tasks and operations on Kubernetes clusters directly from the terminal.

curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl\nchmod +x kubectl\nsudo mv kubectl /usr/local/bin/\n

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#install-helm","title":"Install helm","text":"

\"helm\" is a package manager for Kubernetes that simplifies the deployment and management of applications and services on a Kubernetes cluster. It allows you to define, install, and upgrade complex applications using pre-configured templates called \"charts.\" These charts encapsulate all the necessary resources, configurations, and dependencies required to run an application.

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3\nchmod 700 get_helm.sh\n./get_helm.sh\nhelm list -A\n

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#install-multus-cni","title":"Install multus-cni","text":"

\"multus-cni\" is a project that provides a Kubernetes network plugin, specifically a \"Container Network Interface\" (CNI) plugin, which enables the attachment of multiple network interfaces to pods in a Kubernetes cluster.

git clone https://github.com/k8snetworkplumbingwg/multus-cni.git \n

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#deploy-free5gc","title":"Deploy free5GC","text":""},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#useful-kubectl-command","title":"Useful kubectl command","text":"

Now, I will proceed to introduce a selection of kubectl command that can be employed during the deployment of free5GC.

\"kubectl get pods\" retrieves a list of running pods in the current namespace along with their names, statuses, and other relevant information.

kubectl get pods \n
\"kubectl describe pod\" is used to get detailed information about a specific pod, including its status, events, labels, and more.

kubectl describe pod [pod-name]\n
\"kubectl logs\" fetches the logs of a specific pod, helping you troubleshoot issues and monitor application output.

kubectl logs [pod-name]\n
\"kubectl exec -it\" allows you to execute a command inside a running pod. The -it flag enables interactive terminal access.
kubectl exec -it [pod-name] -- [command]\n
\"kubectl apply -f \" deploys resources defined in a YAML file, such as pods, services, or deployments, to your cluster.
kubectl apply -f [yaml-file]\n
\"kubectl delete\" deletes a specific resource by specifying its type and name, freeing up resources and cleaning the cluster.
kubectl delete [resource-type] [resource-name]\n
\"kubectl expose deployment\" creates a new service, typically of type LoadBalancer, to expose a deployment's pods to external network traffic.
kubectl expose deployment [deployment-name] --type=LoadBalancer --port=[port]\n

\"kubectl get services\" lists all services running in the current namespace along with their details, including ClusterIP, external IP (if applicable), and ports.

kubectl get services\n
\"kubectl get nodes\" retrieves information about the worker nodes in the cluster, displaying their statuses, roles, and other essential data.
kubectl get nodes\n
\"kubectl describe node\" provides detailed information about a specific node, including its capacity, allocated resources, and conditions.
kubectl describe node [node-name]\n
\"kubectl get namespaces\" displays all available namespaces in the cluster, which are used to isolate resources and manage multi-tenancy.
kubectl get namespaces\n
\"kubectl create namespace\" creates a new namespace, allowing you to logically separate and organize resources.
kubectl create namespace [namespace-name]\n
\"kubectl port-forward\" enables you to create a network tunnel between your local machine and a specific pod running within a Kubernetes cluster. This allows you to access services or applications running inside the pod as if they were running on your local machine. The command forwards traffic from a specified local port to a port on the selected pod.
kubectl port-forward [pod-name] [local-port]:[remote-port]\n

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#start-minikube","title":"Start minikube","text":"

Use flannel as cni plugin to start minikue. Flannel is a popular \"Container Network Interface\" (CNI) plugin used for networking in Kubernetes and other container orchestration platforms. It provides a simple and lightweight network fabric designed to facilitate communication between containers and pods in a distributed environment, such as a Kubernetes cluster.

sudo usermod -aG docker $USER && newgrp docker\nminikube start --driver=docker --cpus=4 --memory=8g --disk-size=20g --cni=flannel\n## verify minikube installation\nminikube status \n

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#enable-multus-cni-plugin","title":"Enable Multus-CNI Plugin","text":"
cd multus-cni\ncat ./deployments/multus-daemonset.yml | kubectl apply -f -\n
"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#install-free5gc-and-ueransim","title":"Install free5GC and UERANSIM","text":"

If you have only one interface on each Kubernetes node and its name is toto. Then you have to set these parameters to toto: global.n2network.masterIf global.n3network.masterIf global.n4network.masterIf global.n6network.masterIf global.n9network.masterIf

kubectl create ns free5gc\ngit clone https://github.com/Orange-OpenSource/towards5gs-helm.git\ncd towards5gs-helm/charts/\nhelm -n free5gc install free5gc-v1 ./free5gc/\nhelm -n free5gc install ueransim-v1 ./ueransim/\nwatch kubectl get pods -n free5gc\n

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#start-webconsole","title":"Start WebConsole","text":"

free5GC offers a user-friendly web tool called WebConsole, designed to facilitate the creation and management of User Equipment (UE) registrations. This tool serves as a valuable resource for multiple 5G network functions (NFs), streamlining the process of handling UE registrations and associated tasks.

kubectl port-forward --namespace free5gc svc/webui-service 5000:5000\n
Execute the following command in your local machine's terminal, and subsequently, you will be able to access the WebConsole via localhost:5000. You can login with username admin and password free5gc.
ssh -L localhost:5000:localhost:5000 ubuntu@[VM ip]\n

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#service-monitoring","title":"Service Monitoring","text":""},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#install-prometheusgrafana-services","title":"install Prometheus/Grafana services","text":"

For monitoring Kubernetes, I utilized Prometheus and Grafana. The installation of Prometheus and Grafana services is facilitated through the Helm chart provided by the prometheus-community.

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts\nhelm repo update\nkubectl create namespace prometheus\nhelm install prometheus prometheus-community/kube-prometheus-stack -n prometheus\nwatch kubectl get pods -n prometheus\n

kubectl port-forward -n prometheus svc/prometheus-grafana 8080:80\n
Execute the following command in your local machine's terminal, and subsequently, you will be able to access the WebConsole via localhost:8080.
ssh -L localhost:8080:localhost:8080 ubuntu@[VM ip]\n
A variety of dashboards are available, offering different perspectives for those who are interested. Below is a snapshot of one such dashboard option.

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#reference","title":"Reference","text":"

https://free5gc.org/

https://medium.com/rahasak/deploying-5g-core-network-with-free5gc-kubernets-and-helm-charts-29741cea3922

https://github.com/Orange-OpenSource/towards5gs-helm

https://github.com/k8snetworkplumbingwg/multus-cni

"},{"location":"blog/IntroduceKubernetesAndDeploymentfree5GConKubernetesWithHelm/main/#about","title":"About","text":"

Hello, I am Elisa Lee. My ongoing research revolves around VoNR (Voice over New Radio). I encourage any inquiries or identification of errors within the article, as they are welcomed for correction. Your feedback is invaluable, so please don't hesitate to reach out via email to share your insights.

"},{"location":"blog/fuzzing/main/","title":"Fuzz Testing in Go: Discovering Vulnerabilities and Analyzing a Real Case (CVE-2022-43677)","text":"

Note

Author: Yu-Sheng Liu Date: 2023/8/9

"},{"location":"blog/fuzzing/main/#overview","title":"Overview","text":"

In this article, we begin by introducing the concept of fuzz testing and its significance in software testing. Subsequently, we present Go Fuzzing as an illustrative example to demonstrate how to implement fuzz testing in Go. Lastly, we showcase a practical case, CVE-2022-43677, to exemplify how we conduct fuzz testing on the free5GC system.

"},{"location":"blog/fuzzing/main/#fuzz-testing","title":"Fuzz Testing","text":""},{"location":"blog/fuzzing/main/#what-is-fuzz-testing-fuzzing","title":"What is Fuzz Testing (Fuzzing)?","text":"

Fuzz testing, commonly known as fuzzing, is an automated software testing technique used to uncover vulnerabilities, defects, and unexpected behavior in computer systems, applications, and networks. The primary objective of fuzzing is to identify security flaws, crashes, or abnormal program behavior caused by invalid or unexpected inputs.

"},{"location":"blog/fuzzing/main/#how-fuzz-testing-works","title":"How Fuzz Testing Works","text":"

Fuzz testing involves subjecting the target software or system to a large number of inputs, including random or malformed data, to see how it handles them. The idea is to explore edge cases and input combinations that may not have been adequately tested during traditional software testing. Here's how the fuzzing process typically works:

  1. Test Input Generation:

    • Fuzzing tools generate test inputs based on various techniques, which can be broadly categorized as:
      • Random Fuzzing: The simplest approach where random data is generated as input.
      • Mutation-Based Fuzzing: Starting with valid inputs, the tool applies mutations to create variations of the original data.
      • Grammar-Based Fuzzing: Using a predefined grammar or structure to generate valid and invalid inputs.
      • Seed Corpus: Using existing inputs (e.g., files, network packets) as the starting set for mutation.
  2. Test Execution:

    • The generated inputs are provided as input to the target application, component, or system.
    • The application is executed with each input, and its behavior is monitored during runtime.
  3. Monitoring and Analysis:

    • The fuzzer observes the application's behavior, including any crashes, exceptions, hangs, or memory-related issues.
    • Code coverage analysis is often performed to determine which parts of the code were exercised during the testing.
  4. Feedback and Iteration:

    • Fuzzing tools use feedback mechanisms to prioritize and select inputs that lead to new code paths or unique behavior.
    • The process is iterated with refined inputs to continue exploring deeper into the application.
"},{"location":"blog/fuzzing/main/#types-of-fuzz-testing","title":"Types of Fuzz Testing","text":"
  1. Black Box Fuzzing:

    • The tester has no access to the application's internal code or design.
    • Random or mutated inputs are provided to the application to observe its behavior.
    • Suitable for testing closed-source software or systems where the tester has limited knowledge.
  2. White Box Fuzzing:

    • The tester has access to the application's source code and can leverage this knowledge for targeted testing.
    • Inputs can be intelligently crafted to explore specific code paths and functions.
    • Provides more in-depth coverage but requires access to the application's code.
  3. Grey Box Fuzzing:

    • A combination of black box and white box approaches.
    • The tester has partial knowledge of the application, such as certain APIs or protocols, but not complete access to the source code.
    • Offers a balance between targeted testing and exploration of unknown behaviors.
"},{"location":"blog/fuzzing/main/#advantages-of-fuzz-testing","title":"Advantages of Fuzz Testing","text":"
  1. Bug and Vulnerability Discovery:

    • Fuzzing can uncover previously unknown security vulnerabilities and software defects, including memory corruption errors and input validation issues.
  2. Automation and Efficiency:

    • Fuzzing is an automated testing process, which allows it to scale and test large codebases quickly and efficiently.
  3. Diverse Test Inputs:

    • Fuzzing generates a wide range of test inputs, exploring various edge cases that might not be covered by manual testing.
  4. Early Vulnerability Detection:

    • Fuzzing can be integrated into the development process, enabling early detection and mitigation of vulnerabilities before deployment.
"},{"location":"blog/fuzzing/main/#conclusion-for-fuzz-testing","title":"Conclusion for fuzz testing","text":"

Fuzz testing, or fuzzing, is a powerful and essential technique in the realm of software security testing. By providing a diverse set of inputs and exploring uncharted code paths, fuzz testing uncovers vulnerabilities and defects that might otherwise remain hidden.

Next, we will use Go fuzzing as an example to introduce how to develop a fuzzing in Go.

"},{"location":"blog/fuzzing/main/#go-fuzzing","title":"Go Fuzzing","text":"

Go officially supports fuzzing starting from Go 1.18, and its official figure provides a brief and clear summary of the fuzzing function components.

Similar to Go's unit test functions, the fuzzing function in Go must follow the naming convention FuzzXxx and take an argument of type *testing.F. This argument has two main functions, Add and Fuzz.

  1. Add Function:

    • You can use the Add function to add your own test data to the seed corpus for fuzz testing. The seed corpus is the initial set of inputs that go-fuzz will use to start the fuzzing process.
  2. Fuzz Function:

    • The Fuzz function will be the target function that you want to test using fuzzing. It must have *testing.T as its first argument, similar to regular unit tests.
    • Additionally, the Fuzz function supports variadic arguments with the following basic data types:
      • string, []byte
      • int, int8, int16, int32/rune, int64
      • uint, uint8/byte, uint16, uint32, uint64
      • float32, float64
      • bool

These data types represent the different kinds of input data that can be passed to the Fuzz function during the fuzzing process. The fuzzer will generate and mutate inputs of these types to explore different code paths and uncover bugs or unexpected behavior in the target function.

In summary, when writing fuzzing functions in Go, remember to use the FuzzXxx naming pattern, accept *testing.F as an argument, utilize the Add function to customize the seed corpus, and use the Fuzz function with supported basic data types to perform fuzz testing on your target functions.

You can use the command to execute the fuzz testing:

go test -fuzz=<regex> -fuzztime=<duration or times>\n\n# Execute the fuzz testing until it crashs or finding some errors\ngo test -fuzz=Fuzz\n\n# Execute the fuzz testing ten iterations\ngo test -fuzz=Fuzz -fuzztime=10x\n\n# Execute the fuzz testing twenty seconds\ngo test -fuzz=Fuzz -fuzztime=20s\n

"},{"location":"blog/fuzzing/main/#simple-example-division","title":"Simple Example - Division","text":"

We have developed a very simple function called Division that accepts two arguments, dividend and divisor, and then returns two results: quotient and remainder.

func Division(dividend, divisor int32) (\nquotient, remainder int32,\n) {\nquotient = dividend / divisor\nremainder = dividend % divisor\n\nreturn\n}\n

In the FuzzDivision function, we utilize the data generated by the Go fuzzer to test our Division function.

func FuzzDivision(f *testing.F) {\nf.Fuzz(func(t *testing.T,\nn1, n2 int32,\n) {\nq, r := Division(n1, n2)\n\nrequire.Equal(t, n1, n2*q+r)\n})\n}\n

We expected to see:

n1 / n2 = q ... r\nn1 = n2 * q + r\n

There should not be any problems with this implementation.

Then we can use the following command to start the fuzz testing.

go test -fuzz=^FuzzDivision$\n

The fuzz testing reports the error \"integer divide by zero\".

As a normal user, we understand that the divisor cannot be zero. However, the input data may not always be as expected. This is precisely why we use fuzz testing\u2014to help us find edge cases and uncover unexpected behavior.

Go stores the data that caused the fuzz testing to fail. You can check them using the following command. * Note: The file name, 29bf8459dc5d452f64d41eb8a253f6a672939b146b07fcced0b17e99729e9b91, may not be the same.

cat testdata/fuzz/FuzzDivision/29bf8459dc5d452f64d41eb8a253f6a672939b146b07fcced0b17e99729e9b91\n

The content of the file is as follows:

go test fuzz v1\nint32(-7)\nrune('\\x00')\n

The first line indicates the encoding version, and the subsequent lines represent the argument values that triggered the error during the fuzz testing.

Now we can modify our Division function to check the divisor if it is zero.

var ErrorDivideByZero = fmt.Errorf(\"integer divide by zero\")\n\nfunc Division(dividend, divisor int32) (\nquotient, remainder int32, err error,\n) {\nif divisor == 0 {\nerr = ErrorDivideByZero\nreturn\n}\n\nquotient = dividend / divisor\nremainder = dividend % divisor\n\nreturn\n}\n

Similarly, the FuzzDivision fuzzing function now checks for the presence of the ErrorDivideByZero error.

func FuzzDivision(f *testing.F) {\nf.Add(int32(67), int32(3))\n\nf.Fuzz(func(t *testing.T,\nn1, n2 int32,\n) {\nif q, r, err := Division(n1, n2); err != ErrorDivideByZero {\nrequire.Equal(t, n1, n2*q+r)\n}\n})\n}\n

Now, we can use the following command to re-test the failing case.

go test -run=FuzzDivision/29bf8459dc5d452f64d41eb8a253f6a672939b146b07fcced0b17e99729e9b91\n
"},{"location":"blog/fuzzing/main/#conclusion-for-go-fuzzing","title":"Conclusion for Go Fuzzing","text":"

We have used a simple example to describe how to develop a fuzzing function in Go and how to leverage the Go command-line tool to execute fuzz testing.

Next, we will examine a real case, CVE-2022-43677, and demonstrate the process of developing a fuzzing function to identify edge cases.

"},{"location":"blog/fuzzing/main/#cve-2022-43677","title":"CVE-2022-43677","text":"

Accroding to the descriptoin:

In free5GC 3.2.1, a malformed NGAP message can crash the AMF and NGAP decoders via an index-out-of-range panic in aper.GetBitString.

In response to this vulnerability, we have developed a fuzzing function to test the NGAP decoder. The function utilizes two approaches: modifying the NGAP message's content under a valid template or adjusting its format by changing the Information Elements (IEs) with variable lengths.

// Put the code under the free5gc/test\nfunc FuzzNgapDecode(f *testing.F) {\nf.Fuzz(func(t *testing.T,\nmodifyWhat uint8,\nchangeIe0, changeIe1, changeIe2, changeIe3, changeIe4 bool,\nvalueIe0A uint32,\nvalueIe2ACellId uint64, valueIe2ATac uint32,\nvalueIe3A uint64,\nvalueIe4A uint64,\nvalueIePlmn uint32,\n) {\nvar idx, n int\nvar sendMsg []byte\nvar registrationRequest []byte\nvar bs []byte\nvar err error\nvar ngapPdu ngapType.NGAPPDU\nvar mobileIdentity5GS nasType.MobileIdentity5GS\nvar ue *test.RanUeContext\n\n// New UE\nue = test.NewRanUeContext(\"imsi-2089300007487\", 1, security.AlgCiphering128NEA0, security.AlgIntegrity128NIA2,\nmodels.AccessType__3_GPP_ACCESS)\nue.AmfUeNgapId = 1\nue.AuthenticationSubs = test.GetAuthSubscription(TestGenAuthData.MilenageTestSet19.K,\nTestGenAuthData.MilenageTestSet19.OPC,\nTestGenAuthData.MilenageTestSet19.OP)\n\nmobileIdentity5GS = nasType.MobileIdentity5GS{\nLen:    12, // suci\nBuffer: []uint8{0x01, 0x02, 0xf8, 0x39, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x47, 0x78},\n}\n\nif modifyWhat%2 == DoModifyContent {\nif changeIe0 {\n// RAN UE NGAP ID\nue.RanUeNgapId = int64(valueIe0A)\n}\n\nregistrationRequest = nasTestpacket.GetRegistrationRequest(\nnasMessage.RegistrationType5GSInitialRegistration, mobileIdentity5GS, nil, ue.GetUESecurityCapability(), nil, nil, nil)\nngapPdu = ngapTestpacket.BuildInitialUEMessage(ue.RanUeNgapId, registrationRequest, \"\")\n\nif changeIe2 {\n// User Location Information\nfor _, ie := range ngapPdu.InitiatingMessage.Value.InitialUEMessage.ProtocolIEs.List {\nif ie.Id.Value == ngapType.ProtocolIEIDUserLocationInformation {\nbs = make([]byte, 4)\nvalueIePlmn &= uint32(PlmnMask)\nbinary.LittleEndian.PutUint32(bs, valueIePlmn)\n\nNgRan := ie.Value.UserLocationInformation.UserLocationInformationNR\nNgRan.NRCGI.PLMNIdentity.Value = bs[:PlmnByteLen]\nNgRan.TAI.PLMNIdentity.Value = bs[:PlmnByteLen]\n\nbs = make([]byte, 8)\nvalueIe2ACellId &= uint64(CellIdMask)\nbinary.LittleEndian.PutUint64(bs, valueIe2ACellId)\nNgRan.NRCGI.NRCellIdentity.Value.Bytes = bs[:CellIdByteLen]\n\nbs = make([]byte, 4)\nvalueIe2ATac &= uint32(TacMask)\nbinary.LittleEndian.PutUint32(bs, valueIe2ATac)\nNgRan.TAI.TAC.Value = bs[:TacByteLen]\n}\n}\n}\nif changeIe3 {\n// RRC Establishment Cause\nfor _, ie := range ngapPdu.InitiatingMessage.Value.InitialUEMessage.ProtocolIEs.List {\nif ie.Id.Value == ngapType.ProtocolIEIDRRCEstablishmentCause {\nie.Value.RRCEstablishmentCause.Value = aper.Enumerated(valueIe3A)\n}\n}\n}\nif changeIe4 {\n// UE Context Request\nfor _, ie := range ngapPdu.InitiatingMessage.Value.InitialUEMessage.ProtocolIEs.List {\nif ie.Id.Value == ngapType.ProtocolIEIDUEContextRequest {\nie.Value.UEContextRequest.Value = aper.Enumerated(valueIe4A)\n}\n}\n}\nsendMsg, err = ngap.Encoder(ngapPdu)\n} else if modifyWhat%2 == DoModifyFormat {\nregistrationRequest = nasTestpacket.GetRegistrationRequest(\nnasMessage.RegistrationType5GSInitialRegistration, mobileIdentity5GS, nil, ue.GetUESecurityCapability(), nil, nil, nil)\n\nif changeIe1 {\nregistrationRequest[3] += 1\nregistrationRequest = append(registrationRequest, registrationRequest[len(registrationRequest)-1])\n} else {\nregistrationRequest[3] -= 1\nregistrationRequest = registrationRequest[:len(registrationRequest)-1]\n}\n\nngapPdu = ngapTestpacket.BuildInitialUEMessage(ue.RanUeNgapId, registrationRequest, \"\")\nsendMsg, err = ngap.Encoder(ngapPdu)\nrequire.Nil(t, err, \"Error: %v\", err)\nrequire.Equal(t, int(sendMsg[3]), len(sendMsg[4:]), \"%v\", sendMsg)\n\nidx = bytes.Index(sendMsg, []byte(\"\\x00\\x70\\x40\"))\nassert.NotEqual(t, idx, -1, \"Can not find UE context Request\")\nif idx != -1 {\nif valueIe4A%8 == 0 || valueIe4A%8 == 1 {\nn = 2\n} else {\nn = int(valueIe4A % 8)\n}\nsendMsg[idx+3] = uint8(n)\nsendMsg = sendMsg[:idx+4]\nbs = make([]byte, 8)\nbinary.LittleEndian.PutUint64(bs, valueIe4A)\n\nfor i := 0; i < n; i++ {\nsendMsg = append(sendMsg, bs[i])\n}\n\nsendMsg[3] += uint8(n - 1) // total length\n}\n}\nrequire.Equal(t, int(sendMsg[3]), len(sendMsg[4:]), \"%v\", sendMsg)\n\n_, err = ngap.Decoder(sendMsg)\n})\n}\n

We can use the following command to execute the fuzz testing.

go test -fuzz=^FuzzNgapDecode$ -run=^FuzzNgapDecode$\n

The test resulted in a crash, which confirms the presence of the vulnerability as described in CVE-2022-43677.

The bug was found in the package aper at version v1.0.4. Fortunately, the latest version of the package has already fixed this issue. To verify the fix, we can update the aper package to the latest commit using the following commands:

# Update package aper to the latest commit\ngo get github.com/free5gc/aper@main\n

After updating the aper package, we can test it again with the fuzzing function:

go test -fuzz=^FuzzNgapDecode$ -run=^FuzzNgapDecode$\n

# Alternatively, re-testing the failing case\ngo test -run=FuzzNgapDecode/87af855bbc381c8d510af5ce897fcdd7f9154574e61c0413223f7e31769c2767\n

"},{"location":"blog/fuzzing/main/#conclusion","title":"Conclusion","text":"

Fuzz testing is a powerful technique for improving the security and reliability of software systems. By subjecting programs to a wide range of inputs, fuzzing can uncover vulnerabilities and defects that might not be found through traditional testing methods. It automates the testing process, making it efficient and scalable for large codebases.

In the context of Go programming, Go fuzzing is well-supported and integrates seamlessly with the standard testing framework. Developers can create fuzzing functions to target specific functions and uncover potential issues using random or mutated inputs.

To demonstrate the effectiveness of fuzz testing, we presented a real case, CVE-2022-43677, which affected free5GC version 3.2.1. By developing a fuzzing function for the NGAP decoder, we were able to identify a vulnerability that caused a crash.

In conclusion, fuzz testing is a critical practice in software development, enabling developers to proactively discover and resolve bugs and vulnerabilities. It empowers them to deliver more secure and robust software systems, providing users with a higher level of confidence in the applications they use. By incorporating fuzz testing as part of the software development lifecycle, developers can significantly enhance the quality and security of their software products.

"},{"location":"blog/fuzzing/main/#reference","title":"Reference","text":"
  • Go Fuzzing
  • CVE-2022-43677
"},{"location":"blog/fuzzing/main/#about","title":"About","text":"

I'm Yu-Sheng Liu, a master's student at National Yang Ming Chiao Tung University. My research topic focuses on improving the performance of the 5G core network, such as reducing the latency of message propagation in SBI. If you have any questions, please don't hesitate to contact me!

  • LinkedIn
"},{"location":"guide/","title":"Index","text":""},{"location":"guide/#user-guide","title":"User Guide","text":""},{"location":"guide/#information","title":"Information","text":"
  • Hardware tested
  • Supported features
"},{"location":"guide/#roadmap","title":"Roadmap","text":"

Here are the features on the roadmap. These items are planned to be supported in the near future:

  • OAuth on SBA
  • Charging Function (CHF)
  • Network Exposure Function (NEF)
"},{"location":"guide/#free5gc-installation-guide","title":"free5GC Installation Guide","text":"

For people who are not familiar with virtual machines and Linux installation, here are some example demonstrations:

  • Creating a Ubuntu VM using VirtualBox
  • Creating and Configuring a free5GC VM
  • Installing and Testing free5GC Core Network
  • Installing a UE/RAN Simulator
  • free5GC Simple Apps
  • All of tutorial videos are available at our Youtube Channel EN/ZH-TW
  • Environment setup of multiple SMF, DNN, and UPF
"},{"location":"guide/#configuration","title":"Configuration","text":"
  • Environment
  • Basic
  • SMF
  • Webconsole
  • Select UPF based on S-NSSAI
  • Select nearby UPF according to the connected gNodeB
  • ULCL
  • Netns5g - A free5gc and UERANSIM deployment using Linux network namespaces
"},{"location":"guide/#deployment","title":"Deployment","text":"

For Container deployment:

  • free5GC Compose (Docker Compose)
  • Towards5gs-helm (Kubernetes)
"},{"location":"guide/#others","title":"Others","text":"
  • Release Note
  • Trouble Shooting
  • Appendix
"},{"location":"guide/1-vm-en/","title":"1 vm en","text":""},{"location":"guide/1-vm-en/#ubuntu-virtual-machine-installation-demo","title":"Ubuntu Virtual Machine Installation Demo","text":"

In this demo, we will

  • install VirtualBox
  • create a Ubuntu Server VM using VirtualBox
  • use SSH to connect to the Ubuntu VM to install free5GC stage 3
  • Update and upgrade Ubuntu
"},{"location":"guide/1-vm-en/#1-install-virtualbox","title":"1. Install VirtualBox","text":"

Search virtualbox download, or visit virtualbox.org to download and install VirtualBox (currently 6.1.18) for your operation system.

Once installed VirtualBox, launch and see if you have something like this:

"},{"location":"guide/1-vm-en/#2-download-ubuntu-server","title":"2. Download Ubuntu Server","text":"

Search ubuntu server download on the web and download the latest Ubuntu Server LTS, or visit ubuntu.com, choose Manual Installation Option to download the .iso file (currently 20.04.2 LTS)

You should have downloaded a .iso image file with name like ubuntu-20.04.1-live-server-amd64.iso, probably in your download directory.

"},{"location":"guide/1-vm-en/#3-create-a-ubuntu-server-vm","title":"3. Create a Ubuntu Server VM","text":"

Launch VirtualBox and create your first Ubuntu VM using the downloaded .iso image file. We use Ubuntu Server instead of Ubuntu Desktop because we only need a basic server machine without too many unnecessary functionalities. The resulting overhead to your host machine is smaller, and the VM starts up faster too.

Tips

  • Name the first VM using a generic name as ubuntu, ubuntu-server, or ubuntu-20.04.
  • You can pick 1 or 2 (or more) CPUs, and about 2048M memory, although you can change them later.
  • In addition to the default NAT network interface, also add another \u201cHost-only\u201d network interface.

Refer to the videos Creating VM, Setting up VM.

"},{"location":"guide/1-vm-en/#31-start-installing-ubuntu","title":"3.1 Start Installing Ubuntu","text":"

Some notes about installing Ubuntu:

  • It is recommended that you choose short username and password for ease of typing later
  • Not choosing LVM will make it a little bit easier later if you want to extend your disk space
  • Choose to include SSH Server
  • Let security update complete

Refer to videos Install Ubuntu 1, Install Ubuntu 2.

"},{"location":"guide/1-vm-en/#32-log-in-into-ubuntu","title":"3.2 Log in into Ubuntu","text":"

Reboot after Ubuntu installation complete; wait a little bit for some initialization steps complete. Then log in with your username and password.

First try the ifconfig command\uff1a

ubuntu@ubuntu:~$ ifconfig\nCommand 'ifconfig' not found, but can be installed with:\nsudo apt install net-tools\nubuntu@ubuntu:~$\n

If some messages like above show, it means ifconfig has not been installed yet. (ifconfig is no longer installed by defaults in newer Ubuntu, and is replaced by more versatile ip command, but we will use it here for simplicity).

Follow its suggestion and install ifconfig:

ubuntu@ubuntu:~$ sudo apt install net-tools\n
Below shows the installation result:

Run ifconfig again to check the network interfaces:

Your display may look different, but take notes about the IP address of the Host-only interface card. The example above shows 192.168.56.101. You can SSH from your host machine into this Ubuntu VM using the IP later. (Another IP address, 10.0.2.15 is the IP address of the NAT interface card, the apps in your host machine cannot access it).

Finally check if the VM has internet access:

ubuntu@ubuntu:~$ ping google.com\n

Refer to the first part of the video Ping, SSH, and Upgrade.

"},{"location":"guide/1-vm-en/#4-connect-to-the-ubuntu-vm-using-ssh","title":"4. Connect to the Ubuntu VM using SSH","text":"

Launch your favorite SSH client from the host machine. Some operation systems (Mac, Ubuntu, some Windows) have pre-installed SSH clients. If you are using Windows, you can also download third-party SSH clients. For example, search \u201cwindows ssh download\u201d on the web.

The benefit of using SSH is that you can easily copy and paste commands from your machine to Ubuntu VM for execution, and vice versa. You can also create multiple SSH connections with the Ubuntu VM for control and monitoring at the same time.

Below shows some examples on a Mac host machine. Suppose the Host-only network IP is 192.168.56.101, and tue username is ubuntu:

ssh 192.168.56.101 -l ubuntu\n
The first time you connect to the VM, your SSH client may show some message asking you for confirmation. Enter yes:

Tips

If somehow SSH shows some warning messages telling you the machine has potential security risk, you may have to remove an entry in the file <your home directory>/.ssh/known_hosts related the the IP address.

If you log in successfully, you will enter a command line interface:

Repeat the basic commands such as ping, ifconfig to see if the VM is working properly. If so, we can access the Ubuntu VM \u201cremotely\u201d from now on.

"},{"location":"guide/1-vm-en/#5-update-and-upgrade-your-ubuntu","title":"5. Update and Upgrade your Ubuntu","text":"

Let also update and upgrade the Ubuntu VM right now to make sure it is up-to-date with proper security updates.

sudo apt update\nsudo apt upgrade\n

"},{"location":"guide/2-config-vm-en/","title":"2 config vm en","text":""},{"location":"guide/2-config-vm-en/#creating-a-free5gc-vm-and-setting-up-network","title":"Creating a free5GC VM and Setting up Network","text":"

In this demo we will exercise:

  • Cloning an existing VM, and install free5GC on it
  • Setting up the networking for the free5GC VM

Tips

Refer to video Clone VM and Change IP.

"},{"location":"guide/2-config-vm-en/#1-check-up-an-existing-vm-for-cloning","title":"1. Check up an existing VM for Cloning","text":"

Launch VirtualBox, and make sure the Ubuntu VM (ubuntu) we created before can boot up, then:

  • Log in into the VM using SSH from the host machine, and check if the VM has internet access
  • Make sure you have done sudo apt update and sudo apt upgrade (or you can do it again)
  • Shutdown the VM. You can:
  • use command sudo shutdown -P now, or
  • click the \u201cClose Window\u201d of the Ubuntu VM terminal and choose the middle option (better not force to turn off the machine power)
  • later if you just want to reboot, enter sudo shutdown -r now
"},{"location":"guide/2-config-vm-en/#2-create-a-free5gc-vm","title":"2. Create a free5GC VM","text":"

First let\u2019s clone a new VM:

  • Select an existing VM (ubuntu) and click the buttons on the right: / Snapshopts / Clone.
  • Name the new VM free5gc.
  • The MAC address rule: Create new MAC addresses for all network cards.
  • Choose the Link cloning option (or you can also choose to complete clone the VM if you like).

After the new VM is created:

  • Start up the new free5gc VM, and use the same username and password to log in.
  • In the Ubuntu terminal, issue ping and ifconfig again to make sure it has internet access, and also make note of the IP address of the Host-only network interface.
    • for example the IP could still be 192.168.56.101, and the interface name is enp0s8.
  • Log in into free5gc VM using SSH, and make sure all things working properly.
"},{"location":"guide/2-config-vm-en/#3-change-hostname","title":"3. Change hostname","text":"

The cloned free5gc VM still has host name ubuntu (or the name you gave it in the original VM). Let\u2019s rename the VM to free5gc. You can do this by editing the file /etc/hostname (using vi or nano):

sudo nano /etc/hostname\n# or \nsudo vi /etc/hostname\n
In the file, change ubuntu into free5gc\u3002If you are using nano \uff0cyou can press Ctrl-O to save the file, then Ctrl-X to exit.

Let\u2019s also change the file /etc/hosts by replacing the ubuntu inside into free5gc:

sudo nano /etc/hosts\n

New content of the file /etc/hosts looks like this:

127.0.0.1 localhost\n127.0.1.1 free5gc\n...\n

The changes will take effect after next reboot.

"},{"location":"guide/2-config-vm-en/#4-setting-static-ip-address","title":"4. Setting Static IP Address","text":"

The Host-only network interface, by default, gets its IP address through DHCP. The cloned free5gc VM seems to have trouble obtaining new IP address. We can change the host-only interface to use static IP address instead, which can save a lot of trouble later.

Here let\u2019s fix the static IP address as 192.168.56.101:

$ cd /etc/netplan\n$ ls\n00-installer-config.yaml\n$ cat 00-installer-config.yaml\n
The original content of the file 00-installer-config.yaml looks like:
# This is the network config written by 'subiquity'\nnetwork:\n  ethernets:\n    enp0s3:\n      dhcp4: true\n    enp0s8:\n      dhcp4: true\n  version: 2\n
meaning the VM has two network interfaces. Using ifconfig we know that enp0s8 is the name of the Host-only network interface. We can edit the file:
sudo nano 00-installer-config.yaml\n
and change it into:
# This is the network config written by 'subiquity'\nnetwork:\n  ethernets:\n    enp0s3:\n      dhcp4: true\n    enp0s8:\n      dhcp4: no\n      addresses: [192.168.56.101/24]\n  version: 2\n
First check if the new content is correct:
sudo netplan try\n
Press enter to exit, if successful. The apply tne new interface setting:
sudo netplan apply\n
Run ifconfig to see if the network setting has been changed correctly:
enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500\n        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255\n        inet6 fe80::a00:27ff:fec4:254f  prefixlen 64  scopeid 0x20<link>\n        ether 08:00:27:c4:25:4f  txqueuelen 1000  (Ethernet)\n        RX packets 2  bytes 1180 (1.1 KB)\n        RX errors 0  dropped 0  overruns 0  frame 0\n        TX packets 18  bytes 1894 (1.8 KB)\n        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0\n\nenp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500\n        inet 192.168.56.101  netmask 255.255.255.0  broadcast 192.168.56.255\n        inet6 fe80::a00:27ff:fe7e:ada6  prefixlen 64  scopeid 0x20<link>\n        ether 08:00:27:7e:ad:a6  txqueuelen 1000  (Ethernet)\n        RX packets 8420  bytes 531867 (531.8 KB)\n        RX errors 0  dropped 0  overruns 0  frame 0\n        TX packets 10887  bytes 823487 (823.4 KB)\n        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0\n\nlo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536\n        inet 127.0.0.1  netmask 255.0.0.0\n        inet6 ::1  prefixlen 128  scopeid 0x10<host>\n        loop  txqueuelen 1000  (Local Loopback)\n        RX packets 6621  bytes 596035 (596.0 KB)\n        RX errors 0  dropped 0  overruns 0  frame 0\n        TX packets 6621  bytes 596035 (596.0 KB)\n        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0\n
We can also check the routing table, just to have a grasp of what is going on regarding the network setting:
$ route -n\nKernel IP routing table\nDestination     Gateway         Genmask         Flags Metric Ref    Use Iface\n0.0.0.0         10.0.2.2        0.0.0.0         UG    100    0        0 enp0s3\n10.0.2.0        0.0.0.0         255.255.255.0   U     0      0        0 enp0s3\n10.0.2.2        0.0.0.0         255.255.255.255 UH    100    0        0 enp0s3\n192.168.56.0    0.0.0.0         255.255.255.0   U     0      0        0 enp0s8\n

For the display above, we learn that the Host-only network 192.168.56.0/24 does not have internet access by itself (even though we can access it using SSH from the host machine). Internet access is through the NAT network 10.0.2.0/24, with the gateway being 10.0.2.2 (provided by VirtualBox). Now we can SSH into free5gc VM using 192.168.56.101:

ssh 192.168.56.101 -l ubuntu\n
This is also how we interact with free5gc VM from now on.

"},{"location":"guide/3-install-free5gc/","title":"3 install free5gc","text":""},{"location":"guide/3-install-free5gc/#installation","title":"Installation","text":""},{"location":"guide/3-install-free5gc/#a-prerequisites","title":"A. Prerequisites","text":"
  1. Linux Kernel Version

    • In order to use the UPF element, you must use the 5.0.0-23-generic or 5.4.x version of the Linux kernel. free5gc uses the gtp5g kernel module, which has been tested and compiled against that kernel versions only. If you installed Ubuntu 20.04, the version looks like 5.4.x. To determine the version of the Linux kernel you are using:
        $ uname -r\n    5.4.0-65-generic\n

You will not be able to run most of the tests in Test section unless you deploy a UPF.

  1. Golang Version

    • As noted above, free5gc is built and tested with Go 1.17.8
    • To check the version of Go on your system, from a command prompt:
        go version\n
    • If another version of Go is installed, remove the existing version and install Go 1.17.8:
        # this assumes your current version of Go is in the default location\nsudo rm -rf /usr/local/go\n    wget https://dl.google.com/go/go1.17.8.linux-amd64.tar.gz\n    sudo tar -C /usr/local -zxvf go1.17.8.linux-amd64.tar.gz\n
    • If Go is not installed on your system:
        wget https://dl.google.com/go/go1.17.8.linux-amd64.tar.gz\n    sudo tar -C /usr/local -zxvf go1.17.8.linux-amd64.tar.gz\n    mkdir -p ~/go/{bin,pkg,src}\n# The following assume that your shell is bash\necho 'export GOPATH=$HOME/go' >> ~/.bashrc\n    echo 'export GOROOT=/usr/local/go' >> ~/.bashrc\n    echo 'export PATH=$PATH:$GOPATH/bin:$GOROOT/bin' >> ~/.bashrc\n    echo 'export GO111MODULE=auto' >> ~/.bashrc\n    source ~/.bashrc\n
    • Further information and installation instructions for golang are available at the official golang site.
  2. Control-plane Supporting Packages

sudo apt -y update\nsudo apt -y install mongodb wget git\nsudo systemctl start mongodb\n
  • WARNING: MongoDB 5.0+ requires a CPU with AVX support. Or downgrade your MongoDB to 4.4

    • see https://www.mongodb.com/community/forums/t/mongodb-5-0-cpu-intel-g4650-compatibility/116610/2

    • see also docker-library/mongo#485 (comment)

  • User-plane Supporting Packages

sudo apt -y update\nsudo apt -y install git gcc g++ cmake autoconf libtool pkg-config libmnl-dev libyaml-dev\n
  1. Linux Host Network Settings
sudo sysctl -w net.ipv4.ip_forward=1\nsudo iptables -t nat -A POSTROUTING -o <dn_interface> -j MASQUERADE\nsudo iptables -A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1400\nsudo systemctl stop ufw\n
"},{"location":"guide/3-install-free5gc/#b-install-control-plane-elements","title":"B. Install Control Plane Elements","text":"
  1. Clone the free5GC repository

    • To install the latest stable build (v3.3.0):
        cd ~\n    git clone --recursive -b v3.3.0 -j `nproc` https://github.com/free5gc/free5gc.git\n    cd free5gc\n
    • (Alternatively) to install the latest nightly build:
        cd ~/free5gc\n    git checkout main\n    git submodule sync\n    git submodule update --init --jobs `nproc`\ngit submodule foreach git checkout main\n    git submodule foreach git pull --jobs `nproc`\n
  2. Compile network function services in free5gc

    • To do so individually (e.g., AMF only):
        cd ~/free5gc\n    make amf\n
    • To build all network functions:
        cd ~/free5gc\n    make\n
"},{"location":"guide/3-install-free5gc/#c-install-user-plane-function-upf","title":"C. Install User Plane Function (UPF)","text":"
  1. As noted above, the GTP kernel module used by the UPF requires that you use Linux kernel version 5.0.0-23-generic or 5.4.x. To verify your version:
uname -r\n
  1. Retrieve the 5G GTP-U kernel module using git and build it
git clone -b v0.8.1 https://github.com/free5gc/gtp5g.git\ncd gtp5g\nmake\nsudo make install\n
  1. Build the UPF (you may skip this step if you built all network functions above):

  2. to build using make:

cd ~/free5gc\nmake upf\n
  1. Customize the UPF as desired. The UPF configuration file in run.sh is free5gc/config/upfcfg.yaml.
"},{"location":"guide/3-install-free5gc/#d-install-webconsole","title":"D. Install WebConsole","text":"
  1. Before building WebConsole, install nodejs and yarn packages first:
sudo apt remove cmdtest\nsudo apt remove yarn\ncurl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -\necho \"deb https://dl.yarnpkg.com/debian/ stable main\" | sudo tee /etc/apt/sources.list.d/yarn.list\ncurl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -\nsudo apt-get update\nsudo apt-get install -y nodejs yarn\n
  1. Build WebConsole

  2. to build using make:

cd ~/free5gc\nmake webconsole\n
  • (Alternatively) to build manually:
cd ~/free5gc/webconsole/frontend\nyarn install\nyarn build\nrm -rf ../public\ncp -R build ../public\ncd ..\ngo build -o bin/webconsole server.go\n

Note: 2GB or more of OS memory is recommended. WebConsole may be failed to build if memory is less then 1GB.

"},{"location":"guide/4-test-free5gc/","title":"4 test free5gc","text":""},{"location":"guide/4-test-free5gc/#test-free5gc","title":"Test free5GC","text":"

Start a Wireshark capture on any core-connected interface, applying the filter 'pfcp||icmp||gtp'.

In order to run the tests, first do this:

cd ~/free5gc\nmake upf\nchmod +x ./test.sh\n

The tests are all run from within ~/free5gc.

a. TestRegistration

./test.sh TestRegistration\n

b. TestGUTIRegistration

./test.sh TestGUTIRegistration\n

c. TestServiceRequest

./test.sh TestServiceRequest\n

d. TestXnHandover

./test.sh TestXnHandover\n

e. TestDeregistration

./test.sh TestDeregistration\n

f. TestPDUSessionReleaseRequest

./test.sh TestPDUSessionReleaseRequest\n

g. TestPaging

./test.sh TestPaging\n

h. TestN2Handover

./test.sh TestN2Handover\n

i. TestNon3GPP

./test.sh TestNon3GPP\n

j. TestReSynchronization

./test.sh TestReSynchronization\n

k. TestULCL

./test_ulcl.sh TestRequestTwoPDUSessions\n
"},{"location":"guide/5-install-ueransim/","title":"5 install ueransim","text":""},{"location":"guide/5-install-ueransim/#installing-ueransim-a-ueran-simulator","title":"Installing UERANSIM - a UE/RAN Simulator","text":"

In this demo we will practice:

  • Installing UERANSIM
  • Configuring free5GC and UERANSIM
  • Running UERANSIM against free5GC
"},{"location":"guide/5-install-ueransim/#1-install-ueramsim-vm","title":"1. Install ueramsim VM","text":"

Repeat the steps of cloning free5gc VM from the base VM, create a new VM for the UERANSIM simulator:

  • Name the VM ueransim, and create new MAC addresses for all network cards.
  • Make sure the VM has internet access and can log in using SSH.
  • Change the hostname to ueransim.
  • Make the Host-only network interface have static IP address 192.168.56.102.
  • Reboot the ueransim VM, as well as the free5gc VM.
  • You can ping 192.168.56.101 from the ueransim VM, and also ping 192.168.56.102 from the free5gc VM.
"},{"location":"guide/5-install-ueransim/#2-install-ueransim","title":"2. Install UERANSIM","text":"

Search \u201cueransim\u201d on the web, and get the web site. On the web site, review what the UERANSIM open-source project is about, then browse into the installation page.

To download UERANSIM:

cd ~\ngit clone https://github.com/aligungr/UERANSIM\ncd UERANSIM\ngit checkout 3a96298\n

Update and upgrade ueransim VM first:

sudo apt update\nsudo apt upgrade\n

Install required tools:

sudo apt install make\nsudo apt install g++\nsudo apt install libsctp-dev lksctp-tools\nsudo apt install iproute2\nsudo snap install cmake --classic\n

Build UERANSIM:

cd ~/UERANSIM\nmake\n

"},{"location":"guide/5-install-ueransim/#3-install-free5gc-webconsole","title":"3. Install free5GC WebConsole","text":"

free5GC provides a simple web tool WebConsole to help creating and managing UE registrations to be used by various 5G network functions (NF). To build WebConsole we need Node.js and Yarn.

First SSH into free5gc (192.168.56.101)\uff0cand remove obsolete tools that may exists:

sudo apt remove cmdtest\nsudo apt remove yarn\n

Then install Node.js and Yarn:

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -\necho \"deb https://dl.yarnpkg.com/debian/ stable main\" | sudo tee /etc/apt/sources.list.d/yarn.list\nsudo apt-get update\nsudo apt-get install -y nodejs yarn\n

To build WebConsole:

cd ~/free5gc\nmake webconsole\n

"},{"location":"guide/5-install-ueransim/#4-use-webconsole-to-add-an-ue","title":"4. Use WebConsole to Add an UE","text":"

First start up the WebConsole server:

cd ~/free5gc/webconsole\ngo run server.go\n

The screen shows the port number :5000 at the end. Open your web browser from your host machine, and enter the URL http://192.168.56.101:5000

  • On the login page, enter username admin and password free5gc.
  • Once logged in, widen the page until you see \u201cSubscribers\u201d on the left-hand side column.
  • Choose Subscribers and create a new data:
    • Note that other than the \u201cOperator Code Type\u201d field which you should choose \u201cOP\u201d for now, leave other fields unchanged. This registration data is used for ease of testing and actual use later.
  • After the data is created successfully, you can press Ctrl-C on the terminal to quit WebConsole.
"},{"location":"guide/5-install-ueransim/#5-setting-free5gc-and-ueransim-parameters","title":"5. Setting free5GC and UERANSIM Parameters","text":"

In free5gc VM, we need to edit three files:

  • ~/free5gc/config/amfcfg.yaml
  • ~/free5gc/config/smfcfg.yaml
  • ~/free5gc/config/upfcfg.yaml

First SSH into free5gc VM, and change ~/free5gc/config/amfcfg.yaml:

cd ~/free5gc\nnano config/amfcfg.yaml\n

Replace ngapIpList IP from 127.0.0.1 to 192.168.56.101, namely from:

...\n  ngapIpList:  # the IP list of N2 interfaces on this AMF\n  - 127.0.0.1\n
into:
...\n  ngapIpList:  # the IP list of N2 interfaces on this AMF\n  - 192.168.56.101  # 127.0.0.1\n

Next edit ~/free5gc/config/smfcfg.yaml:

nano config/smfcfg.yaml\n
and in the entry inside userplane_information / up_nodes / UPF / interfaces / endpoints, change the IP from 127.0.0.8 to 192.168.56.101, namely from:
...\n  interfaces: # Interface list for this UPF\n   - interfaceType: N3 # the type of the interface (N3 or N9)\n     endpoints: # the IP address of this N3/N9 interface on this UPF\n       - 127.0.0.8\n
into:
...\n  interfaces: # Interface list for this UPF\n   - interfaceType: N3 # the type of the interface (N3 or N9)\n     endpoints: # the IP address of this N3/N9 interface on this UPF\n       - 192.168.56.101  # 127.0.0.8\n
Finally, edit ~/free5gc/config/upfcfg.yaml\uff0cand chage gtpu IP from 127.0.0.8 into 192.168.56.101, namely from:
...\n  gtpu:\n    forwarder: gtp5g\n    # The IP list of the N3/N9 interfaces on this UPF\n    # If there are multiple connection, set addr to 0.0.0.0 or list all the addresses\n    ifList:\n      - addr: 127.0.0.8\n        type: N3\n
into:
...\n  gtpu:\n    forwarder: gtp5g\n    # The IP list of the N3/N9 interfaces on this UPF\n    # If there are multiple connection, set addr to 0.0.0.0 or list all the addresses\n    ifList:\n      - addr: 192.168.56.101  # 127.0.0.8\n        type: N3\n

"},{"location":"guide/5-install-ueransim/#6-setting-ueransim","title":"6. Setting UERANSIM","text":"

In the ueransim VM, there are two files related to free5GC\uff1a

  • ~/UERANSIM/config/free5gc-gnb.yaml
  • ~/UERANSIM/config/free5gc-ue.yaml

The second file is for UE, which we don\u2019t have to change if the data inside is consistent with the (default) registration data we set using WebConsole previously.

First SSH into ueransim, and edit the file ~/UERANSIM/config/free5gc-gnb.yaml, and change the ngapIp IP, as well as the gtpIp IP, from 127.0.0.1 to 192.168.56.102\uff0cand also change the IP in amfConfigs into 192.168.56.101, that is, from:

...\n  ngapIp: 127.0.0.1   # gNB's local IP address for N2 Interface (Usually same with local IP)\n  gtpIp: 127.0.0.1    # gNB's local IP address for N3 Interface (Usually same with local IP)\n\n  # List of AMF address information\n  amfConfigs:\n    - address: 127.0.0.1\n
into:
...\n  ngapIp: 192.168.56.102  # 127.0.0.1   # gNB's local IP address for N2 Interface (Usually same with local IP)\n  gtpIp: 192.168.56.102  # 127.0.0.1    # gNB's local IP address for N3 Interface (Usually same with local IP)\n\n  # List of AMF address information\n  amfConfigs:\n    - address: 192.168.56.101  # 127.0.0.1\n
Next we examine the file ~/UERANSIM/config/free5gc-ue.yaml\uff0cand see if the settings is consistent with those in free5GC (via WebConsole), for example:
# IMSI number of the UE. IMSI = [MCC|MNC|MSISDN] (In total 15 or 16 digits)\nsupi: 'imsi-208930000000003'\n# Mobile Country Code value\nmcc: '208'\n# Mobile Network Code value (2 or 3 digits)\nmnc: '93'\n\n# Permanent subscription key\nkey: '8baf473f2f8fd09487cccbd7097c6862'\n# Operator code (OP or OPC) of the UE\nop: '8e27b6af0e692e750f32667a3b14605d'\n# This value specifies the OP type and it can be either 'OP' or 'OPC'\nopType: 'OP'\n\n...\n\n# Initial PDU sessions to be established\nsessions:\n  - type: 'IPv4'\n    apn: 'internet'\n    slice:\n      sst: 0x01\n      sd: 0x010203\n\n# List of requested S-NSSAIs by this UE\nslices:\n  - sst: 0x01\n    sd: 0x010203\n\n...\n
The data appear to be the same as what we set in WebConsole.

"},{"location":"guide/5-install-ueransim/#7-testing-ueransim-against-free5gc","title":"7. Testing UERANSIM against free5GC","text":"

SSH into free5gc. If you have rebooted free5gc, remember to do:

sudo sysctl -w net.ipv4.ip_forward=1\nsudo iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE\nsudo systemctl stop ufw\n

In addition, execute the following command:

sudo iptables -I FORWARD 1 -j ACCEPT\n

Also, make sure you have make proper changes to the free5GC configuration files, then run ./run.sh:

cd ~/free5gc\n./run.sh\n

At this time free5GC has been started.

Next, prepare three additional SSH terminals from your host machine (if you know how to use tmux, you can use just one).

In terminal 1: SSH into ueransim, make sure UERANSIM is built, and configuration files have been changed correctly, then execute nr-gnb:

cd ~/UERANSIM\nbuild/nr-gnb -c config/free5gc-gnb.yaml\n

In terminal 2, SSH into ueransim, and execute nr-ue with admin right:

cd ~/UERANSIM\nsudo build/nr-ue -c config/free5gc-ue.yaml # for multiple-UEs, use -n and -t for number and delay\n

In terminal 3, SSH into ueransim, and ping 192.168.56.101 to see free5gc is alive. Then, use ifconfig to see if the tunnel uesimtun0 has been created (by nr-ue):

$ ifconfig\n\nenp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500\n        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255\n        inet6 fe80::a00:27ff:fe65:1472  prefixlen 64  scopeid 0x20<link>\n        ether 08:00:27:65:14:72  txqueuelen 1000  (Ethernet)\n        RX packets 80  bytes 32423 (32.4 KB)\n        RX errors 0  dropped 0  overruns 0  frame 0\n        TX packets 90  bytes 12860 (12.8 KB)\n        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0\n\nenp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500\n        inet 192.168.56.102  netmask 255.255.255.0  broadcast 192.168.56.255\n        inet6 fe80::a00:27ff:fe5e:be64  prefixlen 64  scopeid 0x20<link>\n        ether 08:00:27:5e:be:64  txqueuelen 1000  (Ethernet)\n        RX packets 1515  bytes 130490 (130.4 KB)\n        RX errors 0  dropped 0  overruns 0  frame 0\n        TX packets 1010  bytes 206670 (206.6 KB)\n        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0\n\nlo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536\n        inet 127.0.0.1  netmask 255.0.0.0\n        inet6 ::1  prefixlen 128  scopeid 0x10<host>\n        loop  txqueuelen 1000  (Local Loopback)\n        RX packets 3445  bytes 174416 (174.4 KB)\n        RX errors 0  dropped 0  overruns 0  frame 0\n        TX packets 3445  bytes 174416 (174.4 KB)\n        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0\n\nuesimtun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1500\n        inet 60.60.0.1  netmask 255.255.255.255  destination 60.60.0.1\n        inet6 fe80::2034:d00:a76:84b7  prefixlen 64  scopeid 0x20<link>\n        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)\n        RX packets 3  bytes 252 (252.0 B)\n        RX errors 0  dropped 0  overruns 0  frame 0\n        TX packets 13  bytes 732 (732.0 B)\n        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0\n

Now use ping:

ping -I uesimtun0 google.com\n
If ping gets replies, then free5GC is running properly. Congratulations!

"},{"location":"guide/6-simple-app/","title":"6 simple app","text":""},{"location":"guide/6-simple-app/#free5gc-simple-apps","title":"free5GC Simple Apps","text":"

In this demo we will use free5GC together with UERANSIM to exercise on some simple network applications:

  • ping + tcpdump
  • wget and curl
"},{"location":"guide/6-simple-app/#ping-tcpdump","title":"ping + tcpdump","text":"

First start up free5GC and ueransim VMs. This requires one SSH terminal for free5gc, and two for ueransim.

Open another SSH terminal and log in into ueransim:

ssh 192.168.56.102 -l ubuntu\n
Use ifconfig to check if uesimtun0 tunnel has been created, and use ping to check if we can ping through it\uff1a
$ ping google.com\nPING google.com (172.217.27.142) 56(84) bytes of data.\n64 bytes from tsa03s02-in-f14.1e100.net (172.217.27.142): icmp_seq=1 ttl=63 time=3.98 ms\n64 bytes from tsa03s02-in-f14.1e100.net (172.217.27.142): icmp_seq=2 ttl=63 time=3.87 ms\n64 bytes from tsa03s02-in-f14.1e100.net (172.217.27.142): icmp_seq=3 ttl=63 time=4.06 ms\n^C\n--- google.com ping statistics ---\n3 packets transmitted, 3 received, 0% packet loss, time 2003ms\nrtt min/avg/max/mdev = 3.872/3.970/4.060/0.076 ms\n

$ ping -I uesimtun0 google.com\nPING google.com (172.217.27.142) from 60.60.0.1 uesimtun0: 56(84) bytes of data.\n64 bytes from tsa03s02-in-f14.1e100.net (172.217.27.142): icmp_seq=1 ttl=61 time=5.85 ms\n64 bytes from tsa03s02-in-f14.1e100.net (172.217.27.142): icmp_seq=2 ttl=61 time=4.87 ms\n64 bytes from tsa03s02-in-f14.1e100.net (172.217.27.142): icmp_seq=3 ttl=61 time=4.76 ms\n^C\n--- google.com ping statistics ---\n3 packets transmitted, 3 received, 0% packet loss, time 2004ms\nrtt min/avg/max/mdev = 4.760/5.160/5.847/0.487 ms\n

Also use route -n to observe if current routing table shows some routing rules regarding the two network interfaces enp0s3 and enp0s8:

$ route -n\nKernel IP routing table\nDestination     Gateway         Genmask         Flags Metric Ref    Use Iface\n0.0.0.0         10.0.2.2        0.0.0.0         UG    100    0        0 enp0s3\n10.0.2.0        0.0.0.0         255.255.255.0   U     0      0        0 enp0s3\n10.0.2.2        0.0.0.0         255.255.255.255 UH    100    0        0 enp0s3\n192.168.56.0    0.0.0.0         255.255.255.0   U     0      0        0 enp0s8\n

The network 10.0.2.0/24 and its enp0s3 interface are related to VirtualBox NAT network card. We can bring down this interface:

$ sudo ifconfig enp0s3 down\n$ route -n\nKernel IP routing table\nDestination     Gateway         Genmask         Flags Metric Ref    Use Iface\n192.168.56.0    0.0.0.0         255.255.255.0   U     0      0        0 enp0s8\n
As shown aboe we have only Host-only network 192.168.56.0/24 left. Run ping again:
$ ping 8.8.8.8\nping: connect: Network is unreachable\n

And see that it can not ping through, but runing:

$ ping -I uesimtun0 8.8.8.8\nPING 8.8.8.8 (8.8.8.8) from 60.60.0.1 uesimtun0: 56(84) bytes of data.\n64 bytes from 8.8.8.8: icmp_seq=1 ttl=61 time=7.17 ms\n64 bytes from 8.8.8.8: icmp_seq=2 ttl=61 time=5.41 ms\n64 bytes from 8.8.8.8: icmp_seq=3 ttl=61 time=5.15 ms\n^C\n--- 8.8.8.8 ping statistics ---\n3 packets transmitted, 3 received, 0% packet loss, time 2005ms\nrtt min/avg/max/mdev = 5.150/5.907/7.165/0.895 ms\n

shows some responses, since we ask ping to go through the free5GC core network. To make ping 8.8.8.8 in addition to ping -I uesimtun0 8.8.8.8 work, we can set the uesimtun0 interface (IP 60.60.0.1) as the new default gateway:

$ sudo ip r add default dev uesimtun0\n$ route -n\nKernel IP routing table\nDestination     Gateway         Genmask         Flags Metric Ref    Use Iface\n0.0.0.0         0.0.0.0         0.0.0.0         U     0      0        0 uesimtun0\n192.168.56.0    0.0.0.0         255.255.255.0   U     0      0        0 enp0s8\n
Now traffic not for the 192.168.56.0/24 network will go to uesimtun0, and ping 8.8.8.8 works this time:
$ ping 8.8.8.8\nPING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.\n64 bytes from 8.8.8.8: icmp_seq=1 ttl=61 time=5.02 ms\n64 bytes from 8.8.8.8: icmp_seq=2 ttl=61 time=6.31 ms\n64 bytes from 8.8.8.8: icmp_seq=3 ttl=61 time=5.41 ms\n^C\n--- 8.8.8.8 ping statistics ---\n3 packets transmitted, 3 received, 0% packet loss, time 2004ms\nrtt min/avg/max/mdev = 5.017/5.581/6.312/0.541 ms\n...\n

Note that normally we are using ueransim to simulate \u201cterminal\u201d UE device, not as a network device or proxy, therefore the above two routing rules suffice.

Now if we still want to run:

$ ping google.com\nping: google.com: Temporary failure in name resolution\n

we will get unresolved domain name. To solve this, we can modify the file /etc/resolv.conf:

sudo nano /etc/resolv.conf\n

and change the nameserver IP to 8.8.8.8:

nameserver 8.8.8.8\n

After the change, we can see ping getting responses:

$ ping google.com\nPING google.com (216.58.200.46) 56(84) bytes of data.\n64 bytes from tsa01s08-in-f46.1e100.net (216.58.200.46): icmp_seq=1 ttl=61 time=5.19 ms\n64 bytes from tsa01s08-in-f46.1e100.net (216.58.200.46): icmp_seq=2 ttl=61 time=50.4 ms\n64 bytes from tsa01s08-in-f46.1e100.net (216.58.200.46): icmp_seq=3 ttl=61 time=5.66 ms\n^C\n--- google.com ping statistics ---\n3 packets transmitted, 3 received, 0% packet loss, time 2004ms\nrtt min/avg/max/mdev = 5.191/20.423/50.414/21.207 ms\n

We can also examine the network traffic happening underneath in the scenario above. First we open another SSH terminal into ueransim, and run the following command:

$ sudo tcpdump -n -i any host 60.60.0.1 or 192.168.56.101\ntcpdump: verbose output suppressed, use -v or -vv for full protocol decode\nlistening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes\n

then run ping 8.8.8.8 again, wait for a couple seconds, then Ctrl-C to exit. We see the data packets actually going in and out uesimtun0.

$ sudo tcpdump -n -i any host 60.60.0.1 or 192.168.56.101\ntcpdump: verbose output suppressed, use -v or -vv for full protocol decode\nlistening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes\n10:24:56.138729 IP 192.168.56.101.38412 > 192.168.56.102.38740: sctp (1) [HB REQ]\n10:24:56.138783 IP 192.168.56.102.38740 > 192.168.56.101.38412: sctp (1) [HB ACK]\n10:24:58.456532 IP 60.60.0.1 > 8.8.8.8: ICMP echo request, id 33, seq 1, length 64\n10:24:58.457416 IP 192.168.56.102.2152 > 192.168.56.101.2152: UDP, length 100\n10:24:58.462136 IP 192.168.56.101.2152 > 192.168.56.102.2152: UDP, length 92\n10:24:58.462324 IP 8.8.8.8 > 60.60.0.1: ICMP echo reply, id 33, seq 1, length 64\n10:24:59.458823 IP 60.60.0.1 > 8.8.8.8: ICMP echo request, id 33, seq 2, length 64\n10:24:59.459031 IP 192.168.56.102.2152 > 192.168.56.101.2152: UDP, length 100\n10:24:59.464214 IP 192.168.56.101.2152 > 192.168.56.102.2152: UDP, length 92\n10:24:59.464396 IP 8.8.8.8 > 60.60.0.1: ICMP echo reply, id 33, seq 2, length 64\n10:25:00.461293 IP 60.60.0.1 > 8.8.8.8: ICMP echo request, id 33, seq 3, length 64\n10:25:00.462178 IP 192.168.56.102.2152 > 192.168.56.101.2152: UDP, length 100\n10:25:00.474941 IP 192.168.56.101.2152 > 192.168.56.102.2152: UDP, length 92\n10:25:00.475561 IP 8.8.8.8 > 60.60.0.1: ICMP echo reply, id 33, seq 3, length 64\n10:25:01.463946 IP 60.60.0.1 > 8.8.8.8: ICMP echo request, id 33, seq 4, length 64\n10:25:01.464523 IP 192.168.56.102.2152 > 192.168.56.101.2152: UDP, length 100\n10:25:01.469297 IP 192.168.56.101.2152 > 192.168.56.102.2152: UDP, length 92\n10:25:01.470314 IP 8.8.8.8 > 60.60.0.1: ICMP echo reply, id 33, seq 4, length 64\n

"},{"location":"guide/6-simple-app/#wget","title":"wget","text":"

Simply look for any web page for file download on the web. For example, if we choose Golang web site as an example, we may find the URL:

https://golang.org/dl/go1.15.8.darwin-amd64.pkg\n
Using the same network settings is the previous exercise, just
wget https://golang.org/dl/go1.15.8.darwin-amd64.pkg\n
And see if you can download a Golang 1.15.8 install file.

"},{"location":"guide/6-simple-app/#ptt-ssh-bbsupttcc","title":"ptt (ssh bbsu@ptt.cc)","text":"

You can actually use SSH in the ueransim VM to access remote site. For example, you can SSH to a well-known terminal-based BBS site in Taiwan:

ssh bbsu@ppt.cc\n

"},{"location":"guide/6-simple-app/#youtube","title":"Youtube","text":"

You can also use Youtube as an example app. To achieve this goal, you can install a desktop VM with graphical UI, such as Ubuntu Desktop, and follow the same procedure to install and start up UERANSIM, then access Youtube through uesimtun0 and free5GC.

To reduce resource consumption on your host machine, you may install Lubuntu (at https://lubuntu.me), a more light-weight Ubuntu desktop distro instead. But since viewing free5GC YouTube Channel requires quite sime CPU consumption, you may have to set at least 2 CPUs and 2048 MB memory for the VM.

Refer to videos Access Youtube on Lubuntu (1, 2, 3, 4 and 5).

"},{"location":"guide/Appendix/","title":"Appendix","text":""},{"location":"guide/Appendix/#appendix","title":"Appendix","text":""},{"location":"guide/Appendix/#appendix-a-oam","title":"Appendix A: OAM","text":"
  1. Run the OAM server
    cd webconsole\ngo run server.go\n
  2. Access the OAM by
    URL: http://localhost:5000\nUsername: admin\nPassword: free5gc\n
  3. Now you can see the information of currently registered UEs (e.g. Supi, connected state, etc.) in the core network at the tab \"DASHBOARD\" of free5GC webconsole

Note: You can add the subscribers here too

"},{"location":"guide/Appendix/#appendix-b-orchestrator","title":"Appendix B: Orchestrator","text":"

Please refer to free5gmano

"},{"location":"guide/Appendix/#appendix-c-iptv","title":"Appendix C: IPTV","text":"

Please refer to free5GC/IPTV

"},{"location":"guide/Appendix/#appendix-d-system-environment-cleaning","title":"Appendix D: System Environment Cleaning","text":"

The below commands may be helpful for development purposes.

  1. Remove POSIX message queues
    • ls /dev/mqueue/
    • rm /dev/mqueue/*
  2. Remove gtp5g tunnels (using tools in libgtp5gnl)
    • cd ./src/upf/lib/libgtp5gnl/tools
    • ./gtp5g-tunnel list pdr
    • ./gtp5g-tunnel list far
  3. Remove gtp5g devices (using tools in libgtp5gnl)
    • cd ./src/upf/lib/libgtp5gnl/tools
    • sudo ./gtp5g-link del {Dev-Name}
"},{"location":"guide/Appendix/#appendix-e-change-kernel-version","title":"Appendix E: Change Kernel Version","text":"
  1. Check the previous kernel version: uname -r
  2. Search specific kernel version and install, take 5.0.0-23-generic for example
    sudo apt search 'linux-image-5.0.0-23-generic'\nsudo apt install 'linux-image-5.0.0-23-generic'\nsudo apt install 'linux-headers-5.0.0-23-generic'\n
  3. Update initramfs and grub
    sudo update-initramfs -u -k all\nsudo update-grub\n
  4. Reboot, enter grub and choose kernel version 5.0.0-23-generic
    sudo reboot\n
"},{"location":"guide/Appendix/#optional-remove-kernel-image","title":"Optional: Remove Kernel Image","text":"
sudo apt remove 'linux-image-5.0.0-23-generic'\nsudo apt remove 'linux-headers-5.0.0-23-generic'\n
"},{"location":"guide/Appendix/#appendix-f-program-the-sim-card","title":"Appendix F: Program the SIM Card","text":"

Install packages:

sudo apt-get install pcscd pcsc-tools libccid python-dev swig python-setuptools python-pip libpcsclite-dev\nsudo pip install pycrypto\n

Download PySIM

git clone git://git.osmocom.org/pysim.git\n

Change to pyscard folder and install

cd <pyscard-path>\nsudo /usr/bin/python setup.py build_ext install\n

Verify your reader is ready

sudo pcsc_scan\n

Check whether your reader can read the SIM card

cd <pysim-path>\n./pySim-read.py \u2013p 0\n

Program your SIM card information

./pySim-prog.py -p 0 -x 208 -y 93 -t sysmoUSIM-SJS1 -i 208930000000003 --op=8e27b6af0e692e750f32667a3b14605d -k 8baf473f2f8fd09487cccbd7097c6862 -s 8988211000000088313 -a 23605945\n

You can get your SIM card from sysmocom. You also need a card reader to write your SIM card. You can get a card reader from here or use other similar devices.

"},{"location":"guide/Configuration/","title":"Configuration","text":""},{"location":"guide/Configuration/#configuration","title":"Configuration","text":""},{"location":"guide/Configuration/#sbi-configuration","title":"SBI Configuration","text":"

There are registerIP and bindingIP design on every NF's sbi interface.

This is due to some orchestration, such as Kubernets or OpenStack, has the design of service IP mapping.

Use Kubernets as an example. K8S has the service type that enable users to define the service IP outside the pod. But the service IP may be different from the IP assigned inside the pod. Therefore, if we register the binding IP inside the pod to NRF, NRF cannot know which service IP outside the pod has attached. As the result, we need to separate registerIP from bindingIP in this scenario.

If you are not sure what IP you should set, just configure it as the same IP address.

"},{"location":"guide/Configuration/#sample-configuration","title":"Sample configuration","text":"

We provide a sample config to connect to outer ran under /sample/ran_attach_config/. The architecture is as following.

As the result, user's RAN IP must set to 192.168.0.0/24 subnet or let the routing route to this subnet.

Notice: If user wants to use the setting, aware to set 192.168.0.1 to your host as well.

"},{"location":"guide/Configuration/#smf-configuration","title":"SMF Configuration","text":""},{"location":"guide/Configuration/#a-configure-smf-with-s-nssai","title":"A. Configure SMF with S-NSSAI","text":"
  1. Configure NF Registration SMF S-NSSAI in smfcfg.yaml
"},{"location":"guide/Configuration/#b-configure-uplink-classifier-ulcl-information-in-smf","title":"B. Configure Uplink Classifier (ULCL) information in SMF","text":"
  1. Configure UE routing path in uerouting.yaml
  • DestinationIP and DestinationPort will be the packet destination.
  • UPF field will be the packet datapath when it match the destination above.

For more detail of SMF config, please refer to here.

"},{"location":"guide/Environment/","title":"Environment","text":""},{"location":"guide/Environment/#recommended-environment","title":"Recommended Environment","text":"

free5gc has been tested against the following environment:

  • Software
    • OS: Ubuntu 20.04.1
    • gcc 7.3.0
    • Go 1.14.4 linux/amd64
    • kernel version 5.4.0-42-generic

The listed kernel version is required for the UPF element.

  • Minimum Hardware

    • CPU: Intel i5 processor
    • RAM: 4GB
    • Hard drive: 160GB
    • NIC: Any 1Gbps Ethernet card supported in the Linux kernel
  • Recommended Hardware

    • CPU: Intel i7 processor
    • RAM: 8GB
    • Hard drive: 160GB
    • NIC: Any 10Gbps Ethernet card supported in the Linux kernel

This guide assumes that you will run all 5GC elements on a single machine.

"},{"location":"guide/New-Subscriber-via-webconsole/","title":"New Subscriber via webconsole","text":""},{"location":"guide/New-Subscriber-via-webconsole/#new-subscriber-via-webconsole","title":"New Subscriber via webconsole","text":""},{"location":"guide/New-Subscriber-via-webconsole/#1-install-webconsole","title":"1. Install webconsole","text":""},{"location":"guide/New-Subscriber-via-webconsole/#2-optionaldelete-mongodb","title":"2. (Optional)Delete MongoDB","text":"

If another version of free5GC was ran before, you have to delete MongoDB.

$ mongo --eval \"db.dropDatabase()\" free5gc\n
"},{"location":"guide/New-Subscriber-via-webconsole/#3-run-webconsole-server","title":"3. Run WebConsole server","text":"
$ cd ~/free5gc/webconsole\n$ ./bin/webconsole\n
"},{"location":"guide/New-Subscriber-via-webconsole/#4-use-browser-to-connect-to-webconsole","title":"4. Use browser to connect to WebConsole","text":"

Enter :5000 in URL bar.

Username: admin\nPassword: free5gc\n
"},{"location":"guide/New-Subscriber-via-webconsole/#5-add-new-subscriber","title":"5. Add new subscriber","text":"
  • Choose SUBSCRIBERS in the left side and press New Subscriber button
  • Fill the data and press Submit button
"},{"location":"guide/New-Subscriber-via-webconsole/#6-new-subscriber-is-added-successfully","title":"6. New subscriber is added successfully","text":""},{"location":"guide/New-Subscriber-via-webconsole/#7-modify-the-existed-subscriber","title":"7. Modify the existed subscriber","text":"

There are some issues for subscriber modification. If you want to modify the existed subscriber, please Delete it first and New again for now.

"},{"location":"guide/SMF-Config/","title":"SMF Config","text":""},{"location":"guide/SMF-Config/#smf-config-ulcl-config","title":"SMF Config / ULCL Config","text":"

This document explains the detail of SMF config. Also provide some examples about conversion between config file and real userplane topology

ULCL limitation: The branching UPF now can't connect to the Internet. It only serves as a Intranet in the UPF topology. (Please refers to the topology of example 2)

"},{"location":"guide/SMF-Config/#sbi","title":"SBI","text":"Field meaning scheme The protocol for SBI registerIPv4 IP used to register to NRF bindingIPv4 IP used to bind the service port SMF bind the SBI service to this port"},{"location":"guide/SMF-Config/#pfcp","title":"PFCP","text":"Field meaning addr The IP address of N4 interface on the SMF (PFCP)"},{"location":"guide/SMF-Config/#userplane-information","title":"Userplane Information","text":"Field meaning userplane_information Includes topology and information of RAN and UPFs which are controlled by this SMF up_nodes The node in the user plane topology. Includes gNodeB, I-UPF and A-UPF links The edge in the user plane topology type Indicate it is RAN or specific kind of UPF node_id The PFCP IPv4 address for UPF

Note: up_resource_ip serves as default user plane IP for the UPF. In this version, UPF will determine its user plane IP by itself. So setting up_resource_ip in SMF config won't affect real config in user plane.

"},{"location":"guide/SMF-Config/#amf-config","title":"AMF Config","text":"

To understand whole PDU session config, we must take a step forward to understand the AMF config.

Field meaning NGAPIPList The IP list of N2 interfaces on the AMF SBI Same meaning with SMF/SBI."},{"location":"guide/SMF-Config/#example-1","title":"Example 1","text":""},{"location":"guide/SMF-Config/#smf-config","title":"SMF Config","text":"
  • sbi:
    • scheme: http
    • registerIPv4: 127.0.0.2
    • bindingIPv4: 127.0.0.2
    • port: 8000
  • pfcp:
    • addr: 10.200.200.1
  • userplane_information:
    • up_nodes:
      • gNB1:
        • type: AN
      • UPF:
        • type: UPF
        • node_id: 10.200.200.102
    • links:
      • A: gNB1
      • B: UPF
"},{"location":"guide/SMF-Config/#amf-config_1","title":"AMF Config","text":"
  • ngapIpList:
    • 127.0.0.1
  • sbi:
    • scheme: http
    • registerIPv4: 127.0.0.18
    • bindingIPv4: 127.0.0.18
    • port: 8000
"},{"location":"guide/SMF-Config/#representing-topology","title":"Representing Topology","text":""},{"location":"guide/SMF-Config/#example-2","title":"Example 2","text":""},{"location":"guide/SMF-Config/#smf-config_1","title":"SMF Config","text":"
  • sbi:
    • scheme: https
    • registerIPv4: 127.0.0.2
    • bindingIPv4: 127.0.0.2
    • port: 29502
  • pfcp:
    • addr: 10.200.200.1
  • userplane_information:
    • up_nodes:
      • gNB1:
        • type: AN
      • BranchingUPF:
        • type: UPF
        • node_id: 10.200.200.102
      • AnchorUPF1:
        • type: UPF
        • node_id: 10.200.200.101
      • AnchorUPF2:
        • type: UPF
        • node_id: 10.200.200.103
      • links:
      • A: gNB1 B: BranchingUPF
      • A: BranchingUPF B: AnchorUPF1
      • A: BranchingUPF B: AnchorUPF2
"},{"location":"guide/SMF-Config/#amf-config_2","title":"AMF Config","text":"
  • ngapIpList:
    • 127.0.0.1
  • sbi:
    • scheme: https
    • registerIPv4: 127.0.0.18
    • bindingIPv4: 127.0.0.18
    • port: 8000
"},{"location":"guide/SMF-Config/#representing-topology_1","title":"Representing Topology","text":""},{"location":"guide/Trouble_Shooting/","title":"Trouble Shooting","text":""},{"location":"guide/Trouble_Shooting/#trouble-shooting","title":"Trouble Shooting","text":""},{"location":"guide/Trouble_Shooting/#1-error-sctp-failed-to-connect-given-amf-n3iwfngap","title":"1. ERROR: [SCTP] Failed to connect given AMF N3IWF=NGAP","text":"

This error occured when N3IWF was started before AMF finishing initialization. This error usually appears when you run the TestNon3GPP in the first time.

Rerun the test should be fine. If it still not be solved, larger the sleeping time in line 110 of test.sh.

"},{"location":"guide/Trouble_Shooting/#2-testnon3gpp","title":"2. TestNon3GPP","text":"

TestNon3GPP will modify the config/amfcfg.conf. So, if you had killed the TestNon3GPP test before it finished, you might need to copy config/amfcfg.conf.bak back to config/amfcfg.conf to let other tests pass.

cp config/amfcfg.conf.bak config/amfcfg.conf

"},{"location":"guide/Trouble_Shooting/#3-db-on-tls-to-h2c","title":"3. DB on TLS to H2C","text":"

If you meet any problems about https or mogodb, it maybe couse our new version from v3.0.1 to v3.0.2 has change http to H2C verion. Try the command below.

mongo --eval \"db.NfProfile.drop()\" free5gc

"},{"location":"guide/Trouble_Shooting/#4-mqcreate-error-creating-message-queue-too-many-open-files-upfutil-upf","title":"4. MQCreate() Error creating message queue: Too many open files UPF=Util (UPF)","text":"

Remove POSIX message queues

ls /dev/mqueue/\nrm /dev/mqueue/*\n
"},{"location":"guide/Trouble_Shooting/#5-remove-gtp-devices-using-tools-in-libgtp5gnl-upf","title":"5. Remove gtp devices (using tools in libgtp5gnl) (UPF)","text":"
cd lib/libgtp5gnl/tools\nsudo ./gtp5g-link del {Dev-Name}\n
"},{"location":"guide/Trouble_Shooting/#6-upf-cli-run-error-open-gtp5g-open-link-create-file-exists","title":"6. UPF Cli Run Error: open Gtp5g: open link: create: file exists","text":"
sudo ip link del upfgtp\n
"},{"location":"guide/Trouble_Shooting/#7-decode-http2-packet-in-wireshark","title":"7. Decode HTTP/2 packet in Wireshark","text":"
  1. Run Network Function

    Check has XXFsslkey.log

  2. Edit >> Preference >> Protocols >> SSL (TLS)

  3. Add keylog

  4. Filter http2

"},{"location":"guide/Trouble_Shooting/#7-decode-h2c-http2-clear-text-without-tls","title":"7. Decode H2C (HTTP2 clear text without TLS)","text":"

The similar reason as NEA0 NAS message. Althrough H2C is clear text, wirshark still considers these packets as the normal TCP packets and does not decode them by HTTP2.

To see the details of H2C packets, do the following configuration.

  1. Analyze \u2192 Decode As\u2026

  2. click Add button to add the decode rules

    Decode the packets from the TCP ports listened by each NF as HTTP2 packets.

"},{"location":"guide/features/","title":"Features","text":""},{"location":"guide/features/#free5gc-specification","title":"free5GC Specification","text":"
  • 3GPP TS 23.501/23.502-Rel-15
  • 5G Standalone (SA) supported
  • Serviced-Based Interface (SBI) supported
    • Namf, Nsmf, Nausf, Nudm, Nudr, Nnssf, Nnrf, Npcf
  • N1, N2, N3, N4, N6, N9, interfaces supported
  • 5G SA Network Functions supported:
    • AMF: Access and Mobility Management Function
      • Registration Management, Connection Management, Reachability Management, Mobility Management, and Authentication
    • SMF: Session Management Function
      • Session Management, IP Assigning/Management
    • UPF: User Plane Function
      • Support multiple UPF and ULCL (uplink classifier)
      • Session and Service Continuity (SSC) mode 1
      • Packet Routing/Forwarding
    • AUSF: Authentication Server Function
    • NRF: NF Repository Function
    • UDM: Unified Data Management
    • UDR: Unified Data Repository
    • PCF: Policy and Charging Function
    • NSSF: Network Slice Selection Function
    • N3IWF: Non-3GPP Interworking Function
"},{"location":"guide/features/#supported-features","title":"Supported features","text":"
  • Registration
    • Initial Registration
    • Periodic Registration
    • Mobility Registration
  • Authentication
    • 5G-AKA
    • EAP-AKA'
  • NAS Security
    • Ciphering: NEA0, NEA1, NEA2, NEA3
    • Integrity: NIA0, NIA1, NIA2, NIA3
  • Deregistration:
    • UE-initiated Deregistration
  • Service Request:
    • UE triggered Service Request
    • Network Triggered Service Request
  • AN Release
  • PDU Session Establishment
  • PDU Session Modification (v3.3.0)
  • PDU Session Release
  • Handover
    • N2 Handover (Indirect mode not supported)
    • Xn Handover
  • QoS
    • Control Plane only:
      1. 5QI, ARP, GBR, MBR of QoS Flow (v3.3.0)
      2. Session-AMBR supported
  • Collection and reporting of usage data over N4 interface
    • Volume measurement periodically
  • UP Security
  • Multiple UPFs and ULCL (Uplink Classifier)
  • Multiple Slice and DNN
  • Dynamic/Static IPv4 address allocation
"},{"location":"guide/hardware/","title":"Hardware","text":""},{"location":"guide/hardware/#hardware-tested","title":"Hardware Tested","text":"

Some 5G UE and gNodeB hardware have been tested with free5GC by partners or community members:

  • 5G UE (Support 5G SA):

    • APAL 5G Dongle
    • APAL 5G MiFi
    • Samsung S21 5G
    • Huawei P40 5G (forum link)
    • Huawei Mate30 5G (forum link)
  • gNodeB:

    • Alpha gNodeB
    • Compal gNodeB
    • FII gNodeB
    • ITRI gNodeB
    • Lions gNodeB
    • Amarisoft gNodeB (forum link)
    • Nokia gNodeB (forum link)
    • Nokia (AMIA AirScale Indoor Subrack 473098A)

Reports of tested hardware not listed above on Github issue or free5GC forum are welcome.

PS: if you don't have any hardware available, we suggest to use UERANSIM to simulate.

(Refer to Advanced environment setup section)

"},{"location":"membership/","title":"Index","text":""},{"location":"membership/#sponsorship-info","title":"Sponsorship Info","text":""},{"location":"membership/#sponsorship-tiers","title":"Sponsorship Tiers","text":"

free5GC is a nonprofit organization dedicated to developing innovative and next-generation features for open-source code of the 5G Core (5GC) Network under Apache 2.0 license. Your generous support and sponsorship will sustain our technology development and the operation of the community. Your company/organization logo will be displayed on the free5GC website and listed as the sponsorship you participate. Here are the sponsorship tiers we offer.

  • Sponsor \u2013 donation under US $17,000
  • Bronze Sponsor \u2013 donation from US $17,000 to US $34,000
  • Silver Sponsor \u2013 donation from US $34,000 to US $68,000
  • Gold Sponsor \u2013 donation from US $68,000 to US $102,000
  • Platinum Sponsor \u2013 donation for more than US $102,000

Your generosity is appreciated. You can now support free5GC by using your credit cards. Please visit https://fund.nycu.edu.tw/plans/HYnZMprdAGx for donation.

Tips

  • You don\u2019t need to donate to use free5GC. You can download free5GC from https://github.com/free5gc/free5gc.
  • The license of free5GC follows Apache 2.0. That is, anyone can use free5GC for commercial purposes for free. We will not charge any license fee.
  • if you have any questions or problems regarding donation and sponsorship, please email us at free5GC.org@gmail.com.
"},{"location":"support/","title":"Index","text":""},{"location":"support/#technical-support","title":"Technical Support","text":"

If you encounter the usage problem on free5GC, please join our official forum forum.free5gc.org and initiate a new discussion.

Otherwise, you can raise the issue on our GitHub repository for reporting the bugs/suggestions (related to vulnerability/functionality/deployment/testing), or create the pull request for contributing to our community!

Tips

If your problem can not be solved via the platforms listed above, please send an email directly to free5GC.org@gmail.com. Thanks.

"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 00000000..0f8724ef --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 00000000..396e5673 Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/stylesheets/extra.css b/stylesheets/extra.css new file mode 100644 index 00000000..a9523c1b --- /dev/null +++ b/stylesheets/extra.css @@ -0,0 +1,18 @@ +:root { + --md-primary-fg-color: #84c2ea; + --md-primary-fg-color--light: #84c2ea; + --md-primary-fg-color--dark: #84c2ea; + } + +.info-block { + display: flex; + justify-content: space-between; + flex-wrap: wrap; +} + +.info-block-img { + max-height: 8vh !important; + width: auto; + height: auto; + margin-top: 10px; +} diff --git a/support/index.html b/support/index.html new file mode 100644 index 00000000..38ff1e0d --- /dev/null +++ b/support/index.html @@ -0,0 +1,646 @@ + + + + + + + + + + + + + + + + + + Index - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Technical Support

+

If you encounter the usage problem on free5GC, please join our official forum forum.free5gc.org and initiate a new discussion.

+

Otherwise, you can raise the issue on our GitHub repository for reporting the bugs/suggestions (related to vulnerability/functionality/deployment/testing), or create the pull request for contributing to our community!

+
+

Tips

+

If your problem can not be solved via the platforms listed above, please send an email directly to free5GC.org@gmail.com.
+Thanks.

+
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/videos/index.html b/videos/index.html new file mode 100644 index 00000000..ba4d5fce --- /dev/null +++ b/videos/index.html @@ -0,0 +1,706 @@ + + + + + + + + + + + + + + + + + + + + Other Videos - free5GC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

Other videos showing free5GC

+
    +
  1. +

    Akraino Blueprints: Integrated Cloud Native Private Wireless, The Linux Foundation, October 11, 2021

    +
  2. +
  3. +

    SD Core Techinar July 7 2021, Open Networking Foundation, July 13, 2021

    +
  4. +
  5. +

    Aarna Networks MWC 2021 Demo, Aarna Networks Channel, June 27, 2021

    +
  6. +
  7. +

    OpenStack Tacker Demo, Open Infrastructure Foundation, April 26, 2021

    +
  8. +
  9. +

    OpenNess Tungsten Fabric free5GC demo, Aarna Networks Channel, February 16, 2021

    +
  10. +
  11. +

    5G Core on Diamanti, Diamanti, Inc., February 3, 2021

    +
  12. +
  13. +

    free5GC (5G Core) Orchestration on Kubernetes with Tungsten Fabric CNI and Testing, Aarna Networks Channel, December 2, 2020

    +
  14. +
  15. +

    IoT LoRa (sensors and gateway in hardware), RAN in hardware (SDR) and software, and the free5GC, LABORA Research Group, July 3, 2020

    +
  16. +
  17. +

    UE and eNodeB in Hardware (conventional cell phone + SDR) and free5GC: a pratical approach in 5G, LABORA Research Group, July 3, 2020

    +
  18. +
  19. +

    OpenAirInterface and free5GC: a pratical approach in 5G networks, LABORA Research Group, June 29, 2020

    +
  20. +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file