From 82bc7145009e0d2e6ab9dd5f0898ea3c73d5600a Mon Sep 17 00:00:00 2001 From: Tim Liu Date: Sat, 17 Feb 2024 02:34:02 +0000 Subject: [PATCH 01/15] update pkg version --- go.mod | 14 +++++++------- go.sum | 33 +++++++++++++++------------------ 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 11a5ce0a..e1614469 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,12 @@ require ( github.com/antihax/optional v1.0.0 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/davecgh/go-spew v1.1.1 - github.com/free5gc/aper v1.0.4 - github.com/free5gc/nas v1.1.0 - github.com/free5gc/ngap v1.0.6 - github.com/free5gc/openapi v1.0.7-0.20240117084712-52ad99299693 - github.com/free5gc/pfcp v1.0.6 - github.com/free5gc/util v1.0.5-0.20231001095115-433858e5be94 + github.com/free5gc/aper v1.0.5 + github.com/free5gc/nas v1.1.2 + github.com/free5gc/ngap v1.0.7 + github.com/free5gc/openapi v1.0.7 + github.com/free5gc/pfcp v1.0.7 + github.com/free5gc/util v1.0.5 github.com/gin-gonic/gin v1.9.1 github.com/google/uuid v1.3.0 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 @@ -29,7 +29,7 @@ require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect - github.com/free5gc/tlv v1.0.2-0.20230131124215-8b6ebd69bf93 // indirect + github.com/free5gc/tlv v1.0.2 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect diff --git a/go.sum b/go.sum index 4cd40b00..2b867b7a 100644 --- a/go.sum +++ b/go.sum @@ -62,22 +62,22 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= -github.com/free5gc/aper v1.0.4 h1:Ufbf5lzbXBOhSdUSaIdAhFMOjggsX4p6eWMrpzrrD60= -github.com/free5gc/aper v1.0.4/go.mod h1:3K/m47BIPR2xhBkuHD1unp2LnArVtt3iTI4De0bCqpI= -github.com/free5gc/nas v1.1.0 h1:8mIncMWG0L9BA+3oMlrYocfZ6qE+P7jZ1oe/tnXLWAs= -github.com/free5gc/nas v1.1.0/go.mod h1:fjWwpyp7/wOyL72HTkjvIe9YTCfGyZosjITsI5sXyuU= -github.com/free5gc/ngap v1.0.6 h1:f9sKqHMNrFZVo9Kp8hAyrCXSoI8l746N5O+DFn7vKHA= -github.com/free5gc/ngap v1.0.6/go.mod h1:TG1kwwU/EyIlJ3bxY591rdxpD5ZeYnLZTzoWjcfvrBM= -github.com/free5gc/openapi v1.0.4/go.mod h1:KRCnnp0GeK0Bl4gnrX79cQAidKXNENf8VRdG0y9R0Fc= +github.com/free5gc/aper v1.0.5-0.20230614030933-c73735898582/go.mod h1:ybHxhYnRqQ9wD4yB9r/3MZdbCYCjtqUyfLpSnJpwWd4= +github.com/free5gc/aper v1.0.5 h1:sUYFFmOXDLjyL4rU6zFnq81M4YluqP90Pso5e/J4UhA= +github.com/free5gc/aper v1.0.5/go.mod h1:ybHxhYnRqQ9wD4yB9r/3MZdbCYCjtqUyfLpSnJpwWd4= +github.com/free5gc/nas v1.1.2 h1:BB31Crg8XyYwwAGPQbsyoMiMw7nrf8iZI3/ZY6ArPYE= +github.com/free5gc/nas v1.1.2/go.mod h1:aWQK2lvv//0mkEhavMPtx04Z5uom6eQfSse62ZCA3YA= +github.com/free5gc/ngap v1.0.7 h1:9VCFVptF7oEc+K/XwEjpH2MFi37SKOjsCGkZh7qp6bA= +github.com/free5gc/ngap v1.0.7/go.mod h1:03jSQMwwdFmtkYwS4gXP6SlftVZrOeMcdzOReh18hwE= github.com/free5gc/openapi v1.0.6/go.mod h1:iw/N0E+FlX44EEx24IBi2EdZW8v+bkj3ETWPGnlK9DI= -github.com/free5gc/openapi v1.0.7-0.20240117084712-52ad99299693 h1:gFyYBsErQAkx4OVHXYqjO0efO9gPWydQavQcjU0CkHY= -github.com/free5gc/openapi v1.0.7-0.20240117084712-52ad99299693/go.mod h1:qv9KqEucoZSeENPRFGxfTe+33ZWYyiYFx1Rj+H0DoWA= -github.com/free5gc/pfcp v1.0.6 h1:dKEVyZWozF1G+yk1JXw/1ggtIRI0v362say/Q6VDZTE= -github.com/free5gc/pfcp v1.0.6/go.mod h1:WzpW7Zxhx5WONMumNKRWbPn7pl/iTYp2FqRLNiOWUjs= -github.com/free5gc/tlv v1.0.2-0.20230131124215-8b6ebd69bf93 h1:QPSSI5zw4goiIfxem9doVyMqTO8iKLQ536pzpET5Y+Q= -github.com/free5gc/tlv v1.0.2-0.20230131124215-8b6ebd69bf93/go.mod h1:KbbQJIgGaA2jIwnTJgJ/lE3JSDEp3898S6c4TEq0Vyg= -github.com/free5gc/util v1.0.5-0.20231001095115-433858e5be94 h1:tNylIqH/m5Kq+3KuC+jjXGl06Y6EmM8yq61ZUgNrPBY= -github.com/free5gc/util v1.0.5-0.20231001095115-433858e5be94/go.mod h1:aMszJZbCkcg5xaGgzya+55jz+OPMsJqPLq5Z3fWDFPE= +github.com/free5gc/openapi v1.0.7 h1:I0HOgqRgER6DbyqB6EBxusmbeouIhcOn4eOJvL3veJA= +github.com/free5gc/openapi v1.0.7/go.mod h1:qv9KqEucoZSeENPRFGxfTe+33ZWYyiYFx1Rj+H0DoWA= +github.com/free5gc/pfcp v1.0.7 h1:20/4PGok8Ihy+NfYQzic39zVq3ZB4/gdZhDO1676TMQ= +github.com/free5gc/pfcp v1.0.7/go.mod h1:57l3+7h2o1Sg8vbgl0kflROwuEQltx2VbULLrV9F1Ts= +github.com/free5gc/tlv v1.0.2 h1:gb7PRbJFrYXlbqIKk0t3XuxJNecc4A7X2Y+CXS/FzEM= +github.com/free5gc/tlv v1.0.2/go.mod h1:maEgHMIoJBYlRxVSrhiYzsKHyVh4d4pV0yl86DuTbv8= +github.com/free5gc/util v1.0.5 h1:MjyEIX6gGbdS8FUAOxhE0FsMD6pmv5T+45LjBabVhS8= +github.com/free5gc/util v1.0.5/go.mod h1:jgiW/bNbNbX87CSTKXyfvkhQeDY9ThK+TtWTu4ILCS8= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -324,7 +324,6 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -376,7 +375,6 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -402,7 +400,6 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= From 9600d2539f6e40ad7f3477ec9b42477ab89379f9 Mon Sep 17 00:00:00 2001 From: Tim Liu Date: Sat, 17 Feb 2024 02:34:26 +0000 Subject: [PATCH 02/15] add go 1.21 to github workflow --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 87ba0914..13bd9a17 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.18' ] + go: [ '1.18', '1.21' ] name: Go ${{ matrix.go }} sample steps: - uses: actions/checkout@v3 From 5aab12868188f4311f23cdbe74b9b10b4907c29c Mon Sep 17 00:00:00 2001 From: CTFang Date: Mon, 4 Mar 2024 00:23:16 +0800 Subject: [PATCH 03/15] Feature: Support Converged Charging (#94) * support converged charging * flow status * add pdu level charging urr to default data path * fix: only onlince charging need to request unit * fix: release charging session in all pdu session release case * fix: don't send charging request for non-charging urr * rm untested code * update openapi/pfcp hash * add nil & error checking * update go.sum * add more error checking * fix test fail * fix ci error * add comment for addPduLevelChargingRuleToFlow() * add comment & fix potential synchronization issues * fix typo & linter error * handle assigned when IP in ipFilterRule is assigned * fix typo * fix typo & set default value of RequestedUnit * fix NewSMContext * fix: remove SwapSrcAndDst() * fix: UL, DL flow description should be same * remove SMF's default data path to reduce redundant PDRs * fix: testcase's ip.dst should not be any * style: fix naked return * update util's hash * fix: duplicated URRs in PDR * fix: Volume Threshold IE should be added to PFCP Session Modification Request Update URR to prevent the flow rule be blocked * remove SMContext.UrrIDGenerator * fix: MBQE, MAQE's URR * comment out these variable: N3N6, N3N9, N9N6 * remove FlowDescription judgement * remove unused code and add comments * Add back defalt urr rule * Fix: Add GetTokenCtx() in CHF Selection * Remove unused comments --------- Co-authored-by: roy19991013 <80-ChienAn@users.noreply.gitlab.nems.cs.nctu.edu.tw> Co-authored-by: Tim Liu Co-authored-by: Ian Chen Co-authored-by: Ian Chen Co-authored-by: ianchen0119 Co-authored-by: brianchennn --- go.mod | 3 + go.sum | 23 +- internal/context/charging.go | 33 ++ internal/context/context.go | 14 + internal/context/datapath.go | 140 +++++++- internal/context/pcc_rule.go | 56 +-- internal/context/pfcp_reports.go | 95 +++++ internal/context/pfcp_rules.go | 35 ++ internal/context/sm_context.go | 154 ++++++-- internal/context/sm_context_policy.go | 97 ++++- internal/context/sm_context_policy_test.go | 7 + internal/context/upf.go | 10 +- internal/context/user_plane_information.go | 10 +- internal/logger/logger.go | 2 + internal/pfcp/handler/handler.go | 51 +-- internal/pfcp/message/build.go | 92 +++++ internal/pfcp/message/send.go | 8 +- internal/sbi/callback/api_default.go | 36 ++ internal/sbi/callback/routers.go | 6 + internal/sbi/consumer/converged_charging.go | 117 ++++++ internal/sbi/producer/callback.go | 55 +++ internal/sbi/producer/charging_trigger.go | 377 ++++++++++++++++++++ internal/sbi/producer/datapath.go | 30 +- internal/sbi/producer/gsm_handler_test.go | 2 +- internal/sbi/producer/pdu_session.go | 55 ++- internal/sbi/producer/ulcl_procedure.go | 22 +- pkg/factory/config.go | 1 + 27 files changed, 1377 insertions(+), 154 deletions(-) create mode 100644 internal/context/charging.go create mode 100644 internal/context/pfcp_reports.go create mode 100644 internal/sbi/consumer/converged_charging.go create mode 100644 internal/sbi/producer/charging_trigger.go diff --git a/go.mod b/go.mod index e1614469..6f59bb65 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/kr/pretty v0.3.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mitchellh/mapstructure v1.4.2 // indirect @@ -50,6 +51,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.8.0 // indirect github.com/russross/blackfriday/v2 v2.0.1 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect @@ -64,5 +66,6 @@ require ( golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.6 // indirect google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 2b867b7a..348f08a4 100644 --- a/go.sum +++ b/go.sum @@ -34,6 +34,7 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1/go.mod h1:nuudZmJhzWtx2212z+pkuy7B6nkBqa+xwNXZHL1j8cg= +github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1/go.mod h1:nuudZmJhzWtx2212z+pkuy7B6nkBqa+xwNXZHL1j8cg= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= @@ -54,6 +55,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -173,11 +176,14 @@ github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= @@ -197,12 +203,16 @@ github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= @@ -262,6 +272,11 @@ golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= @@ -400,6 +415,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -538,8 +554,9 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= diff --git a/internal/context/charging.go b/internal/context/charging.go new file mode 100644 index 00000000..b8c73e16 --- /dev/null +++ b/internal/context/charging.go @@ -0,0 +1,33 @@ +package context + +import ( + "github.com/free5gc/openapi/models" +) + +type ChargingLevel uint8 + +// For a rating group that is pdu session charging level, all volume in a pdu session will be charged +// For a rating group that is flow charging level (or Rating group level (32.255)), +// only volume in a flow will be charged +const ( + PduSessionCharging ChargingLevel = iota + FlowCharging +) + +type RequestType uint8 + +// For each charging event, it will have a corresponding charging request type, see 32.255 Table 5.2.1.4.1 +const ( + CHARGING_INIT RequestType = iota + CHARGING_UPDATE + CHARGING_RELEASE +) + +type ChargingInfo struct { + ChargingMethod models.QuotaManagementIndicator + VolumeLimitExpiryTimer *Timer + EventLimitExpiryTimer *Timer + ChargingLevel ChargingLevel + RatingGroup int32 + UpfId string +} diff --git a/internal/context/context.go b/internal/context/context.go index ce342f1b..b9d4ced5 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -3,6 +3,7 @@ package context import ( "context" "fmt" + "math" "net" "os" "sync/atomic" @@ -18,6 +19,7 @@ import ( "github.com/free5gc/pfcp/pfcpType" "github.com/free5gc/smf/internal/logger" "github.com/free5gc/smf/pkg/factory" + "github.com/free5gc/util/idgenerator" ) func Init() { @@ -79,6 +81,16 @@ type SMFContext struct { UEPreConfigPathPool map[string]*UEPreConfigPaths UEDefaultPathPool map[string]*UEDefaultPaths LocalSEIDCount uint64 + + // Each pdu session should have a unique charging id + ChargingIDGenerator *idgenerator.IDGenerator +} + +func GenerateChargingID() int32 { + if id, err := smfContext.ChargingIDGenerator.Allocate(); err == nil { + return int32(id) + } + return 0 } func ResolveIP(host string) net.IP { @@ -241,6 +253,8 @@ func InitSmfContext(config *factory.Config) { smfContext.UserPlaneInformation = NewUserPlaneInformation(&configuration.UserPlaneInformation) + smfContext.ChargingIDGenerator = idgenerator.NewGenerator(1, math.MaxUint32) + SetupNFProfile(config) smfContext.Locality = configuration.Locality diff --git a/internal/context/datapath.go b/internal/context/datapath.go index de75c44c..d8a31d59 100644 --- a/internal/context/datapath.go +++ b/internal/context/datapath.go @@ -3,6 +3,7 @@ package context import ( "fmt" "strconv" + "strings" "github.com/google/uuid" @@ -306,6 +307,14 @@ func (dataPathPool DataPathPool) GetDefaultPath() *DataPath { return nil } +func (dataPathPool DataPathPool) ResetDefaultPath() error { + for _, path := range dataPathPool { + path.IsDefaultPath = false + } + + return nil +} + func (dataPath *DataPath) String() string { firstDPNode := dataPath.FirstDPNode @@ -345,6 +354,10 @@ func getUrrIdKey(uuid string, urrId uint32) string { return uuid + ":" + strconv.Itoa(int(urrId)) } +func GetUpfIdFromUrrIdKey(urrIdKey string) string { + return strings.Split(urrIdKey, ":")[0] +} + func (node DataPathNode) addUrrToNode(smContext *SMContext, urrId uint32, isMeasurePkt, isMeasureBeforeQos bool) { var urr *URR var ok bool @@ -360,19 +373,19 @@ func (node DataPathNode) addUrrToNode(smContext *SMContext, urrId uint32, isMeas logger.PduSessLog.Errorln("new URR failed") return } - smContext.UrrUpfMap[id] = urr } if urr != nil { if node.UpLinkTunnel != nil && node.UpLinkTunnel.PDR != nil { - node.UpLinkTunnel.PDR.URR = append(node.UpLinkTunnel.PDR.URR, urr) + node.UpLinkTunnel.PDR.AppendURRs([]*URR{urr}) } if node.DownLinkTunnel != nil && node.DownLinkTunnel.PDR != nil { - node.DownLinkTunnel.PDR.URR = append(node.DownLinkTunnel.PDR.URR, urr) + node.DownLinkTunnel.PDR.AppendURRs([]*URR{urr}) } } } +// Add reserve urr to datapath UPF func (datapath *DataPath) addUrrToPath(smContext *SMContext) { if smContext.UrrReportTime == 0 && smContext.UrrReportThreshold == 0 { logger.PduSessLog.Errorln("URR Report time and threshold is 0") @@ -385,16 +398,17 @@ func (datapath *DataPath) addUrrToPath(smContext *SMContext) { if curDataPathNode.IsANUPF() { if curDataPathNode.Next() == nil { - MBQEUrrId = smContext.UrrIdMap[N3N6_MBEQ_URR] - MAQEUrrId = smContext.UrrIdMap[N3N6_MAEQ_URR] + MBQEUrrId = smContext.UrrIdMap[N3N6_MBQE_URR] + MAQEUrrId = smContext.UrrIdMap[N3N6_MAQE_URR] } else { - MBQEUrrId = smContext.UrrIdMap[N3N9_MBEQ_URR] - MAQEUrrId = smContext.UrrIdMap[N3N9_MAEQ_URR] + MBQEUrrId = smContext.UrrIdMap[N3N9_MBQE_URR] + MAQEUrrId = smContext.UrrIdMap[N3N9_MAQE_URR] } } else { - MBQEUrrId = smContext.UrrIdMap[N9N6_MBEQ_URR] - MAQEUrrId = smContext.UrrIdMap[N9N6_MAEQ_URR] + MBQEUrrId = smContext.UrrIdMap[N9N6_MBQE_URR] + MAQEUrrId = smContext.UrrIdMap[N9N6_MAQE_URR] } + curDataPathNode.addUrrToNode(smContext, MBQEUrrId, true, true) curDataPathNode.addUrrToNode(smContext, MAQEUrrId, true, false) } @@ -422,7 +436,7 @@ func (dataPath *DataPath) ActivateTunnelAndPDR(smContext *SMContext, precedence // Note: This should be after Activate Tunnels if smContext.UrrReportTime != 0 || smContext.UrrReportThreshold != 0 { dataPath.addUrrToPath(smContext) - logger.PduSessLog.Warn("Create URR") + logger.PduSessLog.Trace("Create URR") } else { logger.PduSessLog.Warn("No Create URR") } @@ -530,6 +544,8 @@ func (dataPath *DataPath) ActivateTunnelAndPDR(smContext *SMContext, precedence } ULFAR := ULPDR.FAR + // If the flow is disable, the tunnel and the session rules will not be created + ULFAR.ApplyAction = pfcpType.ApplyAction{ Buff: false, Drop: false, @@ -537,6 +553,7 @@ func (dataPath *DataPath) ActivateTunnelAndPDR(smContext *SMContext, precedence Forw: true, Nocp: false, } + ULFAR.ForwardingParameters = &ForwardingParameters{ DestinationInterface: pfcpType.DestinationInterface{ InterfaceValue: pfcpType.DestinationInterfaceCore, @@ -633,6 +650,7 @@ func (dataPath *DataPath) ActivateTunnelAndPDR(smContext *SMContext, precedence if nextDLDest := curDataPathNode.Prev(); nextDLDest != nil { logger.PduSessLog.Traceln("In DLPDR OuterHeaderCreation") nextDLTunnel := nextDLDest.DownLinkTunnel + // If the flow is disable, the tunnel and the session rules will not be created DLFAR.ApplyAction = pfcpType.ApplyAction{ Buff: false, @@ -712,6 +730,108 @@ func (p *DataPath) RemovePDR() { } } +func (p *DataPath) GetChargingUrr(smContext *SMContext) []*URR { + var chargingUrrs []*URR + var urrs []*URR + + for node := p.FirstDPNode; node != nil; node = node.Next() { + // Charging rules only apply to anchor UPF + // Note: ULPDR and DLPDR share the same URR but have different FAR + // See AddChargingRules() for more details + if node.IsAnchorUPF() { + if node.UpLinkTunnel != nil && node.UpLinkTunnel.PDR != nil { + urrs = node.UpLinkTunnel.PDR.URR + } else if node.DownLinkTunnel != nil && node.DownLinkTunnel.PDR != nil { + urrs = node.DownLinkTunnel.PDR.URR + } + + for _, urr := range urrs { + if smContext.ChargingInfo[urr.URRID] != nil { + chargingUrrs = append(chargingUrrs, urr) + } + } + } + } + + return chargingUrrs +} + +func (p *DataPath) AddChargingRules(smContext *SMContext, chgLevel ChargingLevel, chgData *models.ChargingData) { + if chgData == nil { + return + } + + for node := p.FirstDPNode; node != nil; node = node.Next() { + // Charging rules only apply to anchor UPF + if node.IsAnchorUPF() { + var urr *URR + chgInfo := &ChargingInfo{ + RatingGroup: chgData.RatingGroup, + ChargingLevel: chgLevel, + UpfId: node.UPF.UUID(), + } + + // urrId, err := node.UPF.urrIDGenerator.Allocate() + urrId, err := smContext.UrrIDGenerator.Allocate() + if err != nil { + logger.PduSessLog.Errorln("Generate URR Id failed") + return + } + + currentUUID := node.UPF.UUID() + id := getUrrIdKey(currentUUID, uint32(urrId)) + + if oldURR, ok := smContext.UrrUpfMap[id]; !ok { + // For online charging, the charging trigger "Start of the Service data flow" are needed. + // Therefore, the START reporting trigger in the urr are needed to detect the Start of the SDF + if chgData.Online { + if newURR, err := node.UPF.AddURR(uint32(urrId), + NewMeasureInformation(false, false), + SetStartOfSDFTrigger()); err != nil { + logger.PduSessLog.Errorln("new URR failed") + return + } else { + urr = newURR + } + + chgInfo.ChargingMethod = models.QuotaManagementIndicator_ONLINE_CHARGING + } else if chgData.Offline { + // For offline charging, URR only need to report based on the volume threshold + if newURR, err := node.UPF.AddURR(uint32(urrId), + NewMeasureInformation(false, false), + NewVolumeThreshold(smContext.UrrReportThreshold)); err != nil { + logger.PduSessLog.Errorln("new URR failed") + return + } else { + urr = newURR + } + + chgInfo.ChargingMethod = models.QuotaManagementIndicator_OFFLINE_CHARGING + } + smContext.UrrUpfMap[id] = urr + } else { + urr = oldURR + } + + if urr != nil { + logger.PduSessLog.Tracef("Successfully add URR %d for Rating group %d", urr.URRID, chgData.RatingGroup) + + smContext.ChargingInfo[urr.URRID] = chgInfo + if node.UpLinkTunnel != nil && node.UpLinkTunnel.PDR != nil { + if !isUrrExist(node.UpLinkTunnel.PDR.URR, urr) { + node.UpLinkTunnel.PDR.AppendURRs([]*URR{urr}) + } + } + if node.DownLinkTunnel != nil && node.DownLinkTunnel.PDR != nil { + if !isUrrExist(node.DownLinkTunnel.PDR.URR, urr) { + node.DownLinkTunnel.PDR.AppendURRs([]*URR{urr}) + } + } + } + } + } +} + func (p *DataPath) AddQoS(smContext *SMContext, qfi uint8, qos *models.QosData) { // QFI = 1 -> default QFI if qos == nil && qfi != 1 { diff --git a/internal/context/pcc_rule.go b/internal/context/pcc_rule.go index 12f33171..1afd5a31 100644 --- a/internal/context/pcc_rule.go +++ b/internal/context/pcc_rule.go @@ -41,6 +41,14 @@ func (r *PCCRule) FlowDescription() string { return "" } +func (r *PCCRule) RefChgDataID() string { + if len(r.RefChgData) > 0 { + // now 1 pcc rule only maps to 1 Charging data + return r.RefChgData[0] + } + return "" +} + func (r *PCCRule) RefQosDataID() string { if len(r.RefQosData) > 0 { // now 1 pcc rule only maps to 1 QoS data @@ -61,6 +69,22 @@ func (r *PCCRule) RefTcDataID() string { return "" } +func (r *PCCRule) IdentifyChargingLevel() (ChargingLevel, error) { + dlIPFilterRule, err := flowdesc.Decode(r.FlowDescription()) + if err != nil { + return 0, err + } + // For the PCC rule that are applicable for all datapath, + // it's charging level will be PDU-based + if dlIPFilterRule.Src == "any" && dlIPFilterRule.Dst == "assigned" { + return PduSessionCharging, nil + } else { + // For the PCC rule that is applicable for all datapath for a datapath, + // it's charging level will be flow-based + return FlowCharging, nil + } +} + func (r *PCCRule) UpdateDataPathFlowDescription(dlFlowDesc string) error { if r.Datapath == nil { return fmt.Errorf("pcc[%s]: no data path", r.PccRuleId) @@ -69,26 +93,10 @@ func (r *PCCRule) UpdateDataPathFlowDescription(dlFlowDesc string) error { if dlFlowDesc == "" { return fmt.Errorf("pcc[%s]: no flow description", r.PccRuleId) } - ulFlowDesc := getUplinkFlowDescription(dlFlowDesc) - if ulFlowDesc == "" { - return fmt.Errorf("pcc[%s]: uplink flow description parsing error", r.PccRuleId) - } - r.Datapath.UpdateFlowDescription(ulFlowDesc, dlFlowDesc) - return nil -} - -func getUplinkFlowDescription(dlFlowDesc string) string { - ulIPFilterRule, err := flowdesc.Decode(dlFlowDesc) - if err != nil { - return "" - } - ulIPFilterRule.SwapSrcAndDst() - ulFlowDesc, err := flowdesc.Encode(ulIPFilterRule) - if err != nil { - return "" - } - return ulFlowDesc + ulFlowDesc := dlFlowDesc + r.Datapath.UpdateFlowDescription(ulFlowDesc, dlFlowDesc) // UL, DL flow description should be same + return nil } func (r *PCCRule) AddDataPathForwardingParameters(c *SMContext, @@ -113,8 +121,12 @@ func (r *PCCRule) AddDataPathForwardingParameters(c *SMContext, return } } - r.Datapath.AddForwardingParameters(routeProf.ForwardingPolicyID, - c.Tunnel.DataPathPool.GetDefaultPath().FirstDPNode.GetUpLinkPDR().PDI.LocalFTeid.Teid) + if c.Tunnel.DataPathPool.GetDefaultPath() == nil { + logger.CtxLog.Infoln("No Default Data Path") + } else { + r.Datapath.AddForwardingParameters(routeProf.ForwardingPolicyID, + c.Tunnel.DataPathPool.GetDefaultPath().FirstDPNode.GetUpLinkPDR().PDI.LocalFTeid.Teid) + } } func (r *PCCRule) BuildNasQoSRule(smCtx *SMContext, @@ -195,7 +207,7 @@ func createNasPacketFilter( } } - if ipFilterRule.Dst != "any" { + if ipFilterRule.Dst != "assigned" { _, ipNet, err := net.ParseCIDR(ipFilterRule.Dst) if err != nil { return nil, fmt.Errorf("parse IP fail: %s", err) diff --git a/internal/context/pfcp_reports.go b/internal/context/pfcp_reports.go new file mode 100644 index 00000000..14bc737d --- /dev/null +++ b/internal/context/pfcp_reports.go @@ -0,0 +1,95 @@ +package context + +import ( + "github.com/free5gc/openapi/models" + "github.com/free5gc/pfcp" + "github.com/free5gc/pfcp/pfcpType" + "github.com/free5gc/smf/internal/logger" +) + +func (smContext *SMContext) HandleReports( + UsageReportRequest []*pfcp.UsageReportPFCPSessionReportRequest, + UsageReportModification []*pfcp.UsageReportPFCPSessionModificationResponse, + UsageReportDeletion []*pfcp.UsageReportPFCPSessionDeletionResponse, + nodeId pfcpType.NodeID, reportTpye models.TriggerType, +) { + var usageReport UsageReport + upf := RetrieveUPFNodeByNodeID(nodeId) + upfId := upf.UUID() + + for _, report := range UsageReportRequest { + usageReport.UrrId = report.URRID.UrrIdValue + usageReport.UpfId = upfId + usageReport.TotalVolume = report.VolumeMeasurement.TotalVolume + usageReport.UplinkVolume = report.VolumeMeasurement.UplinkVolume + usageReport.DownlinkVolume = report.VolumeMeasurement.DownlinkVolume + usageReport.TotalPktNum = report.VolumeMeasurement.TotalPktNum + usageReport.UplinkPktNum = report.VolumeMeasurement.UplinkPktNum + usageReport.DownlinkPktNum = report.VolumeMeasurement.DownlinkPktNum + usageReport.ReportTpye = identityTriggerType(report.UsageReportTrigger) + + if reportTpye != "" { + usageReport.ReportTpye = reportTpye + } + + smContext.UrrReports = append(smContext.UrrReports, usageReport) + } + for _, report := range UsageReportModification { + usageReport.UrrId = report.URRID.UrrIdValue + usageReport.UpfId = upfId + usageReport.TotalVolume = report.VolumeMeasurement.TotalVolume + usageReport.UplinkVolume = report.VolumeMeasurement.UplinkVolume + usageReport.DownlinkVolume = report.VolumeMeasurement.DownlinkVolume + usageReport.TotalPktNum = report.VolumeMeasurement.TotalPktNum + usageReport.UplinkPktNum = report.VolumeMeasurement.UplinkPktNum + usageReport.DownlinkPktNum = report.VolumeMeasurement.DownlinkPktNum + usageReport.ReportTpye = identityTriggerType(report.UsageReportTrigger) + + if reportTpye != "" { + usageReport.ReportTpye = reportTpye + } + + smContext.UrrReports = append(smContext.UrrReports, usageReport) + } + for _, report := range UsageReportDeletion { + usageReport.UrrId = report.URRID.UrrIdValue + usageReport.UpfId = upfId + usageReport.TotalVolume = report.VolumeMeasurement.TotalVolume + usageReport.UplinkVolume = report.VolumeMeasurement.UplinkVolume + usageReport.DownlinkVolume = report.VolumeMeasurement.DownlinkVolume + usageReport.TotalPktNum = report.VolumeMeasurement.TotalPktNum + usageReport.UplinkPktNum = report.VolumeMeasurement.UplinkPktNum + usageReport.DownlinkPktNum = report.VolumeMeasurement.DownlinkPktNum + usageReport.ReportTpye = identityTriggerType(report.UsageReportTrigger) + + if reportTpye != "" { + usageReport.ReportTpye = reportTpye + } + + smContext.UrrReports = append(smContext.UrrReports, usageReport) + } +} + +func identityTriggerType(usarTrigger *pfcpType.UsageReportTrigger) models.TriggerType { + var trigger models.TriggerType + + if usarTrigger.Volth { + trigger = models.TriggerType_QUOTA_THRESHOLD + } else if usarTrigger.Volqu { + trigger = models.TriggerType_QUOTA_EXHAUSTED + } else if usarTrigger.Quvti { + trigger = models.TriggerType_VALIDITY_TIME + } else if usarTrigger.Start { + trigger = models.TriggerType_START_OF_SERVICE_DATA_FLOW + } else if usarTrigger.Immer { + logger.PduSessLog.Trace("Reports Query by SMF, trigger should be filled later") + return "" + } else if usarTrigger.Termr { + trigger = models.TriggerType_FINAL + } else { + logger.PduSessLog.Trace("Report is not a charging trigger") + return "" + } + + return trigger +} diff --git a/internal/context/pfcp_rules.go b/internal/context/pfcp_rules.go index ca4ef3c0..6344ad27 100644 --- a/internal/context/pfcp_rules.go +++ b/internal/context/pfcp_rules.go @@ -11,6 +11,7 @@ const ( RULE_CREATE RuleState = 1 RULE_UPDATE RuleState = 2 RULE_REMOVE RuleState = 3 + RULE_QUERY RuleState = 4 ) type RuleState uint8 @@ -44,8 +45,10 @@ type URR struct { MeasureMethod string // vol or time ReportingTrigger pfcpType.ReportingTriggers MeasurementPeriod time.Duration + QuotaValidityTime time.Time MeasurementInformation pfcpType.MeasurementInformation VolumeThreshold uint64 + VolumeQuota uint64 State RuleState } @@ -60,16 +63,31 @@ func NewMeasureInformation(isMeasurePkt, isMeasureBeforeQos bool) UrrOpt { func NewMeasurementPeriod(time time.Duration) UrrOpt { return func(urr *URR) { + urr.ReportingTrigger.Perio = true urr.MeasurementPeriod = time } } func NewVolumeThreshold(threshold uint64) UrrOpt { return func(urr *URR) { + urr.ReportingTrigger.Volth = true urr.VolumeThreshold = threshold } } +func NewVolumeQuota(quota uint64) UrrOpt { + return func(urr *URR) { + urr.ReportingTrigger.Volqu = true + urr.VolumeQuota = quota + } +} + +func SetStartOfSDFTrigger() UrrOpt { + return func(urr *URR) { + urr.ReportingTrigger.Start = true + } +} + func MeasureInformation(isMeasurePkt, isMeasureBeforeQos bool) pfcpType.MeasurementInformation { var measureInformation pfcpType.MeasurementInformation measureInformation.Mnop = isMeasurePkt @@ -77,6 +95,23 @@ func MeasureInformation(isMeasurePkt, isMeasureBeforeQos bool) pfcpType.Measurem return measureInformation } +func (pdr *PDR) AppendURRs(urrs []*URR) { + for _, urr := range urrs { + if !isUrrExist(pdr.URR, urr) { + pdr.URR = append(pdr.URR, urr) + } + } +} + +func isUrrExist(URRs []*URR, urr *URR) bool { // check if urr is in URRs list + for _, URR := range URRs { + if urr.URRID == URR.URRID { + return true + } + } + return false +} + // Packet Detection. 7.5.2.2-2 type PDI struct { SourceInterface pfcpType.SourceInterface diff --git a/internal/context/sm_context.go b/internal/context/sm_context.go index 0215a504..30bbb061 100644 --- a/internal/context/sm_context.go +++ b/internal/context/sm_context.go @@ -19,6 +19,7 @@ import ( "github.com/free5gc/ngap/ngapType" "github.com/free5gc/openapi" "github.com/free5gc/openapi/Namf_Communication" + "github.com/free5gc/openapi/Nchf_ConvergedCharging" "github.com/free5gc/openapi/Nnrf_NFDiscovery" "github.com/free5gc/openapi/Npcf_SMPolicyControl" "github.com/free5gc/openapi/models" @@ -44,18 +45,19 @@ const ( type UrrType int +// Reserved URR report for ID = 0 ~ 6 const ( - N3N6_MBEQ_URR UrrType = iota - N3N6_MAEQ_URR - N3N9_MBEQ_URR - N3N9_MAEQ_URR - N9N6_MBEQ_URR - N9N6_MAEQ_URR + N3N6_MBQE_URR UrrType = iota + N3N6_MAQE_URR + N3N9_MBQE_URR + N3N9_MAQE_URR + N9N6_MBQE_URR + N9N6_MAQE_URR NOT_FOUND_URR ) func (t UrrType) String() string { - urrTypeList := []string{"N3N6_MBEQ", "N3N6_MAEQ", "N3N9_MBEQ", "N3N9_MAEQ", "N9N6_MBEQ", "N9N6_MAEQ"} + urrTypeList := []string{"N3N6_MBQE", "N3N6_MAQE", "N3N9_MBQE", "N3N9_MAQE", "N9N6_MBQE", "N9N6_MAQE"} return urrTypeList[t] } @@ -99,6 +101,7 @@ type EventExposureNotification struct { type UsageReport struct { UrrId uint32 + UpfId string TotalVolume uint64 UplinkVolume uint64 @@ -153,9 +156,11 @@ type SMContext struct { // Client SMPolicyClient *Npcf_SMPolicyControl.APIClient CommunicationClient *Namf_Communication.APIClient + ChargingClient *Nchf_ConvergedCharging.APIClient AMFProfile models.NfProfile SelectedPCFProfile models.NfProfile + SelectedCHFProfile models.NfProfile SmStatusNotifyUri string Tunnel *UPTunnel @@ -171,6 +176,7 @@ type SMContext struct { PCCRules map[string]*PCCRule SessionRules map[string]*SessionRule TrafficControlDatas map[string]*TrafficControlData + ChargingData map[string]*models.ChargingData QosDatas map[string]*models.QosData UpPathChgEarlyNotification map[string]*EventExposureNotification // Key: Uri+NotifId @@ -196,8 +202,21 @@ type SMContext struct { UrrUpfMap map[string]*URR UrrReportTime time.Duration UrrReportThreshold uint64 - UrrReports []UsageReport - + // Cache the usage reports, sent from UPF + // Those information will be included in CDR. + UrrReports []UsageReport + + // Charging Related + ChargingDataRef string + // Each PDU session has a unique charging id + ChargingID int32 + RequestedUnit int32 + // key = urrid + // All urr can map to a rating group + // However, a rating group may map to more than one urr + // e.g. In UL CL case, the rating group for recoreding PDU Session volume may map to two URR + // one is for PSA 1, the other is for PSA 2. + ChargingInfo map[uint32]*ChargingInfo // NAS Pti uint8 EstAcceptCause5gSMValue uint8 @@ -282,11 +301,19 @@ func NewSMContext(id string, pduSessID int32) *SMContext { smContext.GenerateUrrId() smContext.UrrUpfMap = make(map[string]*URR) + smContext.ChargingInfo = make(map[uint32]*ChargingInfo) + smContext.ChargingID = GenerateChargingID() + if factory.SmfConfig.Configuration != nil { smContext.UrrReportTime = time.Duration(factory.SmfConfig.Configuration.UrrPeriod) * time.Second smContext.UrrReportThreshold = factory.SmfConfig.Configuration.UrrThreshold logger.CtxLog.Infof("UrrPeriod: %v", smContext.UrrReportTime) logger.CtxLog.Infof("UrrThreshold: %d", smContext.UrrReportThreshold) + if factory.SmfConfig.Configuration.RequestedUnit != 0 { + smContext.RequestedUnit = factory.SmfConfig.Configuration.RequestedUnit + } else { + smContext.RequestedUnit = 1000 + } } return smContext @@ -350,22 +377,22 @@ func GetSMContextBySEID(SEID uint64) *SMContext { func (smContext *SMContext) GenerateUrrId() { if id, err := smContext.UrrIDGenerator.Allocate(); err == nil { - smContext.UrrIdMap[N3N6_MBEQ_URR] = uint32(id) + smContext.UrrIdMap[N3N6_MBQE_URR] = uint32(id) } if id, err := smContext.UrrIDGenerator.Allocate(); err == nil { - smContext.UrrIdMap[N3N6_MAEQ_URR] = uint32(id) + smContext.UrrIdMap[N3N6_MAQE_URR] = uint32(id) } if id, err := smContext.UrrIDGenerator.Allocate(); err == nil { - smContext.UrrIdMap[N9N6_MBEQ_URR] = uint32(id) + smContext.UrrIdMap[N9N6_MBQE_URR] = uint32(id) } if id, err := smContext.UrrIDGenerator.Allocate(); err == nil { - smContext.UrrIdMap[N9N6_MAEQ_URR] = uint32(id) + smContext.UrrIdMap[N9N6_MAQE_URR] = uint32(id) } if id, err := smContext.UrrIDGenerator.Allocate(); err == nil { - smContext.UrrIdMap[N3N9_MBEQ_URR] = uint32(id) + smContext.UrrIdMap[N3N9_MBQE_URR] = uint32(id) } if id, err := smContext.UrrIDGenerator.Allocate(); err == nil { - smContext.UrrIdMap[N3N9_MAEQ_URR] = uint32(id) + smContext.UrrIdMap[N3N9_MAQE_URR] = uint32(id) } } @@ -409,6 +436,57 @@ func (smContext *SMContext) PDUAddressToNAS() ([12]byte, uint8) { return addr, addrLen } +// CHFSelection will select CHF for this SM Context +func (smContext *SMContext) CHFSelection() error { + // Send NFDiscovery for find CHF + localVarOptionals := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{ + // Supi: optional.NewString(smContext.Supi), + } + + ctx, _, err := smfContext.GetTokenCtx(models.ServiceName_NNRF_DISC, models.NfType_NRF) + if err != nil { + return err + } + + rsp, res, err := GetSelf(). + NFDiscoveryClient. + NFInstancesStoreApi. + SearchNFInstances(ctx, models.NfType_CHF, models.NfType_SMF, &localVarOptionals) + if err != nil { + return err + } + defer func() { + if rspCloseErr := res.Body.Close(); rspCloseErr != nil { + logger.PduSessLog.Errorf("SmfEventExposureNotification response body cannot close: %+v", rspCloseErr) + } + }() + + if res != nil { + if status := res.StatusCode; status != http.StatusOK { + apiError := err.(openapi.GenericOpenAPIError) + problemDetails := apiError.Model().(models.ProblemDetails) + + logger.CtxLog.Warningf("NFDiscovery SMF return status: %d\n", status) + logger.CtxLog.Warningf("Detail: %v\n", problemDetails.Title) + } + } + + // Select CHF from available CHF + + smContext.SelectedCHFProfile = rsp.NfInstances[0] + + // Create Converged Charging Client for this SM Context + for _, service := range *smContext.SelectedCHFProfile.NfServices { + if service.ServiceName == models.ServiceName_NCHF_CONVERGEDCHARGING { + ConvergedChargingConf := Nchf_ConvergedCharging.NewConfiguration() + ConvergedChargingConf.SetBasePath(service.ApiPrefix) + smContext.ChargingClient = Nchf_ConvergedCharging.NewAPIClient(ConvergedChargingConf) + } + } + + return nil +} + // PCFSelection will select PCF for this SM Context func (smContext *SMContext) PCFSelection() error { ctx, _, err := GetSelf().GetTokenCtx(models.ServiceName_NNRF_DISC, "NRF") @@ -422,7 +500,7 @@ func (smContext *SMContext) PCFSelection() error { localVarOptionals.PreferredLocality = optional.NewString(GetSelf().Locality) } - rep, res, err := GetSelf(). + rsp, res, err := GetSelf(). NFDiscoveryClient. NFInstancesStoreApi. SearchNFInstances(ctx, models.NfType_PCF, models.NfType_SMF, &localVarOptionals) @@ -447,7 +525,7 @@ func (smContext *SMContext) PCFSelection() error { // Select PCF from available PCF - smContext.SelectedPCFProfile = rep.NfInstances[0] + smContext.SelectedPCFProfile = rsp.NfInstances[0] // Create SMPolicyControl Client for this SM Context for _, service := range *smContext.SelectedPCFProfile.NfServices { @@ -565,6 +643,7 @@ func (c *SMContext) AllocUeIP() error { return nil } +// This function create a data path to be default data path. func (c *SMContext) SelectDefaultDataPath() error { if c.SelectionParam == nil || c.SelectedUPF == nil { return fmt.Errorf("SelectDefaultDataPath err: SelectionParam or SelectedUPF is nil") @@ -577,10 +656,10 @@ func (c *SMContext) SelectDefaultDataPath() error { c.Tunnel.DataPathPool = uePreConfigPaths.DataPathPool c.Tunnel.PathIDGenerator = uePreConfigPaths.PathIDGenerator defaultPath = c.Tunnel.DataPathPool.GetDefaultPath() - } else { - // UE has no pre-config path. + } else if c.Tunnel.DataPathPool.GetDefaultPath() == nil { + // UE has no pre-config path and default path // Use default route - c.Log.Infof("Has no pre-config route") + c.Log.Infof("Has no pre-config route. Has no default path") defaultUPPath := GetUserPlaneInformation().GetDefaultUserPlanePathByDNNAndUPF( c.SelectionParam, c.SelectedUPF) defaultPath = GenerateDataPath(defaultUPPath) @@ -588,18 +667,26 @@ func (c *SMContext) SelectDefaultDataPath() error { defaultPath.IsDefaultPath = true c.Tunnel.AddDataPath(defaultPath) } + } else { + c.Log.Infof("Has no pre-config route. Has default path") + defaultPath = c.Tunnel.DataPathPool.GetDefaultPath() } if defaultPath == nil { - return fmt.Errorf("Data Path not found, Selection Parameter: %s", + return fmt.Errorf("data path not found, Selection Parameter: %s", c.SelectionParam.String()) } - defaultPath.ActivateTunnelAndPDR(c, DefaultPrecedence) + + if !defaultPath.Activated { + defaultPath.ActivateTunnelAndPDR(c, DefaultPrecedence) + } + return nil } func (c *SMContext) CreatePccRuleDataPath(pccRule *PCCRule, tcData *TrafficControlData, qosData *models.QosData, + chgData *models.ChargingData, ) error { var targetRoute models.RouteToLocation if tcData != nil && len(tcData.RouteToLocs) > 0 { @@ -618,11 +705,25 @@ func (c *SMContext) CreatePccRuleDataPath(pccRule *PCCRule, if createdDataPath == nil { return fmt.Errorf("fail to create data path for pcc rule[%s]", pccRule.PccRuleId) } + + // Try to use a default pcc rule as default data path + if c.Tunnel.DataPathPool.GetDefaultPath() == nil && + pccRule.Precedence == 255 { + createdDataPath.IsDefaultPath = true + } + createdDataPath.GBRFlow = isGBRFlow(qosData) createdDataPath.ActivateTunnelAndPDR(c, uint32(pccRule.Precedence)) c.Tunnel.AddDataPath(createdDataPath) pccRule.Datapath = createdDataPath pccRule.AddDataPathForwardingParameters(c, &targetRoute) + + if chgLevel, err := pccRule.IdentifyChargingLevel(); err != nil { + c.Log.Warnf("fail to identify charging level[%+v] for pcc rule[%s]", err, pccRule.PccRuleId) + } else { + pccRule.Datapath.AddChargingRules(c, chgLevel, chgData) + } + pccRule.Datapath.AddQoS(c, pccRule.QFI, qosData) c.AddQosFlow(pccRule.QFI, qosData) return nil @@ -810,15 +911,6 @@ func (smContext *SMContext) IsAllowedPDUSessionType(requestedPDUSessionType uint return nil } -func (smContext *SMContext) GetUrrTypeById(urrId uint32) (UrrType, error) { - for urrType, id := range smContext.UrrIdMap { - if id == urrId { - return urrType, nil - } - } - return NOT_FOUND_URR, fmt.Errorf("Urr type not found ") -} - func (smContext *SMContext) StopT3591() { if smContext.T3591 != nil { smContext.T3591.Stop() diff --git a/internal/context/sm_context_policy.go b/internal/context/sm_context_policy.go index 4df99329..8361ee68 100644 --- a/internal/context/sm_context_policy.go +++ b/internal/context/sm_context_policy.go @@ -5,6 +5,7 @@ import ( "reflect" "github.com/free5gc/openapi/models" + "github.com/free5gc/smf/internal/logger" "github.com/free5gc/smf/pkg/factory" ) @@ -68,6 +69,57 @@ func (c *SMContext) RemoveQosFlow(qfi uint8) { delete(c.AdditonalQosFlows, qfi) } +// For urr that created for Pdu session level charging, it shall be applied to all data path +func (c *SMContext) addPduLevelChargingRuleToFlow(pccRules map[string]*PCCRule) { + var pduLevelChargingUrrs []*URR + + // First, select charging URRs from pcc rule, which charging level is PDU Session level + for id, pcc := range pccRules { + if chargingLevel, err := pcc.IdentifyChargingLevel(); err != nil { + continue + } else if chargingLevel == PduSessionCharging { + pduPcc := pccRules[id] + pduLevelChargingUrrs = pduPcc.Datapath.GetChargingUrr(c) + break + } + } + + for _, flowPcc := range pccRules { + if chgLevel, err := flowPcc.IdentifyChargingLevel(); err != nil { + continue + } else if chgLevel == FlowCharging { + for node := flowPcc.Datapath.FirstDPNode; node != nil; node = node.Next() { + if node.IsAnchorUPF() { + // only the traffic on the PSA UPF will be charged + if node.UpLinkTunnel != nil && node.UpLinkTunnel.PDR != nil { + node.UpLinkTunnel.PDR.AppendURRs(pduLevelChargingUrrs) + } + if node.DownLinkTunnel != nil && node.DownLinkTunnel.PDR != nil { + node.DownLinkTunnel.PDR.AppendURRs(pduLevelChargingUrrs) + } + } + } + } + } + + defaultPath := c.Tunnel.DataPathPool.GetDefaultPath() + if defaultPath == nil { + logger.CtxLog.Errorln("No default data path") + return + } + + for node := defaultPath.FirstDPNode; node != nil; node = node.Next() { + if node.IsAnchorUPF() { + if node.UpLinkTunnel != nil && node.UpLinkTunnel.PDR != nil { + node.UpLinkTunnel.PDR.AppendURRs(pduLevelChargingUrrs) + } + if node.DownLinkTunnel != nil && node.DownLinkTunnel.PDR != nil { + node.DownLinkTunnel.PDR.AppendURRs(pduLevelChargingUrrs) + } + } + } +} + func (c *SMContext) ApplyPccRules( decision *models.SmPolicyDecision, ) error { @@ -78,7 +130,7 @@ func (c *SMContext) ApplyPccRules( finalPccRules := make(map[string]*PCCRule) finalTcDatas := make(map[string]*TrafficControlData) finalQosDatas := make(map[string]*models.QosData) - + finalChgDatas := make(map[string]*models.ChargingData) // Handle QoSData for id, qos := range decision.QosDecs { if qos == nil { @@ -106,12 +158,15 @@ func (c *SMContext) ApplyPccRules( tgtTcID := tgtPcc.RefTcDataID() _, tgtTcData = c.getSrcTgtTcData(decision.TraffContDecs, tgtTcID) + tgtChgID := tgtPcc.RefChgDataID() + _, tgtChgData := c.getSrcTgtChgData(decision.ChgDecs, tgtChgID) + tgtQosID := tgtPcc.RefQosDataID() _, tgtQosData := c.getSrcTgtQosData(decision.QosDecs, tgtQosID) tgtPcc.SetQFI(c.AssignQFI(tgtQosID)) // Create Data path for targetPccRule - if err := c.CreatePccRuleDataPath(tgtPcc, tgtTcData, tgtQosData); err != nil { + if err := c.CreatePccRuleDataPath(tgtPcc, tgtTcData, tgtQosData, tgtChgData); err != nil { return err } if srcPcc != nil { @@ -133,7 +188,7 @@ func (c *SMContext) ApplyPccRules( finalQosDatas[tgtQosID] = tgtQosData } } - if err := checkUpPathChgEvent(c, srcTcData, tgtTcData); err != nil { + if err := checkUpPathChangeEvt(c, srcTcData, tgtTcData); err != nil { c.Log.Warnf("Check UpPathChgEvent err: %v", err) } // Remove handled pcc rule @@ -145,18 +200,22 @@ func (c *SMContext) ApplyPccRules( tcID := pcc.RefTcDataID() srcTcData, tgtTcData := c.getSrcTgtTcData(decision.TraffContDecs, tcID) + chgID := pcc.RefChgDataID() + srcChgData, tgtChgData := c.getSrcTgtChgData(decision.ChgDecs, chgID) + qosID := pcc.RefQosDataID() srcQosData, tgtQosData := c.getSrcTgtQosData(decision.QosDecs, qosID) if !reflect.DeepEqual(srcTcData, tgtTcData) || - !reflect.DeepEqual(srcQosData, tgtQosData) { + !reflect.DeepEqual(srcQosData, tgtQosData) || + !reflect.DeepEqual(srcChgData, tgtChgData) { // Remove old Data path c.PreRemoveDataPath(pcc.Datapath) // Create new Data path - if err := c.CreatePccRuleDataPath(pcc, tgtTcData, tgtQosData); err != nil { + if err := c.CreatePccRuleDataPath(pcc, tgtTcData, tgtQosData, tgtChgData); err != nil { return err } - if err := checkUpPathChgEvent(c, srcTcData, tgtTcData); err != nil { + if err := checkUpPathChangeEvt(c, srcTcData, tgtTcData); err != nil { c.Log.Warnf("Check UpPathChgEvent err: %v", err) } } @@ -167,11 +226,18 @@ func (c *SMContext) ApplyPccRules( if qosID != "" { finalQosDatas[qosID] = tgtQosData } + if chgID != "" { + finalChgDatas[chgID] = tgtChgData + } } + // For PCC rule that is for Pdu session level charging, add the created session rules to all other flow + // so that all volume in the Pdu session could be recorded and charged for the Pdu session + c.addPduLevelChargingRuleToFlow(finalPccRules) c.PCCRules = finalPccRules c.TrafficControlDatas = finalTcDatas c.QosDatas = finalQosDatas + c.ChargingData = finalChgDatas return nil } @@ -192,6 +258,23 @@ func (c *SMContext) getSrcTgtTcData( return srcTcData, tgtTcData } +func (c *SMContext) getSrcTgtChgData( + decisionChgDecs map[string]*models.ChargingData, + chgID string, +) (*models.ChargingData, *models.ChargingData) { + if chgID == "" { + return nil, nil + } + + srcChgData := c.ChargingData[chgID] + tgtChgData := decisionChgDecs[chgID] + if tgtChgData == nil { + // no TcData in decision, use source TcData as target TcData + tgtChgData = srcChgData + } + return srcChgData, tgtChgData +} + func (c *SMContext) getSrcTgtQosData( decisionQosDecs map[string]*models.QosData, qosID string, @@ -266,7 +349,7 @@ func applyFlowInfoOrPFD(pcc *PCCRule) error { return nil } -func checkUpPathChgEvent(c *SMContext, +func checkUpPathChangeEvt(c *SMContext, srcTcData, tgtTcData *TrafficControlData, ) error { var srcRoute, tgtRoute models.RouteToLocation diff --git a/internal/context/sm_context_policy_test.go b/internal/context/sm_context_policy_test.go index a04030d3..a43d3f64 100644 --- a/internal/context/sm_context_policy_test.go +++ b/internal/context/sm_context_policy_test.go @@ -98,11 +98,18 @@ var testConfig = factory.Config{ Description: "SMF procdeure test configuration", }, Configuration: &factory.Configuration{ + Sbi: &factory.Sbi{ + Scheme: "http", + RegisterIPv4: "127.0.0.1", + BindingIPv4: "127.0.0.1", + Port: 8000, + }, UserPlaneInformation: userPlaneConfig, }, } func initConfig() { + InitSmfContext(&testConfig) factory.SmfConfig = &testConfig } diff --git a/internal/context/upf.go b/internal/context/upf.go index 8b11f475..ead327ac 100644 --- a/internal/context/upf.go +++ b/internal/context/upf.go @@ -109,6 +109,14 @@ type UPFInterfaceInfo struct { EndpointFQDN string } +func GetUpfById(uuid string) *UPF { + upf, ok := upfPool.Load(uuid) + if ok { + return upf.(*UPF) + } + return nil +} + // NewUPFInterfaceInfo parse the InterfaceUpfInfoItem to generate UPFInterfaceInfo func NewUPFInterfaceInfo(i *factory.InterfaceUpfInfoItem) *UPFInterfaceInfo { interfaceInfo := new(UPFInterfaceInfo) @@ -542,8 +550,6 @@ func (upf *UPF) AddURR(urrId uint32, opts ...UrrOpt) (*URR, error) { urr := new(URR) urr.MeasureMethod = MesureMethodVol urr.MeasurementInformation = MeasureInformation(true, false) - urr.ReportingTrigger.Perio = true - urr.ReportingTrigger.Volth = true for _, opt := range opts { opt(urr) diff --git a/internal/context/user_plane_information.go b/internal/context/user_plane_information.go index 0a2e7772..b76c3296 100644 --- a/internal/context/user_plane_information.go +++ b/internal/context/user_plane_information.go @@ -761,7 +761,7 @@ func getPathBetween(cur *UPNode, dest *UPNode, visited map[*UPNode]bool, path = make([]*UPNode, 0) path = append(path, cur) pathExist = true - return + return path, pathExist } selectedSNssai := selection.SNssai @@ -773,16 +773,14 @@ func getPathBetween(cur *UPNode, dest *UPNode, visited map[*UPNode]bool, continue } - path_tail, path_exist := getPathBetween(node, dest, visited, selection) + path_tail, pathExist := getPathBetween(node, dest, visited, selection) - if path_exist { + if pathExist { path = make([]*UPNode, 0) path = append(path, cur) - path = append(path, path_tail...) - pathExist = true - return + return path, pathExist } } } diff --git a/internal/logger/logger.go b/internal/logger/logger.go index 2acaf1e8..7e1fce33 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -23,6 +23,7 @@ var ( GsmLog *logrus.Entry PfcpLog *logrus.Entry PduSessLog *logrus.Entry + ChargingLog *logrus.Entry UtilLog *logrus.Entry ) @@ -43,5 +44,6 @@ func init() { GsmLog = NfLog.WithField(logger_util.FieldCategory, "GSM") PfcpLog = NfLog.WithField(logger_util.FieldCategory, "PFCP") PduSessLog = NfLog.WithField(logger_util.FieldCategory, "PduSess") + ChargingLog = NfLog.WithField(logger_util.FieldCategory, "Charging") UtilLog = NfLog.WithField(logger_util.FieldCategory, "Util") } diff --git a/internal/pfcp/handler/handler.go b/internal/pfcp/handler/handler.go index 109a1208..47418290 100644 --- a/internal/pfcp/handler/handler.go +++ b/internal/pfcp/handler/handler.go @@ -10,6 +10,7 @@ import ( smf_context "github.com/free5gc/smf/internal/context" "github.com/free5gc/smf/internal/logger" pfcp_message "github.com/free5gc/smf/internal/pfcp/message" + "github.com/free5gc/smf/internal/sbi/producer" ) func HandlePfcpHeartbeatRequest(msg *pfcpUdp.Message) { @@ -195,54 +196,14 @@ func HandlePfcpSessionReportRequest(msg *pfcpUdp.Message) { } if req.ReportType.Usar && req.UsageReport != nil { - HandleReports(req.UsageReport, nil, nil, smContext, upfNodeID) + smContext.HandleReports(req.UsageReport, nil, nil, upfNodeID, "") + // After receiving the Usage Report, it should send charging request to the CHF + // and update the URR with the quota or other charging information according to + // the charging response + producer.ReportUsageAndUpdateQuota(smContext) } // TS 23.502 4.2.3.3 2b. Send Data Notification Ack, SMF->UPF cause.CauseValue = pfcpType.CauseRequestAccepted pfcp_message.SendPfcpSessionReportResponse(msg.RemoteAddr, cause, seqFromUPF, remoteSEID) } - -func HandleReports( - UsageReportReport []*pfcp.UsageReportPFCPSessionReportRequest, - UsageReportModification []*pfcp.UsageReportPFCPSessionModificationResponse, - UsageReportDeletion []*pfcp.UsageReportPFCPSessionDeletionResponse, - smContext *smf_context.SMContext, - nodeId pfcpType.NodeID, -) { - var usageReport smf_context.UsageReport - - for _, report := range UsageReportReport { - usageReport.UrrId = report.URRID.UrrIdValue - usageReport.TotalVolume = report.VolumeMeasurement.TotalVolume - usageReport.UplinkVolume = report.VolumeMeasurement.UplinkVolume - usageReport.DownlinkVolume = report.VolumeMeasurement.DownlinkVolume - usageReport.TotalPktNum = report.VolumeMeasurement.TotalPktNum - usageReport.UplinkPktNum = report.VolumeMeasurement.UplinkPktNum - usageReport.DownlinkPktNum = report.VolumeMeasurement.DownlinkPktNum - - smContext.UrrReports = append(smContext.UrrReports, usageReport) - } - for _, report := range UsageReportModification { - usageReport.UrrId = report.URRID.UrrIdValue - usageReport.TotalVolume = report.VolumeMeasurement.TotalVolume - usageReport.UplinkVolume = report.VolumeMeasurement.UplinkVolume - usageReport.DownlinkVolume = report.VolumeMeasurement.DownlinkVolume - usageReport.TotalPktNum = report.VolumeMeasurement.TotalPktNum - usageReport.UplinkPktNum = report.VolumeMeasurement.UplinkPktNum - usageReport.DownlinkPktNum = report.VolumeMeasurement.DownlinkPktNum - - smContext.UrrReports = append(smContext.UrrReports, usageReport) - } - for _, report := range UsageReportDeletion { - usageReport.UrrId = report.URRID.UrrIdValue - usageReport.TotalVolume = report.VolumeMeasurement.TotalVolume - usageReport.UplinkVolume = report.VolumeMeasurement.UplinkVolume - usageReport.DownlinkVolume = report.VolumeMeasurement.DownlinkVolume - usageReport.TotalPktNum = report.VolumeMeasurement.TotalPktNum - usageReport.UplinkPktNum = report.VolumeMeasurement.UplinkPktNum - usageReport.DownlinkPktNum = report.VolumeMeasurement.DownlinkPktNum - - smContext.UrrReports = append(smContext.UrrReports, usageReport) - } -} diff --git a/internal/pfcp/message/build.go b/internal/pfcp/message/build.go index 73313ce6..8ddbbb78 100644 --- a/internal/pfcp/message/build.go +++ b/internal/pfcp/message/build.go @@ -200,6 +200,13 @@ func urrToCreateURR(urr *context.URR) *pfcp.CreateURR { MeasurementPeriod: uint32(urr.MeasurementPeriod / time.Second), } } + if !urr.QuotaValidityTime.IsZero() { + createURR.QuotaValidityTime = &pfcpType.QuotaValidityTime{ + QuotaValidityTime: uint32(urr.QuotaValidityTime.Sub( + time.Date(1900, time.January, 1, 0, 0, 0, 0, time.UTC)) / 1000000000), + } + } + if urr.VolumeThreshold != 0 { createURR.VolumeThreshold = &pfcpType.VolumeThreshold{ Dlvol: true, @@ -208,6 +215,17 @@ func urrToCreateURR(urr *context.URR) *pfcp.CreateURR { UplinkVolume: urr.VolumeThreshold, } } + if urr.VolumeQuota != 0 { + createURR.VolumeQuota = &pfcpType.VolumeQuota{ + Tovol: true, + Dlvol: true, + Ulvol: true, + TotalVolume: urr.VolumeQuota, + DownlinkVolume: urr.VolumeQuota, + UplinkVolume: urr.VolumeQuota, + } + } + createURR.MeasurementInformation = &urr.MeasurementInformation return createURR @@ -249,6 +267,14 @@ func pdrToUpdatePDR(pdr *context.PDR) *pfcp.UpdatePDR { FarIdValue: pdr.FAR.FARID, } + for _, urr := range pdr.URR { + if urr != nil { + updatePDR.URRID = append(updatePDR.URRID, &pfcpType.URRID{ + UrrIdValue: urr.URRID, + }) + } + } + return updatePDR } @@ -290,6 +316,57 @@ func farToUpdateFAR(far *context.FAR) *pfcp.UpdateFAR { return updateFAR } +func urrToUpdateURR(urr *context.URR) *pfcp.UpdateURR { + updateURR := new(pfcp.UpdateURR) + + updateURR.URRID = &pfcpType.URRID{ + UrrIdValue: urr.URRID, + } + updateURR.MeasurementMethod = &pfcpType.MeasurementMethod{} + switch urr.MeasureMethod { + case context.MesureMethodVol: + updateURR.MeasurementMethod.Volum = true + case context.MesureMethodTime: + updateURR.MeasurementMethod.Durat = true + } + updateURR.ReportingTriggers = &urr.ReportingTrigger + if urr.MeasurementPeriod != 0 { + updateURR.MeasurementPeriod = &pfcpType.MeasurementPeriod{ + MeasurementPeriod: uint32(urr.MeasurementPeriod / time.Second), + } + } + if urr.QuotaValidityTime.IsZero() { + updateURR.QuotaValidityTime = &pfcpType.QuotaValidityTime{ + QuotaValidityTime: uint32(urr.QuotaValidityTime.Sub( + time.Date(1900, time.January, 1, 0, 0, 0, 0, time.UTC)) / 1000000000), + } + } + + if urr.VolumeThreshold != 0 { + updateURR.VolumeThreshold = &pfcpType.VolumeThreshold{ + Dlvol: true, + Ulvol: true, + Tovol: true, + TotalVolume: urr.VolumeThreshold, + DownlinkVolume: urr.VolumeThreshold, + UplinkVolume: urr.VolumeThreshold, + } + } + if urr.VolumeQuota != 0 { + updateURR.VolumeQuota = &pfcpType.VolumeQuota{ + Tovol: true, + Dlvol: true, + Ulvol: true, + TotalVolume: urr.VolumeQuota, + DownlinkVolume: urr.VolumeQuota, + UplinkVolume: urr.VolumeQuota, + } + } + updateURR.MeasurementInformation = &urr.MeasurementInformation + + return updateURR +} + func BuildPfcpSessionEstablishmentRequest( upNodeID pfcpType.NodeID, upN4Addr string, @@ -427,6 +504,7 @@ func BuildPfcpSessionModificationRequest( msg.UpdatePDR = make([]*pfcp.UpdatePDR, 0, 2) msg.UpdateFAR = make([]*pfcp.UpdateFAR, 0, 2) + msg.UpdateURR = make([]*pfcp.UpdateURR, 0, 12) nodeIDtoIP := upNodeID.ResolveNodeIdToIp().String() @@ -490,6 +568,20 @@ func BuildPfcpSessionModificationRequest( switch urr.State { case context.RULE_INITIAL: msg.CreateURR = append(msg.CreateURR, urrToCreateURR(urr)) + case context.RULE_UPDATE: + msg.UpdateURR = append(msg.UpdateURR, urrToUpdateURR(urr)) + case context.RULE_REMOVE: + msg.RemoveURR = append(msg.RemoveURR, &pfcp.RemoveURR{ + URRID: &pfcpType.URRID{ + UrrIdValue: urr.URRID, + }, + }) + case context.RULE_QUERY: + msg.QueryURR = append(msg.QueryURR, &pfcp.QueryURR{ + URRID: &pfcpType.URRID{ + UrrIdValue: urr.URRID, + }, + }) } urr.State = context.RULE_CREATE } diff --git a/internal/pfcp/message/send.go b/internal/pfcp/message/send.go index c891cf35..c92a5fad 100644 --- a/internal/pfcp/message/send.go +++ b/internal/pfcp/message/send.go @@ -78,7 +78,7 @@ func SendPfcpAssociationReleaseRequest(upNodeID pfcpType.NodeID) (resMsg *pfcpUd pfcpMsg, err := BuildPfcpAssociationReleaseRequest() if err != nil { logger.PfcpLog.Errorf("Build PFCP Association Release Request failed: %v", err) - return + return nil, err } message := &pfcp.Message{ @@ -148,7 +148,7 @@ func SendPfcpSessionEstablishmentRequest( ctx, pdrList, farList, barList, qerList, urrList) if err != nil { logger.PfcpLog.Errorf("Build PFCP Session Establishment Request failed: %v", err) - return + return nil, err } message := &pfcp.Message{ @@ -231,7 +231,7 @@ func SendPfcpSessionModificationRequest( ctx, pdrList, farList, barList, qerList, urrList) if err != nil { logger.PfcpLog.Errorf("Build PFCP Session Modification Request failed: %v", err) - return + return nil, err } seqNum := getSeqNumber() @@ -305,7 +305,7 @@ func SendPfcpSessionDeletionRequest(upf *context.UPF, ctx *context.SMContext) (r pfcpMsg, err := BuildPfcpSessionDeletionRequest() if err != nil { logger.PfcpLog.Errorf("Build PFCP Session Deletion Request failed: %v", err) - return + return nil, err } seqNum := getSeqNumber() remoteSEID := ctx.PFCPContext[nodeIDtoIP.String()].RemoteSEID diff --git a/internal/sbi/callback/api_default.go b/internal/sbi/callback/api_default.go index 3fea413f..4e168e6e 100644 --- a/internal/sbi/callback/api_default.go +++ b/internal/sbi/callback/api_default.go @@ -11,6 +11,7 @@ package callback import ( "net/http" + "strings" "github.com/gin-gonic/gin" @@ -60,3 +61,38 @@ func HTTPSmPolicyUpdateNotification(c *gin.Context) { func SmPolicyControlTerminationRequestNotification(c *gin.Context) { c.JSON(http.StatusOK, gin.H{}) } + +func HTTPChargingNotification(c *gin.Context) { + var req models.ChargingNotifyRequest + + requestBody, err := c.GetRawData() + if err != nil { + logger.PduSessLog.Errorln("GetRawData failed") + } + + err = openapi.Deserialize(&req, requestBody, "application/json") + if err != nil { + logger.PduSessLog.Errorln("Deserialize request failed") + } + + reqWrapper := httpwrapper.NewRequest(c.Request, req) + reqWrapper.Params["notifyUri"] = c.Params.ByName("notifyUri") + smContextRef := strings.Split(reqWrapper.Params["notifyUri"], "_")[1] + + HTTPResponse := producer.HandleChargingNotification(reqWrapper.Body.(models.ChargingNotifyRequest), smContextRef) + + for key, val := range HTTPResponse.Header { + c.Header(key, val[0]) + } + + resBody, err := openapi.Serialize(HTTPResponse.Body, "application/json") + if err != nil { + logger.PduSessLog.Errorln("Serialize failed") + } + + _, err = c.Writer.Write(resBody) + if err != nil { + logger.PduSessLog.Errorln("Write failed") + } + c.Status(HTTPResponse.Status) +} diff --git a/internal/sbi/callback/routers.go b/internal/sbi/callback/routers.go index 745391f2..4d318d32 100644 --- a/internal/sbi/callback/routers.go +++ b/internal/sbi/callback/routers.go @@ -70,4 +70,10 @@ var routes = Routes{ "/sm-policies/:smContextRef/terminate", SmPolicyControlTerminationRequestNotification, }, + { + "ChargingNotification", + "POST", + "/:notifyUri", + HTTPChargingNotification, + }, } diff --git a/internal/sbi/consumer/converged_charging.go b/internal/sbi/consumer/converged_charging.go new file mode 100644 index 00000000..e7980823 --- /dev/null +++ b/internal/sbi/consumer/converged_charging.go @@ -0,0 +1,117 @@ +package consumer + +import ( + "context" + "fmt" + "net/http" + "strings" + "time" + + "github.com/free5gc/nas/nasConvert" + "github.com/free5gc/openapi" + "github.com/free5gc/openapi/models" + smf_context "github.com/free5gc/smf/internal/context" + "github.com/free5gc/smf/internal/logger" +) + +func buildConvergedChargingRequest(smContext *smf_context.SMContext, + multipleUnitUsage []models.MultipleUnitUsage, +) *models.ChargingDataRequest { + var triggers []models.Trigger + + smfSelf := smf_context.GetSelf() + date := time.Now() + + for _, unitUsage := range multipleUnitUsage { + for _, usedUnit := range unitUsage.UsedUnitContainer { + triggers = append(triggers, usedUnit.Triggers...) + } + } + + req := &models.ChargingDataRequest{ + ChargingId: smContext.ChargingID, + SubscriberIdentifier: smContext.Supi, + NfConsumerIdentification: &models.NfIdentification{ + NodeFunctionality: models.NodeFunctionality_SMF, + NFName: smfSelf.Name, + // not sure if NFIPv4Address is RegisterIPv4 or BindingIPv4 + NFIPv4Address: smfSelf.RegisterIPv4, + }, + InvocationTimeStamp: &date, + Triggers: triggers, + PDUSessionChargingInformation: &models.PduSessionChargingInformation{ + ChargingId: smContext.ChargingID, + UserInformation: &models.UserInformation{ + ServedGPSI: smContext.Gpsi, + ServedPEI: smContext.Pei, + }, + PduSessionInformation: &models.PduSessionInformation{ + PduSessionID: smContext.PDUSessionID, + NetworkSlicingInfo: &models.NetworkSlicingInfo{ + SNSSAI: smContext.SNssai, + }, + + PduType: nasConvert.PDUSessionTypeToModels(smContext.SelectedPDUSessionType), + ServingNetworkFunctionID: &models.ServingNetworkFunctionId{ + ServingNetworkFunctionInformation: &models.NfIdentification{ + NodeFunctionality: models.NodeFunctionality_AMF, + }, + }, + DnnId: smContext.Dnn, + }, + }, + NotifyUri: fmt.Sprintf("%s://%s:%d/nsmf-callback/notify_%s", + smf_context.GetSelf().URIScheme, + smf_context.GetSelf().RegisterIPv4, + smf_context.GetSelf().SBIPort, + smContext.Ref, + ), + MultipleUnitUsage: multipleUnitUsage, + } + + return req +} + +func SendConvergedChargingRequest(smContext *smf_context.SMContext, requestType smf_context.RequestType, + multipleUnitUsage []models.MultipleUnitUsage, +) (*models.ChargingDataResponse, *models.ProblemDetails, error) { + logger.ChargingLog.Info("Handle SendConvergedChargingRequest") + + req := buildConvergedChargingRequest(smContext, multipleUnitUsage) + + var rsp models.ChargingDataResponse + var httpResponse *http.Response + var err error + + // select the appropriate converged charging service based on trigger type + switch requestType { + case smf_context.CHARGING_INIT: + rsp, httpResponse, err = smContext.ChargingClient.DefaultApi.ChargingdataPost(context.Background(), *req) + chargingDataRef := strings.Split(httpResponse.Header.Get("Location"), "/") + smContext.ChargingDataRef = chargingDataRef[len(chargingDataRef)-1] + case smf_context.CHARGING_UPDATE: + rsp, httpResponse, err = smContext.ChargingClient.DefaultApi.ChargingdataChargingDataRefUpdatePost( + context.Background(), smContext.ChargingDataRef, *req) + case smf_context.CHARGING_RELEASE: + httpResponse, err = smContext.ChargingClient.DefaultApi.ChargingdataChargingDataRefReleasePost(context.Background(), + smContext.ChargingDataRef, *req) + } + + defer func() { + if resCloseErr := httpResponse.Body.Close(); resCloseErr != nil { + logger.ChargingLog.Errorf("RegisterNFInstance response body cannot close: %+v", resCloseErr) + } + }() + + if err == nil { + return &rsp, nil, nil + } else if httpResponse != nil { + if httpResponse.Status != err.Error() { + return nil, nil, err + } + problem := err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + return nil, &problem, nil + } else { + return nil, nil, openapi.ReportError("server no response") + } +} diff --git a/internal/sbi/producer/callback.go b/internal/sbi/producer/callback.go index 38067c27..18adc46f 100644 --- a/internal/sbi/producer/callback.go +++ b/internal/sbi/producer/callback.go @@ -2,6 +2,7 @@ package producer import ( "context" + "fmt" "net/http" "github.com/free5gc/openapi/Nsmf_EventExposure" @@ -11,6 +12,60 @@ import ( "github.com/free5gc/util/httpwrapper" ) +func HandleChargingNotification(chargingNotifyRequest models.ChargingNotifyRequest, + smContextRef string, +) *httpwrapper.Response { + logger.ChargingLog.Info("Handle Charging Notification") + + problemDetails := chargingNotificationProcedure(chargingNotifyRequest, smContextRef) + if problemDetails != nil { + return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + } else { + return httpwrapper.NewResponse(http.StatusNoContent, nil, nil) + } +} + +// While receive Charging Notification from CHF, SMF will send Charging Information to CHF and update UPF +// The Charging Notification will be sent when CHF found the changes of the quota file. +func chargingNotificationProcedure(req models.ChargingNotifyRequest, smContextRef string) *models.ProblemDetails { + if smContext := smf_context.GetSMContextByRef(smContextRef); smContext != nil { + smContext.SMLock.Lock() + defer smContext.SMLock.Unlock() + upfUrrMap := make(map[string][]*smf_context.URR) + for _, reauthorizeDetail := range req.ReauthorizationDetails { + rg := reauthorizeDetail.RatingGroup + logger.ChargingLog.Infof("Force update charging information for rating group %d", rg) + for _, urr := range smContext.UrrUpfMap { + chgInfo := smContext.ChargingInfo[urr.URRID] + if chgInfo.RatingGroup == rg || + chgInfo.ChargingLevel == smf_context.PduSessionCharging { + logger.ChargingLog.Tracef("Query URR (%d) for Rating Group (%d)", urr.URRID, rg) + upfId := smContext.ChargingInfo[urr.URRID].UpfId + upfUrrMap[upfId] = append(upfUrrMap[upfId], urr) + } + } + } + for upfId, urrList := range upfUrrMap { + upf := smf_context.GetUpfById(upfId) + if upf == nil { + logger.ChargingLog.Warnf("Cound not find upf %s", upfId) + continue + } + QueryReport(smContext, upf, urrList, models.TriggerType_FORCED_REAUTHORISATION) + } + ReportUsageAndUpdateQuota(smContext) + } else { + problemDetails := &models.ProblemDetails{ + Status: http.StatusNotFound, + Cause: "CONTEXT_NOT_FOUND", + Detail: fmt.Sprintf("SM Context [%s] Not Found ", smContextRef), + } + return problemDetails + } + + return nil +} + func HandleSMPolicyUpdateNotify(smContextRef string, request models.SmPolicyNotification) *httpwrapper.Response { logger.PduSessLog.Infoln("In HandleSMPolicyUpdateNotify") decision := request.SmPolicyDecision diff --git a/internal/sbi/producer/charging_trigger.go b/internal/sbi/producer/charging_trigger.go new file mode 100644 index 00000000..aecf2d72 --- /dev/null +++ b/internal/sbi/producer/charging_trigger.go @@ -0,0 +1,377 @@ +package producer + +import ( + "time" + + "github.com/free5gc/openapi/models" + "github.com/free5gc/pfcp" + "github.com/free5gc/pfcp/pfcpType" + smf_context "github.com/free5gc/smf/internal/context" + "github.com/free5gc/smf/internal/logger" + pfcp_message "github.com/free5gc/smf/internal/pfcp/message" + "github.com/free5gc/smf/internal/sbi/consumer" +) + +func CreateChargingSession(smContext *smf_context.SMContext) { + _, problemDetails, err := consumer.SendConvergedChargingRequest(smContext, smf_context.CHARGING_INIT, nil) + if problemDetails != nil { + logger.ChargingLog.Errorf("Send Charging Data Request[Init] Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.ChargingLog.Errorf("Send Charging Data Request[Init] Error[%+v]", err) + } else { + logger.ChargingLog.Infof("Send Charging Data Request[Init] successfully") + } +} + +func UpdateChargingSession(smContext *smf_context.SMContext, urrList []*smf_context.URR, trigger models.Trigger) { + var multipleUnitUsage []models.MultipleUnitUsage + + for _, urr := range urrList { + if chgInfo := smContext.ChargingInfo[urr.URRID]; chgInfo != nil { + rg := chgInfo.RatingGroup + logger.PduSessLog.Tracef("Receive Usage Report from URR[%d], correspopnding Rating Group[%d], ChargingMethod %v", + urr.URRID, rg, chgInfo.ChargingMethod) + triggerTime := time.Now() + + uu := models.UsedUnitContainer{ + QuotaManagementIndicator: chgInfo.ChargingMethod, + Triggers: []models.Trigger{trigger}, + TriggerTimestamp: &triggerTime, + } + + muu := models.MultipleUnitUsage{ + RatingGroup: rg, + UPFID: chgInfo.UpfId, + UsedUnitContainer: []models.UsedUnitContainer{uu}, + } + + multipleUnitUsage = append(multipleUnitUsage, muu) + } + } + + _, problemDetails, err := consumer.SendConvergedChargingRequest(smContext, + smf_context.CHARGING_UPDATE, multipleUnitUsage) + if problemDetails != nil { + logger.ChargingLog.Errorf("Send Charging Data Request[Init] Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.ChargingLog.Errorf("Send Charging Data Request[Init] Error[%+v]", err) + } else { + logger.ChargingLog.Infof("Send Charging Data Request[Init] successfully") + } +} + +func ReleaseChargingSession(smContext *smf_context.SMContext) { + multipleUnitUsage := buildMultiUnitUsageFromUsageReport(smContext) + + _, problemDetails, err := consumer.SendConvergedChargingRequest(smContext, + smf_context.CHARGING_RELEASE, multipleUnitUsage) + if problemDetails != nil { + logger.ChargingLog.Errorf("Send Charging Data Request[Termination] Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.ChargingLog.Errorf("Send Charging Data Request[Termination] Error[%+v]", err) + } else { + logger.ChargingLog.Infof("Send Charging Data Request[Termination] successfully") + } +} + +// Report usage report to the CHF and update the URR with the charging information in the charging response +func ReportUsageAndUpdateQuota(smContext *smf_context.SMContext) { + multipleUnitUsage := buildMultiUnitUsageFromUsageReport(smContext) + + if len(multipleUnitUsage) != 0 { + rsp, problemDetails, err := consumer.SendConvergedChargingRequest(smContext, + smf_context.CHARGING_UPDATE, multipleUnitUsage) + + if problemDetails != nil { + logger.ChargingLog.Errorf("Send Charging Data Request[Update] Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.ChargingLog.Errorf("Send Charging Data Request[Update] Error[%+v]", err) + } else { + var pfcpResponseStatus smf_context.PFCPSessionResponseStatus + + upfUrrMap := make(map[string][]*smf_context.URR) + + logger.ChargingLog.Infof("Send Charging Data Request[Update] successfully") + smContext.SetState(smf_context.PFCPModification) + + updateGrantedQuota(smContext, rsp.MultipleUnitInformation) + // Usually only the anchor UPF need to be updated + for _, urr := range smContext.UrrUpfMap { + upfId := smContext.ChargingInfo[urr.URRID].UpfId + + if urr.State == smf_context.RULE_UPDATE { + upfUrrMap[upfId] = append(upfUrrMap[upfId], urr) + } + } + + if len(upfUrrMap) == 0 { + logger.ChargingLog.Infof("Do not have urr that need to update charging information") + return + } + + for upfId, urrList := range upfUrrMap { + upf := smf_context.GetUpfById(upfId) + if upf == nil { + logger.PduSessLog.Warnf("Cound not find upf %s", upfId) + continue + } + rcvMsg, err := pfcp_message.SendPfcpSessionModificationRequest( + upf, smContext, nil, nil, nil, nil, urrList) + if err != nil { + logger.PduSessLog.Warnf("Sending PFCP Session Modification Request to AN UPF error: %+v", err) + pfcpResponseStatus = smf_context.SessionUpdateFailed + } else { + logger.PduSessLog.Infoln("Received PFCP Session Modification Response") + pfcpResponseStatus = smf_context.SessionUpdateSuccess + } + + rsp := rcvMsg.PfcpMessage.Body.(pfcp.PFCPSessionModificationResponse) + if rsp.Cause == nil || rsp.Cause.CauseValue != pfcpType.CauseRequestAccepted { + logger.PduSessLog.Warn("Received PFCP Session Modification Not Accepted Response from AN UPF") + pfcpResponseStatus = smf_context.SessionUpdateFailed + } + + switch pfcpResponseStatus { + case smf_context.SessionUpdateSuccess: + logger.PfcpLog.Traceln("In case SessionUpdateSuccess") + smContext.SetState(smf_context.Active) + case smf_context.SessionUpdateFailed: + logger.PfcpLog.Traceln("In case SessionUpdateFailed") + smContext.SetState(smf_context.Active) + } + } + } + } else { + logger.ChargingLog.Infof("No report need to be charged") + } +} + +func buildMultiUnitUsageFromUsageReport(smContext *smf_context.SMContext) []models.MultipleUnitUsage { + logger.ChargingLog.Infof("build MultiUnitUsageFromUsageReport") + + var ratingGroupUnitUsagesMap map[int32]models.MultipleUnitUsage + var multipleUnitUsage []models.MultipleUnitUsage + + ratingGroupUnitUsagesMap = make(map[int32]models.MultipleUnitUsage) + for _, ur := range smContext.UrrReports { + if ur.ReportTpye != "" { + var triggers []models.Trigger + + chgInfo := smContext.ChargingInfo[ur.UrrId] + if chgInfo == nil { + logger.PduSessLog.Tracef("URR %d is not for charging", ur.UrrId) + continue + } + + if chgInfo.ChargingLevel == smf_context.FlowCharging && ur.ReportTpye == models.TriggerType_VOLUME_LIMIT { + triggers = []models.Trigger{ + { + TriggerType: ur.ReportTpye, + TriggerCategory: models.TriggerCategory_DEFERRED_REPORT, + }, + } + } else { + triggers = []models.Trigger{ + { + TriggerType: ur.ReportTpye, + TriggerCategory: models.TriggerCategory_IMMEDIATE_REPORT, + }, + } + } + + rg := chgInfo.RatingGroup + logger.PduSessLog.Tracef("Receive Usage Report from URR[%d], correspopnding Rating Group[%d], ChargingMethod %v", + ur.UrrId, rg, chgInfo.ChargingMethod) + triggerTime := time.Now() + + uu := models.UsedUnitContainer{ + QuotaManagementIndicator: chgInfo.ChargingMethod, + Triggers: triggers, + TriggerTimestamp: &triggerTime, + DownlinkVolume: int32(ur.DownlinkVolume), + UplinkVolume: int32(ur.UplinkVolume), + TotalVolume: int32(ur.TotalVolume), + } + if unitUsage, ok := ratingGroupUnitUsagesMap[rg]; !ok { + requestUnit := &models.RequestedUnit{} + + // Only online charging should request unit + // offline charging is only for recording usage + switch chgInfo.ChargingMethod { + case models.QuotaManagementIndicator_ONLINE_CHARGING: + requestUnit = &models.RequestedUnit{ + TotalVolume: smContext.RequestedUnit, + DownlinkVolume: smContext.RequestedUnit, + UplinkVolume: smContext.RequestedUnit, + } + } + + ratingGroupUnitUsagesMap[rg] = models.MultipleUnitUsage{ + RatingGroup: rg, + UPFID: ur.UpfId, + UsedUnitContainer: []models.UsedUnitContainer{uu}, + RequestedUnit: requestUnit, + } + } else { + unitUsage.UsedUnitContainer = append(unitUsage.UsedUnitContainer, uu) + ratingGroupUnitUsagesMap[rg] = unitUsage + } + } else { + logger.PduSessLog.Tracef("Report for urr (%d) will not be charged", ur.UrrId) + } + } + + smContext.UrrReports = []smf_context.UsageReport{} + + for _, unitUsage := range ratingGroupUnitUsagesMap { + multipleUnitUsage = append(multipleUnitUsage, unitUsage) + } + + return multipleUnitUsage +} + +func getUrrByRg(smContext *smf_context.SMContext, upfId string, rg int32) *smf_context.URR { + for _, urr := range smContext.UrrUpfMap { + if smContext.ChargingInfo[urr.URRID] != nil && + smContext.ChargingInfo[urr.URRID].RatingGroup == rg && + smContext.ChargingInfo[urr.URRID].UpfId == upfId { + return urr + } + } + + return nil +} + +// Update the urr by the charging information renewed by chf +func updateGrantedQuota(smContext *smf_context.SMContext, multipleUnitInformation []models.MultipleUnitInformation) { + for _, ui := range multipleUnitInformation { + trigger := pfcpType.ReportingTriggers{} + + rg := ui.RatingGroup + upfId := ui.UPFID + + if urr := getUrrByRg(smContext, upfId, rg); urr != nil { + urr.State = smf_context.RULE_UPDATE + chgInfo := smContext.ChargingInfo[urr.URRID] + + for _, t := range ui.Triggers { + switch t.TriggerType { + case models.TriggerType_VOLUME_LIMIT: + // According to 32.255, the for the trigger "Expirt of datavolume limit" have two reporting level + // In the Pdu sesion level, the report should be "Immediate report", + // that is this report should send to CHF immediately + // In the Rating Group level, the report should be "Defferd report", that is this report should send to CHF + // when the in the next charging request triggereed + // by charging trigger that belongs to the type of immediate report + + // TODO: Currently CHF cannot identify the report level since it only knows the rating group, + // so the both charging level of "Expirt of datavolume limit" + // will be included in the report, and the report type will be determined by the SMF + switch chgInfo.ChargingLevel { + case smf_context.PduSessionCharging: + if t.TriggerCategory == models.TriggerCategory_IMMEDIATE_REPORT { + smContext.Log.Infof("Add Volume Limit Expiry Timer for Pdu session, it's rating group is [%d]", rg) + + if chgInfo.VolumeLimitExpiryTimer != nil { + chgInfo.VolumeLimitExpiryTimer.Stop() + chgInfo.VolumeLimitExpiryTimer = nil + } + + chgInfo.VolumeLimitExpiryTimer = smf_context.NewTimer(time.Duration(t.VolumeLimit)*time.Second, 1, + func(expireTimes int32) { + smContext.SMLock.Lock() + defer smContext.SMLock.Unlock() + urrList := []*smf_context.URR{urr} + upf := smf_context.GetUpfById(ui.UPFID) + if upf != nil { + QueryReport(smContext, upf, urrList, models.TriggerType_VOLUME_LIMIT) + ReportUsageAndUpdateQuota(smContext) + } + }, + func() { + smContext.Log.Tracef("Volume Limit Expiry for Pdu session, it's rating group is [%d]", rg) + chgInfo.VolumeLimitExpiryTimer.Stop() + chgInfo.VolumeLimitExpiryTimer = nil + }) + } + case smf_context.FlowCharging: + if t.TriggerCategory == models.TriggerCategory_DEFERRED_REPORT { + smContext.Log.Infof("Add Volume Limit Expiry Timer for rating group [%d] ", rg) + + if chgInfo.VolumeLimitExpiryTimer != nil { + chgInfo.VolumeLimitExpiryTimer.Stop() + chgInfo.VolumeLimitExpiryTimer = nil + } + + chgInfo.VolumeLimitExpiryTimer = smf_context.NewTimer(time.Duration(t.VolumeLimit)*time.Second, 1, + func(expireTimes int32) { + smContext.SMLock.Lock() + defer smContext.SMLock.Unlock() + urrList := []*smf_context.URR{urr} + upf := smf_context.GetUpfById(ui.UPFID) + if upf != nil { + QueryReport(smContext, upf, urrList, models.TriggerType_VOLUME_LIMIT) + } + }, + func() { + smContext.Log.Tracef("Volume Limit Expiry for rating group [%d]", rg) + chgInfo.VolumeLimitExpiryTimer.Stop() + chgInfo.VolumeLimitExpiryTimer = nil + }) + } + } + case models.TriggerType_MAX_NUMBER_OF_CHANGES_IN_CHARGING_CONDITIONS: + switch chgInfo.ChargingLevel { + case smf_context.PduSessionCharging: + chgInfo.EventLimitExpiryTimer = smf_context.NewTimer(time.Duration(t.EventLimit)*time.Second, 1, + func(expireTimes int32) { + smContext.SMLock.Lock() + defer smContext.SMLock.Unlock() + urrList := []*smf_context.URR{urr} + upf := smf_context.GetUpfById(ui.UPFID) + if upf != nil { + QueryReport(smContext, upf, urrList, models.TriggerType_VOLUME_LIMIT) + ReportUsageAndUpdateQuota(smContext) + } + }, + func() { + smContext.Log.Tracef("Event Limit Expiry Timer is triggered") + chgInfo.EventLimitExpiryTimer = nil + }) + default: + smContext.Log.Tracef("MAX_NUMBER_OF_CHANGES_IN_CHARGING_CONDITIONS" + + "should only be applied to PDU session level charging") + } + case models.TriggerType_QUOTA_THRESHOLD: + if ui.VolumeQuotaThreshold != 0 { + trigger.Volth = true + urr.VolumeThreshold = uint64(ui.VolumeQuotaThreshold) + } + // The difference between the quota validity time and the volume limit is + // that the validity time is counted by the UPF, the volume limit is counted by the SMF + case models.TriggerType_VALIDITY_TIME: + if ui.ValidityTime != 0 { + urr.ReportingTrigger.Quvti = true + urr.QuotaValidityTime = time.Now().Add(time.Second * time.Duration(ui.ValidityTime)) + } + case models.TriggerType_QUOTA_EXHAUSTED: + if chgInfo.ChargingMethod == models.QuotaManagementIndicator_ONLINE_CHARGING { + if ui.GrantedUnit != nil { + trigger.Volqu = true + urr.VolumeQuota = uint64(ui.GrantedUnit.TotalVolume) + } else { + // No granted quota, so set the urr.VolumeQuota to 0, upf should stop send traffic + logger.ChargingLog.Warnf("No granted quota") + trigger.Volqu = true + urr.VolumeQuota = 0 + } + } + } + } + + urr.ReportingTrigger = trigger + } else { + logger.PduSessLog.Warnf("Do not find charging Information for rating group[%d]\n", rg) + } + } +} diff --git a/internal/sbi/producer/datapath.go b/internal/sbi/producer/datapath.go index 167229b6..e6e2c4db 100644 --- a/internal/sbi/producer/datapath.go +++ b/internal/sbi/producer/datapath.go @@ -10,7 +10,6 @@ import ( "github.com/free5gc/pfcp/pfcpUdp" smf_context "github.com/free5gc/smf/internal/context" "github.com/free5gc/smf/internal/logger" - "github.com/free5gc/smf/internal/pfcp/handler" pfcp_message "github.com/free5gc/smf/internal/pfcp/message" ) @@ -89,7 +88,7 @@ func ActivateUPFSession( if !exist || sessionContext.RemoteSEID == 0 { go establishPfcpSession(smContext, pfcp, resChan) } else { - go modifyExistingPfcpSession(smContext, pfcp, resChan) + go modifyExistingPfcpSession(smContext, pfcp, resChan, "") } } @@ -97,6 +96,28 @@ func ActivateUPFSession( close(resChan) } +func QueryReport(smContext *smf_context.SMContext, upf *smf_context.UPF, + urrs []*smf_context.URR, reportResaon models.TriggerType, +) { + for _, urr := range urrs { + urr.State = smf_context.RULE_QUERY + } + + pfcpState := &PFCPState{ + upf: upf, + urrList: urrs, + } + + resChan := make(chan SendPfcpResult) + go modifyExistingPfcpSession(smContext, pfcpState, resChan, reportResaon) + pfcpResult := <-resChan + + if pfcpResult.Err != nil { + logger.PduSessLog.Errorf("Query URR Report by PFCP Session Mod Request fail: %v", pfcpResult.Err) + return + } +} + func establishPfcpSession(smContext *smf_context.SMContext, state *PFCPState, resCh chan<- SendPfcpResult, @@ -140,6 +161,7 @@ func modifyExistingPfcpSession( smContext *smf_context.SMContext, state *PFCPState, resCh chan<- SendPfcpResult, + reportResaon models.TriggerType, ) { logger.PduSessLog.Infoln("Sending PFCP Session Modification Request") @@ -165,7 +187,7 @@ func modifyExistingPfcpSession( if rsp.UsageReport != nil { SEID := rcvMsg.PfcpMessage.Header.SEID upfNodeID := smContext.GetNodeIDByLocalSEID(SEID) - handler.HandleReports(nil, rsp.UsageReport, nil, smContext, upfNodeID) + smContext.HandleReports(nil, rsp.UsageReport, nil, upfNodeID, reportResaon) } } else { resCh <- SendPfcpResult{ @@ -425,7 +447,7 @@ func deletePfcpSession(upf *smf_context.UPF, ctx *smf_context.SMContext, resCh c if rsp.UsageReport != nil { SEID := rcvMsg.PfcpMessage.Header.SEID upfNodeID := ctx.GetNodeIDByLocalSEID(SEID) - handler.HandleReports(nil, nil, rsp.UsageReport, ctx, upfNodeID) + ctx.HandleReports(nil, nil, rsp.UsageReport, upfNodeID, "") } } else { logger.PduSessLog.Warn("Received PFCP Session Deletion Not Accepted Response") diff --git a/internal/sbi/producer/gsm_handler_test.go b/internal/sbi/producer/gsm_handler_test.go index df977d68..61f6391b 100644 --- a/internal/sbi/producer/gsm_handler_test.go +++ b/internal/sbi/producer/gsm_handler_test.go @@ -30,7 +30,7 @@ func TestBuildNASPacketFilterFromPacketFilterInfo(t *testing.T) { }, flowInfo: models.FlowInformation{ FlowDirection: models.FlowDirectionRm_BIDIRECTIONAL, - FlowDescription: "permit out ip from any to any", + FlowDescription: "permit out ip from any to assigned", }, }, { diff --git a/internal/sbi/producer/pdu_session.go b/internal/sbi/producer/pdu_session.go index cd0ad298..80aa5cc2 100644 --- a/internal/sbi/producer/pdu_session.go +++ b/internal/sbi/producer/pdu_session.go @@ -188,6 +188,15 @@ func HandlePDUSessionSMContextCreate(isDone <-chan struct{}, } smContext.SMPolicyID = smPolicyID + // PDU session create is a charging event + logger.PduSessLog.Infof("CHF Selection for SMContext SUPI[%s] PDUSessionID[%d]\n", + smContext.Supi, smContext.PDUSessionID) + if err = smContext.CHFSelection(); err != nil { + logger.PduSessLog.Errorln("chf selection error:", err) + } else { + CreateChargingSession(smContext) + } + // Update SessionRule from decision if err = smContext.ApplySessionRules(smPolicyDecision); err != nil { smContext.Log.Errorf("PDUSessionSMContextCreate err: %v", err) @@ -196,7 +205,13 @@ func HandlePDUSessionSMContextCreate(isDone <-chan struct{}, &Nsmf_PDUSession.SubscriptionDenied) } - if err = smContext.SelectDefaultDataPath(); err != nil { + // If PCF prepares default Pcc Rule, SMF do not need to create defaultDataPath. + if err := smContext.ApplyPccRules(smPolicyDecision); err != nil { + smContext.Log.Errorf("apply sm policy decision error: %+v", err) + } + + // SelectDefaultDataPath() will create a default data path if default data path is not found. + if err := smContext.SelectDefaultDataPath(); err != nil { smContext.SetState(smf_context.InActive) smContext.Log.Errorf("PDUSessionSMContextCreate err: %v", err) return makeEstRejectResAndReleaseSMContext(smContext, @@ -204,20 +219,6 @@ func HandlePDUSessionSMContextCreate(isDone <-chan struct{}, &Nsmf_PDUSession.InsufficientResourceSliceDnn) } - if err = smContext.ApplyPccRules(smPolicyDecision); err != nil { - smContext.Log.Errorf("apply sm policy decision error: %+v", err) - } - - // UECM registration - problemDetails, err := consumer.UeCmRegistration(smContext) - if problemDetails != nil { - smContext.Log.Errorf("UECM_Registration Error: %+v", problemDetails) - } else if err != nil { - smContext.Log.Errorf("UECM_Registration Error: %+v", err) - } else { - smContext.Log.Traceln("UECM Registration Successful") - } - // generate goroutine to handle PFCP and // reply PDUSessionSMContextCreate rsp immediately needUnlock = false @@ -459,6 +460,24 @@ func HandlePDUSessionSMContextUpdate(smContextRef string, body models.UpdateSmCo smContext.SetState(smf_context.ModificationPending) response.JsonData.UpCnxState = models.UpCnxState_DEACTIVATED smContext.UpCnxState = body.JsonData.UpCnxState + // UE location change is a charging event + // TODO: This is not tested yet + if smContext.UeLocation != body.JsonData.UeLocation { + // All rating group related to this Pdu session should send charging request + for _, dataPath := range tunnel.DataPathPool { + if dataPath.Activated { + for curDataPathNode := dataPath.FirstDPNode; curDataPathNode != nil; curDataPathNode = curDataPathNode.Next() { + if curDataPathNode.IsANUPF() { + urrList = append(urrList, curDataPathNode.UpLinkTunnel.PDR.URR...) + QueryReport(smContext, curDataPathNode.UPF, urrList, models.TriggerType_USER_LOCATION_CHANGE) + } + } + } + } + + ReportUsageAndUpdateQuota(smContext) + } + smContext.UeLocation = body.JsonData.UeLocation // Set FAR and An, N3 Release Info @@ -783,6 +802,8 @@ func HandlePDUSessionSMContextUpdate(smContextRef string, body models.UpdateSmCo } case smf_context.SessionReleaseSuccess: + ReleaseChargingSession(smContext) + smContext.Log.Traceln("In case SessionReleaseSuccess") smContext.SetState(smf_context.InActivePending) httpResponse = &httpwrapper.Response{ @@ -908,6 +929,8 @@ func HandlePDUSessionSMContextRelease(smContextRef string, body models.ReleaseSm switch pfcpResponseStatus { case smf_context.SessionReleaseSuccess: + ReleaseChargingSession(smContext) + smContext.Log.Traceln("In case SessionReleaseSuccess") smContext.SetState(smf_context.InActive) httpResponse = &httpwrapper.Response{ @@ -1004,6 +1027,8 @@ func HandlePDUSessionSMContextLocalRelease(smContext *smf_context.SMContext, cre switch pfcpResponseStatus { case smf_context.SessionReleaseSuccess: + ReleaseChargingSession(smContext) + logger.CtxLog.Traceln("In case SessionReleaseSuccess") smContext.SetState(smf_context.InActivePending) if createData.SmContextStatusUri != smContext.SmStatusNotifyUri { diff --git a/internal/sbi/producer/ulcl_procedure.go b/internal/sbi/producer/ulcl_procedure.go index 71883e52..7a2e0aed 100644 --- a/internal/sbi/producer/ulcl_procedure.go +++ b/internal/sbi/producer/ulcl_procedure.go @@ -4,6 +4,7 @@ import ( "net" "reflect" + "github.com/free5gc/openapi/models" "github.com/free5gc/pfcp/pfcpType" "github.com/free5gc/pfcp/pfcpUdp" "github.com/free5gc/smf/internal/context" @@ -77,6 +78,19 @@ func EstablishPSA2(smContext *context.SMContext) { qerList := upLinkPDR.QER urrList := upLinkPDR.URR + chgUrrList := []*context.URR{} + for _, urr := range urrList { + if urr.ReportingTrigger.Start { + chgUrrList = append(chgUrrList, urr) + } + } + + // According to 32.255 5.2.2.7, Addition of additional PDU Session Anchor is a charging event + UpdateChargingSession(smContext, chgUrrList, models.Trigger{ + TriggerType: models.TriggerType_ADDITION_OF_UPF, + TriggerCategory: models.TriggerCategory_IMMEDIATE_REPORT, + }) + lastNode := node.Prev() if lastNode != nil && !reflect.DeepEqual(lastNode.UPF.NodeID, ulcl.NodeID) { @@ -100,7 +114,7 @@ func EstablishPSA2(smContext *context.SMContext) { if !exist || sessionContext.RemoteSEID == 0 { go establishPfcpSession(smContext, pfcpState, resChan) } else { - go modifyExistingPfcpSession(smContext, pfcpState, resChan) + go modifyExistingPfcpSession(smContext, pfcpState, resChan, "") } } else { if reflect.DeepEqual(node.UPF.NodeID, ulcl.NodeID) { @@ -170,7 +184,7 @@ func EstablishULCL(smContext *context.SMContext) { curDPNodeIP := ulcl.NodeID.ResolveNodeIdToIp().String() pendingUPFs = append(pendingUPFs, curDPNodeIP) - go modifyExistingPfcpSession(smContext, pfcpState, resChan) + go modifyExistingPfcpSession(smContext, pfcpState, resChan, "") break } } @@ -215,7 +229,7 @@ func UpdatePSA2DownLink(smContext *context.SMContext) { curDPNodeIP := node.UPF.NodeID.ResolveNodeIdToIp().String() pendingUPFs = append(pendingUPFs, curDPNodeIP) - go modifyExistingPfcpSession(smContext, pfcpState, resChan) + go modifyExistingPfcpSession(smContext, pfcpState, resChan, "") logger.PfcpLog.Info("[SMF] Update PSA2 downlink msg has been send") break } @@ -327,7 +341,7 @@ func UpdateRANAndIUPFUpLink(smContext *context.SMContext) { curDPNodeIP := curDPNode.UPF.NodeID.ResolveNodeIdToIp().String() pendingUPFs = append(pendingUPFs, curDPNodeIP) - go modifyExistingPfcpSession(smContext, pfcpState, resChan) + go modifyExistingPfcpSession(smContext, pfcpState, resChan, "") } } diff --git a/pkg/factory/config.go b/pkg/factory/config.go index 8d4a23cd..2303b004 100644 --- a/pkg/factory/config.go +++ b/pkg/factory/config.go @@ -90,6 +90,7 @@ type Configuration struct { T3591 *TimerValue `yaml:"t3591" valid:"required"` T3592 *TimerValue `yaml:"t3592" valid:"required"` NwInstFqdnEncoding bool `yaml:"nwInstFqdnEncoding" valid:"type(bool),optional"` + RequestedUnit int32 `yaml:"requestedUnit,omitempty" valid:"optional"` } type Logger struct { From 021615279cb8a78af9b76c5dadb544b155ce97ac Mon Sep 17 00:00:00 2001 From: "CTFang@WireLab" Date: Wed, 6 Mar 2024 05:23:23 +0000 Subject: [PATCH 04/15] Fix: Add CHF ConvergeCharging with OAuth2 Token --- internal/sbi/consumer/converged_charging.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/sbi/consumer/converged_charging.go b/internal/sbi/consumer/converged_charging.go index e7980823..88cf858d 100644 --- a/internal/sbi/consumer/converged_charging.go +++ b/internal/sbi/consumer/converged_charging.go @@ -1,7 +1,6 @@ package consumer import ( - "context" "fmt" "net/http" "strings" @@ -83,17 +82,22 @@ func SendConvergedChargingRequest(smContext *smf_context.SMContext, requestType var httpResponse *http.Response var err error + ctx, pd, err := smf_context.GetSelf().GetTokenCtx(models.ServiceName_NCHF_CONVERGEDCHARGING, models.NfType_CHF) + if err != nil { + return nil, pd, err + } + // select the appropriate converged charging service based on trigger type switch requestType { case smf_context.CHARGING_INIT: - rsp, httpResponse, err = smContext.ChargingClient.DefaultApi.ChargingdataPost(context.Background(), *req) + rsp, httpResponse, err = smContext.ChargingClient.DefaultApi.ChargingdataPost(ctx, *req) chargingDataRef := strings.Split(httpResponse.Header.Get("Location"), "/") smContext.ChargingDataRef = chargingDataRef[len(chargingDataRef)-1] case smf_context.CHARGING_UPDATE: rsp, httpResponse, err = smContext.ChargingClient.DefaultApi.ChargingdataChargingDataRefUpdatePost( - context.Background(), smContext.ChargingDataRef, *req) + ctx, smContext.ChargingDataRef, *req) case smf_context.CHARGING_RELEASE: - httpResponse, err = smContext.ChargingClient.DefaultApi.ChargingdataChargingDataRefReleasePost(context.Background(), + httpResponse, err = smContext.ChargingClient.DefaultApi.ChargingdataChargingDataRefReleasePost(ctx, smContext.ChargingDataRef, *req) } From 4aef596d742401b6f8bafa5e8fd958bce509c9d6 Mon Sep 17 00:00:00 2001 From: Tim Liu Date: Wed, 6 Mar 2024 16:01:54 +0000 Subject: [PATCH 05/15] update go.sum --- go.sum | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/go.sum b/go.sum index 348f08a4..9b799c8e 100644 --- a/go.sum +++ b/go.sum @@ -183,7 +183,7 @@ github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NB github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= @@ -269,14 +269,13 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= From 73cc42fa17574ebc92fbcea6ad9857867183cc28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 08:47:07 +0800 Subject: [PATCH 06/15] Bump google.golang.org/protobuf from 1.30.0 to 1.33.0 (#97) Bumps google.golang.org/protobuf from 1.30.0 to 1.33.0. --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 6f59bb65..3220038d 100644 --- a/go.mod +++ b/go.mod @@ -65,7 +65,7 @@ require ( golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.6 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 9b799c8e..1700e124 100644 --- a/go.sum +++ b/go.sum @@ -34,7 +34,6 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1/go.mod h1:nuudZmJhzWtx2212z+pkuy7B6nkBqa+xwNXZHL1j8cg= -github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1/go.mod h1:nuudZmJhzWtx2212z+pkuy7B6nkBqa+xwNXZHL1j8cg= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= @@ -56,7 +55,6 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -269,12 +267,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= @@ -414,7 +408,6 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -550,8 +543,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= From 071c172dc5a24129311bf0f2f3b35e159c661b32 Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Wed, 20 Mar 2024 12:24:17 +0800 Subject: [PATCH 07/15] mv dl/up teid generator to smCtx (#98) --- internal/context/context.go | 2 ++ internal/context/datapath.go | 21 ++------------------ internal/context/ngap_build.go | 2 +- internal/context/ngap_handler.go | 2 +- internal/context/sm_context.go | 34 ++++++++++++++++++++++++++++++++ internal/context/upf.go | 18 ----------------- 6 files changed, 40 insertions(+), 39 deletions(-) diff --git a/internal/context/context.go b/internal/context/context.go index b9d4ced5..3da5ecb4 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -258,6 +258,8 @@ func InitSmfContext(config *factory.Config) { SetupNFProfile(config) smfContext.Locality = configuration.Locality + + TeidGenerator = idgenerator.NewGenerator(1, math.MaxUint32) } func InitSMFUERouting(routingConfig *factory.RoutingConfig) { diff --git a/internal/context/datapath.go b/internal/context/datapath.go index d8a31d59..e6611dc5 100644 --- a/internal/context/datapath.go +++ b/internal/context/datapath.go @@ -144,12 +144,7 @@ func (node *DataPathNode) ActivateUpLinkTunnel(smContext *SMContext) error { return err } - if teid, err := destUPF.GenerateTEID(); err != nil { - logger.CtxLog.Errorf("Generate uplink TEID fail: %s", err) - return err - } else { - node.UpLinkTunnel.TEID = teid - } + node.UpLinkTunnel.TEID = smContext.LocalULTeid return nil } @@ -171,12 +166,7 @@ func (node *DataPathNode) ActivateDownLinkTunnel(smContext *SMContext) error { return err } - if teid, err := destUPF.GenerateTEID(); err != nil { - logger.CtxLog.Errorf("Generate downlink TEID fail: %s", err) - return err - } else { - node.DownLinkTunnel.TEID = teid - } + node.DownLinkTunnel.TEID = smContext.LocalDLTeid return nil } @@ -214,9 +204,6 @@ func (node *DataPathNode) DeactivateUpLinkTunnel(smContext *SMContext) { } } } - - teid := node.UpLinkTunnel.TEID - node.UPF.teidGenerator.FreeID(int64(teid)) } func (node *DataPathNode) DeactivateDownLinkTunnel(smContext *SMContext) { @@ -252,9 +239,6 @@ func (node *DataPathNode) DeactivateDownLinkTunnel(smContext *SMContext) { } } } - - teid := node.DownLinkTunnel.TEID - node.UPF.teidGenerator.FreeID(int64(teid)) } func (node *DataPathNode) GetUPFID() (id string, err error) { @@ -771,7 +755,6 @@ func (p *DataPath) AddChargingRules(smContext *SMContext, chgLevel ChargingLevel UpfId: node.UPF.UUID(), } - // urrId, err := node.UPF.urrIDGenerator.Allocate() urrId, err := smContext.UrrIDGenerator.Allocate() if err != nil { logger.PduSessLog.Errorln("Generate URR Id failed") diff --git a/internal/context/ngap_build.go b/internal/context/ngap_build.go index af0c60da..4c25f9f7 100644 --- a/internal/context/ngap_build.go +++ b/internal/context/ngap_build.go @@ -16,7 +16,7 @@ func BuildPDUSessionResourceSetupRequestTransfer(ctx *SMContext) ([]byte, error) ANUPF := ctx.Tunnel.DataPathPool.GetDefaultPath().FirstDPNode UpNode := ANUPF.UPF teidOct := make([]byte, 4) - binary.BigEndian.PutUint32(teidOct, ANUPF.UpLinkTunnel.TEID) + binary.BigEndian.PutUint32(teidOct, ctx.LocalULTeid) resourceSetupRequestTransfer := ngapType.PDUSessionResourceSetupRequestTransfer{} diff --git a/internal/context/ngap_handler.go b/internal/context/ngap_handler.go index 54892bfb..19d5efa4 100644 --- a/internal/context/ngap_handler.go +++ b/internal/context/ngap_handler.go @@ -266,7 +266,7 @@ func HandleHandoverRequestAcknowledgeTransfer(b []byte, ctx *SMContext) (err err originPDR := ctx.Tunnel.DataPathPool.GetDefaultPath().FirstDPNode.UpLinkTunnel.PDR - if teid, err := ANUPF.GenerateTEID(); err != nil { + if teid, err := GenerateTEID(); err != nil { return err } else { ctx.IndirectForwardingTunnel.FirstDPNode.UpLinkTunnel.TEID = teid diff --git a/internal/context/sm_context.go b/internal/context/sm_context.go index 30bbb061..e520d1b8 100644 --- a/internal/context/sm_context.go +++ b/internal/context/sm_context.go @@ -114,6 +114,8 @@ type UsageReport struct { ReportTpye models.TriggerType } +var TeidGenerator *idgenerator.IDGenerator + type SMContext struct { *models.SmContextCreateData @@ -128,6 +130,9 @@ type SMContext struct { Identifier string PDUSessionID int32 + LocalULTeid uint32 + LocalDLTeid uint32 + UpCnxState models.UpCnxState HoState models.HoState @@ -242,6 +247,21 @@ type SMContext struct { SMLock sync.Mutex } +func GenerateTEID() (uint32, error) { + var id uint32 + if tmpID, err := TeidGenerator.Allocate(); err != nil { + return 0, err + } else { + id = uint32(tmpID) + } + + return id, nil +} + +func ReleaseTEID(teid uint32) { + TeidGenerator.FreeID(int64(teid)) +} + func canonicalName(id string, pduSessID int32) string { return fmt.Sprintf("%s-%d", id, pduSessID) } @@ -316,6 +336,17 @@ func NewSMContext(id string, pduSessID int32) *SMContext { } } + var err error + smContext.LocalDLTeid, err = GenerateTEID() + if err != nil { + return nil + } + + smContext.LocalULTeid, err = GenerateTEID() + if err != nil { + return nil + } + return smContext } @@ -361,6 +392,9 @@ func RemoveSMContext(ref string) { seidSMContextMap.Delete(pfcpSessionContext.LocalSEID) } + ReleaseTEID(smContext.LocalULTeid) + ReleaseTEID(smContext.LocalDLTeid) + smContextPool.Delete(ref) canonicalRef.Delete(canonicalName(smContext.Supi, smContext.PDUSessionID)) smContext.Log.Infof("smContext[%s] is deleted from pool", ref) diff --git a/internal/context/upf.go b/internal/context/upf.go index ead327ac..98c59736 100644 --- a/internal/context/upf.go +++ b/internal/context/upf.go @@ -90,7 +90,6 @@ type UPF struct { barIDGenerator *idgenerator.IDGenerator urrIDGenerator *idgenerator.IDGenerator qerIDGenerator *idgenerator.IDGenerator - teidGenerator *idgenerator.IDGenerator } // UPFSelectionParams ... parameters for upf selection @@ -252,7 +251,6 @@ func NewUPF(nodeID *pfcpType.NodeID, ifaces []*factory.InterfaceUpfInfoItem) (up upf.barIDGenerator = idgenerator.NewGenerator(1, math.MaxUint8) upf.qerIDGenerator = idgenerator.NewGenerator(1, math.MaxUint32) upf.urrIDGenerator = idgenerator.NewGenerator(1, math.MaxUint32) - upf.teidGenerator = idgenerator.NewGenerator(1, math.MaxUint32) upf.N3Interfaces = make([]*UPFInterfaceInfo, 0) upf.N9Interfaces = make([]*UPFInterfaceInfo, 0) @@ -295,22 +293,6 @@ func (upf *UPF) GetInterface(interfaceType models.UpInterfaceType, dnn string) * return nil } -func (upf *UPF) GenerateTEID() (uint32, error) { - if upf.UPFStatus != AssociatedSetUpSuccess { - err := fmt.Errorf("this upf not associate with smf") - return 0, err - } - - var id uint32 - if tmpID, err := upf.teidGenerator.Allocate(); err != nil { - return 0, err - } else { - id = uint32(tmpID) - } - - return id, nil -} - func (upf *UPF) PFCPAddr() *net.UDPAddr { return &net.UDPAddr{ IP: upf.NodeID.ResolveNodeIdToIp(), From 35c324a415eb428f0d0840289f0ba92cc21e2190 Mon Sep 17 00:00:00 2001 From: Tim Liu Date: Wed, 27 Mar 2024 16:04:26 +0000 Subject: [PATCH 08/15] update pkg hash --- go.mod | 8 ++++---- go.sum | 21 ++++++++------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index 3220038d..a977ac7a 100644 --- a/go.mod +++ b/go.mod @@ -7,11 +7,11 @@ require ( github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/davecgh/go-spew v1.1.1 github.com/free5gc/aper v1.0.5 - github.com/free5gc/nas v1.1.2 - github.com/free5gc/ngap v1.0.7 - github.com/free5gc/openapi v1.0.7 + github.com/free5gc/nas v1.1.3 + github.com/free5gc/ngap v1.0.8 + github.com/free5gc/openapi v1.0.8 github.com/free5gc/pfcp v1.0.7 - github.com/free5gc/util v1.0.5 + github.com/free5gc/util v1.0.6 github.com/gin-gonic/gin v1.9.1 github.com/google/uuid v1.3.0 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 diff --git a/go.sum b/go.sum index 1700e124..7d38e597 100644 --- a/go.sum +++ b/go.sum @@ -63,22 +63,20 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= -github.com/free5gc/aper v1.0.5-0.20230614030933-c73735898582/go.mod h1:ybHxhYnRqQ9wD4yB9r/3MZdbCYCjtqUyfLpSnJpwWd4= github.com/free5gc/aper v1.0.5 h1:sUYFFmOXDLjyL4rU6zFnq81M4YluqP90Pso5e/J4UhA= github.com/free5gc/aper v1.0.5/go.mod h1:ybHxhYnRqQ9wD4yB9r/3MZdbCYCjtqUyfLpSnJpwWd4= -github.com/free5gc/nas v1.1.2 h1:BB31Crg8XyYwwAGPQbsyoMiMw7nrf8iZI3/ZY6ArPYE= -github.com/free5gc/nas v1.1.2/go.mod h1:aWQK2lvv//0mkEhavMPtx04Z5uom6eQfSse62ZCA3YA= -github.com/free5gc/ngap v1.0.7 h1:9VCFVptF7oEc+K/XwEjpH2MFi37SKOjsCGkZh7qp6bA= -github.com/free5gc/ngap v1.0.7/go.mod h1:03jSQMwwdFmtkYwS4gXP6SlftVZrOeMcdzOReh18hwE= -github.com/free5gc/openapi v1.0.6/go.mod h1:iw/N0E+FlX44EEx24IBi2EdZW8v+bkj3ETWPGnlK9DI= -github.com/free5gc/openapi v1.0.7 h1:I0HOgqRgER6DbyqB6EBxusmbeouIhcOn4eOJvL3veJA= -github.com/free5gc/openapi v1.0.7/go.mod h1:qv9KqEucoZSeENPRFGxfTe+33ZWYyiYFx1Rj+H0DoWA= +github.com/free5gc/nas v1.1.3 h1:eYkvT8GGieD06MExw3JLeIPA88Yg89DFjptVBnadIyQ= +github.com/free5gc/nas v1.1.3/go.mod h1:PMyj7SQ6+JWHie/ESmy6pZJrYMlqNxowAgCnrZNyvoI= +github.com/free5gc/ngap v1.0.8 h1:ffzSJW26qbZolwbL8yIjrCoEn7PUc/VE91f/zjJIFMs= +github.com/free5gc/ngap v1.0.8/go.mod h1:d5u7tYsBwxmLr3zw7wyBruRjc/gbdsHVhmdGFnVmfBU= +github.com/free5gc/openapi v1.0.8 h1:QjfQdB6VVA1GRnzOJ7nILzrI7gMiY0lH64JHVW7vF34= +github.com/free5gc/openapi v1.0.8/go.mod h1:w6y9P/uySczc1d9OJZAEuB2FImR/z60Wg2BekPAVt3M= github.com/free5gc/pfcp v1.0.7 h1:20/4PGok8Ihy+NfYQzic39zVq3ZB4/gdZhDO1676TMQ= github.com/free5gc/pfcp v1.0.7/go.mod h1:57l3+7h2o1Sg8vbgl0kflROwuEQltx2VbULLrV9F1Ts= github.com/free5gc/tlv v1.0.2 h1:gb7PRbJFrYXlbqIKk0t3XuxJNecc4A7X2Y+CXS/FzEM= github.com/free5gc/tlv v1.0.2/go.mod h1:maEgHMIoJBYlRxVSrhiYzsKHyVh4d4pV0yl86DuTbv8= -github.com/free5gc/util v1.0.5 h1:MjyEIX6gGbdS8FUAOxhE0FsMD6pmv5T+45LjBabVhS8= -github.com/free5gc/util v1.0.5/go.mod h1:jgiW/bNbNbX87CSTKXyfvkhQeDY9ThK+TtWTu4ILCS8= +github.com/free5gc/util v1.0.6 h1:dBt9drcXtYKE/cY5XuQcuffgsYclPIpIArhSeS6M+DQ= +github.com/free5gc/util v1.0.6/go.mod h1:eSGN7POUM8LNTvg/E591XR6447a6/w1jFWGKNZPHcXw= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -186,7 +184,6 @@ github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -334,7 +331,6 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= @@ -557,7 +553,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 753c8dca99037dc49baab96cccfae08302e4ac1c Mon Sep 17 00:00:00 2001 From: "CTFang@WireLab" Date: Tue, 2 Apr 2024 09:11:09 +0000 Subject: [PATCH 09/15] feat: UserPlanInfo OAM service --- internal/sbi/oam/api_get_smf_config.go | 13 +++++++++++++ internal/sbi/oam/routers.go | 6 ++++++ internal/sbi/producer/oam.go | 10 ++++++++++ 3 files changed, 29 insertions(+) create mode 100644 internal/sbi/oam/api_get_smf_config.go diff --git a/internal/sbi/oam/api_get_smf_config.go b/internal/sbi/oam/api_get_smf_config.go new file mode 100644 index 00000000..9afc1db6 --- /dev/null +++ b/internal/sbi/oam/api_get_smf_config.go @@ -0,0 +1,13 @@ +package oam + +import ( + "github.com/gin-gonic/gin" + + "github.com/free5gc/smf/internal/sbi/producer" +) + +func HTTPGetSMFUserPlaneInfo(c *gin.Context) { + HTTPResponse := producer.HandleGetSMFUserPlaneInfo() + + c.JSON(HTTPResponse.Status, HTTPResponse.Body) +} diff --git a/internal/sbi/oam/routers.go b/internal/sbi/oam/routers.go index 4ec639fa..782ba96c 100644 --- a/internal/sbi/oam/routers.go +++ b/internal/sbi/oam/routers.go @@ -62,4 +62,10 @@ var routes = Routes{ "/ue-pdu-session-info/:smContextRef", HTTPGetUEPDUSessionInfo, }, + { + "Get SMF Userplane Information", + "GET", + "/user-plane-info/", + HTTPGetSMFUserPlaneInfo, + }, } diff --git a/internal/sbi/producer/oam.go b/internal/sbi/producer/oam.go index ee7da81f..4e2dd673 100644 --- a/internal/sbi/producer/oam.go +++ b/internal/sbi/producer/oam.go @@ -6,6 +6,7 @@ import ( "github.com/free5gc/openapi/models" "github.com/free5gc/smf/internal/context" + "github.com/free5gc/smf/pkg/factory" "github.com/free5gc/util/httpwrapper" ) @@ -54,3 +55,12 @@ func HandleOAMGetUEPDUSessionInfo(smContextRef string) *httpwrapper.Response { } return httpResponse } + +func HandleGetSMFUserPlaneInfo() *httpwrapper.Response { + httpResponse := &httpwrapper.Response{ + Header: nil, + Status: http.StatusOK, + Body: factory.SmfConfig.Configuration.UserPlaneInformation, + } + return httpResponse +} From dfe05b6515cbe834fc44f9145443dde36ba79d52 Mon Sep 17 00:00:00 2001 From: ming-hsien Date: Sat, 13 Apr 2024 13:22:04 +0000 Subject: [PATCH 10/15] chore: bump go to 1.21 Co-authored-by: pf-lin --- .github/workflows/go.yml | 6 +-- .github/workflows/golangci-lint.yml | 10 ++--- go.mod | 2 +- go.sum | 57 ----------------------------- pkg/factory/factory.go | 6 +-- pkg/service/init.go | 6 +-- 6 files changed, 15 insertions(+), 72 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 13bd9a17..47390256 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,13 +11,13 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.18', '1.21' ] + go: [ '1.21' ] name: Go ${{ matrix.go }} sample steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 1169dd43..4fdc07a5 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -14,18 +14,18 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.18' ] + go: [ '1.21' ] steps: - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run golangci-lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v4 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - version: v1.45.2 + version: v1.57.2 # Optional: working directory, useful for monorepos # working-directory: somedir diff --git a/go.mod b/go.mod index a977ac7a..c1523701 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/free5gc/smf -go 1.17 +go 1.21 require ( github.com/antihax/optional v1.0.0 diff --git a/go.sum b/go.sum index 7d38e597..2428e65e 100644 --- a/go.sum +++ b/go.sum @@ -33,7 +33,6 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1/go.mod h1:nuudZmJhzWtx2212z+pkuy7B6nkBqa+xwNXZHL1j8cg= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= @@ -62,7 +61,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/free5gc/aper v1.0.5 h1:sUYFFmOXDLjyL4rU6zFnq81M4YluqP90Pso5e/J4UhA= github.com/free5gc/aper v1.0.5/go.mod h1:ybHxhYnRqQ9wD4yB9r/3MZdbCYCjtqUyfLpSnJpwWd4= github.com/free5gc/nas v1.1.3 h1:eYkvT8GGieD06MExw3JLeIPA88Yg89DFjptVBnadIyQ= @@ -94,7 +92,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= @@ -125,7 +122,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -135,7 +131,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -160,7 +155,6 @@ github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplb github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -168,7 +162,6 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= @@ -193,7 +186,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= @@ -224,7 +216,6 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -232,7 +223,6 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tim-ywliu/nested-logrus-formatter v1.3.2 h1:jugNJ2/CNCI79SxOJCOhwUHeN3O7/7/bj+ZRGOFlCSw= github.com/tim-ywliu/nested-logrus-formatter v1.3.2/go.mod h1:oGPmcxZB65j9Wo7mCnQKSrKEJtVDqyjD666SGmyStXI= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= @@ -241,15 +231,9 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mongodb.org/mongo-driver v1.8.4/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -263,11 +247,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -300,8 +279,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -328,11 +305,6 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -350,8 +322,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -378,38 +348,15 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -425,7 +372,6 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -457,8 +403,6 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -539,7 +483,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/factory/factory.go b/pkg/factory/factory.go index 35e57da0..955a6d25 100644 --- a/pkg/factory/factory.go +++ b/pkg/factory/factory.go @@ -6,7 +6,7 @@ package factory import ( "fmt" - "io/ioutil" + "os" "github.com/asaskevich/govalidator" "gopkg.in/yaml.v2" @@ -26,7 +26,7 @@ func InitConfigFactory(f string, cfg *Config) error { f = SmfDefaultConfigPath } - if content, err := ioutil.ReadFile(f); err != nil { + if content, err := os.ReadFile(f); err != nil { return fmt.Errorf("[Factory] %+v", err) } else { logger.CfgLog.Infof("Read config from [%s]", f) @@ -43,7 +43,7 @@ func InitRoutingConfigFactory(f string, cfg *RoutingConfig) error { // Use default config path f = SmfDefaultUERoutingPath } - if content, err := ioutil.ReadFile(f); err != nil { + if content, err := os.ReadFile(f); err != nil { return err } else { logger.CfgLog.Infof("Read config from [%s]", f) diff --git a/pkg/service/init.go b/pkg/service/init.go index c612ce3c..48daa10b 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -3,7 +3,7 @@ package service import ( "context" "fmt" - "io/ioutil" + "io" "os" "os/signal" "runtime/debug" @@ -49,7 +49,7 @@ func (a *SmfApp) SetLogEnable(enable bool) { logger.MainLog.Infof("Log enable is set to [%v]", enable) if enable && logger.Log.Out == os.Stderr { return - } else if !enable && logger.Log.Out == ioutil.Discard { + } else if !enable && logger.Log.Out == io.Discard { return } @@ -57,7 +57,7 @@ func (a *SmfApp) SetLogEnable(enable bool) { if enable { logger.Log.SetOutput(os.Stderr) } else { - logger.Log.SetOutput(ioutil.Discard) + logger.Log.SetOutput(io.Discard) } } From 3231ad6e09a49eb30ad8ab2c4964eb2514539b23 Mon Sep 17 00:00:00 2001 From: ming-hsien Date: Sat, 13 Apr 2024 14:20:16 +0000 Subject: [PATCH 11/15] fix: golangci-lint error Co-authored-by: pf-lin --- cmd/main.go | 2 +- internal/context/ngap_handler.go | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 0112fc16..c46f444e 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -44,7 +44,7 @@ func main() { Usage: "Output NF log to `FILE`", }, } - rand.Seed(time.Now().UnixNano()) + rand.New(rand.NewSource(time.Now().UnixNano())) if err := app.Run(os.Args); err != nil { logger.MainLog.Errorf("SMF Run error: %v\n", err) diff --git a/internal/context/ngap_handler.go b/internal/context/ngap_handler.go index 19d5efa4..24874dcb 100644 --- a/internal/context/ngap_handler.go +++ b/internal/context/ngap_handler.go @@ -44,7 +44,6 @@ func HandlePDUSessionResourceSetupResponseTransfer(b []byte, ctx *SMContext) (er resourceSetupResponseTransfer := ngapType.PDUSessionResourceSetupResponseTransfer{} err = aper.UnmarshalWithParams(b, &resourceSetupResponseTransfer, "valueExt") - if err != nil { return err } @@ -109,7 +108,6 @@ func HandlePDUSessionResourceSetupUnsuccessfulTransfer(b []byte, ctx *SMContext) resourceSetupUnsuccessfulTransfer := ngapType.PDUSessionResourceSetupUnsuccessfulTransfer{} err = aper.UnmarshalWithParams(b, &resourceSetupUnsuccessfulTransfer, "valueExt") - if err != nil { return err } @@ -196,7 +194,6 @@ func HandlePathSwitchRequestSetupFailedTransfer(b []byte, ctx *SMContext) (err e pathSwitchRequestSetupFailedTransfer := ngapType.PathSwitchRequestSetupFailedTransfer{} err = aper.UnmarshalWithParams(b, &pathSwitchRequestSetupFailedTransfer, "valueExt") - if err != nil { return err } @@ -229,7 +226,6 @@ func HandleHandoverRequestAcknowledgeTransfer(b []byte, ctx *SMContext) (err err handoverRequestAcknowledgeTransfer := ngapType.HandoverRequestAcknowledgeTransfer{} err = aper.UnmarshalWithParams(b, &handoverRequestAcknowledgeTransfer, "valueExt") - if err != nil { return err } From a4eac497460e804bc0f414dd2f49d7db023a34b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 09:08:25 +0800 Subject: [PATCH 12/15] Bump golang.org/x/net from 0.17.0 to 0.23.0 (#102) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.17.0 to 0.23.0. - [Commits](https://github.com/golang/net/compare/v0.17.0...v0.23.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index c1523701..896431a1 100644 --- a/go.mod +++ b/go.mod @@ -59,10 +59,10 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/net v0.23.0 // indirect golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.6 // indirect google.golang.org/protobuf v1.33.0 // indirect diff --git a/go.sum b/go.sum index 2428e65e..ec1e9ba3 100644 --- a/go.sum +++ b/go.sum @@ -247,8 +247,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -305,8 +305,8 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -350,8 +350,8 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From f89bf2e89cf6bdbdbaef4223edfacccb3de6b926 Mon Sep 17 00:00:00 2001 From: CTFang Date: Thu, 2 May 2024 10:57:35 +0800 Subject: [PATCH 13/15] feat: Create commit-msg-check.yml --- .github/workflows/commit-msg-check.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/commit-msg-check.yml diff --git a/.github/workflows/commit-msg-check.yml b/.github/workflows/commit-msg-check.yml new file mode 100644 index 00000000..deac7043 --- /dev/null +++ b/.github/workflows/commit-msg-check.yml @@ -0,0 +1,15 @@ +name: 'Commit Message Check' + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + name: Conventional Commits + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: webiny/action-conventional-commits@v1.3.0 From 6769b6f3dedd0cf735a6fc2c8eb1a200cd02a00a Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Tue, 21 May 2024 15:20:45 +0800 Subject: [PATCH 14/15] fix: loss MBR in QER if flow type is a non-GBR flow --- internal/context/datapath.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/context/datapath.go b/internal/context/datapath.go index e6611dc5..c6b80fe7 100644 --- a/internal/context/datapath.go +++ b/internal/context/datapath.go @@ -847,6 +847,12 @@ func (p *DataPath) AddQoS(smContext *SMContext, qfi uint8, qos *models.QosData) ULMBR: util.BitRateTokbps(qos.MaxbrUl), DLMBR: util.BitRateTokbps(qos.MaxbrDl), } + } else { + // Non-GBR flow should follows session-AMBR + newQER.MBR = &pfcpType.MBR{ + ULMBR: util.BitRateTokbps(smContext.DnnConfiguration.SessionAmbr.Uplink), + DLMBR: util.BitRateTokbps(smContext.DnnConfiguration.SessionAmbr.Downlink), + } } qer = newQER } From 5e7392f204373c76b22e0f86af44b37e5da00082 Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Tue, 21 May 2024 07:32:59 +0000 Subject: [PATCH 15/15] fix: unit test failed --- internal/context/context.go | 6 ++++-- internal/context/sm_context.go | 3 ++- internal/context/sm_context_policy_test.go | 6 ++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/internal/context/context.go b/internal/context/context.go index 3da5ecb4..154b997a 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -87,8 +87,10 @@ type SMFContext struct { } func GenerateChargingID() int32 { - if id, err := smfContext.ChargingIDGenerator.Allocate(); err == nil { - return int32(id) + if smfContext.ChargingIDGenerator != nil { + if id, err := smfContext.ChargingIDGenerator.Allocate(); err == nil { + return int32(id) + } } return 0 } diff --git a/internal/context/sm_context.go b/internal/context/sm_context.go index e520d1b8..62aee29e 100644 --- a/internal/context/sm_context.go +++ b/internal/context/sm_context.go @@ -324,7 +324,8 @@ func NewSMContext(id string, pduSessID int32) *SMContext { smContext.ChargingInfo = make(map[uint32]*ChargingInfo) smContext.ChargingID = GenerateChargingID() - if factory.SmfConfig.Configuration != nil { + if factory.SmfConfig != nil && + factory.SmfConfig.Configuration != nil { smContext.UrrReportTime = time.Duration(factory.SmfConfig.Configuration.UrrPeriod) * time.Second smContext.UrrReportThreshold = factory.SmfConfig.Configuration.UrrThreshold logger.CtxLog.Infof("UrrPeriod: %v", smContext.UrrReportTime) diff --git a/internal/context/sm_context_policy_test.go b/internal/context/sm_context_policy_test.go index a43d3f64..b688b8fd 100644 --- a/internal/context/sm_context_policy_test.go +++ b/internal/context/sm_context_policy_test.go @@ -671,6 +671,12 @@ func TestApplyPccRules(t *testing.T) { }, } smctx.SelectedSessionRuleID = "SessRuleId-1" + smctx.DnnConfiguration = models.DnnConfiguration{ + SessionAmbr: &models.Ambr{ + Uplink: "1 Gbps", + Downlink: "1 Gbps", + }, + } err := smctx.AllocUeIP() require.NoError(t, err) err = smctx.SelectDefaultDataPath()