diff --git a/config/config.yml b/config/config.yml index 734a14ae..437be8bd 100644 --- a/config/config.yml +++ b/config/config.yml @@ -15,7 +15,7 @@ gnodeb: sd: "000001" # optional, can be removed if not used ue: - msin: "0000000120" + msin: "0000001000" key: "00112233445566778899AABBCCDDEEFF" opc: "00112233445566778899AABBCCDDEEFF" amf: "8000" diff --git a/go.mod b/go.mod index 32f068df..d2a1c883 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module my5G-RANTester go 1.21 require ( + github.com/RoaringBitmap/roaring v1.3.0 + github.com/cilium/ebpf v0.12.3 github.com/davecgh/go-spew v1.1.1 github.com/free5gc/go-gtp5gnl v1.4.5 github.com/free5gc/nas v1.1.1 @@ -12,29 +14,41 @@ require ( github.com/ishidawataru/sctp v0.0.0-20230406120618-7ff4192f6ff2 github.com/khirono/go-nl v1.0.4 github.com/khirono/go-rtnllink v1.1.1 + github.com/lorenzosaino/go-sysctl v0.3.1 github.com/mitchellh/mapstructure v1.4.2 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 + github.com/rs/zerolog v1.31.0 github.com/sirupsen/logrus v1.9.2 github.com/stretchr/testify v1.7.0 github.com/tetratelabs/wazero v1.3.0 github.com/urfave/cli/v2 v2.25.5 github.com/vishvananda/netlink v1.1.0 github.com/wmnsk/go-gtp v0.8.6 - golang.org/x/net v0.16.0 + golang.org/x/net v0.18.0 + golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c gopkg.in/yaml.v2 v2.4.0 ) require ( + github.com/BurntSushi/toml v1.2.1 // indirect github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1 // indirect github.com/antonfisher/nested-logrus-formatter v1.3.1 // indirect + github.com/bits-and-blooms/bitset v1.2.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/golang-jwt/jwt v3.2.1+incompatible // indirect github.com/khirono/go-genl v1.0.1 // indirect - github.com/kr/text v0.2.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mschoch/smat v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/vishvananda/netns v0.0.4 // indirect + github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 // indirect + golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d // indirect + golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect + golang.org/x/mod v0.6.0 // indirect + golang.org/x/tools v0.2.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + honnef.co/go/tools v0.3.2 // indirect ) diff --git a/go.sum b/go.sum index 474cd0e3..7bccf7df 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,23 @@ +github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/RoaringBitmap/roaring v1.3.0 h1:aQmu9zQxDU0uhwR8SXOH/OrqEf+X8A0LQmwW3JX8Lcg= +github.com/RoaringBitmap/roaring v1.3.0/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE= github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1 h1:+JkXLHME8vLJafGhOH4aoV2Iu8bR55nU6iKMVfYVLjY= github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1/go.mod h1:nuudZmJhzWtx2212z+pkuy7B6nkBqa+xwNXZHL1j8cg= github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= +github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= +github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -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= +github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= +github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/free5gc/go-gtp5gnl v1.4.5 h1:w4mHuEue4hwpnQdYc19C5sXmxvYLZ0s2vJyDNdmt2wk= github.com/free5gc/go-gtp5gnl v1.4.5/go.mod h1:TT5aXB90NuSPMehuIK9lV2yJFnq6Qjw37ZqNB1QAKh0= github.com/free5gc/nas v1.1.1 h1:xUsqOOrb3kH38TQCzwZY7WN6WJkIerjERNjORDtnCbo= @@ -16,10 +26,11 @@ github.com/free5gc/openapi v1.0.6 h1:ytRjU/YZRI8UhKKyfajXSyGB6s1YDFkJ1weeAGJ8LXw github.com/free5gc/openapi v1.0.6/go.mod h1:iw/N0E+FlX44EEx24IBi2EdZW8v+bkj3ETWPGnlK9DI= github.com/free5gc/util v1.0.4 h1:GxliLpjI3NHMrKck3PDfx4OLJUuBjU182sVj+zbZK50= github.com/free5gc/util v1.0.4/go.mod h1:H0DjCCEcHsdokJC7+/fowtZ85QgT6UndyaiA/NSH/LM= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -34,18 +45,33 @@ github.com/khirono/go-nl v1.0.4 h1:MKdgv6HiJyFvM5qb8r7Sy6LbcUmK4yB7542u6JM0sBE= github.com/khirono/go-nl v1.0.4/go.mod h1:PzYeSjD38fzV7mX5DuaCZvnwx2kD/o7XgHyzuJxoi7U= github.com/khirono/go-rtnllink v1.1.1 h1:VsJbbW2HbqIZ62qit5FsehxR0gnrfDp7GE9fSTqHUDY= github.com/khirono/go-rtnllink v1.1.1/go.mod h1:FqrOS6/iGjmK30oNB3snEtXXd0JRT9nJ/98/605IiO0= -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.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lorenzosaino/go-sysctl v0.3.1 h1:3phX80tdITw2fJjZlwbXQnDWs4S30beNcMbw0cn0HtY= +github.com/lorenzosaino/go-sysctl v0.3.1/go.mod h1:5grcsBRpspKknNS1qzt1eIeRDLrhpKZAtz8Fcuvs1Rc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +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.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 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/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= +github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +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/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= +github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= @@ -64,29 +90,43 @@ github.com/urfave/cli/v2 v2.25.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6f github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= -github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= +github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/wmnsk/go-gtp v0.8.6 h1:Z2lHnNlQ49jdySoWpcZPOsGPFjDb+5BQm9rO9Nn47E0= github.com/wmnsk/go-gtp v0.8.6/go.mod h1:7Ja5ik6qMx451Oa4LXdXYl53277fL/X7Ob8nCb5T6TY= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI= +golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d h1:+W8Qf4iJtMGKkyAygcKohjxTk4JPsL9DpzApJ22m5Ic= +golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= -golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c h1:3kC/TjQ+xzIblQv39bCOyRk8fbEeJcDHwbyxPUU2BpA= +golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= @@ -96,3 +136,5 @@ 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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.3.2 h1:ytYb4rOqyp1TSa2EPvNVwtPQJctSELKaMyLfqNP4+34= +honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= diff --git a/internal/cmd/gogtp5g-link/main.go b/internal/cmd/gogtp5g-link/main.go deleted file mode 100644 index ac162200..00000000 --- a/internal/cmd/gogtp5g-link/main.go +++ /dev/null @@ -1,163 +0,0 @@ -package link - -import ( - "fmt" - "net" - "os" - "path" - "sync" - "syscall" - - "github.com/free5gc/go-gtp5gnl" - "github.com/khirono/go-nl" - "github.com/khirono/go-rtnllink" -) - -func CmdDel(ifname string) error { - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_ROUTE) - if err != nil { - return err - } - defer conn.Close() - - c := nl.NewClient(conn, mux) - - err = rtnllink.Remove(c, ifname) - if err != nil { - return err - } - - return nil -} - -func CmdAdd(ifname string, role int, ip string, stopSignal chan bool) error { - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_ROUTE) - if err != nil { - return err - } - defer conn.Close() - - c := nl.NewClient(conn, mux) - - laddr, err := net.ResolveUDPAddr("udp", ip+":2152") - if err != nil { - return err - } - conn2, err := net.ListenUDP("udp", laddr) - if err != nil { - return err - } - defer conn2.Close() - f, err := conn2.File() - if err != nil { - return err - } - defer f.Close() - - linkinfo := &nl.Attr{ - Type: syscall.IFLA_LINKINFO, - Value: nl.AttrList{ - { - Type: rtnllink.IFLA_INFO_KIND, - Value: nl.AttrString("gtp5g"), - }, - { - Type: rtnllink.IFLA_INFO_DATA, - Value: nl.AttrList{ - { - Type: gtp5gnl.IFLA_FD1, - Value: nl.AttrU32(f.Fd()), - }, - { - Type: gtp5gnl.IFLA_HASHSIZE, - Value: nl.AttrU32(131072), - }, - { - Type: gtp5gnl.IFLA_ROLE, - Value: nl.AttrU32(role), - }, - }, - }, - }, - } - err = rtnllink.Create(c, ifname, linkinfo) - if err != nil { - return err - } - - err = rtnllink.Up(c, ifname) - if err != nil { - return err - } - - <-stopSignal - - return nil -} - -func usage(prog string) { - fmt.Fprintf(os.Stderr, "usage: %v [--ran]\n", prog) -} - -func main() { - prog := path.Base(os.Args[0]) - if len(os.Args) < 4 { - usage(prog) - os.Exit(1) - } - cmd := os.Args[1] - ifname := os.Args[2] - ip := os.Args[3] - var role int - if len(os.Args) > 4 && os.Args[4] == "--ran" { - role = 1 - } - - switch cmd { - case "add": - err := CmdAdd(ifname, role, ip, nil) - if err != nil { - fmt.Fprintf(os.Stderr, "%v: %v\n", prog, err) - os.Exit(1) - } - case "del": - err := CmdDel(ifname) - if err != nil { - fmt.Fprintf(os.Stderr, "%v: %v\n", prog, err) - os.Exit(1) - } - default: - fmt.Fprintf(os.Stderr, "%v: unknown command %q\n", prog, cmd) - os.Exit(1) - } -} diff --git a/internal/cmd/gogtp5g-tunnel/cmd.go b/internal/cmd/gogtp5g-tunnel/cmd.go deleted file mode 100644 index 3b6ad0a8..00000000 --- a/internal/cmd/gogtp5g-tunnel/cmd.go +++ /dev/null @@ -1,67 +0,0 @@ -package tunnel - -import ( - "strings" -) - -type CmdNode interface { - Find([]string) (CmdFunc, []string) -} - -type CmdNodeList []CmdNode - -func (nl CmdNodeList) Find(args []string) (CmdFunc, []string) { - for _, n := range nl { - f, params := n.Find(args) - if f != nil { - return f, params - } - } - return nil, args -} - -type CmdToken struct { - Name string - Desc string - Next CmdNode -} - -func (t CmdToken) Find(args []string) (CmdFunc, []string) { - if len(args) < 1 { - return nil, args - } - if !strings.HasPrefix(t.Name, args[0]) { - return nil, args - } - if t.Next == nil { - return nil, args - } - return t.Next.Find(args[1:]) -} - -type CmdFunc func([]string) error - -func (f CmdFunc) Find(args []string) (CmdFunc, []string) { - return f, args -} - -type CmdParser struct { - args []string - pos int -} - -func NewCmdParser(args []string) *CmdParser { - c := new(CmdParser) - c.args = args - c.pos = 0 - return c -} - -func (c *CmdParser) GetToken() (string, bool) { - if c.pos >= len(c.args) { - return "", false - } - tok := c.args[c.pos] - c.pos++ - return tok, true -} diff --git a/internal/cmd/gogtp5g-tunnel/cmd_far.go b/internal/cmd/gogtp5g-tunnel/cmd_far.go deleted file mode 100644 index 6e1d5a8a..00000000 --- a/internal/cmd/gogtp5g-tunnel/cmd_far.go +++ /dev/null @@ -1,361 +0,0 @@ -package tunnel - -import ( - "encoding/json" - "errors" - "fmt" - "net" - "strconv" - "sync" - "syscall" - - "github.com/free5gc/go-gtp5gnl" - "github.com/khirono/go-nl" -) - -func ParseFAROptions(args []string) ([]nl.Attr, error) { - var attrs []nl.Attr - var paramv nl.AttrList - p := NewCmdParser(args) - for { - opt, ok := p.GetToken() - if !ok { - break - } - switch opt { - case "--action": - // --action - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 8) - if err != nil { - return attrs, err - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.FAR_APPLY_ACTION, - Value: nl.AttrU16(v), - }) - case "--hdr-creation": - // --hdr-creation - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - desc, err := strconv.ParseUint(arg, 0, 16) - if err != nil { - return attrs, err - } - arg2, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - teid, err := strconv.ParseUint(arg2, 0, 32) - if err != nil { - return attrs, err - } - arg3, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - addr := net.ParseIP(arg3) - if addr == nil { - return attrs, fmt.Errorf("invalid IP address %q", arg3) - } - addr = addr.To4() - if addr == nil { - return attrs, fmt.Errorf("option value is not IPv4 %q", arg3) - } - arg4, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - port, err := strconv.ParseUint(arg4, 0, 16) - if err != nil { - return attrs, err - } - paramv = append(paramv, nl.Attr{ - Type: gtp5gnl.FORWARDING_PARAMETER_OUTER_HEADER_CREATION, - Value: nl.AttrList{ - { - Type: gtp5gnl.OUTER_HEADER_CREATION_DESCRIPTION, - Value: nl.AttrU8(desc), - }, - { - Type: gtp5gnl.OUTER_HEADER_CREATION_O_TEID, - Value: nl.AttrU32(teid), - }, - { - Type: gtp5gnl.OUTER_HEADER_CREATION_PEER_ADDR_IPV4, - Value: nl.AttrBytes(addr), - }, - { - Type: gtp5gnl.OUTER_HEADER_CREATION_PORT, - Value: nl.AttrU16(port), - }, - }, - }) - case "--fwd-policy": - // --fwd-policy - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - paramv = append(paramv, nl.Attr{ - Type: gtp5gnl.FORWARDING_PARAMETER_FORWARDING_POLICY, - Value: nl.AttrString(arg), - }) - default: - return attrs, fmt.Errorf("unknown option %q", opt) - } - } - - if len(paramv) != 0 { - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.FAR_FORWARDING_PARAMETER, - Value: paramv, - }) - } - - return attrs, nil -} - -// add far [options...] -func CmdAddFAR(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - attrs, err := ParseFAROptions(args[2:]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - return gtp5gnl.CreateFAROID(c, link, oid, attrs) -} - -// mod far [options...] -func CmdModFAR(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - attrs, err := ParseFAROptions(args[2:]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - return gtp5gnl.UpdateFAROID(c, link, oid, attrs) -} - -// delete far -func CmdDeleteFAR(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - return gtp5gnl.RemoveFAROID(c, link, oid) -} - -// get far -func CmdGetFAR(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - far, err := gtp5gnl.GetFAROID(c, link, oid) - if err != nil { - return err - } - - j, err := json.MarshalIndent(far, "", " ") - if err != nil { - return err - } - fmt.Printf("%s\n", j) - return nil -} - -// list far -func CmdListFAR(args []string) error { - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - fars, err := gtp5gnl.GetFARAll(c) - if err != nil { - return err - } - - j, err := json.MarshalIndent(fars, "", " ") - if err != nil { - return err - } - fmt.Printf("%s\n", j) - return nil -} diff --git a/internal/cmd/gogtp5g-tunnel/cmd_pdr.go b/internal/cmd/gogtp5g-tunnel/cmd_pdr.go deleted file mode 100644 index 1a4eec91..00000000 --- a/internal/cmd/gogtp5g-tunnel/cmd_pdr.go +++ /dev/null @@ -1,493 +0,0 @@ -package tunnel - -import ( - "encoding/json" - "errors" - "fmt" - "net" - "strconv" - "sync" - "syscall" - - "github.com/free5gc/go-gtp5gnl" - "github.com/khirono/go-nl" -) - -func ParsePDROptions(args []string) ([]nl.Attr, error) { - var attrs []nl.Attr - var sdfv nl.AttrList - var pdiv nl.AttrList - p := NewCmdParser(args) - for { - opt, ok := p.GetToken() - if !ok { - break - } - switch opt { - case "--pcd": - // --pcd - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 32) - if err != nil { - return attrs, err - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.PDR_PRECEDENCE, - Value: nl.AttrU32(v), - }) - case "--hdr-rm": - // --hdr-rm - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 8) - if err != nil { - return attrs, err - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.PDR_OUTER_HEADER_REMOVAL, - Value: nl.AttrU8(v), - }) - case "--far-id": - // --far-id - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 32) - if err != nil { - return attrs, err - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.PDR_FAR_ID, - Value: nl.AttrU32(v), - }) - case "--ue-ipv4": - // --ue-ipv4 - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v := net.ParseIP(arg) - if v == nil { - return attrs, fmt.Errorf("invalid IP address %q", arg) - } - v = v.To4() - if v == nil { - return attrs, fmt.Errorf("option value is not IPv4 %q", arg) - } - pdiv = append(pdiv, nl.Attr{ - Type: gtp5gnl.PDI_UE_ADDR_IPV4, - Value: nl.AttrBytes(v), - }) - case "--f-teid": - // --f-teid - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - teid, err := strconv.ParseUint(arg, 0, 32) - if err != nil { - return attrs, err - } - arg2, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - addr := net.ParseIP(arg2) - if addr == nil { - return attrs, fmt.Errorf("invalid IP address %q", arg2) - } - addr = addr.To4() - if addr == nil { - return attrs, fmt.Errorf("option value is not IPv4 %q", arg2) - } - pdiv = append(pdiv, nl.Attr{ - Type: gtp5gnl.PDI_F_TEID, - Value: nl.AttrList{ - { - Type: gtp5gnl.F_TEID_I_TEID, - Value: nl.AttrU32(teid), - }, - { - Type: gtp5gnl.F_TEID_GTPU_ADDR_IPV4, - Value: nl.AttrBytes(addr), - }, - }, - }) - case "--sdf-desp": - // --sdf-desp - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - fd, err := ParseFlowDesc(arg) - if err != nil { - return attrs, err - } - sdfv = append(sdfv, nl.Attr{ - Type: gtp5gnl.SDF_FILTER_FLOW_DESCRIPTION, - Value: fd, - }) - case "--sdf-tos-traff-cls": - // --sdf-tos-traff-cls - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 16) - if err != nil { - return attrs, err - } - sdfv = append(sdfv, nl.Attr{ - Type: gtp5gnl.SDF_FILTER_TOS_TRAFFIC_CLASS, - Value: nl.AttrU16(v), - }) - case "--sdf-scy-param-idx": - // --sdf-scy-param-idx - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 32) - if err != nil { - return attrs, err - } - sdfv = append(sdfv, nl.Attr{ - Type: gtp5gnl.SDF_FILTER_SECURITY_PARAMETER_INDEX, - Value: nl.AttrU32(v), - }) - case "--sdf-flow-label": - // --sdf-flow-label - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 32) - if err != nil { - return attrs, err - } - sdfv = append(sdfv, nl.Attr{ - Type: gtp5gnl.SDF_FILTER_FLOW_LABEL, - Value: nl.AttrU32(v), - }) - case "--sdf-id": - // --sdf-id - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 32) - if err != nil { - return attrs, err - } - sdfv = append(sdfv, nl.Attr{ - Type: gtp5gnl.SDF_FILTER_SDF_FILTER_ID, - Value: nl.AttrU32(v), - }) - case "--qer-id": - // --qer-id - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 32) - if err != nil { - return attrs, err - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.PDR_QER_ID, - Value: nl.AttrU32(v), - }) - case "--gtpu-src-ip": - // --gtpu-src-ip - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v := net.ParseIP(arg) - if v == nil { - return attrs, fmt.Errorf("invalid IP address %q", arg) - } - v = v.To4() - if v == nil { - return attrs, fmt.Errorf("option value is not IPv4 %q", arg) - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.PDR_ROLE_ADDR_IPV4, - Value: nl.AttrBytes(v), - }) - case "--buffer-usock-path": - // --buffer-usock-path - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.PDR_UNIX_SOCKET_PATH, - Value: nl.AttrString(arg), - }) - default: - return attrs, fmt.Errorf("unknown option %q", opt) - } - } - - if len(sdfv) != 0 { - pdiv = append(pdiv, nl.Attr{ - Type: gtp5gnl.PDI_SDF_FILTER, - Value: sdfv, - }) - } - - if len(pdiv) != 0 { - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.PDR_PDI, - Value: pdiv, - }) - } - - return attrs, nil -} - -// add pdr [options...] -func CmdAddPDR(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - attrs, err := ParsePDROptions(args[2:]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - return gtp5gnl.CreatePDROID(c, link, oid, attrs) -} - -// mod pdr [options...] -func CmdModPDR(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - attrs, err := ParsePDROptions(args[2:]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - return gtp5gnl.UpdatePDROID(c, link, oid, attrs) -} - -// delete pdr -func CmdDeletePDR(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - return gtp5gnl.RemovePDROID(c, link, oid) -} - -// get pdr -func CmdGetPDR(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - pdr, err := gtp5gnl.GetPDROID(c, link, oid) - if err != nil { - return err - } - - j, err := json.MarshalIndent(pdr, "", " ") - if err != nil { - return err - } - fmt.Printf("%s\n", j) - return nil -} - -// list pdr -func CmdListPDR(args []string) error { - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - pdrs, err := gtp5gnl.GetPDRAll(c) - if err != nil { - return err - } - - j, err := json.MarshalIndent(pdrs, "", " ") - if err != nil { - return err - } - fmt.Printf("%s\n", j) - return nil -} diff --git a/internal/cmd/gogtp5g-tunnel/cmd_qer.go b/internal/cmd/gogtp5g-tunnel/cmd_qer.go deleted file mode 100644 index 77a55468..00000000 --- a/internal/cmd/gogtp5g-tunnel/cmd_qer.go +++ /dev/null @@ -1,435 +0,0 @@ -package tunnel - -import ( - "encoding/json" - "errors" - "fmt" - "strconv" - "sync" - "syscall" - - "github.com/free5gc/go-gtp5gnl" - "github.com/khirono/go-nl" -) - -func ParseQEROptions(args []string) ([]nl.Attr, error) { - var attrs []nl.Attr - var mbrv nl.AttrList - var gbrv nl.AttrList - p := NewCmdParser(args) - for { - opt, ok := p.GetToken() - if !ok { - break - } - switch opt { - case "--gate-status": - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 8) - if err != nil { - return attrs, err - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.QER_GATE, - Value: nl.AttrU8(v), - }) - case "--mbr-uhigh": - return attrs, fmt.Errorf("option %q is deprecated", opt) - case "--mbr-ulow": - return attrs, fmt.Errorf("option %q is deprecated", opt) - case "--mbr-dhigh": - return attrs, fmt.Errorf("option %q is deprecated", opt) - case "--mbr-dlow": - return attrs, fmt.Errorf("option %q is deprecated", opt) - case "--gbr-uhigh": - return attrs, fmt.Errorf("option %q is deprecated", opt) - case "--gbr-ulow": - return attrs, fmt.Errorf("option %q is deprecated", opt) - case "--gbr-dhigh": - return attrs, fmt.Errorf("option %q is deprecated", opt) - case "--gbr-dlow": - return attrs, fmt.Errorf("option %q is deprecated", opt) - case "--mbr-ul": - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 40) - if err != nil { - return attrs, err - } - mbrv = append(mbrv, nl.Attr{ - Type: gtp5gnl.QER_MBR_UL_HIGH32, - Value: nl.AttrU32(v >> 8), - }) - mbrv = append(mbrv, nl.Attr{ - Type: gtp5gnl.QER_MBR_UL_LOW8, - Value: nl.AttrU8(v), - }) - case "--mbr-dl": - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 40) - if err != nil { - return attrs, err - } - mbrv = append(mbrv, nl.Attr{ - Type: gtp5gnl.QER_MBR_DL_HIGH32, - Value: nl.AttrU32(v >> 8), - }) - mbrv = append(mbrv, nl.Attr{ - Type: gtp5gnl.QER_MBR_DL_LOW8, - Value: nl.AttrU8(v), - }) - case "--gbr-ul": - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 40) - if err != nil { - return attrs, err - } - gbrv = append(gbrv, nl.Attr{ - Type: gtp5gnl.QER_GBR_UL_HIGH32, - Value: nl.AttrU32(v >> 8), - }) - gbrv = append(gbrv, nl.Attr{ - Type: gtp5gnl.QER_GBR_UL_LOW8, - Value: nl.AttrU8(v), - }) - case "--gbr-dl": - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 40) - if err != nil { - return attrs, err - } - gbrv = append(gbrv, nl.Attr{ - Type: gtp5gnl.QER_GBR_DL_HIGH32, - Value: nl.AttrU32(v >> 8), - }) - gbrv = append(gbrv, nl.Attr{ - Type: gtp5gnl.QER_GBR_DL_LOW8, - Value: nl.AttrU8(v), - }) - case "--qer-corr-id": - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 32) - if err != nil { - return attrs, err - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.QER_CORR_ID, - Value: nl.AttrU32(v), - }) - case "--rqi": - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 8) - if err != nil { - return attrs, err - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.QER_RQI, - Value: nl.AttrU8(v), - }) - case "--qfi": - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 8) - if err != nil { - return attrs, err - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.QER_QFI, - Value: nl.AttrU8(v), - }) - case "--ppi": - arg, ok := p.GetToken() - if !ok { - return attrs, fmt.Errorf("option requires argument %q", opt) - } - v, err := strconv.ParseUint(arg, 0, 8) - if err != nil { - return attrs, err - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.QER_PPI, - Value: nl.AttrU8(v), - }) - case "--rcsr": - return attrs, fmt.Errorf("option %q is deprecated", opt) - default: - return attrs, fmt.Errorf("unknown option %q", opt) - } - } - - if len(mbrv) != 0 { - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.QER_MBR, - Value: mbrv, - }) - } - if len(gbrv) != 0 { - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.QER_GBR, - Value: gbrv, - }) - } - - return attrs, nil -} - -// add qer [options...] -func CmdAddQER(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - attrs, err := ParseQEROptions(args[2:]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - return gtp5gnl.CreateQEROID(c, link, oid, attrs) -} - -// mod qer [options...] -func CmdModQER(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - attrs, err := ParseQEROptions(args[2:]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - return gtp5gnl.UpdateQEROID(c, link, oid, attrs) -} - -// delete far -func CmdDeleteQER(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - return gtp5gnl.RemoveQEROID(c, link, oid) -} - -// get qer -func CmdGetQER(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - qer, err := gtp5gnl.GetQEROID(c, link, oid) - if err != nil { - return err - } - - j, err := json.MarshalIndent(qer, "", " ") - if err != nil { - return err - } - fmt.Printf("%s\n", j) - return nil -} - -// list qer -func CmdListQER(args []string) error { - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - qers, err := gtp5gnl.GetQERAll(c) - if err != nil { - return err - } - - j, err := json.MarshalIndent(qers, "", " ") - if err != nil { - return err - } - fmt.Printf("%s\n", j) - return nil -} diff --git a/internal/cmd/gogtp5g-tunnel/cmd_urr.go b/internal/cmd/gogtp5g-tunnel/cmd_urr.go deleted file mode 100644 index cef7e7dc..00000000 --- a/internal/cmd/gogtp5g-tunnel/cmd_urr.go +++ /dev/null @@ -1,275 +0,0 @@ -package tunnel - -import ( - "encoding/json" - "errors" - "fmt" - "sync" - "syscall" - - "github.com/free5gc/go-gtp5gnl" - "github.com/khirono/go-nl" -) - -func ParseURROptions(args []string) ([]nl.Attr, error) { - var attrs []nl.Attr - p := NewCmdParser(args) - for { - opt, ok := p.GetToken() - if !ok { - break - } - switch opt { - //TODO: - } - } - - return attrs, nil -} - -// add urr [options...] -func CmdAddURR(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - attrs, err := ParseURROptions(args[2:]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - return gtp5gnl.CreateURROID(c, link, oid, attrs) -} - -// mod urr [options...] -func CmdModURR(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - attrs, err := ParseURROptions(args[2:]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - USAReports, err := gtp5gnl.UpdateURROID(c, link, oid, attrs) - - fmt.Printf("Reports: %+v\n", USAReports) - - return err -} - -// delete urr -func CmdDeleteURR(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - USAReports, err := gtp5gnl.RemoveURROID(c, link, oid) - - fmt.Printf("Reports: %+v\n", USAReports) - - return err -} - -// get urr -func CmdGetURR(args []string) error { - if len(args) < 2 { - return errors.New("too few parameter") - } - ifname := args[0] - oid, err := ParseOID(args[1]) - if err != nil { - return err - } - - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - link, err := gtp5gnl.GetLink(ifname) - if err != nil { - return err - } - - urr, err := gtp5gnl.GetURROID(c, link, oid) - if err != nil { - return err - } - - j, err := json.MarshalIndent(urr, "", " ") - if err != nil { - return err - } - fmt.Printf("%s\n", j) - return nil -} - -// list urr -func CmdListURR(args []string) error { - var wg sync.WaitGroup - mux, err := nl.NewMux() - if err != nil { - return err - } - defer func() { - mux.Close() - wg.Wait() - }() - wg.Add(1) - go func() { - mux.Serve() - wg.Done() - }() - - conn, err := nl.Open(syscall.NETLINK_GENERIC) - if err != nil { - return err - } - defer conn.Close() - - c, err := gtp5gnl.NewClient(conn, mux) - if err != nil { - return err - } - - urrs, err := gtp5gnl.GetURRAll(c) - if err != nil { - return err - } - - j, err := json.MarshalIndent(urrs, "", " ") - if err != nil { - return err - } - fmt.Printf("%s\n", j) - return nil -} diff --git a/internal/cmd/gogtp5g-tunnel/cmdtree.go b/internal/cmd/gogtp5g-tunnel/cmdtree.go deleted file mode 100644 index 40b994a5..00000000 --- a/internal/cmd/gogtp5g-tunnel/cmdtree.go +++ /dev/null @@ -1,109 +0,0 @@ -package tunnel - -var CmdTree = CmdNodeList{ - CmdToken{ - Name: "add", - Next: CmdNodeList{ - CmdToken{ - Name: "pdr", - Next: CmdFunc(CmdAddPDR), - }, - CmdToken{ - Name: "far", - Next: CmdFunc(CmdAddFAR), - }, - CmdToken{ - Name: "qer", - Next: CmdFunc(CmdAddQER), - }, - CmdToken{ - Name: "urr", - Next: CmdFunc(CmdAddURR), - }, - }, - }, - CmdToken{ - Name: "mod", - Next: CmdNodeList{ - CmdToken{ - Name: "pdr", - Next: CmdFunc(CmdModPDR), - }, - CmdToken{ - Name: "far", - Next: CmdFunc(CmdModFAR), - }, - CmdToken{ - Name: "qer", - Next: CmdFunc(CmdModQER), - }, - CmdToken{ - Name: "urr", - Next: CmdFunc(CmdModURR), - }, - }, - }, - CmdToken{ - Name: "delete", - Next: CmdNodeList{ - CmdToken{ - Name: "pdr", - Next: CmdFunc(CmdDeletePDR), - }, - CmdToken{ - Name: "far", - Next: CmdFunc(CmdDeleteFAR), - }, - CmdToken{ - Name: "qer", - Next: CmdFunc(CmdDeleteQER), - }, - CmdToken{ - Name: "urr", - Next: CmdFunc(CmdDeleteURR), - }, - }, - }, - CmdToken{ - Name: "get", - Next: CmdNodeList{ - CmdToken{ - Name: "pdr", - Next: CmdFunc(CmdGetPDR), - }, - CmdToken{ - Name: "far", - Next: CmdFunc(CmdGetFAR), - }, - CmdToken{ - Name: "qer", - Next: CmdFunc(CmdGetQER), - }, - CmdToken{ - Name: "urr", - Next: CmdFunc(CmdGetURR), - }, - }, - }, - CmdToken{ - Name: "list", - Next: CmdNodeList{ - CmdToken{ - Name: "pdr", - Next: CmdFunc(CmdListPDR), - }, - CmdToken{ - Name: "far", - Next: CmdFunc(CmdListFAR), - }, - CmdToken{ - Name: "qer", - Next: CmdFunc(CmdListQER), - }, - CmdToken{ - Name: "urr", - Next: CmdFunc(CmdListURR), - }, - }, - }, -} diff --git a/internal/cmd/gogtp5g-tunnel/flowdesc.go b/internal/cmd/gogtp5g-tunnel/flowdesc.go deleted file mode 100644 index 5fd61fba..00000000 --- a/internal/cmd/gogtp5g-tunnel/flowdesc.go +++ /dev/null @@ -1,231 +0,0 @@ -package tunnel - -import ( - "fmt" - "net" - "strconv" - "strings" - "unsafe" - - "github.com/free5gc/go-gtp5gnl" - "github.com/khirono/go-nl" -) - -// IPFilterRule <- action s dir s proto s 'from' s src 'to' s dst -// action <- 'permit' / 'deny' -// dir <- 'in' / 'out' -// proto <- 'ip' / digit -// src <- addr s ports? -// dst <- addr s ports? -// addr <- 'any' / 'assigned' / cidr -// cidr <- ipv4addr ('/' digit)? -// ipv4addr <- digit ('.' digit){3} -// ports <- port (',' port)* -// port <- (digit '-' digit) / digit -// digit <- [1-9][0-9]+ -// s <- ' '+ - -func ParseFlowDesc(s string) (nl.AttrList, error) { - var attrs nl.AttrList - token := strings.Fields(s) - pos := 0 - - if pos >= len(token) { - return nil, fmt.Errorf("too few fields %v", len(token)) - } - switch token[pos] { - case "permit": - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.FLOW_DESCRIPTION_ACTION, - Value: nl.AttrU8(gtp5gnl.SDF_FILTER_PERMIT), - }) - default: - return nil, fmt.Errorf("unknown action %v", token[pos]) - } - pos++ - - if pos >= len(token) { - return nil, fmt.Errorf("too few fields %v", len(token)) - } - switch token[pos] { - case "in": - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.FLOW_DESCRIPTION_DIRECTION, - Value: nl.AttrU8(gtp5gnl.SDF_FILTER_IN), - }) - case "out": - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.FLOW_DESCRIPTION_DIRECTION, - Value: nl.AttrU8(gtp5gnl.SDF_FILTER_OUT), - }) - default: - return nil, fmt.Errorf("unknown direction %v", token[pos]) - } - pos++ - - if pos >= len(token) { - return nil, fmt.Errorf("too few fields %v", len(token)) - } - var proto uint8 - switch token[pos] { - case "ip": - proto = 0xff - default: - v, err := strconv.ParseUint(token[pos], 10, 8) - if err != nil { - return nil, err - } - proto = uint8(v) - } - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.FLOW_DESCRIPTION_PROTOCOL, - Value: nl.AttrU8(proto), - }) - pos++ - - if pos >= len(token) { - return nil, fmt.Errorf("too few fields %v", len(token)) - } - if token[pos] != "from" { - return nil, fmt.Errorf("not match 'from'") - } - pos++ - - if pos >= len(token) { - return nil, fmt.Errorf("too few fields %v", len(token)) - } - src, err := ParseFlowDescIPNet(token[pos]) - if err != nil { - return nil, err - } - pos++ - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.FLOW_DESCRIPTION_SRC_IPV4, - Value: nl.AttrBytes(src.IP), - }) - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.FLOW_DESCRIPTION_SRC_MASK, - Value: nl.AttrBytes(src.Mask), - }) - - if pos >= len(token) { - return nil, fmt.Errorf("too few fields %v", len(token)) - } - sports, err := ParseFlowDescPorts(token[pos]) - if err == nil { - b := EncodePorts(sports) - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.FLOW_DESCRIPTION_SRC_PORT, - Value: nl.AttrBytes(b), - }) - pos++ - } - - if pos >= len(token) { - return nil, fmt.Errorf("too few fields %v", len(token)) - } - if token[pos] != "to" { - return nil, fmt.Errorf("not match 'to'") - } - pos++ - - if pos >= len(token) { - return nil, fmt.Errorf("too few fields %v", len(token)) - } - dst, err := ParseFlowDescIPNet(token[pos]) - if err != nil { - return nil, err - } - pos++ - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.FLOW_DESCRIPTION_DEST_IPV4, - Value: nl.AttrBytes(dst.IP), - }) - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.FLOW_DESCRIPTION_DEST_MASK, - Value: nl.AttrBytes(dst.Mask), - }) - - if pos < len(token) { - dports, err := ParseFlowDescPorts(token[pos]) - if err == nil { - b := EncodePorts(dports) - attrs = append(attrs, nl.Attr{ - Type: gtp5gnl.FLOW_DESCRIPTION_DEST_PORT, - Value: nl.AttrBytes(b), - }) - } - } - - return attrs, nil -} - -func ParseFlowDescIPNet(s string) (*net.IPNet, error) { - if s == "any" { - return &net.IPNet{ - IP: net.IPv6zero, - Mask: net.CIDRMask(0, 128), - }, nil - } - _, ipnet, err := net.ParseCIDR(s) - if err == nil { - return ipnet, nil - } - ip := net.ParseIP(s) - if ip == nil { - return nil, fmt.Errorf("invalid address %v", s) - } - v4 := ip.To4() - if v4 != nil { - ip = v4 - } - n := len(ip) * 8 - return &net.IPNet{ - IP: ip, - Mask: net.CIDRMask(n, n), - }, nil -} - -func ParseFlowDescPorts(s string) ([][]uint16, error) { - var vals [][]uint16 - for _, port := range strings.Split(s, ",") { - digit := strings.SplitN(port, "-", 2) - switch len(digit) { - case 1: - v, err := strconv.ParseUint(digit[0], 10, 16) - if err != nil { - return nil, err - } - vals = append(vals, []uint16{uint16(v)}) - case 2: - start, err := strconv.ParseUint(digit[0], 10, 16) - if err != nil { - return nil, err - } - end, err := strconv.ParseUint(digit[1], 10, 16) - if err != nil { - return nil, err - } - vals = append(vals, []uint16{uint16(start), uint16(end)}) - default: - return nil, fmt.Errorf("invalid port: %q", port) - } - } - return vals, nil -} - -func EncodePorts(ports [][]uint16) []byte { - b := make([]byte, len(ports)*4) - off := 0 - for _, p := range ports { - x := (*uint32)(unsafe.Pointer(&b[off])) - switch len(p) { - case 1: - *x = uint32(p[0])<<16 | uint32(p[0]) - case 2: - *x = uint32(p[0])<<16 | uint32(p[1]) - } - off += 4 - } - return b -} diff --git a/internal/cmd/gogtp5g-tunnel/main.go b/internal/cmd/gogtp5g-tunnel/main.go deleted file mode 100644 index cddddc4b..00000000 --- a/internal/cmd/gogtp5g-tunnel/main.go +++ /dev/null @@ -1,72 +0,0 @@ -package tunnel - -import ( - "fmt" - "os" - "path" - "strings" -) - -func usage(prog string) { - fmt.Fprintf(os.Stderr, `Usage: - %v [...] - %v - %v list - -OID format: - - or - : - -PDR Options: - --pcd - --hdr-rm - --far-id - --ue-ipv4 - --f-teid - --sdf-desp - --sdf-tos-traff-cls - --sdf-scy-param-idx - --sdf-flow-label - --sdf-id - --qer-id - --gtpu-src-ip - --buffer-usock-path - -FAR Options: - --action - --hdr-creation - --fwd-policy - -QER Options: - --gate-status - --mbr-ul - --mbr-dl - --gbr-ul - --gbr-dl - --qer-corr-id - --rqi - --qfi - --ppi -`, prog, prog, prog) -} - -func main() { - prog := path.Base(os.Args[0]) - if len(os.Args) < 3 { - usage(prog) - os.Exit(1) - } - - cmd, args := CmdTree.Find(os.Args[1:]) - if cmd == nil { - fmt.Fprintf(os.Stderr, "%v: unknown command %q\n", prog, strings.Join(os.Args[1:], " ")) - os.Exit(1) - } - - err := cmd(args) - if err != nil { - fmt.Fprintf(os.Stderr, "%v: %v\n", prog, err) - os.Exit(1) - } -} diff --git a/internal/cmd/gogtp5g-tunnel/oid.go b/internal/cmd/gogtp5g-tunnel/oid.go deleted file mode 100644 index a08642cb..00000000 --- a/internal/cmd/gogtp5g-tunnel/oid.go +++ /dev/null @@ -1,29 +0,0 @@ -package tunnel - -import ( - "strconv" - "strings" - - "github.com/free5gc/go-gtp5gnl" -) - -// oid <- (seid ':' id) / id -func ParseOID(s string) (gtp5gnl.OID, error) { - i := strings.IndexRune(s, ':') - if i == -1 { - id, err := strconv.ParseUint(s, 10, 32) - if err != nil { - return nil, err - } - return gtp5gnl.OID{id}, nil - } - seid, err := strconv.ParseUint(s[:i], 10, 64) - if err != nil { - return nil, err - } - id, err := strconv.ParseUint(s[i+1:], 10, 32) - if err != nil { - return nil, err - } - return gtp5gnl.OID{seid, id}, nil -} diff --git a/internal/cmd/gogtp5g-tunnel/oid_test.go b/internal/cmd/gogtp5g-tunnel/oid_test.go deleted file mode 100644 index 9ab53521..00000000 --- a/internal/cmd/gogtp5g-tunnel/oid_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package tunnel - -import ( - "testing" - - "github.com/free5gc/go-gtp5gnl" -) - -func TestParseOID(t *testing.T) { - cases := []struct { - name string - s string - oid gtp5gnl.OID - wantErr bool - }{ - { - s: "456", - oid: gtp5gnl.OID{456}, - }, - { - s: "123:456", - oid: gtp5gnl.OID{123, 456}, - }, - { - s: "a", - wantErr: true, - }, - { - s: "123:a", - wantErr: true, - }, - { - s: "a:456", - wantErr: true, - }, - { - s: ":456", - wantErr: true, - }, - { - s: "123:", - wantErr: true, - }, - { - s: ":", - wantErr: true, - }, - { - s: "", - wantErr: true, - }, - } - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - oid, err := ParseOID(tc.s) - if err != nil { - if !tc.wantErr { - t.Fatal(err) - } - return - } - if !tc.oid.Equal(oid) { - t.Errorf("want %v; but got %v\n", tc.oid, oid) - } - }) - } -} diff --git a/internal/control_test_engine/ue/gtp/service/service.go b/internal/control_test_engine/ue/gtp/service/service.go index 7055c65d..11ed0838 100644 --- a/internal/control_test_engine/ue/gtp/service/service.go +++ b/internal/control_test_engine/ue/gtp/service/service.go @@ -5,22 +5,25 @@ package service import ( + "encoding/binary" "fmt" - gtpLink "my5G-RANTester/internal/cmd/gogtp5g-link" - gtpTunnel "my5G-RANTester/internal/cmd/gogtp5g-tunnel" gnbContext "my5G-RANTester/internal/control_test_engine/gnb/context" "my5G-RANTester/internal/control_test_engine/ue/context" - - log "github.com/sirupsen/logrus" - "github.com/vishvananda/netlink" - + "my5G-RANTester/lib/eupf/ebpf" "net" + "os/exec" "strconv" - "strings" "time" + "unsafe" + + "github.com/cilium/ebpf/link" + "github.com/lorenzosaino/go-sysctl" + log "github.com/sirupsen/logrus" + "github.com/vishvananda/netlink" ) func SetupGtpInterface(ue *context.UEContext, msg gnbContext.UEMessage) { + gnbPduSession := msg.GNBPduSessions[0] pduSession, err := ue.GetPduSession(uint8(gnbPduSession.GetPduSessionId())) pduSession.GnbPduSession = gnbPduSession @@ -34,67 +37,68 @@ func SetupGtpInterface(ue *context.UEContext, msg gnbContext.UEMessage) { return } - if pduSession.Id != 1 { - log.Warn("[GNB][GTP] Only one tunnel per UE is supported for now, no tunnel will be created for second PDU Session of given UE") - return + if err := ebpf.IncreaseResourceLimits(); err != nil { + log.Fatalf("Can't increase resource limits: %s", err.Error()) } - // get UE GNB IP. - pduSession.SetGnbIp(net.ParseIP(msg.GnbIp)) + bpfObjects := ebpf.NewBpfObjects() + if err := bpfObjects.Load(); err != nil { + log.Fatalf("Loading bpf objects failed: %s", err.Error()) + } - ueGnbIp := pduSession.GetGnbIp() - upfIp := pduSession.GnbPduSession.GetUpfIp() - ueIp := pduSession.GetIp() - msin := ue.GetMsin() - nameInf := fmt.Sprintf("val%s", msin) - vrfInf := fmt.Sprintf("vrf%s", msin) - stopSignal := make(chan bool) + /*if err := bpfObjects.ResizeAllMaps(1024, 1024, 1024); err != nil { + log.Fatalf("Resizing bpf objects failed: %s", err.Error()) + }*/ + + if err := sysctl.Set("net.ipv4.ip_forward", "1"); err != nil { + log.Fatalf("Unable to enable IP forwarding: %s", err.Error()) + } - _ = gtpLink.CmdDel(nameInf) + tableId, _ := strconv.ParseInt(fmt.Sprint(gnbPduSession.GetTeidUplink()), 10, 32) + ueVrfInf := fmt.Sprintf("vrf%s", ue.GetMsin()) + ueIp := pduSession.GetIp() - go func() { - // This function should not return as long as the GTP-U UDP socket is open - if err := gtpLink.CmdAdd(nameInf, 1, ueGnbIp.String(), stopSignal); err != nil { - log.Fatal("[GNB][GTP] Unable to create Kernel GTP interface: ", err, msin, nameInf) - return + /* + ueTunInf := fmt.Sprintf("ue%s", ue.GetMsin()) + ueTunDevice := &netlink.Tuntap{ + LinkAttrs: netlink.LinkAttrs{ + Name: ueTunInf, + MTU: 1400, + }, + Mode: netlink.TUNTAP_MODE_TAP, } - }() - - pduSession.SetStopSignal(stopSignal) - time.Sleep(time.Second) + if err := netlink.LinkDel(ueTunDevice); err != nil { + log.Warn("[UE][DATA] Unable to delete tun for UE", err) + } - cmdAddFar := []string{nameInf, "1", "--action", "2"} - log.Debug("[UE][GTP] Setting up GTP Forwarding Action Rule for ", strings.Join(cmdAddFar, " ")) - if err := gtpTunnel.CmdAddFAR(cmdAddFar); err != nil { - log.Fatal("[GNB][GTP] Unable to create FAR: ", err) - return - } + if err := netlink.LinkAdd(ueTunDevice); err != nil { + log.Fatal("[UE][DATA] Unable to create tun for UE", err) + return + } + ueTunDevice2, _ := netlink.LinkByName(ueTunInf) - cmdAddFar = []string{nameInf, "2", "--action", "2", "--hdr-creation", "0", fmt.Sprint(gnbPduSession.GetTeidUplink()), upfIp, "2152"} - log.Debug("[UE][GTP] Setting up GTP Forwarding Action Rule for ", strings.Join(cmdAddFar, " ")) - if err := gtpTunnel.CmdAddFAR(cmdAddFar); err != nil { - log.Fatal("[UE][GTP] Unable to create FAR ", err) - return - } + pduSession.SetTunInterface(ueTunDevice2)*/ - cmdAddPdr := []string{nameInf, "1", "--pcd", "1", "--hdr-rm", "0", "--ue-ipv4", ueIp, "--f-teid", fmt.Sprint(gnbPduSession.GetTeidDownlink()), msg.GnbIp, "--far-id", "1"} - log.Debug("[UE][GTP] Setting up GTP Packet Detection Rule for ", strings.Join(cmdAddPdr, " ")) + netUeIp := net.ParseIP(ueIp).To4() + upfIp := net.ParseIP(pduSession.GnbPduSession.GetUpfIp()).To4() + gnbIp := net.ParseIP(msg.GnbIp).To4() - if err := gtpTunnel.CmdAddPDR(cmdAddPdr); err != nil { - log.Fatal("[GNB][GTP] Unable to create FAR: ", err) - return + ueVrfDevice := &netlink.Vrf{ + LinkAttrs: netlink.LinkAttrs{ + Name: ueVrfInf, + MTU: 1400, + }, + Table: uint32(tableId), } + _ = netlink.LinkDel(ueVrfDevice) - cmdAddPdr = []string{nameInf, "2", "--pcd", "2", "--ue-ipv4", ueIp, "--far-id", "2"} - log.Debug("[UE][GTP] Setting Up GTP Packet Detection Rule for ", strings.Join(cmdAddPdr, " ")) - if err := gtpTunnel.CmdAddPDR(cmdAddPdr); err != nil { - log.Fatal("[UE][GTP] Unable to create FAR ", err) + if err := netlink.LinkAdd(ueVrfDevice); err != nil { + log.Fatal("[UE][DATA] Unable to create VRF for UE", err) return } - netUeIp := net.ParseIP(ueIp) - // add an IP address to a link device. + // add an IP address to a n3Inf device. addrTun := &netlink.Addr{ IPNet: &net.IPNet{ IP: netUeIp.To4(), @@ -102,47 +106,36 @@ func SetupGtpInterface(ue *context.UEContext, msg gnbContext.UEMessage) { }, } - link, _ := netlink.LinkByName(nameInf) - pduSession.SetTunInterface(link) - - if err := netlink.AddrAdd(link, addrTun); err != nil { + if err := netlink.AddrAdd(ueVrfDevice, addrTun); err != nil { log.Fatal("[UE][DATA] Error in adding IP for virtual interface", err) return } - tableId, _ := strconv.Atoi(fmt.Sprint(gnbPduSession.GetTeidUplink())) - - vrfDevice := &netlink.Vrf{ - LinkAttrs: netlink.LinkAttrs{ - Name: vrfInf, - }, - Table: uint32(tableId), - } - _ = netlink.LinkDel(vrfDevice) - - if err := netlink.LinkAdd(vrfDevice); err != nil { - log.Fatal("[UE][DATA] Unable to create VRF for UE", err) - return - } + /* + if err := netlink.LinkSetUp(ueTunDevice2); err != nil { + log.Fatal("[UE][DATA] Unable to set interface vEth UP", err) + return + } - if err := netlink.LinkSetMaster(link, vrfDevice); err != nil { - log.Fatal("[UE][DATA] Unable to set GTP tunnel as slave of VRF interface", err) - return - } + if err := netlink.LinkSetMaster(ueTunDevice2, ueVrfDevice); err != nil { + log.Fatal("[UE][DATA] Unable to set vEth tunnel as slave of VRF interface", err) + return + } + */ - if err := netlink.LinkSetUp(vrfDevice); err != nil { + if err := netlink.LinkSetUp(ueVrfDevice); err != nil { log.Fatal("[UE][DATA] Unable to set interface VRF UP", err) return } - pduSession.SetVrfDevice(vrfDevice) + pduSession.SetVrfDevice(ueVrfDevice) route := &netlink.Route{ Dst: &net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)}, // default - LinkIndex: link.Attrs().Index, // dev gtp- - Scope: netlink.SCOPE_LINK, // scope link + LinkIndex: ueVrfDevice.Attrs().Index, // dev gtp- + Scope: netlink.SCOPE_LINK, // scope n3Inf Protocol: 4, // proto static Priority: 1, // metric 1 - Table: tableId, // table + Table: int(tableId), // table } if err := netlink.RouteReplace(route); err != nil { @@ -150,7 +143,154 @@ func SetupGtpInterface(ue *context.UEContext, msg gnbContext.UEMessage) { } pduSession.SetTunRoute(route) - log.Info(fmt.Sprintf("[UE][GTP] Interface %s has successfully been configured for UE %s", nameInf, ueIp)) - log.Info(fmt.Sprintf("[UE][GTP] You can do traffic for this UE using VRF %s, eg:", vrfInf)) - log.Info(fmt.Sprintf("[UE][GTP] sudo ip vrf exec %s iperf3 -c IPERF_SERVER -p PORT -t 9000", vrfInf)) + route = &netlink.Route{ + Dst: &net.IPNet{IP: netUeIp, Mask: net.CIDRMask(32, 32)}, // default + LinkIndex: ueVrfDevice.Attrs().Index, // dev gtp- + Scope: netlink.SCOPE_HOST, + Protocol: 4, // proto static + Priority: 1, // metric 1 + } + + if err := netlink.RouteReplace(route); err != nil { + log.Fatal("[GNB][GTP] Unable to create Kernel Route ", err) + } + + time.Sleep(time.Duration(100) * time.Millisecond) // Wait for MAC address to be attributed to ueVrfDevice + + links, err := netlink.LinkList() + var n3Device netlink.Link + for _, link := range links { + list, err := netlink.AddrList(link, 0) + if err != nil { + log.Fatal(err) + } + for _, ip := range list { + if ip.Contains(gnbIp) { + n3Device = link + } + if ip.Contains(netUeIp) { + + neigh := &netlink.Neigh{ + LinkIndex: ueVrfDevice.Attrs().Index, + HardwareAddr: link.Attrs().HardwareAddr, + IP: netUeIp, + State: netlink.NUD_PERMANENT, + } + + if err := netlink.NeighAdd(neigh); err != nil { + log.Fatal("[GNB][GTP] Unable to add vrf to neighbour", err) + } + } + } + } + if n3Device == nil { + log.Fatal("[UE][GTP] Unable to determine the N3 interface from ip ", gnbIp) + } + route = &netlink.Route{ + Dst: &net.IPNet{IP: gnbIp, Mask: net.CIDRMask(32, 32)}, // default + LinkIndex: n3Device.Attrs().Index, // dev gtp- + Protocol: 4, // proto static + Priority: 1, // metric 1 + } + + if err := netlink.RouteReplace(route); err != nil { + log.Fatal("[GNB][GTP] Unable to create Kernel Route ", err) + } + + //cmdAddFar := []string{nameInf, "1", "--action", "2"} + //cmdAddFar = []string{nameInf, "2", "--action", "2", "--hdr-creation", "0", fmt.Sprint(gnbPduSession.GetTeidUplink()), msg.UpfIp, "2152"} + //cmdAddPdr := []string{nameInf, "1", "--pcd", "1", "--hdr-rm", "0", "--ue-ipv4", ueIp, "--f-teid", fmt.Sprint(gnbPduSession.GetTeidDownlink()), msg.GnbIp, "--far-id", "1"} + //cmdAddPdr = []string{nameInf, "2", "--pcd", "2", "--ue-ipv4", ueIp, "--far-id", "2"} + + qer := ebpf.QerInfo{GateStatusUL: 0, GateStatusDL: 0, Qfi: 5, MaxBitrateUL: 1000000, MaxBitrateDL: 100000, StartUL: 0, StartDL: 0} + qerId, err := bpfObjects.NewQer(qer) + if err != nil { + log.Fatalf("Could not add FAR: %s", err.Error()) + } + + // Downlink + farDownlink := ebpf.FarInfo{ + Action: 2, + OuterHeaderCreation: 0, + Teid: gnbPduSession.GetTeidDownlink(), + RemoteIP: binary.LittleEndian.Uint32(upfIp), + LocalIP: binary.LittleEndian.Uint32(gnbIp), + IfIndex: uint32(n3Device.Attrs().Index), + TransportLevelMarking: 0, + } + farDownlinkId, err := bpfObjects.NewFar(farDownlink) + if err != nil { + log.Fatalf("Could not add FAR: %s", err.Error()) + } + + pdrDownlink := ebpf.PdrInfo{ + OuterHeaderRemoval: 0, + FarId: farDownlinkId, + QerId: qerId, + SdfFilter: nil, + } + + bpfObjects.PutPdrUplink(gnbPduSession.GetTeidDownlink(), pdrDownlink) + + // Uplink + farUplink := ebpf.FarInfo{ + Action: 2, + OuterHeaderCreation: 0x01, + Teid: gnbPduSession.GetTeidUplink(), + RemoteIP: binary.LittleEndian.Uint32(upfIp), + LocalIP: binary.LittleEndian.Uint32(gnbIp), + IfIndex: uint32(n3Device.Attrs().Index), + TransportLevelMarking: 0, + } + farUplinkId, err := bpfObjects.NewFar(farUplink) + if err != nil { + log.Fatalf("Could not add FAR: %s", err.Error()) + } + + pdrUplink := ebpf.IpEntrypointPdrInfo{ + OuterHeaderRemoval: 0, + FarId: farUplinkId, + QerId: qerId, + } + + bpfObjects.IpEntrypointObjects.PdrMapDownlinkIp4.Put(netUeIp.To4(), unsafe.Pointer(&pdrUplink)) + + for _, ifname := range []string{n3Device.Attrs().Name, ueVrfInf} { + AttachXdpProgram(ifname, bpfObjects) + } + log.Warn(fmt.Sprintf("[UE][GTP] You are using PacketRusher's eBPF Preview mode:")) + log.Info(fmt.Sprintf("[UE][GTP] Interface %s has successfully been configured for UE %s", ueVrfInf, ueIp)) + log.Info(fmt.Sprintf("[UE][GTP] You can do traffic for this UE using VRF %s, eg:", ueVrfInf)) + log.Info(fmt.Sprintf("[UE][GTP] sudo ip vrf exec %s iperf3 -c IPERF_SERVER -p PORT -t 9000", ueVrfInf)) +} + +func AttachXdpProgram(ifaceName string, bpfObjects *ebpf.BpfObjects) { + iface, err := net.InterfaceByName(ifaceName) + if err != nil { + log.Fatalf("Lookup network iface %q: %s", ifaceName, err.Error()) + } + + go func() { + // Attach the program. + _, err = link.AttachXDP(link.XDPOptions{ + Program: bpfObjects.UpfIpEntrypointFunc, + Interface: iface.Index, + Flags: link.XDPGenericMode, + }) + if err != nil { + log.Fatalf("Could not attach XDP program: %s", err.Error()) + } + log.Infof("Attached XDP program to iface %q (index %d)", iface.Name, iface.Index) + ch := make(chan string) + <-ch + }() + + _ = ebpf.UpfXdpActionStatistic{ + BpfObjects: bpfObjects, + } + + cmd := exec.Command("ethtool", "-K", ifaceName, "rx", "off", "tx", "off", "sg", "off", "tso", "off", "gso", "off", "gro", "off", "lro", "off") + if err = cmd.Run(); err != nil { + log.Fatal(err) + } } diff --git a/internal/templates/test-multi-ues-in-queue.go b/internal/templates/test-multi-ues-in-queue.go index e5a42f92..83f42d61 100644 --- a/internal/templates/test-multi-ues-in-queue.go +++ b/internal/templates/test-multi-ues-in-queue.go @@ -17,9 +17,6 @@ import ( ) func TestMultiUesInQueue(numUes int, tunnelEnabled bool, dedicatedGnb bool, loop bool, timeBetweenRegistration int, timeBeforeDeregistration int, timeBeforeHandover int, numPduSessions int) { - if tunnelEnabled && !dedicatedGnb { - log.Fatal("You cannot use the --tunnel option, without using the --dedicatedGnb option") - } if tunnelEnabled && timeBetweenRegistration < 500 { log.Fatal("When using the --tunnel option, --timeBetweenRegistration must be equal to at least 500 ms, or else gtp5g kernel module may crash if you create tunnels too rapidly.") } diff --git a/lib/eupf/ebpf/ipentrypoint_bpf.go b/lib/eupf/ebpf/ipentrypoint_bpf.go new file mode 100644 index 00000000..68886624 --- /dev/null +++ b/lib/eupf/ebpf/ipentrypoint_bpf.go @@ -0,0 +1,241 @@ +// Code generated by bpf2go; DO NOT EDIT. + +package ebpf + +import ( + "bytes" + _ "embed" + "fmt" + "io" + + "github.com/cilium/ebpf" +) + +type IpEntrypointFarInfo struct { + Action uint8 + OuterHeaderCreation uint8 + _ [2]byte + Teid uint32 + Remoteip uint32 + Localip uint32 + IfIndex uint32 + TransportLevelMarking uint16 + _ [2]byte +} + +type IpEntrypointIn6Addr struct{ In6U struct{ U6Addr8 [16]uint8 } } + +type IpEntrypointPdrInfo struct { + FarId uint32 + QerId uint32 + OuterHeaderRemoval uint8 + SdfMode uint8 + _ [6]byte + SdfRules struct { + SdfFilter struct { + Protocol uint8 + _ [15]byte + SrcAddr struct { + Type uint8 + _ [15]byte + Ip [16]byte /* uint128 */ + Mask [16]byte /* uint128 */ + } + SrcPort struct { + LowerBound uint16 + UpperBound uint16 + } + _ [12]byte + DstAddr struct { + Type uint8 + _ [15]byte + Ip [16]byte /* uint128 */ + Mask [16]byte /* uint128 */ + } + DstPort struct { + LowerBound uint16 + UpperBound uint16 + } + _ [12]byte + } + OuterHeaderRemoval uint8 + _ [3]byte + FarId uint32 + QerId uint32 + _ [4]byte + } +} + +type IpEntrypointQerInfo struct { + UlGateStatus uint8 + DlGateStatus uint8 + Qfi uint8 + _ [1]byte + UlMaximumBitrate uint32 + DlMaximumBitrate uint32 + _ [4]byte + UlStart uint64 + DlStart uint64 +} + +type IpEntrypointRouteStat struct { + FibLookupIp4Cache uint64 + FibLookupIp4Ok uint64 + FibLookupIp4ErrorDrop uint64 + FibLookupIp4ErrorPass uint64 + FibLookupIp6Cache uint64 + FibLookupIp6Ok uint64 + FibLookupIp6ErrorDrop uint64 + FibLookupIp6ErrorPass uint64 +} + +type IpEntrypointUpfStatistic struct { + UpfCounters struct { + RxArp uint64 + RxIcmp uint64 + RxIcmp6 uint64 + RxIp4 uint64 + RxIp6 uint64 + RxTcp uint64 + RxUdp uint64 + RxOther uint64 + RxGtpEcho uint64 + RxGtpPdu uint64 + RxGtpOther uint64 + RxGtpUnexp uint64 + } + UpfN3N6Counter struct { + RxN3 uint64 + TxN3 uint64 + RxN6 uint64 + TxN6 uint64 + } + XdpActions [8]uint64 +} + +// LoadIpEntrypoint returns the embedded CollectionSpec for IpEntrypoint. +func LoadIpEntrypoint() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_IpEntrypointBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load IpEntrypoint: %w", err) + } + + return spec, err +} + +// LoadIpEntrypointObjects loads IpEntrypoint and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *IpEntrypointObjects +// *IpEntrypointPrograms +// *IpEntrypointMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func LoadIpEntrypointObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := LoadIpEntrypoint() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// IpEntrypointSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type IpEntrypointSpecs struct { + IpEntrypointProgramSpecs + IpEntrypointMapSpecs +} + +// IpEntrypointSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type IpEntrypointProgramSpecs struct { + UpfIpEntrypointFunc *ebpf.ProgramSpec `ebpf:"upf_ip_entrypoint_func"` +} + +// IpEntrypointMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type IpEntrypointMapSpecs struct { + FarMap *ebpf.MapSpec `ebpf:"far_map"` + PdrMapDownlinkIp4 *ebpf.MapSpec `ebpf:"pdr_map_downlink_ip4"` + PdrMapDownlinkIp6 *ebpf.MapSpec `ebpf:"pdr_map_downlink_ip6"` + PdrMapUplinkIp4 *ebpf.MapSpec `ebpf:"pdr_map_uplink_ip4"` + QerMap *ebpf.MapSpec `ebpf:"qer_map"` + UpfExtStat *ebpf.MapSpec `ebpf:"upf_ext_stat"` + UpfPipeline *ebpf.MapSpec `ebpf:"upf_pipeline"` + UpfRouteStat *ebpf.MapSpec `ebpf:"upf_route_stat"` +} + +// IpEntrypointObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to LoadIpEntrypointObjects or ebpf.CollectionSpec.LoadAndAssign. +type IpEntrypointObjects struct { + IpEntrypointPrograms + IpEntrypointMaps +} + +func (o *IpEntrypointObjects) Close() error { + return _IpEntrypointClose( + &o.IpEntrypointPrograms, + &o.IpEntrypointMaps, + ) +} + +// IpEntrypointMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to LoadIpEntrypointObjects or ebpf.CollectionSpec.LoadAndAssign. +type IpEntrypointMaps struct { + FarMap *ebpf.Map `ebpf:"far_map"` + PdrMapDownlinkIp4 *ebpf.Map `ebpf:"pdr_map_downlink_ip4"` + PdrMapDownlinkIp6 *ebpf.Map `ebpf:"pdr_map_downlink_ip6"` + PdrMapUplinkIp4 *ebpf.Map `ebpf:"pdr_map_uplink_ip4"` + QerMap *ebpf.Map `ebpf:"qer_map"` + UpfExtStat *ebpf.Map `ebpf:"upf_ext_stat"` + UpfPipeline *ebpf.Map `ebpf:"upf_pipeline"` + UpfRouteStat *ebpf.Map `ebpf:"upf_route_stat"` +} + +func (m *IpEntrypointMaps) Close() error { + return _IpEntrypointClose( + m.FarMap, + m.PdrMapDownlinkIp4, + m.PdrMapDownlinkIp6, + m.PdrMapUplinkIp4, + m.QerMap, + m.UpfExtStat, + m.UpfPipeline, + m.UpfRouteStat, + ) +} + +// IpEntrypointPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to LoadIpEntrypointObjects or ebpf.CollectionSpec.LoadAndAssign. +type IpEntrypointPrograms struct { + UpfIpEntrypointFunc *ebpf.Program `ebpf:"upf_ip_entrypoint_func"` +} + +func (p *IpEntrypointPrograms) Close() error { + return _IpEntrypointClose( + p.UpfIpEntrypointFunc, + ) +} + +func _IpEntrypointClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed ipentrypoint_bpf.o +var _IpEntrypointBytes []byte diff --git a/lib/eupf/ebpf/ipentrypoint_bpf.o b/lib/eupf/ebpf/ipentrypoint_bpf.o new file mode 100644 index 00000000..747ea170 Binary files /dev/null and b/lib/eupf/ebpf/ipentrypoint_bpf.o differ diff --git a/lib/eupf/ebpf/n3entrypoint_bpf.go b/lib/eupf/ebpf/n3entrypoint_bpf.go new file mode 100644 index 00000000..cc3902ee --- /dev/null +++ b/lib/eupf/ebpf/n3entrypoint_bpf.go @@ -0,0 +1,118 @@ +// Code generated by bpf2go; DO NOT EDIT. + +package ebpf + +import ( + "bytes" + _ "embed" + "fmt" + "io" + + "github.com/cilium/ebpf" +) + +// LoadN3Entrypoint returns the embedded CollectionSpec for N3Entrypoint. +func LoadN3Entrypoint() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_N3EntrypointBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load N3Entrypoint: %w", err) + } + + return spec, err +} + +// LoadN3EntrypointObjects loads N3Entrypoint and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *N3EntrypointObjects +// *N3EntrypointPrograms +// *N3EntrypointMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func LoadN3EntrypointObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := LoadN3Entrypoint() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// N3EntrypointSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type N3EntrypointSpecs struct { + N3EntrypointProgramSpecs + N3EntrypointMapSpecs +} + +// N3EntrypointSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type N3EntrypointProgramSpecs struct { + UpfN3EntrypointFunc *ebpf.ProgramSpec `ebpf:"upf_n3_entrypoint_func"` +} + +// N3EntrypointMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type N3EntrypointMapSpecs struct { + UpfPipeline *ebpf.MapSpec `ebpf:"upf_pipeline"` +} + +// N3EntrypointObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to LoadN3EntrypointObjects or ebpf.CollectionSpec.LoadAndAssign. +type N3EntrypointObjects struct { + N3EntrypointPrograms + N3EntrypointMaps +} + +func (o *N3EntrypointObjects) Close() error { + return _N3EntrypointClose( + &o.N3EntrypointPrograms, + &o.N3EntrypointMaps, + ) +} + +// N3EntrypointMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to LoadN3EntrypointObjects or ebpf.CollectionSpec.LoadAndAssign. +type N3EntrypointMaps struct { + UpfPipeline *ebpf.Map `ebpf:"upf_pipeline"` +} + +func (m *N3EntrypointMaps) Close() error { + return _N3EntrypointClose( + m.UpfPipeline, + ) +} + +// N3EntrypointPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to LoadN3EntrypointObjects or ebpf.CollectionSpec.LoadAndAssign. +type N3EntrypointPrograms struct { + UpfN3EntrypointFunc *ebpf.Program `ebpf:"upf_n3_entrypoint_func"` +} + +func (p *N3EntrypointPrograms) Close() error { + return _N3EntrypointClose( + p.UpfN3EntrypointFunc, + ) +} + +func _N3EntrypointClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed n3entrypoint_bpf.o +var _N3EntrypointBytes []byte diff --git a/lib/eupf/ebpf/n3entrypoint_bpf.o b/lib/eupf/ebpf/n3entrypoint_bpf.o new file mode 100644 index 00000000..a33d9fb8 Binary files /dev/null and b/lib/eupf/ebpf/n3entrypoint_bpf.o differ diff --git a/lib/eupf/ebpf/n6entrypoint_bpf.go b/lib/eupf/ebpf/n6entrypoint_bpf.go new file mode 100644 index 00000000..2a8bf5d9 --- /dev/null +++ b/lib/eupf/ebpf/n6entrypoint_bpf.go @@ -0,0 +1,118 @@ +// Code generated by bpf2go; DO NOT EDIT. + +package ebpf + +import ( + "bytes" + _ "embed" + "fmt" + "io" + + "github.com/cilium/ebpf" +) + +// LoadN6Entrypoint returns the embedded CollectionSpec for N6Entrypoint. +func LoadN6Entrypoint() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_N6EntrypointBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load N6Entrypoint: %w", err) + } + + return spec, err +} + +// LoadN6EntrypointObjects loads N6Entrypoint and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *N6EntrypointObjects +// *N6EntrypointPrograms +// *N6EntrypointMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func LoadN6EntrypointObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := LoadN6Entrypoint() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// N6EntrypointSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type N6EntrypointSpecs struct { + N6EntrypointProgramSpecs + N6EntrypointMapSpecs +} + +// N6EntrypointSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type N6EntrypointProgramSpecs struct { + UpfN6EntrypointFunc *ebpf.ProgramSpec `ebpf:"upf_n6_entrypoint_func"` +} + +// N6EntrypointMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type N6EntrypointMapSpecs struct { + UpfPipeline *ebpf.MapSpec `ebpf:"upf_pipeline"` +} + +// N6EntrypointObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to LoadN6EntrypointObjects or ebpf.CollectionSpec.LoadAndAssign. +type N6EntrypointObjects struct { + N6EntrypointPrograms + N6EntrypointMaps +} + +func (o *N6EntrypointObjects) Close() error { + return _N6EntrypointClose( + &o.N6EntrypointPrograms, + &o.N6EntrypointMaps, + ) +} + +// N6EntrypointMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to LoadN6EntrypointObjects or ebpf.CollectionSpec.LoadAndAssign. +type N6EntrypointMaps struct { + UpfPipeline *ebpf.Map `ebpf:"upf_pipeline"` +} + +func (m *N6EntrypointMaps) Close() error { + return _N6EntrypointClose( + m.UpfPipeline, + ) +} + +// N6EntrypointPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to LoadN6EntrypointObjects or ebpf.CollectionSpec.LoadAndAssign. +type N6EntrypointPrograms struct { + UpfN6EntrypointFunc *ebpf.Program `ebpf:"upf_n6_entrypoint_func"` +} + +func (p *N6EntrypointPrograms) Close() error { + return _N6EntrypointClose( + p.UpfN6EntrypointFunc, + ) +} + +func _N6EntrypointClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed n6entrypoint_bpf.o +var _N6EntrypointBytes []byte diff --git a/lib/eupf/ebpf/n6entrypoint_bpf.o b/lib/eupf/ebpf/n6entrypoint_bpf.o new file mode 100644 index 00000000..593cc024 Binary files /dev/null and b/lib/eupf/ebpf/n6entrypoint_bpf.o differ diff --git a/lib/eupf/ebpf/objects.go b/lib/eupf/ebpf/objects.go new file mode 100644 index 00000000..d7fb540b --- /dev/null +++ b/lib/eupf/ebpf/objects.go @@ -0,0 +1,203 @@ +package ebpf + +import ( + "errors" + "io" + "os" + + "github.com/RoaringBitmap/roaring" + "github.com/rs/zerolog/log" + + "github.com/cilium/ebpf" +) + +// +// Supported BPF_CFLAGS: +// - ENABLE_LOG: +// - enables debug output to tracepipe (`bpftool prog tracelog`) +// - ENABLE_ROUTE_CACHE +// - enable routing decision cache +// + +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cflags "$BPF_CFLAGS" -target bpf IpEntrypoint xdp/n3n6_entrypoint.c -- -I. -O2 -Wall -g +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target bpf ZeroEntrypoint xdp/zero_entrypoint.c -- -I. -O2 -Wall +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target bpf N3Entrypoint xdp/n3_entrypoint.c -- -I. -O2 -Wall +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target bpf N6Entrypoint xdp/n6_entrypoint.c -- -I. -O2 -Wall + +type BpfObjects struct { + IpEntrypointObjects + + FarIdTracker *IdTracker + QerIdTracker *IdTracker +} + +func NewBpfObjects() *BpfObjects { + return &BpfObjects{ + FarIdTracker: NewIdTracker(1024), + QerIdTracker: NewIdTracker(1024), + } +} + +func (bpfObjects *BpfObjects) Load() error { + pinPath := "/sys/fs/bpf/upf_pipeline" + if err := os.MkdirAll(pinPath, os.ModePerm); err != nil { + log.Info().Msgf("failed to create bpf fs subpath: %+v", err) + return err + } + + collectionOptions := ebpf.CollectionOptions{ + Maps: ebpf.MapOptions{ + // Pin the map to the BPF filesystem and configure the + // library to automatically re-write it in the BPF + // program, so it can be re-used if it already exists or + // create it if not + PinPath: pinPath, + }, + } + + return LoadAllObjects(&collectionOptions, + Loader{LoadIpEntrypointObjects, &bpfObjects.IpEntrypointObjects}) +} + +func (bpfObjects *BpfObjects) Close() error { + return CloseAllObjects( + &bpfObjects.IpEntrypointObjects, + ) +} + +type LoaderFunc func(obj interface{}, opts *ebpf.CollectionOptions) error +type Loader struct { + LoaderFunc + object interface{} +} + +func LoadAllObjects(opts *ebpf.CollectionOptions, loaders ...Loader) error { + for _, loader := range loaders { + if err := loader.LoaderFunc(loader.object, opts); err != nil { + return err + } + } + return nil +} + +func CloseAllObjects(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +func ResizeEbpfMap(eMap **ebpf.Map, eProg *ebpf.Program, newSize uint32) error { + mapInfo, err := (*eMap).Info() + if err != nil { + log.Info().Msgf("Failed get ebpf2 map info: %s", err) + return err + } + mapInfo.MaxEntries = newSize + // Create a new MapSpec using the information from MapInfo + mapSpec := &ebpf.MapSpec{ + Name: mapInfo.Name, + Type: mapInfo.Type, + KeySize: mapInfo.KeySize, + ValueSize: mapInfo.ValueSize, + MaxEntries: mapInfo.MaxEntries, + Flags: mapInfo.Flags, + } + if err != nil { + log.Info().Msgf("Failed to close old ebpf2 map: %s, %+v", err, *eMap) + return err + } + + // Unpin the old map + err = (*eMap).Unpin() + if err != nil { + log.Info().Msgf("Failed to unpin old ebpf2 map: %s, %+v", err, *eMap) + return err + } + + // Close the old map + err = (*eMap).Close() + if err != nil { + log.Info().Msgf("Failed to close old ebpf2 map: %s, %+v", err, *eMap) + return err + } + + // Old map will be garbage collected sometime after this point + + *eMap, err = ebpf.NewMapWithOptions(mapSpec, ebpf.MapOptions{}) + if err != nil { + log.Info().Msgf("Failed to create resized ebpf2 map: %s", err) + return err + } + err = eProg.BindMap(*eMap) + if err != nil { + log.Info().Msgf("Failed to bind resized ebpf2 map: %s", err) + return err + } + return nil +} + +func (bpfObjects *BpfObjects) ResizeAllMaps(qerMapSize uint32, farMapSize uint32, pdrMapSize uint32) error { + // QER + if err := ResizeEbpfMap(&bpfObjects.QerMap, bpfObjects.UpfIpEntrypointFunc, qerMapSize); err != nil { + log.Info().Msgf("Failed to resize qer map: %s", err) + return err + } + // FAR + if err := ResizeEbpfMap(&bpfObjects.FarMap, bpfObjects.UpfIpEntrypointFunc, farMapSize); err != nil { + log.Info().Msgf("Failed to resize far map: %s", err) + return err + } + // PDR + if err := ResizeEbpfMap(&bpfObjects.PdrMapDownlinkIp4, bpfObjects.UpfIpEntrypointFunc, pdrMapSize); err != nil { + log.Info().Msgf("Failed to resize pdr map: %s", err) + return err + } + if err := ResizeEbpfMap(&bpfObjects.PdrMapDownlinkIp6, bpfObjects.UpfIpEntrypointFunc, pdrMapSize); err != nil { + log.Info().Msgf("Failed to resize qer map: %s", err) + return err + } + if err := ResizeEbpfMap(&bpfObjects.PdrMapUplinkIp4, bpfObjects.UpfIpEntrypointFunc, pdrMapSize); err != nil { + log.Info().Msgf("Failed to resize qer map: %s", err) + return err + } + + return nil +} + +type IdTracker struct { + bitmap *roaring.Bitmap + maxSize uint32 +} + +func NewIdTracker(size uint32) *IdTracker { + newBitmap := roaring.NewBitmap() + newBitmap.Flip(0, uint64(size)) + + return &IdTracker{ + bitmap: newBitmap, + maxSize: size, + } +} + +func (t *IdTracker) GetNext() (next uint32, err error) { + + i := t.bitmap.Iterator() + if i.HasNext() { + next := i.Next() + t.bitmap.Remove(next) + return next, nil + } + + return 0, errors.New("pool is empty") +} + +func (t *IdTracker) Release(id uint32) { + if id >= t.maxSize { + return + } + + t.bitmap.Add(id) +} diff --git a/lib/eupf/ebpf/objects_test.go b/lib/eupf/ebpf/objects_test.go new file mode 100644 index 00000000..8440143d --- /dev/null +++ b/lib/eupf/ebpf/objects_test.go @@ -0,0 +1,545 @@ +// Copyright 2023 Edgecom LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ebpf + +import ( + "encoding/binary" + "errors" + "fmt" + "net" + "reflect" + "testing" + "unsafe" + + "github.com/google/gopacket" + "github.com/google/gopacket/layers" +) + +func testArp(bpfObjects *BpfObjects) error { + + packetArp := gopacket.NewSerializeBuffer() + if err := gopacket.SerializeLayers(packetArp, gopacket.SerializeOptions{}, + &layers.Ethernet{ + SrcMAC: net.HardwareAddr{1, 0, 0, 3, 0, 10}, + DstMAC: net.HardwareAddr{1, 0, 0, 3, 0, 20}, + EthernetType: layers.EthernetTypeARP, + }, + &layers.ARP{}, + ); err != nil { + return fmt.Errorf("serializing input packet failed: %v", err) + } + + bpfRet, bufOut, err := bpfObjects.UpfIpEntrypointFunc.Test(packetArp.Bytes()) + if err != nil { + return fmt.Errorf("test run failed: %v", err) + } + if bpfRet != 2 { // XDP_PASS + return fmt.Errorf("unexpected return value: %d", bpfRet) + } + if !reflect.DeepEqual(bufOut, packetArp.Bytes()) { + return errors.New("unexpected data modification") + } + + return nil +} + +func testArpBenchmark(bpfObjects *BpfObjects, repeat int) (int64, error) { + + packetArp := gopacket.NewSerializeBuffer() + if err := gopacket.SerializeLayers(packetArp, gopacket.SerializeOptions{}, + &layers.Ethernet{ + SrcMAC: net.HardwareAddr{1, 0, 0, 3, 0, 10}, + DstMAC: net.HardwareAddr{1, 0, 0, 3, 0, 20}, + EthernetType: layers.EthernetTypeARP, + }, + &layers.ARP{}, + ); err != nil { + return 0, fmt.Errorf("serializing input packet failed: %v", err) + } + + _, duration, err := bpfObjects.UpfIpEntrypointFunc.Benchmark(packetArp.Bytes(), repeat, func() {}) + if err != nil { + return 0, fmt.Errorf("benchmark run failed: %v", err) + } + + return duration.Nanoseconds(), nil +} + +func testGtpBenchmark(bpfObjects *BpfObjects, repeat int) (int64, error) { + + packet := gopacket.NewSerializeBuffer() + if err := gopacket.SerializeLayers(packet, gopacket.SerializeOptions{}, + &layers.Ethernet{ + SrcMAC: net.HardwareAddr{1, 0, 0, 3, 0, 10}, + DstMAC: net.HardwareAddr{1, 0, 0, 3, 0, 20}, + EthernetType: layers.EthernetTypeIPv4, + }, + &layers.IPv4{ + Version: 4, + DstIP: net.IP{10, 3, 0, 10}, + SrcIP: net.IP{10, 3, 0, 20}, + Protocol: layers.IPProtocolUDP, + IHL: 5, + }, + &layers.UDP{ + DstPort: 2152, + SrcPort: 2152, + }, + &layers.GTPv1U{ + Version: 1, + MessageType: 255, // GTPU_G_PDU + TEID: 1, + SequenceNumber: 0, + }, + &layers.IPv4{ + Version: 4, + DstIP: net.IP{1, 1, 1, 1}, + SrcIP: net.IP{10, 60, 0, 1}, + Protocol: layers.IPProtocolICMPv4, + IHL: 5, + }, + &layers.ICMPv4{ + TypeCode: layers.ICMPv4TypeEchoRequest, + Id: 0, + Seq: 0, + }, + ); err != nil { + return 0, fmt.Errorf("serializing input packet failed: %v", err) + } + + _, duration, err := bpfObjects.UpfIpEntrypointFunc.Benchmark(packet.Bytes(), repeat, func() {}) + if err != nil { + return 0, fmt.Errorf("benchmark run failed: %v", err) + } + + return duration.Nanoseconds(), nil +} + +func testGtpWithPDRBenchmark(bpfObjects *BpfObjects, repeat int) (int64, error) { + + teid := uint32(1) + + packet := gopacket.NewSerializeBuffer() + if err := gopacket.SerializeLayers(packet, gopacket.SerializeOptions{}, + &layers.Ethernet{ + SrcMAC: net.HardwareAddr{1, 0, 0, 3, 0, 10}, + DstMAC: net.HardwareAddr{1, 0, 0, 3, 0, 20}, + EthernetType: layers.EthernetTypeIPv4, + }, + &layers.IPv4{ + Version: 4, + DstIP: net.IP{10, 3, 0, 10}, + SrcIP: net.IP{10, 3, 0, 20}, + Protocol: layers.IPProtocolUDP, + IHL: 5, + }, + &layers.UDP{ + DstPort: 2152, + SrcPort: 2152, + }, + &layers.GTPv1U{ + Version: 1, + MessageType: 255, // GTPU_G_PDU + TEID: teid, + SequenceNumber: 0, + }, + &layers.IPv4{ + Version: 4, + DstIP: net.IP{1, 1, 1, 1}, + SrcIP: net.IP{10, 60, 0, 1}, + Protocol: layers.IPProtocolICMPv4, + IHL: 5, + }, + &layers.ICMPv4{ + TypeCode: layers.ICMPv4TypeEchoRequest, + Id: 0, + Seq: 0, + }, + ); err != nil { + return 0, fmt.Errorf("serializing input packet failed: %v", err) + } + + pdr := PdrInfo{OuterHeaderRemoval: 0, FarId: 1, QerId: 1} + far := FarInfo{Action: 2, OuterHeaderCreation: 1, RemoteIP: 1, LocalIP: 2, Teid: 2, TransportLevelMarking: 0} + qer := QerInfo{GateStatusUL: 0, GateStatusDL: 0, Qfi: 0, MaxBitrateUL: 1000000, MaxBitrateDL: 100000, StartUL: 0, StartDL: 0} + + if err := bpfObjects.FarMap.Put(uint32(1), unsafe.Pointer(&far)); err != nil { + return 0, fmt.Errorf("benchmark run failed: %v", err) + } + if err := bpfObjects.QerMap.Put(uint32(1), unsafe.Pointer(&qer)); err != nil { + return 0, fmt.Errorf("benchmark run failed: %v", err) + } + if err := bpfObjects.PdrMapUplinkIp4.Put(teid, unsafe.Pointer(&pdr)); err != nil { + return 0, fmt.Errorf("benchmark run failed: %v", err) + } + + _, duration, err := bpfObjects.UpfIpEntrypointFunc.Benchmark(packet.Bytes(), repeat, func() {}) + if err != nil { + return 0, fmt.Errorf("benchmark run failed: %v", err) + } + + return duration.Nanoseconds(), nil +} + +func testGtpEcho(bpfObjects *BpfObjects) error { + + packetArp := gopacket.NewSerializeBuffer() + if err := gopacket.SerializeLayers(packetArp, gopacket.SerializeOptions{}, + &layers.Ethernet{ + SrcMAC: net.HardwareAddr{1, 0, 0, 3, 0, 10}, + DstMAC: net.HardwareAddr{1, 0, 0, 3, 0, 20}, + EthernetType: layers.EthernetTypeIPv4, + }, + &layers.IPv4{ + Version: 4, + DstIP: net.IP{10, 3, 0, 10}, + SrcIP: net.IP{10, 3, 0, 20}, + Protocol: layers.IPProtocolUDP, + IHL: 5, + }, + &layers.UDP{ + DstPort: 2152, + SrcPort: 2152, + }, + &layers.GTPv1U{ + Version: 1, + MessageType: 1, // GTPU_ECHO_REQUEST + TEID: 0, + SequenceNumber: 0, + }, + ); err != nil { + return fmt.Errorf("serializing input packet failed: %v", err) + } + + bpfRet, bufOut, err := bpfObjects.UpfIpEntrypointFunc.Test(packetArp.Bytes()) + if err != nil { + return fmt.Errorf("test run failed: %v", err) + } + if bpfRet != 3 { // XDP_TX + return fmt.Errorf("unexpected return value: %d", bpfRet) + } + + response := gopacket.NewPacket(bufOut, layers.LayerTypeEthernet, gopacket.Default) + if gtpLayer := response.Layer(layers.LayerTypeGTPv1U); gtpLayer != nil { + gtp, _ := gtpLayer.(*layers.GTPv1U) + + if gtp.MessageType != 2 { //GTPU_ECHO_RESPONSE + return fmt.Errorf("unexpected gtp response: %d", gtp.MessageType) + } + if gtp.SequenceNumber != 0 { + return fmt.Errorf("unexpected gtp sequence: %d", gtp.SequenceNumber) + } + if gtp.TEID != 0 { + return fmt.Errorf("unexpected gtp TEID: %d", gtp.TEID) + } + } else { + return errors.New("unexpected response") + } + + return nil +} + +func testGtpWithSDFFilter(bpfObjects *BpfObjects) error { + + teid := uint32(1) + + packet := gopacket.NewSerializeBuffer() + if err := gopacket.SerializeLayers(packet, gopacket.SerializeOptions{}, + &layers.Ethernet{ + SrcMAC: net.HardwareAddr{1, 0, 0, 3, 0, 10}, + DstMAC: net.HardwareAddr{1, 0, 0, 3, 0, 20}, + EthernetType: layers.EthernetTypeIPv4, + }, + &layers.IPv4{ + Version: 4, + DstIP: net.IP{10, 3, 0, 10}, + SrcIP: net.IP{10, 3, 0, 20}, + Protocol: layers.IPProtocolUDP, + IHL: 5, + }, + &layers.UDP{ + DstPort: 2152, + SrcPort: 2152, + }, + &layers.GTPv1U{ + Version: 1, + MessageType: 255, // GTPU_G_PDU + TEID: teid, + SequenceNumber: 0, + }, + &layers.IPv4{ + Version: 4, + DstIP: net.IP{1, 1, 1, 1}, + SrcIP: net.IP{10, 60, 0, 1}, + Protocol: layers.IPProtocolICMPv4, + IHL: 5, + }, + &layers.ICMPv4{ + TypeCode: layers.ICMPv4TypeEchoRequest, + Id: 0, + Seq: 0, + }, + ); err != nil { + return fmt.Errorf("serializing input packet failed: %v", err) + } + + pdr := PdrInfo{OuterHeaderRemoval: 0, FarId: 1, QerId: 1} + farForward := FarInfo{Action: 2, OuterHeaderCreation: 1, RemoteIP: 1, LocalIP: 2, Teid: 2, TransportLevelMarking: 0} + farDrop := FarInfo{Action: 1, OuterHeaderCreation: 1, RemoteIP: 1, LocalIP: 2, Teid: 2, TransportLevelMarking: 0} + qer := QerInfo{GateStatusUL: 0, GateStatusDL: 0, Qfi: 0, MaxBitrateUL: 1000000, MaxBitrateDL: 100000, StartUL: 0, StartDL: 0} + + if err := bpfObjects.FarMap.Put(uint32(1), unsafe.Pointer(&farForward)); err != nil { + return fmt.Errorf("can't set FAR: %v", err) + } + if err := bpfObjects.FarMap.Put(uint32(2), unsafe.Pointer(&farDrop)); err != nil { + return fmt.Errorf("can't set FAR: %v", err) + } + if err := bpfObjects.QerMap.Put(uint32(1), unsafe.Pointer(&qer)); err != nil { + return fmt.Errorf("can't set QER: %v", err) + } + + if err := bpfObjects.PutPdrUplink(teid, pdr); err != nil { + return fmt.Errorf("can't set uplink PDR: %v", err) + } + + sdf := SdfFilter{ + Protocol: 1, + SrcAddress: IpWMask{Type: 1, Ip: net.IP{10, 60, 0, 1}, Mask: net.IPMask{255, 255, 255, 255}}, + DstAddress: IpWMask{Type: 1, Ip: net.IP{1, 1, 1, 1}, Mask: net.IPMask{255, 255, 255, 255}}, + SrcPortRange: PortRange{LowerBound: 0, UpperBound: 65535}, + DstPortRange: PortRange{LowerBound: 0, UpperBound: 65535}, + } + pdr.SdfFilter = &sdf + pdr.FarId = 2 + if err := bpfObjects.PutPdrUplink(teid, pdr); err != nil { + return fmt.Errorf("can't set uplink PDR: %v", err) + } + + bpfRet, _, err := bpfObjects.UpfIpEntrypointFunc.Test(packet.Bytes()) + if err != nil { + return fmt.Errorf("ebpf2 run failed: %v", err) + } + + if bpfRet != 1 { // XDP_DROP + return fmt.Errorf("unexpected return value: %d", bpfRet) + } + + return nil +} + +func testGtpExtHeader(bpfObjects *BpfObjects) error { + + teid := uint32(2) + + packet := gopacket.NewSerializeBuffer() + if err := gopacket.SerializeLayers(packet, gopacket.SerializeOptions{}, + &layers.Ethernet{ + SrcMAC: net.HardwareAddr{1, 0, 0, 3, 0, 10}, + DstMAC: net.HardwareAddr{1, 0, 0, 3, 0, 20}, + EthernetType: layers.EthernetTypeIPv4, + }, + &layers.IPv4{ + Version: 4, + SrcIP: net.IP{1, 1, 1, 1}, + DstIP: net.IP{10, 60, 0, 1}, + Protocol: layers.IPProtocolICMPv4, + IHL: 5, + }, + &layers.ICMPv4{ + TypeCode: layers.ICMPv4TypeEchoReply, + Id: 0, + Seq: 0, + }, + ); err != nil { + return fmt.Errorf("serializing input packet failed: %v", err) + } + + pdr := PdrInfo{OuterHeaderRemoval: 0, FarId: 1, QerId: 1} + farForward := FarInfo{ + Action: 2, + OuterHeaderCreation: 1, + RemoteIP: binary.LittleEndian.Uint32(net.IP{10, 3, 0, 10}), + LocalIP: binary.LittleEndian.Uint32(net.IP{10, 3, 0, 20}), + Teid: teid, + TransportLevelMarking: 0} + qer := QerInfo{GateStatusUL: 0, GateStatusDL: 0, Qfi: 5, MaxBitrateUL: 1000000, MaxBitrateDL: 100000, StartUL: 0, StartDL: 0} + + if err := bpfObjects.FarMap.Put(uint32(1), unsafe.Pointer(&farForward)); err != nil { + return fmt.Errorf("can't set FAR: %v", err) + } + if err := bpfObjects.QerMap.Put(uint32(1), unsafe.Pointer(&qer)); err != nil { + return fmt.Errorf("can't set QER: %v", err) + } + + if err := bpfObjects.PutPdrDownlink(net.IP{10, 60, 0, 1}, pdr); err != nil { + return fmt.Errorf("can't set downlink PDR: %v", err) + } + + bpfRet, bufOut, err := bpfObjects.UpfIpEntrypointFunc.Test(packet.Bytes()) + if err != nil { + return fmt.Errorf("ebpf2 run failed: %v", err) + } + + if bpfRet != 4 { // XDP_REDIRECT + return fmt.Errorf("unexpected return value: %d", bpfRet) + } + + response := gopacket.NewPacket(bufOut, layers.LayerTypeEthernet, gopacket.Default) + if gtpLayer := response.Layer(layers.LayerTypeGTPv1U); gtpLayer != nil { + gtp, _ := gtpLayer.(*layers.GTPv1U) + + if gtp.MessageType != 255 { //GTPU_G_PDU + return fmt.Errorf("unexpected gtp response: %d", gtp.MessageType) + } + if gtp.ExtensionHeaderFlag != true { + return fmt.Errorf("unexpected gtp extention flag: %t", gtp.ExtensionHeaderFlag) + } + if gtp.TEID != teid { + return fmt.Errorf("unexpected gtp TEID: %d", gtp.TEID) + } + if len(gtp.GTPExtensionHeaders) != 1 { + return fmt.Errorf("unexpected gtp extention header count: %d", len(gtp.GTPExtensionHeaders)) + } + + extHeader := gtp.GTPExtensionHeaders[0] + if extHeader.Type != 0x85 { + return fmt.Errorf("unexpected gtp extention header: %d", gtp.GTPExtensionHeaders[0].Type) + } + if len(extHeader.Content) != 2 { + return fmt.Errorf("unexpected gtp extention header len: %d", len(extHeader.Content)) + } + + if extHeader.Content[1] != 5 { + return fmt.Errorf("unexpected gtp extention header QFI: %d %d", extHeader.Content[0], extHeader.Content[1]) + } + } else { + return fmt.Errorf("unexpected response: %v", response) + } + + return nil +} + +func TestEntrypoint(t *testing.T) { + + if err := IncreaseResourceLimits(); err != nil { + t.Fatalf("Can't increase resource limits: %s", err.Error()) + } + + bpfObjects := &BpfObjects{} + + if err := bpfObjects.Load(); err != nil { + t.Fatalf("Loading bpf objects failed: %s", err.Error()) + } + + defer bpfObjects.Close() + + t.Run("Arp test", func(t *testing.T) { + err := testArp(bpfObjects) + if err != nil { + t.Fatalf("test failed: %s", err) + } + }) + + t.Run("GTP-U Echo test", func(t *testing.T) { + err := testGtpEcho(bpfObjects) + if err != nil { + t.Fatalf("test failed: %s", err) + } + }) + + t.Run("SDF filter test", func(t *testing.T) { + err := testGtpWithSDFFilter(bpfObjects) + if err != nil { + t.Fatalf("test failed: %s", err) + } + }) + + t.Run("GTP Extention Header test", func(t *testing.T) { + err := testGtpExtHeader(bpfObjects) + if err != nil { + t.Fatalf("test failed: %s", err) + } + }) + +} + +func TestEntrypointBenchmark(t *testing.T) { + + if err := IncreaseResourceLimits(); err != nil { + t.Fatalf("Can't increase resource limits: %s", err.Error()) + } + + bpfObjects := &BpfObjects{} + + if err := bpfObjects.Load(); err != nil { + t.Fatalf("Loading bpf objects failed: %s", err.Error()) + } + + defer bpfObjects.Close() + + t.Run("Arp (x1)) benchmark", func(t *testing.T) { + duration, err := testArpBenchmark(bpfObjects, 1) + if err != nil { + t.Fatalf("test failed: %s", err) + } + + t.Logf("%s result: %d ns", t.Name(), duration) + }) + + t.Run("Arp (x1000000) benchmark", func(t *testing.T) { + duration, err := testArpBenchmark(bpfObjects, 1000000) + if err != nil { + t.Fatalf("test failed: %s", err) + } + + t.Logf("%s result: %d ns", t.Name(), duration) + }) + + t.Run("Gtp (x1)) benchmark", func(t *testing.T) { + duration, err := testGtpBenchmark(bpfObjects, 1) + if err != nil { + t.Fatalf("test failed: %s", err) + } + + t.Logf("%s result: %d ns", t.Name(), duration) + }) + + t.Run("Gtp (x1000000) benchmark", func(t *testing.T) { + duration, err := testGtpBenchmark(bpfObjects, 1000000) + if err != nil { + t.Fatalf("test failed: %s", err) + } + + t.Logf("%s result: %d ns", t.Name(), duration) + }) + + t.Run("Gtp with PDR (x1)) benchmark", func(t *testing.T) { + duration, err := testGtpWithPDRBenchmark(bpfObjects, 1) + if err != nil { + t.Fatalf("test failed: %s", err) + } + + t.Logf("%s result: %d ns", t.Name(), duration) + }) + + t.Run("Gtp with PDR (x1000000) benchmark", func(t *testing.T) { + duration, err := testGtpWithPDRBenchmark(bpfObjects, 1000000) + if err != nil { + t.Fatalf("test failed: %s", err) + } + + t.Logf("%s result: %d ns", t.Name(), duration) + }) +} diff --git a/lib/eupf/ebpf/pdr.go b/lib/eupf/ebpf/pdr.go new file mode 100644 index 00000000..ef2ebf3f --- /dev/null +++ b/lib/eupf/ebpf/pdr.go @@ -0,0 +1,303 @@ +package ebpf + +import ( + "encoding/binary" + "encoding/json" + "fmt" + "net" + "unsafe" + + "github.com/cilium/ebpf" + + "github.com/rs/zerolog/log" +) + +// The BPF_ARRAY map type has no delete operation. The only way to delete an element is to replace it with a new one. + +type PdrInfo struct { + OuterHeaderRemoval uint8 + FarId uint32 + QerId uint32 + SdfFilter *SdfFilter +} + +type SdfFilter struct { + Protocol uint8 // 0: icmp, 1: ip, 2: tcp, 3: udp, 4: icmp6 + SrcAddress IpWMask + SrcPortRange PortRange + DstAddress IpWMask + DstPortRange PortRange +} + +type IpWMask struct { + Type uint8 // 0: any, 1: ip4, 2: ip6 + Ip net.IP + Mask net.IPMask +} + +type PortRange struct { + LowerBound uint16 + UpperBound uint16 +} + +func PreprocessPdrWithSdf(lookup func(interface{}, interface{}) error, key interface{}, pdrInfo PdrInfo) (IpEntrypointPdrInfo, error) { + var defaultPdr IpEntrypointPdrInfo + if err := lookup(key, &defaultPdr); err != nil { + return CombinePdrWithSdf(nil, pdrInfo), nil + } + + return CombinePdrWithSdf(&defaultPdr, pdrInfo), nil +} + +func (bpfObjects *BpfObjects) PutPdrUplink(teid uint32, pdrInfo PdrInfo) error { + log.Debug().Msgf("EBPF: Put PDR Uplink: teid=%d, pdrInfo=%+v", teid, pdrInfo) + var pdrToStore IpEntrypointPdrInfo + var err error + if pdrInfo.SdfFilter != nil { + if pdrToStore, err = PreprocessPdrWithSdf(bpfObjects.PdrMapUplinkIp4.Lookup, teid, pdrInfo); err != nil { + return err + } + } else { + pdrToStore = ToIpEntrypointPdrInfo(pdrInfo) + } + return bpfObjects.PdrMapUplinkIp4.Put(teid, unsafe.Pointer(&pdrToStore)) +} + +func (bpfObjects *BpfObjects) PutPdrDownlink(ipv4 net.IP, pdrInfo PdrInfo) error { + log.Debug().Msgf("EBPF: Put PDR Downlink: ipv4=%s, pdrInfo=%+v", ipv4, pdrInfo) + var pdrToStore IpEntrypointPdrInfo + var err error + if pdrInfo.SdfFilter != nil { + if pdrToStore, err = PreprocessPdrWithSdf(bpfObjects.PdrMapDownlinkIp4.Lookup, ipv4, pdrInfo); err != nil { + return err + } + } else { + pdrToStore = ToIpEntrypointPdrInfo(pdrInfo) + } + return bpfObjects.PdrMapDownlinkIp4.Put(ipv4, unsafe.Pointer(&pdrToStore)) +} + +func (bpfObjects *BpfObjects) UpdatePdrUplink(teid uint32, pdrInfo PdrInfo) error { + log.Debug().Msgf("EBPF: Update PDR Uplink: teid=%d, pdrInfo=%+v", teid, pdrInfo) + var pdrToStore IpEntrypointPdrInfo + var err error + if pdrInfo.SdfFilter != nil { + if pdrToStore, err = PreprocessPdrWithSdf(bpfObjects.PdrMapUplinkIp4.Lookup, teid, pdrInfo); err != nil { + return err + } + } else { + pdrToStore = ToIpEntrypointPdrInfo(pdrInfo) + } + return bpfObjects.PdrMapUplinkIp4.Update(teid, unsafe.Pointer(&pdrToStore), ebpf.UpdateExist) +} + +func (bpfObjects *BpfObjects) UpdatePdrDownlink(ipv4 net.IP, pdrInfo PdrInfo) error { + log.Debug().Msgf("EBPF: Update PDR Downlink: ipv4=%s, pdrInfo=%+v", ipv4, pdrInfo) + var pdrToStore IpEntrypointPdrInfo + var err error + if pdrInfo.SdfFilter != nil { + if pdrToStore, err = PreprocessPdrWithSdf(bpfObjects.PdrMapDownlinkIp4.Lookup, ipv4, pdrInfo); err != nil { + return err + } + } else { + pdrToStore = ToIpEntrypointPdrInfo(pdrInfo) + } + return bpfObjects.PdrMapDownlinkIp4.Update(ipv4, unsafe.Pointer(&pdrToStore), ebpf.UpdateExist) +} + +func (bpfObjects *BpfObjects) DeletePdrUplink(teid uint32) error { + log.Debug().Msgf("EBPF: Delete PDR Uplink: teid=%d", teid) + return bpfObjects.PdrMapUplinkIp4.Delete(teid) +} + +func (bpfObjects *BpfObjects) DeletePdrDownlink(ipv4 net.IP) error { + log.Debug().Msgf("EBPF: Delete PDR Downlink: ipv4=%s", ipv4) + return bpfObjects.PdrMapDownlinkIp4.Delete(ipv4) +} + +func (bpfObjects *BpfObjects) PutDownlinkPdrIp6(ipv6 net.IP, pdrInfo PdrInfo) error { + log.Debug().Msgf("EBPF: Put PDR Ipv6 Downlink: ipv6=%s, pdrInfo=%+v", ipv6, pdrInfo) + var pdrToStore IpEntrypointPdrInfo + var err error + if pdrInfo.SdfFilter != nil { + if pdrToStore, err = PreprocessPdrWithSdf(bpfObjects.PdrMapDownlinkIp6.Lookup, ipv6, pdrInfo); err != nil { + return err + } + } else { + pdrToStore = ToIpEntrypointPdrInfo(pdrInfo) + } + return bpfObjects.PdrMapDownlinkIp6.Put(ipv6, unsafe.Pointer(&pdrToStore)) +} + +func (bpfObjects *BpfObjects) UpdateDownlinkPdrIp6(ipv6 net.IP, pdrInfo PdrInfo) error { + log.Debug().Msgf("EBPF: Update PDR Ipv6 Downlink: ipv6=%s, pdrInfo=%+v", ipv6, pdrInfo) + var pdrToStore IpEntrypointPdrInfo + var err error + if pdrInfo.SdfFilter != nil { + if pdrToStore, err = PreprocessPdrWithSdf(bpfObjects.PdrMapDownlinkIp6.Lookup, ipv6, pdrInfo); err != nil { + return err + } + } else { + pdrToStore = ToIpEntrypointPdrInfo(pdrInfo) + } + return bpfObjects.PdrMapDownlinkIp6.Update(ipv6, unsafe.Pointer(&pdrToStore), ebpf.UpdateExist) +} + +func (bpfObjects *BpfObjects) DeleteDownlinkPdrIp6(ipv6 net.IP) error { + log.Debug().Msgf("EBPF: Delete PDR Ipv6 Downlink: ipv6=%s", ipv6) + return bpfObjects.PdrMapDownlinkIp6.Delete(ipv6) +} + +type FarInfo struct { + Action uint8 + OuterHeaderCreation uint8 + Teid uint32 + RemoteIP uint32 + LocalIP uint32 + IfIndex uint32 + TransportLevelMarking uint16 +} + +func (f FarInfo) MarshalJSON() ([]byte, error) { + remoteIP := make(net.IP, 4) + localIP := make(net.IP, 4) + binary.LittleEndian.PutUint32(remoteIP, f.RemoteIP) + binary.LittleEndian.PutUint32(localIP, f.LocalIP) + data := map[string]interface{}{ + "action": f.Action, + "outer_header_creation": f.OuterHeaderCreation, + "teid": f.Teid, + "remote_ip": remoteIP.String(), + "local_ip": localIP.String(), + "transport_level_marking": f.TransportLevelMarking, + } + return json.Marshal(data) +} + +func (bpfObjects *BpfObjects) NewFar(farInfo FarInfo) (uint32, error) { + internalId, err := bpfObjects.FarIdTracker.GetNext() + if err != nil { + return 0, err + } + log.Debug().Msgf("EBPF: Put FAR: internalId=%d, qerInfo=%+v", internalId, farInfo) + return internalId, bpfObjects.FarMap.Put(internalId, unsafe.Pointer(&farInfo)) +} + +func (bpfObjects *BpfObjects) UpdateFar(internalId uint32, farInfo FarInfo) error { + log.Debug().Msgf("EBPF: Update FAR: internalId=%d, farInfo=%+v", internalId, farInfo) + return bpfObjects.FarMap.Update(internalId, unsafe.Pointer(&farInfo), ebpf.UpdateExist) +} + +func (bpfObjects *BpfObjects) DeleteFar(intenalId uint32) error { + log.Debug().Msgf("EBPF: Delete FAR: intenalId=%d", intenalId) + bpfObjects.FarIdTracker.Release(intenalId) + return bpfObjects.FarMap.Update(intenalId, unsafe.Pointer(&FarInfo{}), ebpf.UpdateExist) +} + +type QerInfo struct { + GateStatusUL uint8 + GateStatusDL uint8 + Qfi uint8 + MaxBitrateUL uint32 + MaxBitrateDL uint32 + StartUL uint64 + StartDL uint64 +} + +func (bpfObjects *BpfObjects) NewQer(qerInfo QerInfo) (uint32, error) { + internalId, err := bpfObjects.QerIdTracker.GetNext() + if err != nil { + return 0, err + } + log.Debug().Msgf("EBPF: Put QER: internalId=%d, qerInfo=%+v", internalId, qerInfo) + return internalId, bpfObjects.QerMap.Put(internalId, unsafe.Pointer(&qerInfo)) +} + +func (bpfObjects *BpfObjects) UpdateQer(internalId uint32, qerInfo QerInfo) error { + log.Debug().Msgf("EBPF: Update QER: internalId=%d, qerInfo=%+v", internalId, qerInfo) + return bpfObjects.QerMap.Update(internalId, unsafe.Pointer(&qerInfo), ebpf.UpdateExist) +} + +func (bpfObjects *BpfObjects) DeleteQer(internalId uint32) error { + log.Debug().Msgf("EBPF: Delete QER: internalId=%d", internalId) + bpfObjects.QerIdTracker.Release(internalId) + return bpfObjects.QerMap.Update(internalId, unsafe.Pointer(&QerInfo{}), ebpf.UpdateExist) +} + +type ForwardingPlaneController interface { + PutPdrUplink(teid uint32, pdrInfo PdrInfo) error + PutPdrDownlink(ipv4 net.IP, pdrInfo PdrInfo) error + UpdatePdrUplink(teid uint32, pdrInfo PdrInfo) error + UpdatePdrDownlink(ipv4 net.IP, pdrInfo PdrInfo) error + DeletePdrUplink(teid uint32) error + DeletePdrDownlink(ipv4 net.IP) error + PutDownlinkPdrIp6(ipv6 net.IP, pdrInfo PdrInfo) error + UpdateDownlinkPdrIp6(ipv6 net.IP, pdrInfo PdrInfo) error + DeleteDownlinkPdrIp6(ipv6 net.IP) error + NewFar(farInfo FarInfo) (uint32, error) + UpdateFar(internalId uint32, farInfo FarInfo) error + DeleteFar(internalId uint32) error + NewQer(qerInfo QerInfo) (uint32, error) + UpdateQer(internalId uint32, qerInfo QerInfo) error + DeleteQer(internalId uint32) error +} + +func CombinePdrWithSdf(defaultPdr *IpEntrypointPdrInfo, sdfPdr PdrInfo) IpEntrypointPdrInfo { + var pdrToStore IpEntrypointPdrInfo + // Default mapping options. + if defaultPdr != nil { + pdrToStore.OuterHeaderRemoval = defaultPdr.OuterHeaderRemoval + pdrToStore.FarId = defaultPdr.FarId + pdrToStore.QerId = defaultPdr.QerId + pdrToStore.SdfMode = 2 + } else { + pdrToStore.SdfMode = 1 + } + + // SDF mapping options. + pdrToStore.SdfRules.SdfFilter.Protocol = sdfPdr.SdfFilter.Protocol + pdrToStore.SdfRules.SdfFilter.SrcAddr.Type = sdfPdr.SdfFilter.SrcAddress.Type + pdrToStore.SdfRules.SdfFilter.SrcAddr.Ip = Copy16Ip(sdfPdr.SdfFilter.SrcAddress.Ip) + pdrToStore.SdfRules.SdfFilter.SrcAddr.Mask = Copy16Ip(sdfPdr.SdfFilter.SrcAddress.Mask) + pdrToStore.SdfRules.SdfFilter.SrcPort.LowerBound = sdfPdr.SdfFilter.SrcPortRange.LowerBound + pdrToStore.SdfRules.SdfFilter.SrcPort.UpperBound = sdfPdr.SdfFilter.SrcPortRange.UpperBound + pdrToStore.SdfRules.SdfFilter.DstAddr.Type = sdfPdr.SdfFilter.DstAddress.Type + pdrToStore.SdfRules.SdfFilter.DstAddr.Ip = Copy16Ip(sdfPdr.SdfFilter.DstAddress.Ip) + pdrToStore.SdfRules.SdfFilter.DstAddr.Mask = Copy16Ip(sdfPdr.SdfFilter.DstAddress.Mask) + pdrToStore.SdfRules.SdfFilter.DstPort.LowerBound = sdfPdr.SdfFilter.DstPortRange.LowerBound + pdrToStore.SdfRules.SdfFilter.DstPort.UpperBound = sdfPdr.SdfFilter.DstPortRange.UpperBound + pdrToStore.SdfRules.OuterHeaderRemoval = sdfPdr.OuterHeaderRemoval + pdrToStore.SdfRules.FarId = sdfPdr.FarId + pdrToStore.SdfRules.QerId = sdfPdr.QerId + return pdrToStore +} + +func ToIpEntrypointPdrInfo(defaultPdr PdrInfo) IpEntrypointPdrInfo { + var pdrToStore IpEntrypointPdrInfo + pdrToStore.OuterHeaderRemoval = defaultPdr.OuterHeaderRemoval + pdrToStore.FarId = defaultPdr.FarId + pdrToStore.QerId = defaultPdr.QerId + return pdrToStore +} + +func Copy16Ip[T ~[]byte](arr T) [16]byte { + const Ipv4len = 4 + const Ipv6len = 16 + var c [Ipv6len]byte + var arrLen int + if len(arr) == Ipv4len { + arrLen = Ipv4len + } else if len(arr) == Ipv6len { + arrLen = Ipv6len + } else if len(arr) == 0 || arr == nil { + return c + } + for i := 0; i < arrLen; i++ { + c[i] = (arr)[arrLen-1-i] + } + return c +} + +func (sdfFilter *SdfFilter) String() string { + return fmt.Sprintf("%+v", *sdfFilter) +} diff --git a/lib/eupf/ebpf/stats.go b/lib/eupf/ebpf/stats.go new file mode 100644 index 00000000..f963811d --- /dev/null +++ b/lib/eupf/ebpf/stats.go @@ -0,0 +1,101 @@ +package ebpf + +import ( + "github.com/rs/zerolog/log" +) + +type UpfXdpActionStatistic struct { + BpfObjects *BpfObjects +} + +type UpfCounters struct { + RxArp uint64 + RxIcmp uint64 + RxIcmp6 uint64 + RxIp4 uint64 + RxIp6 uint64 + RxTcp uint64 + RxUdp uint64 + RxOther uint64 + RxGtpEcho uint64 + RxGtpPdu uint64 + RxGtpOther uint64 + RxGtpUnexp uint64 +} + +type UpfStatistic struct { + Counters UpfCounters + XdpStats [5]uint64 +} + +func (current *UpfCounters) Add(new UpfCounters) { + current.RxArp += new.RxArp + current.RxIcmp += new.RxIcmp + current.RxIcmp6 += new.RxIcmp6 + current.RxIp4 += new.RxIp4 + current.RxIp6 += new.RxIp6 + current.RxTcp += new.RxTcp + current.RxUdp += new.RxUdp + current.RxOther += new.RxOther + current.RxGtpEcho += new.RxGtpEcho + current.RxGtpPdu += new.RxGtpPdu + current.RxGtpOther += new.RxGtpOther +} + +// Getters for the upf_xdp_statistic (xdp_action) + +func (stat *UpfXdpActionStatistic) getUpfXdpStatisticField(field uint32) uint64 { + + var statistics []IpEntrypointUpfStatistic + err := stat.BpfObjects.UpfExtStat.Lookup(uint32(0), &statistics) + if err != nil { + log.Info().Msg(err.Error()) + return 0 + } + + var totalValue uint64 = 0 + for _, statistic := range statistics { + totalValue += statistic.XdpActions[field] + } + + return totalValue +} + +func (stat *UpfXdpActionStatistic) GetAborted() uint64 { + return stat.getUpfXdpStatisticField(uint32(0)) +} + +func (stat *UpfXdpActionStatistic) GetDrop() uint64 { + return stat.getUpfXdpStatisticField(uint32(1)) +} + +func (stat *UpfXdpActionStatistic) GetPass() uint64 { + return stat.getUpfXdpStatisticField(uint32(2)) +} + +func (stat *UpfXdpActionStatistic) GetTx() uint64 { + return stat.getUpfXdpStatisticField(uint32(3)) +} + +func (stat *UpfXdpActionStatistic) GetRedirect() uint64 { + return stat.getUpfXdpStatisticField(uint32(4)) +} + +// Getters for the upf_ext_stat (upf_counters) +// #TODO: Do not retrieve the whole struct each time. +func (stat *UpfXdpActionStatistic) GetUpfExtStatField() UpfCounters { + + var statistics []IpEntrypointUpfStatistic + var counters UpfCounters + err := stat.BpfObjects.UpfExtStat.Lookup(uint32(0), &statistics) + if err != nil { + log.Info().Msg(err.Error()) + return counters + } + + for _, statistic := range statistics { + counters.Add(statistic.UpfCounters) + } + + return counters +} diff --git a/lib/eupf/ebpf/utils.go b/lib/eupf/ebpf/utils.go new file mode 100644 index 00000000..aca6c2f7 --- /dev/null +++ b/lib/eupf/ebpf/utils.go @@ -0,0 +1,99 @@ +package ebpf + +import ( + "fmt" + "github.com/cilium/ebpf" + "golang.org/x/sys/unix" + "unsafe" +) + +// IncreaseResourceLimits https://prototype-kernel.readthedocs.io/en/latest/bpf/troubleshooting.html#memory-ulimits +func IncreaseResourceLimits() error { + return unix.Setrlimit(unix.RLIMIT_MEMLOCK, &unix.Rlimit{ + Cur: unix.RLIM_INFINITY, + Max: unix.RLIM_INFINITY, + }) +} + +// https://man7.org/linux/man-pages/man2/bpf.2.html +// A program array map is a special kind of array map whose +// map values contain only file descriptors referring to +// other eBPF programs. Thus, both the key_size and +// value_size must be exactly four bytes. +type BpfMapProgArrayMember struct { + ProgramId uint32 `json:"id"` + ProgramRef uint32 `json:"fd"` + ProgramName string `json:"name"` + ProgramRunCount uint32 `json:"run_count"` + ProgramRunCountEnabled bool `json:"run_count_enabled"` + ProgramDuration uint32 `json:"duration"` + ProgramDurationEnabled bool `json:"duration_enabled"` +} + +func ListMapProgArrayContents(m *ebpf.Map) ([]BpfMapProgArrayMember, error) { + if m.Type() != ebpf.ProgramArray { + return nil, fmt.Errorf("map is not a program array") + } + var bpfMapProgArrayMember []BpfMapProgArrayMember + var ( + key uint32 + val *ebpf.Program + ) + + iter := m.Iterate() + for iter.Next(&key, &val) { + programInfo, _ := val.Info() + programID, _ := programInfo.ID() + runCount, runCountEnabled := programInfo.RunCount() + runDuration, runDurationEnabled := programInfo.Runtime() + bpfMapProgArrayMember = append(bpfMapProgArrayMember, + BpfMapProgArrayMember{ + ProgramId: key, + ProgramRef: uint32(programID), + ProgramName: programInfo.Name, + ProgramRunCount: uint32(runCount), + ProgramRunCountEnabled: runCountEnabled, + ProgramDuration: uint32(runDuration), + ProgramDurationEnabled: runDurationEnabled, + }) + } + return bpfMapProgArrayMember, iter.Err() +} + +type QerMapElement struct { + Id uint32 `json:"id"` + GateStatusUL uint8 `json:"gate_status_ul"` + GateStatusDL uint8 `json:"gate_status_dl"` + Qfi uint8 `json:"qfi"` + MaxBitrateUL uint32 `json:"max_bitrate_ul"` + MaxBitrateDL uint32 `json:"max_bitrate_dl"` +} + +func ListQerMapContents(m *ebpf.Map) ([]QerMapElement, error) { + if m.Type() != ebpf.Array { + return nil, fmt.Errorf("map %s is not a hash", m) + } + + contextMap := make([]QerMapElement, 0) + mapInfo, _ := m.Info() + + var value QerInfo + for i := uint32(0); i < mapInfo.MaxEntries; i++ { + err := m.Lookup(i, unsafe.Pointer(&value)) + if err != nil { + return nil, err + } + contextMap = append(contextMap, + QerMapElement{ + Id: i, + GateStatusUL: value.GateStatusUL, + GateStatusDL: value.GateStatusDL, + Qfi: value.Qfi, + MaxBitrateUL: value.MaxBitrateUL, + MaxBitrateDL: value.MaxBitrateDL, + }, + ) + } + + return contextMap, nil +} diff --git a/lib/eupf/ebpf/xdp/n3_entrypoint.c b/lib/eupf/ebpf/xdp/n3_entrypoint.c new file mode 100644 index 00000000..8c4b932c --- /dev/null +++ b/lib/eupf/ebpf/xdp/n3_entrypoint.c @@ -0,0 +1,29 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "xdp/program_array.h" + +/* N3 only entrypoint. Attach to N3 interfaces only */ +SEC("xdp/upf_n3_entrypoint") +int upf_n3_entrypoint_func(struct xdp_md *ctx) { + bpf_printk("upf n3 entrypoint start\n"); + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; \ No newline at end of file diff --git a/lib/eupf/ebpf/xdp/n3n6_entrypoint.c b/lib/eupf/ebpf/xdp/n3n6_entrypoint.c new file mode 100644 index 00000000..f9b5b94e --- /dev/null +++ b/lib/eupf/ebpf/xdp/n3n6_entrypoint.c @@ -0,0 +1,487 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "xdp/program_array.h" +#include "xdp/statistics.h" +#include "xdp/qer.h" +#include "xdp/pdr.h" +#include "xdp/sdf_filter.h" + +#include "xdp/utils/common.h" +#include "xdp/utils/trace.h" +#include "xdp/utils/packet_context.h" +#include "xdp/utils/parsers.h" +#include "xdp/utils/csum.h" +#include "xdp/utils/gtp_utils.h" +#include "xdp/utils/routing.h" +#include "xdp/utils/icmp.h" + + +#define DEFAULT_XDP_ACTION XDP_PASS + + +static __always_inline enum xdp_action send_to_gtp_tunnel(struct packet_context *ctx, int srcip, int dstip, int ifindex, __u8 tos, __u8 qfi, int teid) { + if (-1 == add_gtp_over_ip4_headers(ctx, srcip, dstip, tos, qfi, teid)) + return XDP_ABORTED; + upf_printk("upf: send gtp pdu %pI4 -> %pI4", &ctx->ip4->saddr, &ctx->ip4->daddr); + increment_counter(ctx->n3_n6_counter, tx_n3); + return route_ipv4(ctx->xdp_ctx, ctx->eth, ctx->ip4, ifindex); +} + + + +static __always_inline __u16 handle_n6_packet_ipv4(struct packet_context *ctx) { + const struct iphdr *ip4 = ctx->ip4; + struct pdr_info *pdr = bpf_map_lookup_elem(&pdr_map_downlink_ip4, &ip4->saddr); + if (!pdr) { + pdr = bpf_map_lookup_elem(&pdr_map_downlink_ip4, &ip4->saddr); + if (!pdr) { + upf_printk("upf: no downlink session for ip:%pI4 %pI4", &ip4->saddr, &ip4->daddr); + return DEFAULT_XDP_ACTION; + } + } + + __u32 far_id = pdr->far_id; + __u32 qer_id = pdr->qer_id; + //__u8 outer_header_removal = pdr->outer_header_removal; + if (pdr->sdf_mode) { + struct sdf_filter *sdf = &pdr->sdf_rules.sdf_filter; + if(match_sdf_filter_ipv4(ctx, sdf)) { + upf_printk("Packet with source ip:%pI4 and destination ip:%pI4 matches SDF filter", &ip4->saddr, &ip4->daddr); + far_id = pdr->sdf_rules.far_id; + qer_id = pdr->sdf_rules.qer_id; + //outer_header_removal = pdr->sdf_rules.outer_header_removal; + } else if(pdr->sdf_mode & 1) { + return DEFAULT_XDP_ACTION; + } + } + + struct far_info *far = bpf_map_lookup_elem(&far_map, &far_id); + if (!far) { + upf_printk("upf: no downlink session far for ip:%pI4 far:%d", &ip4->daddr, far_id); + return XDP_DROP; + } + + upf_printk("upf: downlink session for ip:%pI4 far:%d action:%d", &ip4->daddr, far_id, far->outer_header_creation); + + // Only forwarding action is supported at the moment + if (!(far->action & FAR_FORW)) + return XDP_DROP; + + // Only outer header GTP/UDP/IPv4 is supported at the moment + if (!(far->outer_header_creation & OHC_GTP_U_UDP_IPv4)) + return XDP_DROP; + + struct qer_info *qer = bpf_map_lookup_elem(&qer_map, &qer_id); + if (!qer) { + upf_printk("upf: no downlink session qer for ip:%pI4 qer:%d", &ip4->daddr, qer_id); + return XDP_DROP; + } + + upf_printk("upf: qer:%d gate_status:%d mbr:%d", qer_id, qer->dl_gate_status, qer->dl_maximum_bitrate); + + if (qer->dl_gate_status != GATE_STATUS_OPEN) + return XDP_DROP; + + const __u64 packet_size = ctx->xdp_ctx->data_end - ctx->xdp_ctx->data; + if (XDP_DROP == limit_rate_sliding_window(packet_size, &qer->dl_start, qer->dl_maximum_bitrate)) + return XDP_DROP; + + __u8 tos = far->transport_level_marking >> 8; + + upf_printk("upf: use mapping %pI4 -> TEID:%d", &ip4->daddr, far->teid); + return send_to_gtp_tunnel(ctx, far->localip, far->remoteip, far->if_index, tos, qer->qfi, far->teid); +} + +static __always_inline enum xdp_action handle_n6_packet_ipv6(struct packet_context *ctx) { + const struct ipv6hdr *ip6 = ctx->ip6; + struct pdr_info *pdr = bpf_map_lookup_elem(&pdr_map_downlink_ip6, &ip6->daddr); + if (!pdr) { + upf_printk("upf: no downlink session for ip:%pI6c", &ip6->daddr); + return DEFAULT_XDP_ACTION; + } + + __u32 far_id = pdr->far_id; + __u32 qer_id = pdr->qer_id; + //__u8 outer_header_removal = pdr->outer_header_removal; + if (pdr->sdf_mode) { + struct sdf_filter *sdf = &pdr->sdf_rules.sdf_filter; + if(match_sdf_filter_ipv6(ctx, sdf)) { + upf_printk("Packet with source ip:%pI6c and destination ip:%pI6c matches SDF filter", &ip6->saddr, &ip6->daddr); + far_id = pdr->sdf_rules.far_id; + qer_id = pdr->sdf_rules.qer_id; + //outer_header_removal = pdr->sdf_rules.outer_header_removal; + } else if(pdr->sdf_mode & 1) { + return DEFAULT_XDP_ACTION; + } + } + + struct far_info *far = bpf_map_lookup_elem(&far_map, &far_id); + if (!far) { + upf_printk("upf: no downlink session far for ip:%pI6c far:%d", &ip6->daddr, far_id); + return XDP_DROP; + } + + upf_printk("upf: downlink session for ip:%pI6c far:%d action:%d", &ip6->daddr, far_id, far->action); + + // Only forwarding action supported at the moment + if (!(far->action & FAR_FORW)) + return XDP_DROP; + + // Only outer header GTP/UDP/IPv4 is supported at the moment + if (!(far->outer_header_creation & OHC_GTP_U_UDP_IPv4)) + return XDP_DROP; + + struct qer_info *qer = bpf_map_lookup_elem(&qer_map, &qer_id); + if (!qer) { + upf_printk("upf: no downlink session qer for ip:%pI6c qer:%d", &ip6->daddr, qer_id); + return XDP_DROP; + } + + upf_printk("upf: qer:%d gate_status:%d mbr:%d", qer_id, qer->dl_gate_status, qer->dl_maximum_bitrate); + + if (qer->dl_gate_status != GATE_STATUS_OPEN) + return XDP_DROP; + + const __u64 packet_size = ctx->xdp_ctx->data_end - ctx->xdp_ctx->data; + if (XDP_DROP == limit_rate_sliding_window(packet_size, &qer->dl_start, qer->dl_maximum_bitrate)) + return XDP_DROP; + + __u8 tos = far->transport_level_marking >> 8; + + upf_printk("upf: use mapping %pI6c -> TEID:%d", &ip6->daddr, far->teid); + return send_to_gtp_tunnel(ctx, far->localip, far->remoteip, far->if_index, tos, qer->qfi, far->teid); +} + +static __always_inline enum xdp_action handle_gtp_packet(struct packet_context *ctx) { + if (!ctx->gtp) { + upf_printk("upf: unexpected packet context. no gtp header"); + return DEFAULT_XDP_ACTION; + } + + /* + * Step 1: search for PDR and apply PDR instructions + */ + __u32 teid = bpf_htonl(ctx->gtp->teid); + struct pdr_info *pdr = bpf_map_lookup_elem(&pdr_map_uplink_ip4, &teid); + if (!pdr) { + upf_printk("upf: no session for teid:%d", teid); + return DEFAULT_XDP_ACTION; + } + + __u32 far_id = pdr->far_id; + __u32 qer_id = pdr->qer_id; + __u8 outer_header_removal = pdr->outer_header_removal; + + if (pdr->sdf_mode) { + struct packet_context inner_context = { + .data = (char *)(long)ctx->data, + .data_end = (const char *)(long)ctx->data_end, + }; + + if (inner_context.data + 1 > inner_context.data_end) + return DEFAULT_XDP_ACTION; + int eth_protocol = guess_eth_protocol(inner_context.data); + switch (eth_protocol) { + case ETH_P_IP_BE: + { + int ip_protocol = parse_ip4(&inner_context); + if (-1 == ip_protocol) { + upf_printk("upf: unable to parse IPv4 header"); + return DEFAULT_XDP_ACTION; + } + + if( -1 == parse_l4(ip_protocol, &inner_context)) { + upf_printk("upf: unable to parse L4 header"); + return DEFAULT_XDP_ACTION; + } + + const struct sdf_filter *sdf = &pdr->sdf_rules.sdf_filter; + if(match_sdf_filter_ipv4(&inner_context, sdf)) { + upf_printk("upf: sdf filter matches teid:%d", teid); + far_id = pdr->sdf_rules.far_id; + qer_id = pdr->sdf_rules.qer_id; + outer_header_removal = pdr->sdf_rules.outer_header_removal; + } else { + upf_printk("upf: sdf filter doesn't match teid:%d", teid); + if(pdr->sdf_mode & 1) + return DEFAULT_XDP_ACTION; + } + break; + } + case ETH_P_IPV6_BE: + { + int ip_protocol = parse_ip6(&inner_context); + if (ip_protocol == -1) { + upf_printk("upf: unable to parse IPv6 header"); + return DEFAULT_XDP_ACTION; + } + + if( -1 == parse_l4(ip_protocol, &inner_context)) { + upf_printk("upf: unable to parse L4 header"); + return DEFAULT_XDP_ACTION; + } + + const struct sdf_filter *sdf = &pdr->sdf_rules.sdf_filter; + if(match_sdf_filter_ipv6(&inner_context, sdf)) { + upf_printk("upf: sdf filter matches teid:%d", teid); + far_id = pdr->sdf_rules.far_id; + qer_id = pdr->sdf_rules.qer_id; + outer_header_removal = pdr->sdf_rules.outer_header_removal; + } else { + upf_printk("upf: sdf filter doesn't match teid:%d", teid); + if(pdr->sdf_mode & 1) + return DEFAULT_XDP_ACTION; + } + break; + } + default: + upf_printk("upf: unsupported inner ethernet protocol: %d", eth_protocol); + if(pdr->sdf_mode & 1) + return DEFAULT_XDP_ACTION; + break; + } + } + + /* + * Step 2: search for FAR and apply FAR instructions + */ + struct far_info *far = bpf_map_lookup_elem(&far_map, &far_id); + if (!far) { + upf_printk("upf: no session far for teid:%d far:%d", teid, far_id); + return XDP_DROP; + } + + upf_printk("upf: far:%d action:%d outer_header_creation:%d", far_id, far->action, far->outer_header_creation); + + // Only forwarding action supported at the moment + if (!(far->action & FAR_FORW)) + return XDP_DROP; + + /* + * Step 3: search for QER and apply QER instructions + */ + struct qer_info *qer = bpf_map_lookup_elem(&qer_map, &qer_id); + if (!qer) { + upf_printk("upf: no session qer for teid:%d qer:%d", teid, qer_id); + return XDP_DROP; + } + + upf_printk("upf: qer:%d gate_status:%d mbr:%d", qer_id, qer->ul_gate_status, qer->ul_maximum_bitrate); + + if (qer->ul_gate_status != GATE_STATUS_OPEN) + return XDP_DROP; + + const __u64 packet_size = ctx->xdp_ctx->data_end - ctx->xdp_ctx->data; + if (XDP_DROP == limit_rate_sliding_window(packet_size, &qer->ul_start, qer->ul_maximum_bitrate)) + return XDP_DROP; + + upf_printk("upf: session for teid:%d far:%d outer_header_removal:%d", teid, pdr->far_id, outer_header_removal); + + // N9: Only outer header GTP/UDP/IPv4 is supported at the moment + if (far->outer_header_creation & OHC_GTP_U_UDP_IPv4) + { + upf_printk("upf: session for teid:%d -> %d remote:%pI4", teid, far->teid, &far->remoteip); + update_gtp_tunnel(ctx, far->localip, far->remoteip, 0, far->teid); + } else if (outer_header_removal == OHR_GTP_U_UDP_IPv4) { + long result = remove_gtp_header(ctx); + if (result) { + upf_printk("upf: handle_gtp_packet: can't remove gtp header: %d", result); + return XDP_ABORTED; + } + } + + /* + * Decrement IP TTL and reply TTL exeeded message (debug purspose only) + */ + // if(ctx->ip4 && ctx->ip4->ttl < 2) + // { + // if (-1 == add_icmp_over_ip4_headers(ctx, far->localip, ctx->ip4->saddr)) + // return XDP_ABORTED; + + // upf_printk("upf: send icmp ttl exeeded %pI4 -> %pI4", &ctx->ip4->saddr, &ctx->ip4->daddr); + // return handle_n6_packet_ipv4(ctx); + // } + + /* + * Reply to ping requests (debug purspose only) + */ + if(ctx->ip4 && ctx->ip4->daddr == far->localip && ctx->ip4->protocol == IPPROTO_ICMP) + { + upf_printk("upf: prepare icmp ping reply to request %pI4 -> %pI4", &ctx->ip4->saddr, &ctx->ip4->daddr); + if (-1 == prepare_icmp_echo_reply(ctx, far->localip, ctx->ip4->saddr)) + return XDP_ABORTED; + + upf_printk("upf: send icmp ping reply %pI4 -> %pI4", &ctx->ip4->saddr, &ctx->ip4->daddr); + return handle_n6_packet_ipv4(ctx); + } + + /* + * Step 4: Route packet finally + */ + if (ctx->ip4) { + increment_counter(ctx->n3_n6_counter, tx_n6); + return route_ipv4(ctx->xdp_ctx, ctx->eth, ctx->ip4, far->if_index); + } else if (ctx->ip6) { + increment_counter(ctx->n3_n6_counter, tx_n6); + return route_ipv6(ctx->xdp_ctx, ctx->eth, ctx->ip6); + } else { + return XDP_ABORTED; + } + +} + +static __always_inline enum xdp_action handle_gtpu(struct packet_context *ctx) { + int pdu_type = parse_gtp(ctx); + switch (pdu_type) { + case GTPU_G_PDU: + increment_counter(ctx->counters, rx_gtp_pdu); + return handle_gtp_packet(ctx); + case GTPU_ECHO_REQUEST: + increment_counter(ctx->counters, rx_gtp_echo); + // upf_printk("upf: gtp header [ version=%d, pt=%d, e=%d]", gtp->version, gtp->pt, gtp->e); + // upf_printk("upf: gtp echo request [ type=%d ]", pdu_type); + upf_printk("upf: gtp echo request [ %pI4 -> %pI4 ]", &ctx->ip4->saddr, &ctx->ip4->daddr); + return handle_echo_request(ctx); + case GTPU_ECHO_RESPONSE: + return XDP_PASS; //Pass echo response to userspace program + case GTPU_ERROR_INDICATION: + case GTPU_SUPPORTED_EXTENSION_HEADERS_NOTIFICATION: + case GTPU_END_MARKER: + increment_counter(ctx->counters, rx_gtp_other); + return DEFAULT_XDP_ACTION; + default: + increment_counter(ctx->counters, rx_gtp_unexp); + upf_printk("upf: unexpected gtp message: type=%d", pdu_type); + return DEFAULT_XDP_ACTION; + } +} + +static __always_inline enum xdp_action handle_ip4(struct packet_context *ctx) { + int l4_protocol = parse_ip4(ctx); + switch (l4_protocol) { + case IPPROTO_ICMP: { + increment_counter(ctx->counters, rx_icmp); + break; + } + case IPPROTO_UDP: + increment_counter(ctx->counters, rx_udp); + if (GTP_UDP_PORT == parse_udp(ctx)) { + upf_printk("upf: gtp-u received"); + increment_counter(ctx->n3_n6_counter, rx_n3); + return handle_gtpu(ctx); + } + break; + case IPPROTO_TCP: + increment_counter(ctx->counters, rx_tcp); + break; + default: + increment_counter(ctx->counters, rx_other); + return DEFAULT_XDP_ACTION; + } + + increment_counter(ctx->n3_n6_counter, rx_n6); + return handle_n6_packet_ipv4(ctx); +} + +static __always_inline enum xdp_action handle_ip6(struct packet_context *ctx) { + int l4_protocol = parse_ip6(ctx); + switch (l4_protocol) { + case IPPROTO_ICMPV6: // Let kernel stack take care + upf_printk("upf: icmp received. passing to kernel"); + increment_counter(ctx->counters, rx_icmp6); + return XDP_PASS; + case IPPROTO_UDP: + increment_counter(ctx->counters, rx_udp); + // Don't expect GTP over IPv6 at the moment + // if (GTP_UDP_PORT == parse_udp(ctx)) + // { + // upf_printk("upf: gtp-u received"); + // return handle_gtpu(ctx); + // } + break; + case IPPROTO_TCP: + increment_counter(ctx->counters, rx_tcp); + break; + default: + increment_counter(ctx->counters, rx_other); + return DEFAULT_XDP_ACTION; + } + increment_counter(ctx->n3_n6_counter, rx_n6); + return handle_n6_packet_ipv6(ctx); +} + +static __always_inline enum xdp_action process_packet(struct packet_context *ctx) { + __u16 l3_protocol = parse_ethernet(ctx); + switch (l3_protocol) { + case ETH_P_IPV6: + increment_counter(ctx->counters, rx_ip6); + return handle_ip6(ctx); + case ETH_P_IP: + increment_counter(ctx->counters, rx_ip4); + return handle_ip4(ctx); + case ETH_P_ARP: // Let kernel stack takes care + { + increment_counter(ctx->counters, rx_arp); + upf_printk("upf: arp received. passing to kernel"); + return XDP_PASS; + } + } + + return DEFAULT_XDP_ACTION; +} + +// Combined N3 & N6 entrypoint. Use for "on-a-stick" interfaces +SEC("xdp/upf_ip_entrypoint") +int upf_ip_entrypoint_func(struct xdp_md *ctx) { + // upf_printk("upf n3 & n6 combined entrypoint start"); + const __u32 key = 0; + struct upf_statistic *statistic = bpf_map_lookup_elem(&upf_ext_stat, &key); + if (!statistic) { + const struct upf_statistic initval = {}; + bpf_map_update_elem(&upf_ext_stat, &key, &initval, BPF_ANY); + statistic = bpf_map_lookup_elem(&upf_ext_stat, &key); + if(!statistic) + return XDP_ABORTED; + } + + /* These keep track of the packet pointers and statistic */ + struct packet_context context = { + .data = (char *)(long)ctx->data, + .data_end = (const char *)(long)ctx->data_end, + .xdp_ctx = ctx, + .counters = &statistic->upf_counters, + .n3_n6_counter = &statistic->upf_n3_n6_counter}; + + enum xdp_action action = process_packet(&context); + statistic->xdp_actions[action & EUPF_MAX_XDP_ACTION_MASK] += 1; + + return action; +} + +char _license[] SEC("license") = "GPL"; \ No newline at end of file diff --git a/lib/eupf/ebpf/xdp/n6_entrypoint.c b/lib/eupf/ebpf/xdp/n6_entrypoint.c new file mode 100644 index 00000000..7ad0d9ca --- /dev/null +++ b/lib/eupf/ebpf/xdp/n6_entrypoint.c @@ -0,0 +1,29 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "xdp/program_array.h" + +/* N6 only entrypoint. Attach to N6 interfaces only */ +SEC("xdp/upf_n6_entrypoint") +int upf_n6_entrypoint_func(struct xdp_md *ctx) { + bpf_printk("upf n6 entrypoint start\n"); + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; \ No newline at end of file diff --git a/lib/eupf/ebpf/xdp/pdr.h b/lib/eupf/ebpf/xdp/pdr.h new file mode 100644 index 00000000..6bea593c --- /dev/null +++ b/lib/eupf/ebpf/xdp/pdr.h @@ -0,0 +1,127 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include "xdp/sdf_filter.h" + +#define PDR_MAP_UPLINK_SIZE 1024 +#define PDR_MAP_DOWNLINK_IPV4_SIZE 1024 +#define PDR_MAP_DOWNLINK_IPV6_SIZE 1024 +#define FAR_MAP_SIZE 1024 + + +enum outer_header_removal_values { + OHR_GTP_U_UDP_IPv4 = 0, + OHR_GTP_U_UDP_IPv6 = 1, + OHR_UDP_IPv4 = 2, + OHR_UDP_IPv6 = 3, + OHR_IPv4 = 4, + OHR_IPv6 = 5, + OHR_GTP_U_UDP_IP = 6, + OHR_VLAN_S_TAG = 7, + OHR_S_TAG_C_TAG = 8, +}; + +// Possible optimizations: +// 0. Store SDFs in a separate map. PDR will have only id of corresponding SDF. +// 1. Combine SrcAddress.Type and DstAddress.Type into one __u8 field. Then to retrieve and put data will be used operators & and | . +// 2. Put all fields into one big structure. Sort in specific order to reduce paddings inside structure. + +struct sdf_rules { + struct sdf_filter sdf_filter; + __u8 outer_header_removal; + __u32 far_id; + __u32 qer_id; +}; + +struct pdr_info { + __u32 far_id; + __u32 qer_id; + __u8 outer_header_removal; + __u8 sdf_mode; // 0 - no sdf, 1 - sdf only, 2 - sdf + default + struct sdf_rules sdf_rules; +}; + +/* ipv4 -> PDR */ +struct +{ + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, __u32); + __type(value, struct pdr_info); + __uint(max_entries, PDR_MAP_DOWNLINK_IPV4_SIZE); +} pdr_map_downlink_ip4 SEC(".maps"); + +/* ipv6 -> PDR */ +struct +{ + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, struct in6_addr); + __type(value, struct pdr_info); + __uint(max_entries, PDR_MAP_DOWNLINK_IPV6_SIZE); +} pdr_map_downlink_ip6 SEC(".maps"); + + +/* teid -> PDR */ +struct +{ + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, __u32); + __type(value, struct pdr_info); + __uint(max_entries, PDR_MAP_UPLINK_SIZE); +} pdr_map_uplink_ip4 SEC(".maps"); + +enum far_action_mask { + FAR_DROP = 0x01, + FAR_FORW = 0x02, + FAR_BUFF = 0x04, + FAR_NOCP = 0x08, + FAR_DUPL = 0x10, + FAR_IPMA = 0x20, + FAR_IPMD = 0x40, + FAR_DFRT = 0x80, +}; + +enum outer_header_creation_values { + OHC_GTP_U_UDP_IPv4 = 0x01, + OHC_GTP_U_UDP_IPv6 = 0x02, + OHC_UDP_IPv4 = 0x04, + OHC_UDP_IPv6 = 0x08, +}; + +struct far_info { + __u8 action; + __u8 outer_header_creation; + __u32 teid; + __u32 remoteip; + __u32 localip; + __u32 if_index; + /* first octet DSCP value in the Type-of-Service, second octet shall contain the ToS/Traffic Class mask field, which shall be set to "0xFC". */ + __u16 transport_level_marking; +}; + +/* FAR ID -> FAR */ +struct +{ + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, struct far_info); + __uint(max_entries, FAR_MAP_SIZE); +} far_map SEC(".maps"); diff --git a/lib/eupf/ebpf/xdp/program_array.h b/lib/eupf/ebpf/xdp/program_array.h new file mode 100644 index 00000000..e5cd74cd --- /dev/null +++ b/lib/eupf/ebpf/xdp/program_array.h @@ -0,0 +1,37 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +enum upf_program_type { + UPF_PROG_TYPE_MAIN = 0, + UPF_PROG_TYPE_FAR = 1, + UPF_PROG_TYPE_QER = 2, +}; + +struct +{ + __uint(type, BPF_MAP_TYPE_PROG_ARRAY); + __type(key, uint32_t); + __type(value, uint32_t); + __uint(max_entries, 16); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} upf_pipeline SEC(".maps"); diff --git a/lib/eupf/ebpf/xdp/qer.h b/lib/eupf/ebpf/xdp/qer.h new file mode 100644 index 00000000..e04b7e46 --- /dev/null +++ b/lib/eupf/ebpf/xdp/qer.h @@ -0,0 +1,90 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +enum gate_status { + GATE_STATUS_OPEN = 0, + GATE_STATUS_CLOSED = 1, + GATE_STATUS_RESERVED1 = 2, + GATE_STATUS_RESERVED2 = 3, +}; + +struct qer_info { + __u8 ul_gate_status; + __u8 dl_gate_status; + __u8 qfi; + __u32 ul_maximum_bitrate; + __u32 dl_maximum_bitrate; + __u64 ul_start; + __u64 dl_start; +}; + +#define QER_MAP_SIZE 1024 + +/* QER ID -> QER */ +struct +{ + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, struct qer_info); + __uint(max_entries, QER_MAP_SIZE); +} qer_map SEC(".maps"); + +static __always_inline enum xdp_action limit_rate_simple(struct xdp_md *ctx, __u64 *end, const __u64 rate) { + static const __u64 NSEC_PER_SEC = 1000000000ULL; + + /* Currently 0 rate means that traffic rate is not limited */ + if (rate == 0) + return XDP_PASS; + + __u64 now = bpf_ktime_get_ns(); + if (now > *end) { + __u64 tx_time = (ctx->data_end - ctx->data) * 8 * NSEC_PER_SEC / rate; + *end = now + tx_time; + return XDP_PASS; + } + + return XDP_DROP; +} + +static __always_inline enum xdp_action limit_rate_sliding_window(const __u64 packet_size, __u64 *windows_start, const __u64 rate) { + static const __u64 NSEC_PER_SEC = 1000000000ULL; + static const __u64 window_size = 5000000ULL; + + /* Currently 0 rate means that traffic rate is not limited */ + if (rate == 0) + return XDP_PASS; + + __u64 tx_time = packet_size * 8 * NSEC_PER_SEC / rate; + __u64 now = bpf_ktime_get_ns(); + + __u64 start = *(volatile __u64 *)windows_start; + if (start + tx_time > now) + return XDP_DROP; + + if (start + window_size < now) { + *(volatile __u64 *)&windows_start = now - window_size + tx_time; + return XDP_PASS; + } + + *(volatile __u64 *)&windows_start = start + tx_time; + //__sync_fetch_and_add(&window->start, tx_time); + return XDP_PASS; +} diff --git a/lib/eupf/ebpf/xdp/sdf_filter.h b/lib/eupf/ebpf/xdp/sdf_filter.h new file mode 100644 index 00000000..270f3256 --- /dev/null +++ b/lib/eupf/ebpf/xdp/sdf_filter.h @@ -0,0 +1,152 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xdp/utils/trace.h" +#include "xdp/utils/packet_context.h" +#include "xdp/utils/types.h" +#include "xdp/pdr.h" + +struct ip_subnet { + __u8 type; // 0: any, 1: ip4, 2: ip6 + // If type != any, ip field has meaningful value. + // If IPv4 -> lower 32 bits. If IPv6 -> all 128 bits. + __u128 ip; + // If type != any, mask field has meaningful value. + // If IPv4 mask -> lower 32 bits. If IPv6 mask -> all 128 bits. + // Should always be applied to matching ip (except type == any). + __u128 mask; +}; + +struct port_range { + __u16 lower_bound; // If not specified in SDF: 0 + __u16 upper_bound; // If not specified in SDF: 65535 +}; + +struct sdf_filter { + __u8 protocol; // Required by SDF. 0: icmp, 1: ip, 2: tcp, 3: udp + struct ip_subnet src_addr; + struct port_range src_port; + struct ip_subnet dst_addr; + struct port_range dst_port; +}; + + +static __always_inline __u8 get_sdf_protocol(__u8 ip_protocol) { + switch(ip_protocol) + { + case IPPROTO_ICMP: return 0; + case IPPROTO_TCP: return 2; + case IPPROTO_UDP: return 3; + default: return 1; + } +} + +static __always_inline __u8 match_sdf_filter_ipv4(const struct packet_context *ctx, const struct sdf_filter *sdf) { + if(!ctx || !ctx->ip4 || !sdf) + return 0; + + const struct iphdr *ip4 = ctx->ip4; + __u8 packet_protocol = get_sdf_protocol(ip4->protocol); //TODO: convert protocol in golang part + __u16 packet_src_port = 0; + __u16 packet_dst_port = 0; + if(ctx->udp) { + packet_src_port = bpf_ntohs(ctx->udp->source); //TODO: convert port in golang part + packet_dst_port = bpf_ntohs(ctx->udp->dest); //TODO: convert port in golang part + } else if (ctx->tcp) { + packet_src_port = bpf_ntohs(ctx->tcp->source); //TODO: convert port in golang part + packet_dst_port = bpf_ntohs(ctx->tcp->dest); //TODO: convert port in golang part + } + + __u32 sdf_src_ip = bpf_htonl(sdf->src_addr.ip); + __u32 sdf_dst_ip = bpf_htonl(sdf->dst_addr.ip); + __u32 sdf_src_mask = bpf_htonl(sdf->src_addr.mask); + __u32 sdf_dst_mask = bpf_htonl(sdf->dst_addr.mask); + upf_printk("SDF: filter protocol: %u", sdf->protocol); + upf_printk("SDF: filter source ip: %pI4, destination ip: %pI4", &sdf_src_ip, &sdf_dst_ip); + upf_printk("SDF: filter source ip mask: %pI4, destination ip mask: %pI4", &sdf_src_mask, &sdf_dst_mask); + upf_printk("SDF: filter source port lower bound: %u, source port upper bound: %u", sdf->src_port.lower_bound, sdf->src_port.upper_bound); + upf_printk("SDF: filter destination port lower bound: %u, destination port upper bound: %u", sdf->dst_port.lower_bound, sdf->dst_port.upper_bound); + + upf_printk("SDF: packet protocol: %u", packet_protocol); + upf_printk("SDF: packet source ip: %pI4, destination ip: %pI4", &ip4->saddr, &ip4->daddr); + upf_printk("SDF: packet source port: %u, destination port: %u", packet_src_port, packet_dst_port); + + if ((sdf->protocol != 1 && sdf->protocol != packet_protocol) + || ((ip4->saddr & sdf_src_mask) != sdf_src_ip) + || ((ip4->daddr & sdf_dst_mask) != sdf_dst_ip) + || (packet_src_port < sdf->src_port.lower_bound || packet_src_port > sdf->src_port.upper_bound) + || (packet_dst_port < sdf->dst_port.lower_bound || packet_dst_port > sdf->dst_port.upper_bound)) + { + return 0; + } + + upf_printk("Packet with source ip: %pI4, destination ip: %pI4 matches SDF filter", + &ip4->saddr, &ip4->daddr); + + return 1; +} + +static __always_inline __u8 match_sdf_filter_ipv6(const struct packet_context *ctx, const struct sdf_filter *sdf) { + const struct ipv6hdr *ipv6 = ctx->ip6; + __u8 packet_protocol = get_sdf_protocol(ipv6->nexthdr); + __u128 packet_src_ip_128 = *((__u128*)ipv6->saddr.s6_addr); + __u128 packet_dst_ip_128 = *((__u128*)ipv6->daddr.s6_addr); + __u16 packet_src_port = 0; + __u16 packet_dst_port = 0; + if(ctx->udp) { + packet_src_port = bpf_ntohs(ctx->udp->source); //TODO: convert port in golang part + packet_dst_port = bpf_ntohs(ctx->udp->dest); //TODO: convert port in golang part + } else if (ctx->tcp) { + packet_src_port = bpf_ntohs(ctx->tcp->source); //TODO: convert port in golang part + packet_dst_port = bpf_ntohs(ctx->tcp->dest); //TODO: convert port in golang part + } + + __u128 sdf_src_ip = bpf_htonl(sdf->src_addr.ip); + __u128 sdf_dst_ip = bpf_htonl(sdf->dst_addr.ip); + upf_printk("SDF: filter protocol: %u", sdf->protocol); + upf_printk("SDF: filter source ip: %pI6c, destination ip: %pI6c", &sdf_src_ip, &sdf_dst_ip); + upf_printk("SDF: filter source port lower bound: %u, source port upper bound: %u", sdf->src_port.lower_bound, sdf->src_port.upper_bound); + upf_printk("SDF: filter destination port lower bound: %u, destination port upper bound: %u", sdf->dst_port.lower_bound, sdf->dst_port.upper_bound); + upf_printk("SDF: filter source address mask: %pI4, destination address mask: %pI4", &sdf->dst_addr.mask, &sdf->dst_addr.mask); + + upf_printk("SDF: packet protocol: %u", packet_protocol); + upf_printk("SDF: packet source ip: %pI6c, destination ip: %pI6c", &packet_src_ip_128, &packet_dst_ip_128); + upf_printk("SDF: packet source port: %u, destination port: %u", packet_src_port, packet_dst_port); + + if ((sdf->protocol != 1 && sdf->protocol != packet_protocol) || + (packet_src_ip_128 & sdf->src_addr.mask) != sdf_src_ip || + (packet_dst_ip_128 & sdf->dst_addr.mask) != sdf_dst_ip || + packet_src_port < sdf->src_port.lower_bound || packet_src_port > sdf->src_port.upper_bound || + packet_dst_port < sdf->dst_port.lower_bound || packet_dst_port > sdf->dst_port.upper_bound) { + return 0; + } + + upf_printk("SDF: packet with source ip:%pI6c, destination ip:%pI6c matches SDF filter", + &packet_src_ip_128, &packet_dst_ip_128); + + return 1; +} \ No newline at end of file diff --git a/lib/eupf/ebpf/xdp/statistics.h b/lib/eupf/ebpf/xdp/statistics.h new file mode 100644 index 00000000..6215433e --- /dev/null +++ b/lib/eupf/ebpf/xdp/statistics.h @@ -0,0 +1,61 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +struct upf_counters { + __u64 rx_arp; + __u64 rx_icmp; + __u64 rx_icmp6; + __u64 rx_ip4; + __u64 rx_ip6; + __u64 rx_tcp; + __u64 rx_udp; + __u64 rx_other; + __u64 rx_gtp_echo; + __u64 rx_gtp_pdu; + __u64 rx_gtp_other; + __u64 rx_gtp_unexp; +}; + +struct n3_n6_counters { + __u64 rx_n3; + __u64 tx_n3; + __u64 rx_n6; + __u64 tx_n6; +}; + +#define EUPF_MAX_XDP_ACTION 8 +#define EUPF_MAX_XDP_ACTION_MASK 0x07 + +struct upf_statistic { + struct upf_counters upf_counters; + struct n3_n6_counters upf_n3_n6_counter; + __u64 xdp_actions[EUPF_MAX_XDP_ACTION]; +}; + +struct +{ + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __type(key, __u32); + __type(value, struct upf_statistic); + __uint(max_entries, 1); +} upf_ext_stat SEC(".maps"); + + diff --git a/lib/eupf/ebpf/xdp/upf_program.c b/lib/eupf/ebpf/xdp/upf_program.c new file mode 100644 index 00000000..aa5be97c --- /dev/null +++ b/lib/eupf/ebpf/xdp/upf_program.c @@ -0,0 +1,31 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "xdp/program_array.h" + +SEC("xdp/upf") +int upf_func(struct xdp_md *ctx) { + bpf_printk("upf_program start\n"); + + bpf_printk("tail call to UPF_PROG_TYPE_QER key\n"); + bpf_tail_call(ctx, &upf_pipeline, UPF_PROG_TYPE_QER); + bpf_printk("tail call to UPF_PROG_TYPE_QER key failed\n"); + return XDP_ABORTED; +} + +char _license[] SEC("license") = "GPL"; \ No newline at end of file diff --git a/lib/eupf/ebpf/xdp/utils/common.h b/lib/eupf/ebpf/xdp/utils/common.h new file mode 100644 index 00000000..8080c5fd --- /dev/null +++ b/lib/eupf/ebpf/xdp/utils/common.h @@ -0,0 +1,23 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#define increment_counter(OBJECT, COUNTER) \ + OBJECT->COUNTER++; + +#define increment_counter_sync(OBJECT, COUNTER) \ + __sync_fetch_and_add(&OBJECT->COUNTER, 1); diff --git a/lib/eupf/ebpf/xdp/utils/csum.h b/lib/eupf/ebpf/xdp/utils/csum.h new file mode 100644 index 00000000..3e2089be --- /dev/null +++ b/lib/eupf/ebpf/xdp/utils/csum.h @@ -0,0 +1,45 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +static __always_inline __u16 csum_fold_helper(__u64 csum) { +#pragma unroll + for (int i = 0; i < 4; i++) { + csum = (csum & 0xffff) + (csum >> 16); + } + + return ~csum; +} + +static __always_inline __u64 ipv4_csum(void *data_start, __u32 data_size) { + __u64 csum = bpf_csum_diff(0, 0, data_start, data_size, 0); + return csum_fold_helper(csum); +} + +static __always_inline void ipv4_csum_replace(__u16 *sum, __u16 old, __u16 new) +{ + __u16 csum = ~*sum; + csum += ~old; + csum += csum < (__u16)~old; + csum += new; + csum += csum < (__u16)new; + *sum = ~csum; +} \ No newline at end of file diff --git a/lib/eupf/ebpf/xdp/utils/gtp_utils.h b/lib/eupf/ebpf/xdp/utils/gtp_utils.h new file mode 100644 index 00000000..e78d5baa --- /dev/null +++ b/lib/eupf/ebpf/xdp/utils/gtp_utils.h @@ -0,0 +1,256 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "xdp/utils/gtpu.h" +#include "xdp/utils/packet_context.h" +#include "xdp/utils/trace.h" + +static __always_inline __u32 parse_gtp(struct packet_context *ctx) { + struct gtpuhdr *gtp = (struct gtpuhdr *)ctx->data; + if ((const char *)(gtp + 1) > ctx->data_end) + return -1; + + ctx->data += sizeof(*gtp); + if (gtp->e || gtp->s || gtp->pn) + ctx->data += sizeof(struct gtp_hdr_ext) + 4; + ctx->gtp = gtp; + return gtp->message_type; +} + +static __always_inline __u32 handle_echo_request(struct packet_context *ctx) { + struct ethhdr *eth = ctx->eth; + struct iphdr *iph = ctx->ip4; + struct udphdr *udp = ctx->udp; + struct gtpuhdr *gtp = ctx->gtp; + + gtp->message_type = GTPU_ECHO_RESPONSE; + + /* TODO: add support GTP over IPv6 */ + swap_ip(iph); + swap_port(udp); + swap_mac(eth); + upf_printk("upf: send gtp echo response [ %pI4 -> %pI4 ]", &iph->saddr, &iph->daddr); + return XDP_TX; +} + +static __always_inline int guess_eth_protocol(const char *data) { + const __u8 ip_version = (*(const __u8 *)data) >> 4; + switch (ip_version) { + case 6: { + return ETH_P_IPV6_BE; + } + case 4: { + return ETH_P_IP_BE; + } + default: + /* do nothing with non-ip packets */ + upf_printk("upf: can't process non-IP packet: %d", ip_version); + return -1; + } +} + +static __always_inline long remove_gtp_header(struct packet_context *ctx) { + if (!ctx->gtp) { + upf_printk("upf: remove_gtp_header: not a gtp packet"); + return -1; + } + + size_t ext_gtp_header_size = 0; + struct gtpuhdr *gtp = ctx->gtp; + if (gtp->e || gtp->s || gtp->pn) + ext_gtp_header_size += sizeof(struct gtp_hdr_ext) + 4; + + const size_t gtp_encap_size = sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct gtpuhdr) + ext_gtp_header_size; + + char *data = (char *)(long)ctx->xdp_ctx->data; + const char *data_end = (const char *)(long)ctx->xdp_ctx->data_end; + struct ethhdr *eth = (struct ethhdr *)data; + if ((const char *)(eth + 1) > data_end) { + upf_printk("upf: remove_gtp_header: can't parse eth"); + return -1; + } + + data += gtp_encap_size; + struct ethhdr *new_eth = (struct ethhdr *)data; + if ((const char *)(new_eth + 1) > data_end) { + upf_printk("upf: remove_gtp_header: can't set new eth"); + return -1; + } + + data += sizeof(*new_eth); + if (data + 1 > data_end) + return -1; + + const int eth_proto = guess_eth_protocol(data); + + if (eth_proto == -1) + return -1; + + __builtin_memcpy(new_eth, eth, sizeof(*new_eth)); + + new_eth->h_proto = eth_proto; + + long result = bpf_xdp_adjust_head(ctx->xdp_ctx, gtp_encap_size); + if (result) + return result; + + /* Update packet pointers */ + data = (char *)(long)ctx->xdp_ctx->data; + data_end = (const char *)(long)ctx->xdp_ctx->data_end; + return context_reinit(ctx, data, data_end); +} + +static __always_inline void fill_ip_header(struct iphdr *ip, int saddr, int daddr, __u8 tos, int tot_len) { + ip->version = 4; + ip->ihl = 5; /* No options */ + ip->tos = tos; + ip->tot_len = bpf_htons(tot_len); + ip->id = 0; /* No fragmentation */ + ip->frag_off = 0x0040; /* Don't fragment; Fragment offset = 0 */ + ip->ttl = 64; + ip->protocol = IPPROTO_UDP; + ip->check = 0; + ip->saddr = saddr; + ip->daddr = daddr; +} + +static __always_inline void fill_udp_header(struct udphdr *udp, int port, int len) { + udp->source = bpf_htons(port); + udp->dest = udp->source; + udp->len = bpf_htons(len); + udp->check = 0; +} + +static __always_inline void fill_gtp_header(struct gtpuhdr *gtp, int teid, int len) { + *(__u8 *)gtp = GTP_FLAGS; + gtp->e = 1; + gtp->message_type = GTPU_G_PDU; + gtp->message_length = bpf_htons(len); + gtp->teid = bpf_htonl(teid); +} + +static __always_inline void fill_gtp_ext_header(struct gtp_hdr_ext *gtp_ext) { + gtp_ext->sqn = 0; + gtp_ext->npdu = 0; + gtp_ext->next_ext = GTPU_EXT_TYPE_PDU_SESSION_CONTAINER; +} + +static __always_inline void fill_gtp_ext_header_psc(struct gtp_hdr_ext_pdu_session_container *gtp_ext, int qfi, int pdu_type) { + gtp_ext->length = 1; + gtp_ext->pdu_type = pdu_type; + gtp_ext->spare1 = 0; + gtp_ext->spare2 = 0; + gtp_ext->rqi = 0; + gtp_ext->qfi = qfi; + gtp_ext->next_ext = 0; +} + +static __always_inline __u32 add_gtp_over_ip4_headers(struct packet_context *ctx, int saddr, int daddr, __u8 tos, __u8 qfi, int teid) { + static const size_t gtp_ext_hdr_size = sizeof(struct gtp_hdr_ext) + sizeof(struct gtp_hdr_ext_pdu_session_container); + static const size_t gtp_full_hdr_size = sizeof(struct gtpuhdr) + gtp_ext_hdr_size; + static const size_t gtp_encap_size = sizeof(struct iphdr) + sizeof(struct udphdr) + gtp_full_hdr_size; + + // int ip_packet_len = (ctx->xdp_ctx->data_end - ctx->xdp_ctx->data) - sizeof(*eth); + int ip_packet_len = 0; + if (ctx->ip4) + ip_packet_len = bpf_ntohs(ctx->ip4->tot_len); + else if (ctx->ip6) + ip_packet_len = bpf_ntohs(ctx->ip6->payload_len) + sizeof(struct ipv6hdr); + else + return -1; + + int result = bpf_xdp_adjust_head(ctx->xdp_ctx, (__s32)-gtp_encap_size); + if (result) + return -1; + + char *data = (char *)(long)ctx->xdp_ctx->data; + const char *data_end = (const char *)(long)ctx->xdp_ctx->data_end; + + struct ethhdr *orig_eth = (struct ethhdr *)(data + gtp_encap_size); + if ((const char *)(orig_eth + 1) > data_end) + return -1; + + struct ethhdr *eth = (struct ethhdr *)data; + __builtin_memcpy(eth, orig_eth, sizeof(*eth)); + eth->h_proto = bpf_htons(ETH_P_IP); + + struct iphdr *ip = (struct iphdr *)(eth + 1); + if ((const char *)(ip + 1) > data_end) + return -1; + + /* Add the outer IP header */ + fill_ip_header(ip, saddr, daddr, tos, ip_packet_len + gtp_encap_size); + + /* Add the UDP header */ + struct udphdr *udp = (struct udphdr *)(ip + 1); + if ((const char *)(udp + 1) > data_end) + return -1; + + fill_udp_header(udp, GTP_UDP_PORT, ip_packet_len + sizeof(*udp) + gtp_full_hdr_size); + + /* Add the GTP header */ + struct gtpuhdr *gtp = (struct gtpuhdr *)(udp + 1); + if ((const char *)(gtp + 1) > data_end) + return -1; + + fill_gtp_header(gtp, teid, gtp_ext_hdr_size + ip_packet_len); + + /* Add the GTP ext header */ + struct gtp_hdr_ext *gtp_ext = (struct gtp_hdr_ext *)(gtp + 1); + if ((const char *)(gtp_ext + 1) > data_end) + return -1; + + fill_gtp_ext_header(gtp_ext); + + /* Add the GTP PDU session container header */ + struct gtp_hdr_ext_pdu_session_container *gtp_psc = (struct gtp_hdr_ext_pdu_session_container *)(gtp_ext + 1); + if ((const char *)(gtp_psc + 1) > data_end) + return -1; + + fill_gtp_ext_header_psc(gtp_psc, qfi, PDU_SESSION_CONTAINER_PDU_TYPE_DL_PSU); + + ip->check = ipv4_csum(ip, sizeof(*ip)); + + /* TODO: implement UDP csum which pass ebpf verifier checks successfully */ + // cs = 0; + // const void* udp_start = (void*)udp; + // const __u16 udp_len = bpf_htons(udp->len); + // ipv4_l4_csum(udp, udp_len, &cs, ip); + // udp->check = cs; + + /* Update packet pointers */ + context_set_ip4(ctx, (char *)(long)ctx->xdp_ctx->data, (const char *)(long)ctx->xdp_ctx->data_end, eth, ip, udp, gtp); + return 0; +} + +static __always_inline void update_gtp_tunnel(struct packet_context *ctx, int srcip, int dstip, __u8 tos, int teid) { + + ctx->gtp->teid = bpf_htonl(teid); + ctx->ip4->saddr = srcip; + ctx->ip4->daddr = dstip; + ctx->ip4->check = 0; + ctx->ip4->check = ipv4_csum(ctx->ip4, sizeof(*ctx->ip4)); +} diff --git a/lib/eupf/ebpf/xdp/utils/gtpu.h b/lib/eupf/ebpf/xdp/utils/gtpu.h new file mode 100644 index 00000000..7cec801d --- /dev/null +++ b/lib/eupf/ebpf/xdp/utils/gtpu.h @@ -0,0 +1,76 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#define GTP_UDP_PORT 2152u + +/* Version: GTPv1, Protocol Type: GTP, Others: 0 */ +#define GTP_FLAGS 0x30 + +#define GTPU_ECHO_REQUEST (1) +#define GTPU_ECHO_RESPONSE (2) +#define GTPU_ERROR_INDICATION (26) +#define GTPU_SUPPORTED_EXTENSION_HEADERS_NOTIFICATION (31) +#define GTPU_END_MARKER (254) +#define GTPU_G_PDU (255) + +struct gtpuhdr { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int pn : 1; + unsigned int s : 1; + unsigned int e : 1; + unsigned int spare : 1; + unsigned int pt : 1; + unsigned int version : 3; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int version : 3; + unsigned int pt : 1; + unsigned int spare : 1; + unsigned int e : 1; + unsigned int s : 1; + unsigned int pn : 1; +#else +#error "Please fix " +#endif + __u8 message_type; + __u16 message_length; + __u32 teid; +} __attribute__((packed)); + +/* Optional word of GTP header, present if any of E, S, PN is set. */ +struct gtp_hdr_ext { + __u16 sqn; + __u8 npdu; + __u8 next_ext; +} __attribute__((packed)); + +#define GTPU_EXT_TYPE_PDU_SESSION_CONTAINER (0x85) +#define PDU_SESSION_CONTAINER_PDU_TYPE_DL_PSU (0x00) +#define PDU_SESSION_CONTAINER_PDU_TYPE_UL_PSU (0x01) + +struct gtp_hdr_ext_pdu_session_container { + __u8 length; + __u8 spare1 : 4; + __u8 pdu_type : 4; + __u8 qfi : 6; + __u8 rqi : 1; + __u8 spare2 : 1; + __u8 next_ext; +} __attribute__((packed)); \ No newline at end of file diff --git a/lib/eupf/ebpf/xdp/utils/icmp.h b/lib/eupf/ebpf/xdp/utils/icmp.h new file mode 100644 index 00000000..fb833586 --- /dev/null +++ b/lib/eupf/ebpf/xdp/utils/icmp.h @@ -0,0 +1,109 @@ +// Copyright 2023 Edgecom LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "xdp/utils/csum.h" +#include "xdp/utils/parsers.h" +#include "xdp/utils/packet_context.h" + +static __always_inline void fill_icmp_header(struct icmphdr *icmp) { + icmp->type = ICMP_TIME_EXCEEDED; + icmp->code = ICMP_EXC_TTL; + icmp->un.gateway = 0; + icmp->checksum = 0; +} + +// static __always_inline __u32 add_icmp_over_ip4_headers(struct packet_context *ctx, int saddr, int daddr) { +// static const size_t icmp_encap_size = sizeof(struct iphdr) + sizeof(struct icmphdr); + +// if (!ctx->ip4) +// return -1; + +// const __u32 ip_packet_len = bpf_ntohs(ctx->ip4->tot_len); + +// int result = bpf_xdp_adjust_head(ctx->xdp_ctx, (__s32)-icmp_encap_size); +// if (result) +// return -1; + +// char *data = (char *)(long)ctx->xdp_ctx->data; +// const char *data_end = (const char *)(long)ctx->xdp_ctx->data_end; + +// struct ethhdr *orig_eth = (struct ethhdr *)(data + icmp_encap_size); +// if ((const char *)(orig_eth + 1) > data_end) +// return -1; + +// struct ethhdr *eth = (struct ethhdr *)data; +// __builtin_memcpy(eth, orig_eth, sizeof(*eth)); +// eth->h_proto = bpf_htons(ETH_P_IP); + +// struct iphdr *ip = (struct iphdr *)(eth + 1); +// if ((const char *)(ip + 1) > data_end) +// return -1; + +// /* Add the outer IP header */ +// fill_ip_header(ip, saddr, daddr, 0, ip_packet_len + icmp_encap_size); +// ip->protocol = IPPROTO_ICMP; +// ip->check = ipv4_csum(ip, sizeof(*ip)); + +// /* Add the ICMP header */ +// struct icmphdr *icmp = (struct icmphdr *)(ip + 1); +// if ((const char *)(icmp + 1) > data_end) +// return -1; + +// fill_icmp_header(icmp); +// const __s8 icmp_payload_size = data_end - (const char *)icmp; +// icmp->checksum = ipv4_csum(icmp, icmp_payload_size); + +// /* Update packet pointers */ +// context_set_ip4(ctx, (char *)(long)ctx->xdp_ctx->data, (const char *)(long)ctx->xdp_ctx->data_end, eth, ip, 0, 0); +// return 0; +// } + +static __always_inline __u32 prepare_icmp_echo_reply(struct packet_context *ctx, int saddr, int daddr) { + if (!ctx->ip4) + return -1; + + struct ethhdr *eth = ctx->eth; + swap_mac(eth); + + const char *data_end = (const char *)(long)ctx->xdp_ctx->data_end; + struct iphdr *ip = ctx->ip4; + if ((const char *)(ip + 1) > data_end) + return -1; + + swap_ip(ip); + + struct icmphdr *icmp = (struct icmphdr *)(ip + 1); + if ((const char *)(icmp + 1) > data_end) + return -1; + + if(icmp->type != ICMP_ECHO) + return -1; + + __u16 old = *(__u16*)&icmp->type; + icmp->type = ICMP_ECHOREPLY; + icmp->code = 0; + + ipv4_csum_replace(&icmp->checksum, old, *(__u16*)&icmp->type); + + return 0; +} \ No newline at end of file diff --git a/lib/eupf/ebpf/xdp/utils/packet_context.h b/lib/eupf/ebpf/xdp/utils/packet_context.h new file mode 100644 index 00000000..d9fe0b23 --- /dev/null +++ b/lib/eupf/ebpf/xdp/utils/packet_context.h @@ -0,0 +1,40 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "xdp/utils/gtpu.h" + +/* Header cursor to keep track of current parsing position */ +struct packet_context { + char *data; + const char *data_end; + struct upf_counters *counters; + struct n3_n6_counters *n3_n6_counter; + struct xdp_md *xdp_ctx; + struct ethhdr *eth; + struct iphdr *ip4; + struct ipv6hdr *ip6; + struct udphdr *udp; + struct tcphdr *tcp; + struct gtpuhdr *gtp; +}; diff --git a/lib/eupf/ebpf/xdp/utils/parsers.h b/lib/eupf/ebpf/xdp/utils/parsers.h new file mode 100644 index 00000000..937a1bc4 --- /dev/null +++ b/lib/eupf/ebpf/xdp/utils/parsers.h @@ -0,0 +1,181 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "xdp/utils/packet_context.h" +#include "xdp/utils/trace.h" + +#define ETH_P_IPV6_BE 0xDD86 +#define ETH_P_IP_BE 0x0008 + +static __always_inline int parse_ethernet(struct packet_context *ctx) { + struct ethhdr *eth = (struct ethhdr *)ctx->data; + if ((const char *)(eth + 1) > ctx->data_end) + return -1; + + /* TODO: Add vlan support */ + + ctx->data += sizeof(*eth); + ctx->eth = eth; + return bpf_ntohs(eth->h_proto); +} + +/* 0x3FFF mask to check for fragment offset field */ +#define IP_FRAGMENTED 65343 + +static __always_inline int parse_ip4(struct packet_context *ctx) { + struct iphdr *ip4 = (struct iphdr *)ctx->data; + if ((const char *)(ip4 + 1) > ctx->data_end) + return -1; + + /* do not support fragmented packets as L4 headers may be missing */ + // if (ip4->frag_off & IP_FRAGMENTED) + // return -1; + + ctx->data += ip4->ihl * 4; /* header + options */ + ctx->ip4 = ip4; + return ip4->protocol; +} + +static __always_inline int parse_ip6(struct packet_context *ctx) { + struct ipv6hdr *ip6 = (struct ipv6hdr *)ctx->data; + if ((const char *)(ip6 + 1) > ctx->data_end) + return -1; + + /* TODO: Add extention headers support */ + + ctx->data += sizeof(*ip6); + ctx->ip6 = ip6; + return ip6->nexthdr; +} + +static __always_inline int parse_udp(struct packet_context *ctx) { + struct udphdr *udp = (struct udphdr *)ctx->data; + if ((const char *)(udp + 1) > ctx->data_end) + return -1; + + ctx->data += sizeof(*udp); + ctx->udp = udp; + return bpf_ntohs(udp->dest); +} + +static __always_inline int parse_tcp(struct packet_context *ctx) { + struct tcphdr *tcp = (struct tcphdr *)ctx->data; + if ((const char *)(tcp + 1) > ctx->data_end) + return -1; + + //TODO: parse header lenght correctly (tcp options) + + ctx->data += sizeof(*tcp); + ctx->tcp = tcp; + return bpf_ntohs(tcp->dest); +} + +static __always_inline int parse_l4(int ip_protocol, struct packet_context *ctx) +{ + switch (ip_protocol) { + case IPPROTO_UDP: + return parse_udp(ctx); + case IPPROTO_TCP: + return parse_tcp(ctx); + default: + return 0; + } +} + +static __always_inline void swap_mac(struct ethhdr *eth) { + __u8 mac[6]; + __builtin_memcpy(mac, eth->h_source, sizeof(mac)); + __builtin_memcpy(eth->h_source, eth->h_dest, sizeof(eth->h_source)); + __builtin_memcpy(eth->h_dest, mac, sizeof(eth->h_dest)); +} + +static __always_inline void swap_port(struct udphdr *udp) { + __u16 tmp = udp->dest; + udp->dest = udp->source; + udp->source = tmp; + /* Update UDP checksum */ + udp->check = 0; + // cs = 0; + // ipv4_l4_csum(udp, sizeof(*udp), &cs, iph); + // udp->check = cs; +} + +static __always_inline void swap_ip(struct iphdr *iph) { + __u32 tmp_ip = iph->daddr; + iph->daddr = iph->saddr; + iph->saddr = tmp_ip; + + /* Don't need to recalc csum in case of ip swap */ + // ip->check = ipv4_csum(ip, sizeof(*ip)); +} + +static __always_inline void context_set_ip4(struct packet_context *ctx, char *data, const char *data_end, struct ethhdr *eth, struct iphdr *ip4, struct udphdr *udp, struct gtpuhdr *gtp) { + ctx->data = data; + ctx->data_end = data_end; + ctx->eth = eth; + ctx->ip4 = ip4; + ctx->ip6 = 0; + ctx->udp = udp; + ctx->gtp = gtp; +} + +static __always_inline void context_reset(struct packet_context *ctx, char *data, const char *data_end) { + ctx->data = data; + ctx->data_end = data_end; + ctx->eth = 0; + ctx->ip4 = 0; + ctx->ip6 = 0; + ctx->udp = 0; + ctx->gtp = 0; +} + + +static __always_inline long context_reinit(struct packet_context *ctx, char *data, const char *data_end) { + context_reset(ctx, data, data_end); + + int ethertype = parse_ethernet(ctx); + switch (ethertype) { + case ETH_P_IPV6: { + if (-1 == parse_ip6(ctx)) { + upf_printk("upf: can't parse ip6"); + return -1; + } + return 0; + } + case ETH_P_IP: { + if (-1 == parse_ip4(ctx)) { + upf_printk("upf: can't parse ip4"); + return -1; + } + return 0; + } + + default: + /* do nothing with non-ip packets */ + upf_printk("upf: can't process not an ip packet: %d", ethertype); + return -1; + } +} diff --git a/lib/eupf/ebpf/xdp/utils/routing.h b/lib/eupf/ebpf/xdp/utils/routing.h new file mode 100644 index 00000000..9aeaa11a --- /dev/null +++ b/lib/eupf/ebpf/xdp/utils/routing.h @@ -0,0 +1,204 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xdp/utils/trace.h" + +struct route_stat { + __u64 fib_lookup_ip4_cache; + __u64 fib_lookup_ip4_ok; + __u64 fib_lookup_ip4_error_drop; + __u64 fib_lookup_ip4_error_pass; + __u64 fib_lookup_ip6_cache; + __u64 fib_lookup_ip6_ok; + __u64 fib_lookup_ip6_error_drop; + __u64 fib_lookup_ip6_error_pass; +}; + +struct +{ + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __type(key, __u32); + __type(value, struct route_stat); + __uint(max_entries, 1); +} upf_route_stat SEC(".maps"); + +#ifdef ENABLE_ROUTE_CACHE + +#warning "Routing cache enabled" + +#define ROUTE_CACHE_IPV4_SIZE 256 +#define ROUTE_CACHE_IPV6_SIZE 256 + +struct route_record { + int ifindex; + __u8 smac[6]; + __u8 dmac[6]; +}; + +/* ipv4 -> fib cached result */ +struct +{ + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __type(key, __u32); + __type(value, struct route_record); + __uint(max_entries, ROUTE_CACHE_IPV4_SIZE); +} upf_route_cache_ip4 SEC(".maps"); + +/* ipv6 -> fib cached result */ +struct +{ + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __type(key, struct in6_addr); + __type(value, struct route_record); + __uint(max_entries, ROUTE_CACHE_IPV6_SIZE); +} upf_route_cache_ip6 SEC(".maps"); + +static __always_inline void update_route_cache_ipv4(const struct bpf_fib_lookup *fib_params, __u32 daddr) { + struct route_record route = { + .ifindex = fib_params->ifindex, + }; + __builtin_memcpy(route.smac, fib_params->smac, ETH_ALEN); + __builtin_memcpy(route.dmac, fib_params->dmac, ETH_ALEN); + bpf_map_update_elem(&upf_route_cache_ip4, &daddr, &route, BPF_ANY); +} +#endif + +static __always_inline enum xdp_action do_route_ipv4(struct xdp_md *ctx, struct ethhdr *eth, __u32 ifindex, __u8 (*smac)[6], __u8 (*dmac)[6]) { + //_decr_ttl(ether_proto, l3hdr); + __builtin_memcpy(eth->h_source, smac, ETH_ALEN); + __builtin_memcpy(eth->h_dest, dmac, ETH_ALEN); + + if (ifindex == ctx->ingress_ifindex) + return XDP_TX; + return bpf_redirect(ifindex, 0); +} + +static __always_inline enum xdp_action route_ipv4(struct xdp_md *ctx, struct ethhdr *eth, const struct iphdr *ip4, __u32 ifindex) { + const __u32 key = 0; + struct route_stat *statistic = bpf_map_lookup_elem(&upf_route_stat, &key); + if (!statistic) { + return XDP_ABORTED; + } + +#ifdef ENABLE_ROUTE_CACHE + struct route_record *cache = bpf_map_lookup_elem(&upf_route_cache_ip4, &ip4->daddr); + if (cache) { + upf_printk("upf: bpf_fib_lookup %pI4 -> %pI4: cached ifindex: %d", &ip4->saddr, &ip4->daddr, cache->ifindex); + statistic->fib_lookup_ip4_cache += 1; + return do_route_ipv4(ctx, eth, cache->ifindex, &cache->smac, &cache->dmac); + } +#endif + + struct bpf_fib_lookup fib_params = {}; + fib_params.family = AF_INET; + fib_params.tos = ip4->tos; + fib_params.l4_protocol = ip4->protocol; + fib_params.sport = 0; + fib_params.dport = 0; + fib_params.tot_len = bpf_ntohs(ip4->tot_len); + //fib_params.ipv4_src = ip4->saddr; + fib_params.ipv4_dst = ip4->daddr; + fib_params.ifindex = ifindex; + + int rc = bpf_fib_lookup(ctx, &fib_params, sizeof(fib_params), 0 /*BPF_FIB_LOOKUP_OUTPUT*/); + switch (rc) { + case BPF_FIB_LKUP_RET_SUCCESS: + upf_printk("upf: bpf_fib_lookup1 %pI4 -> %pI4: nexthop: %pI4", &ip4->saddr, &ip4->daddr, &fib_params.ipv4_dst); + statistic->fib_lookup_ip4_ok += 1; + +#ifdef ENABLE_ROUTE_CACHE + update_route_cache_ipv4(&fib_params, ip4->daddr); +#endif + return do_route_ipv4(ctx, eth, fib_params.ifindex, &fib_params.smac, &fib_params.dmac); + + case BPF_FIB_LKUP_RET_BLACKHOLE: + case BPF_FIB_LKUP_RET_UNREACHABLE: + case BPF_FIB_LKUP_RET_PROHIBIT: + upf_printk("upf: bpf_fib_lookup2 %pI4 -> %pI4: %d", &ip4->saddr, &ip4->daddr, rc); + statistic->fib_lookup_ip4_error_drop += 1; + return XDP_DROP; + case BPF_FIB_LKUP_RET_NOT_FWDED: + case BPF_FIB_LKUP_RET_FWD_DISABLED: + case BPF_FIB_LKUP_RET_UNSUPP_LWT: + case BPF_FIB_LKUP_RET_NO_NEIGH: + case BPF_FIB_LKUP_RET_FRAG_NEEDED: + default: + upf_printk("upf: bpf_fib_lookup3 %pI4 -> %pI4: %d", &ip4->saddr, &ip4->daddr, rc); + statistic->fib_lookup_ip4_error_pass += 1; + return XDP_PASS; /* Let's kernel takes care */ + } +} + +static __always_inline enum xdp_action route_ipv6(struct xdp_md *ctx, struct ethhdr *eth, const struct ipv6hdr *ip6) { + const __u32 key = 0; + struct route_stat *statistic = bpf_map_lookup_elem(&upf_route_stat, &key); + if (!statistic) { + return XDP_ABORTED; + } + + struct bpf_fib_lookup fib_params = {}; + fib_params.family = AF_INET; + // fib_params.tos = ip6->flow_lbl; + fib_params.l4_protocol = ip6->nexthdr; + fib_params.sport = 0; + fib_params.dport = 0; + fib_params.tot_len = bpf_ntohs(ip6->payload_len); + __builtin_memcpy(fib_params.ipv6_src, &ip6->saddr, sizeof(ip6->saddr)); + __builtin_memcpy(fib_params.ipv6_dst, &ip6->daddr, sizeof(ip6->daddr)); + fib_params.ifindex = ctx->ingress_ifindex; + + int rc = bpf_fib_lookup(ctx, &fib_params, sizeof(fib_params), 0 /*BPF_FIB_LOOKUP_OUTPUT*/); + switch (rc) { + case BPF_FIB_LKUP_RET_SUCCESS: + upf_printk("upf: bpf_fib_lookup %pI6c -> %pI6c: nexthop: %pI4", &ip6->saddr, &ip6->daddr, &fib_params.ipv4_dst); + statistic->fib_lookup_ip6_ok += 1; + //_decr_ttl(ether_proto, l3hdr); + __builtin_memcpy(eth->h_dest, fib_params.dmac, ETH_ALEN); + __builtin_memcpy(eth->h_source, fib_params.smac, ETH_ALEN); + upf_printk("upf: bpf_redirect: if=%d %lu -> %lu", fib_params.ifindex, fib_params.smac, fib_params.dmac); + + if (fib_params.ifindex == ctx->ingress_ifindex) + return XDP_TX; + + return bpf_redirect(fib_params.ifindex, 0); + case BPF_FIB_LKUP_RET_BLACKHOLE: + case BPF_FIB_LKUP_RET_UNREACHABLE: + case BPF_FIB_LKUP_RET_PROHIBIT: + upf_printk("upf: bpf_fib_lookup %pI6c -> %pI6c: %d", &ip6->saddr, &ip6->daddr, rc); + statistic->fib_lookup_ip6_error_drop += 1; + return XDP_DROP; + case BPF_FIB_LKUP_RET_NOT_FWDED: + case BPF_FIB_LKUP_RET_FWD_DISABLED: + case BPF_FIB_LKUP_RET_UNSUPP_LWT: + case BPF_FIB_LKUP_RET_NO_NEIGH: + case BPF_FIB_LKUP_RET_FRAG_NEEDED: + default: + upf_printk("upf: bpf_fib_lookup %pI6c -> %pI6c: %d", &ip6->saddr, &ip6->daddr, rc); + statistic->fib_lookup_ip6_error_pass += 1; + return XDP_PASS; /* Let's kernel takes care */ + } +} \ No newline at end of file diff --git a/lib/eupf/ebpf/xdp/utils/trace.h b/lib/eupf/ebpf/xdp/utils/trace.h new file mode 100644 index 00000000..dc2a4f36 --- /dev/null +++ b/lib/eupf/ebpf/xdp/utils/trace.h @@ -0,0 +1,33 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +//#define ENABLE_LOG + +#ifdef ENABLE_LOG // trace_pipe logs disabled by default +#warning "Debug log enabled" +#define upf_printk(fmt, ...) \ + ({ \ + static const char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ + }) +#else +#define upf_printk(fmt, ...) +#endif \ No newline at end of file diff --git a/lib/eupf/ebpf/xdp/utils/types.h b/lib/eupf/ebpf/xdp/utils/types.h new file mode 100644 index 00000000..ac9af420 --- /dev/null +++ b/lib/eupf/ebpf/xdp/utils/types.h @@ -0,0 +1,20 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + + +typedef unsigned __int128 __u128; \ No newline at end of file diff --git a/lib/eupf/ebpf/xdp/zero_entrypoint.c b/lib/eupf/ebpf/xdp/zero_entrypoint.c new file mode 100644 index 00000000..8a9cdebe --- /dev/null +++ b/lib/eupf/ebpf/xdp/zero_entrypoint.c @@ -0,0 +1,26 @@ +/** + * Copyright 2023 Edgecom LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +/* Zero entrypoint purposed for enabling native attach mode for veth */ +SEC("xdp/upf_zero_entrypoint") +int upf_n3_entrypoint_func(struct xdp_md *ctx) { + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; \ No newline at end of file diff --git a/lib/eupf/ebpf/zeroentrypoint_bpf.go b/lib/eupf/ebpf/zeroentrypoint_bpf.go new file mode 100644 index 00000000..6876b80d --- /dev/null +++ b/lib/eupf/ebpf/zeroentrypoint_bpf.go @@ -0,0 +1,114 @@ +// Code generated by bpf2go; DO NOT EDIT. + +package ebpf + +import ( + "bytes" + _ "embed" + "fmt" + "io" + + "github.com/cilium/ebpf" +) + +// LoadZeroEntrypoint returns the embedded CollectionSpec for ZeroEntrypoint. +func LoadZeroEntrypoint() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_ZeroEntrypointBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load ZeroEntrypoint: %w", err) + } + + return spec, err +} + +// LoadZeroEntrypointObjects loads ZeroEntrypoint and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *ZeroEntrypointObjects +// *ZeroEntrypointPrograms +// *ZeroEntrypointMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func LoadZeroEntrypointObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := LoadZeroEntrypoint() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// ZeroEntrypointSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type ZeroEntrypointSpecs struct { + ZeroEntrypointProgramSpecs + ZeroEntrypointMapSpecs +} + +// ZeroEntrypointSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type ZeroEntrypointProgramSpecs struct { + UpfN3EntrypointFunc *ebpf.ProgramSpec `ebpf:"upf_n3_entrypoint_func"` +} + +// ZeroEntrypointMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type ZeroEntrypointMapSpecs struct { +} + +// ZeroEntrypointObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to LoadZeroEntrypointObjects or ebpf.CollectionSpec.LoadAndAssign. +type ZeroEntrypointObjects struct { + ZeroEntrypointPrograms + ZeroEntrypointMaps +} + +func (o *ZeroEntrypointObjects) Close() error { + return _ZeroEntrypointClose( + &o.ZeroEntrypointPrograms, + &o.ZeroEntrypointMaps, + ) +} + +// ZeroEntrypointMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to LoadZeroEntrypointObjects or ebpf.CollectionSpec.LoadAndAssign. +type ZeroEntrypointMaps struct { +} + +func (m *ZeroEntrypointMaps) Close() error { + return _ZeroEntrypointClose() +} + +// ZeroEntrypointPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to LoadZeroEntrypointObjects or ebpf.CollectionSpec.LoadAndAssign. +type ZeroEntrypointPrograms struct { + UpfN3EntrypointFunc *ebpf.Program `ebpf:"upf_n3_entrypoint_func"` +} + +func (p *ZeroEntrypointPrograms) Close() error { + return _ZeroEntrypointClose( + p.UpfN3EntrypointFunc, + ) +} + +func _ZeroEntrypointClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed zeroentrypoint_bpf.o +var _ZeroEntrypointBytes []byte diff --git a/lib/eupf/ebpf/zeroentrypoint_bpf.o b/lib/eupf/ebpf/zeroentrypoint_bpf.o new file mode 100644 index 00000000..6e74f321 Binary files /dev/null and b/lib/eupf/ebpf/zeroentrypoint_bpf.o differ diff --git a/lib/eupf/generate.sh b/lib/eupf/generate.sh new file mode 100755 index 00000000..1cdb795c --- /dev/null +++ b/lib/eupf/generate.sh @@ -0,0 +1,2 @@ +#!/bin/bash +go generate -v ./ebpf/... diff --git a/lib/gtp5g/.gitignore b/lib/gtp5g/.gitignore deleted file mode 100644 index ec7395af..00000000 --- a/lib/gtp5g/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -# Compile output -*.o -*.ko -*.cmd -*.mod -*.mod.c -Module.symvers -modules.order - -# Ctags -tags - -# VSCode -.vscode - diff --git a/lib/gtp5g/LICENSE b/lib/gtp5g/LICENSE deleted file mode 100644 index d159169d..00000000 --- a/lib/gtp5g/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/lib/gtp5g/Makefile b/lib/gtp5g/Makefile deleted file mode 100644 index 00c6e4b8..00000000 --- a/lib/gtp5g/Makefile +++ /dev/null @@ -1,98 +0,0 @@ - -RHEL8 := $(shell cat /etc/redhat-release 2>/dev/null | grep -c " 8." ) -ifneq (,$(findstring 1, $(RHEL8))) - RHEL8FLAG := -DRHEL8 -endif - -PWD := $(shell pwd) -MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -MAKEFILE_DIR := $(shell dirname $(MAKEFILE_PATH)) - -CONFIG_MODULE_SIG=n -MODULE_NAME = gtp5g -MOD_KERNEL_PATH := kernel/drivers/net - -ifeq ($(KVER),) - KVER := $(shell uname -r) -endif - -ifeq ($(KDIR),) - KDIR := /lib/modules/$(KVER)/build -endif - -ifneq ($(RHEL8FLAG),) - INSTALL := $(MAKE) -C $(KDIR) M=$$PWD INSTALL_MOD_PATH=$(DESTDIR) INSTALL_MOD_DIR=$(MOD_KERNEL_PATH) modules_install -else - INSTALL := cp $(MODULE_NAME).ko $(DESTDIR)/lib/modules/$(KVER)/$(MOD_KERNEL_PATH) - RUN_DEPMOD := true -endif - -ifneq ($(RUN_DEPMOD),) - DEPMOD := /sbin/depmod -a -else - DEPMOD := true -endif - -MY_CFLAGS += -g -DDEBUG $(RHEL8FLAG) -# MY_CFLAGS += -DMATCH_IP # match IP address(in F-TEID) or not -EXTRA_CFLAGS += -Wno-misleading-indentation -Wuninitialized -CC += ${MY_CFLAGS} - -EXTRA_CFLAGS += -I $(MAKEFILE_DIR)/include - -5G_MOD := src/gtp5g.o - -5G_LOG := src/log.o - -5G_UTIL := src/util.o - -5G_GTPU := src/gtpu/dev.o \ - src/gtpu/encap.o \ - src/gtpu/hash.o \ - src/gtpu/link.o \ - src/gtpu/net.o \ - src/gtpu/pktinfo.o - -5G_GENL := src/genl/genl.o \ - src/genl/genl_version.o \ - src/genl/genl_pdr.o \ - src/genl/genl_far.o \ - src/genl/genl_qer.o \ - src/genl/genl_urr.o \ - src/genl/genl_report.o \ - src/genl/genl_bar.o - -5G_PFCP := src/pfcp/api_version.o \ - src/pfcp/pdr.o \ - src/pfcp/far.o \ - src/pfcp/qer.o \ - src/pfcp/urr.o \ - src/pfcp/bar.o \ - src/pfcp/seid.o - -5G_PROC := src/proc.o - -# Build files -obj-m += $(MODULE_NAME).o -$(MODULE_NAME)-objs := $(5G_MOD) $(5G_LOG) $(5G_UTIL) $(5G_GTPU) \ - $(5G_GENL) $(5G_PFCP) $(5G_PROC) - -default: module - -module: - $(MAKE) -C $(KDIR) M=$(PWD) modules -clean: - $(MAKE) -C $(KDIR) M=$(PWD) clean - -install: - $(INSTALL) - modprobe udp_tunnel - $(DEPMOD) - modprobe $(MODULE_NAME) - echo "gtp5g" >> /etc/modules - -uninstall: - rm -f $(DESTDIR)/lib/modules/$(KVER)/$(MOD_KERNEL_PATH)/$(MODULE_NAME).ko - $(DEPMOD) - sed -zi "s/gtp5g\n//g" /etc/modules - rmmod -f $(MODULE_NAME) diff --git a/lib/gtp5g/README.md b/lib/gtp5g/README.md deleted file mode 100644 index c411f54f..00000000 --- a/lib/gtp5g/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# gtp5g - 5G compatible GTP kernel module -gtp5g is a customized Linux kernel module gtp5g to handle packet by PFCP IEs such as PDR and FAR. -For detailed information, please reference to 3GPP specification TS 29.281 and TS 29.244. - -## Notice -Due to the evolution of Linux kernel, this module would not work with every kernel version. -Please run this module with kernel version `5.0.0-23-generic`, upper than `5.4` (Ubuntu 20.04) or RHEL8. - -Please check the [libgtp5gnl](https://github.com/free5gc/libgtp5gnl) version is the same as gtp5g, -because the type translating between libgtp5gnl and gtp5g had been changed. - -## Usage -### Compile -``` -git clone https://github.com/free5gc/gtp5g.git && cd gtp5g -make clean && make -``` - -### Install kernel module -Install the module to the system and load automatically at boot -``` -sudo make install -``` - -### Remove kernel module -Remove the kernel module from the system -``` -sudo make uninstall -``` -### Create a gtp5g interface and update Rules -The gtp5g interface will be created by using libgtp5gnl scripts -1) Checkout the latest or compatible source of libgtp5gnl -2) cd libgtp5gnl -3) Create an interface and update rules - + sudo ./run.sh UPF_PDR_FAR_QER -4) Troubleshoot - ``` - dmesg - ``` - ``` - # if UPF used legacy netlink struct without SEID, need use #SEID=0 to query related info as below: - echo #interfaceName #SEID #PDRID > /proc/gtp5g/pdr - echo #interfaceName #SEID #FARID > /proc/gtp5g/far - echo #interfaceName #SEID #QERID > /proc/gtp5g/qer - ``` - ``` - cat /proc/gtp5g/pdr - cat /proc/gtp5g/far - cat /proc/gtp5g/qer - ``` -5) Delete an interface - + sudo ./run.sh Clean - + Note: It will delete list of rules and interface diff --git a/lib/gtp5g/include/api_version.h b/lib/gtp5g/include/api_version.h deleted file mode 100644 index 35f831f8..00000000 --- a/lib/gtp5g/include/api_version.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __API_VERSION_H__ -#define __API_VERSION_H__ - -extern void set_far_action_u16(bool); -extern bool far_action_is_u16(void); - -#endif // __API_VERSION_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/bar.h b/lib/gtp5g/include/bar.h deleted file mode 100644 index 7616fe89..00000000 --- a/lib/gtp5g/include/bar.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __BAR_H__ -#define __BAR_H__ - -#include -#include -#include - -#include "dev.h" - -#define SEID_U32ID_HEX_STR_LEN 24 - -struct bar { - struct hlist_node hlist_id; - u64 seid; - u8 id; - uint8_t delay; - uint16_t count; - struct net_device *dev; - struct rcu_head rcu_head; -}; - -extern void bar_context_delete(struct bar *); -extern struct bar *find_bar_by_id(struct gtp5g_dev *, u64, u32); -extern void bar_update(struct bar *, struct gtp5g_dev *); -extern void bar_append(u64, u32, struct bar *, struct gtp5g_dev *); -extern int bar_get_far_ids(u32 *, int, struct bar *, struct gtp5g_dev *); -extern void bar_set_far(u64, u32, struct hlist_node *, struct gtp5g_dev *); - -#endif // __BAR_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/common.h b/lib/gtp5g/include/common.h deleted file mode 100644 index d654a1fc..00000000 --- a/lib/gtp5g/include/common.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __COMMON_H__ -#define __COMMON_H__ - -#define MAX_PDR_PER_SESSION 0xFF - -#endif // __COMMON_H__ diff --git a/lib/gtp5g/include/dev.h b/lib/gtp5g/include/dev.h deleted file mode 100644 index 0bbdeab3..00000000 --- a/lib/gtp5g/include/dev.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __GTP5G_DEV_H__ -#define __GTP5G_DEV_H__ - -#include -#include -#include - -struct gtp5g_dev { - struct list_head list; - struct sock *sk1u; // UDP socket from user space - struct net_device *dev; - unsigned int role; - unsigned int hash_size; - struct hlist_head *pdr_id_hash; - struct hlist_head *far_id_hash; - struct hlist_head *qer_id_hash; - struct hlist_head *bar_id_hash; - struct hlist_head *urr_id_hash; - - struct hlist_head *i_teid_hash; // Used for GTP-U packet detect - struct hlist_head *addr_hash; // Used for IPv4 packet detect - - /* IEs list related to PDR */ - struct hlist_head *related_far_hash; // PDR list waiting the FAR to handle - struct hlist_head *related_qer_hash; // PDR list waiting the QER to handle - struct hlist_head *related_bar_hash; - struct hlist_head *related_urr_hash; - - /* Used by proc interface */ - struct list_head proc_list; -}; - -extern const struct net_device_ops gtp5g_netdev_ops; - -extern struct gtp5g_dev *gtp5g_find_dev(struct net *, int, int); - -extern int dev_hashtable_new(struct gtp5g_dev *, int); -extern void gtp5g_hashtable_free(struct gtp5g_dev *); - -#endif // __GTP5G_DEV_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/encap.h b/lib/gtp5g/include/encap.h deleted file mode 100644 index 551658d1..00000000 --- a/lib/gtp5g/include/encap.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __ENCAP_H__ -#define __ENCAP_H__ - -#include - -#include "dev.h" -#include "pktinfo.h" - -enum gtp5g_msg_type_attrs { - GTP5G_BUFFER = 1, - GTP5G_REPORT, - - __GTP5G_MSG_TYPE_ATTR_MAX, -}; -#define GTP5G_MSG_TYPE_ATTR_MAX (__GTP5G_MSG_TYPE_ATTR_MAX - 1); - -enum gtp5g_buffer_attrs { - /* gtp5g_device_attrs in this part */ - - GTP5G_BUFFER_PAD = 3, - GTP5G_BUFFER_PACKET, - GTP5G_BUFFER_ID, - GTP5G_BUFFER_SEID, - GTP5G_BUFFER_ACTION, - - /* Add newly supported feature ON ABOVE - * for compatability with older version of - * free5GC's UPF or libgtp5gnl - * */ - - __GTP5G_BUFFER_ATTR_MAX, -}; -#define GTP5G_BUFFER_ATTR_MAX (__GTP5G_BUFFER_ATTR_MAX - 1) - -extern struct sock *gtp5g_encap_enable(int, int, struct gtp5g_dev *); -extern void gtp5g_encap_disable(struct sock *); -extern int gtp5g_handle_skb_ipv4(struct sk_buff *, struct net_device *, - struct gtp5g_pktinfo *); - -#endif // __ENCAP_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/far.h b/lib/gtp5g/include/far.h deleted file mode 100644 index 1f711e60..00000000 --- a/lib/gtp5g/include/far.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef __FAR_H__ -#define __FAR_H__ - -#include -#include -#include -#include - -#include "pktinfo.h" -#include "bar.h" -#include "pdr.h" - -#define SEID_U32ID_HEX_STR_LEN 24 - -#define FAR_ACTION_UPSPEC 0x00 -#define FAR_ACTION_DROP 0x01 -#define FAR_ACTION_FORW 0x02 -#define FAR_ACTION_BUFF 0x04 -#define FAR_ACTION_MASK 0x07 -#define FAR_ACTION_NOCP 0x08 -#define FAR_ACTION_DUPL 0x10 - -#define FAR_ACTION_U8 1 -#define FAR_ACTION_U16 2 - -struct outer_header_creation { - u16 description; - u32 teid; - struct in_addr peer_addr_ipv4; - u16 port; -}; - -struct forwarding_policy { - int len; - char identifier[0xff + 1]; - /* Exact value to handle forwarding policy */ - u32 mark; -}; - -struct forwarding_parameter { - struct outer_header_creation *hdr_creation; - struct forwarding_policy *fwd_policy; -}; - -struct far { - struct hlist_node hlist_id; - struct hlist_node hlist_related_bar; - u64 seid; - u32 id; - u16 action; - struct forwarding_parameter __rcu *fwd_param; - u8 *bar_id; - struct bar *bar; - struct net_device *dev; - struct rcu_head rcu_head; -}; - -extern void far_context_delete(struct far *); -extern struct far *find_far_by_id(struct gtp5g_dev *, u64, u32); -extern void far_update(struct far *, struct gtp5g_dev *, u8 *, - struct gtp5g_emark_pktinfo *); -extern void far_append(u64, u32, struct far *, struct gtp5g_dev *); -extern int far_get_pdr_ids(u16 *, int, struct far *, struct gtp5g_dev *); -extern int far_set_pdr(struct pdr *, struct gtp5g_dev *); -extern void del_related_far_hash(struct gtp5g_dev *, struct pdr *); - -#endif // __FAR_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/genl.h b/lib/gtp5g/include/genl.h deleted file mode 100644 index e08d0873..00000000 --- a/lib/gtp5g/include/genl.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef __GTP5G_GENL_H__ -#define __GTP5G_GENL_H__ - -#include - -enum gtp5g_cmd { - GTP5G_CMD_UNSPEC = 0, - - GTP5G_CMD_ADD_PDR, - GTP5G_CMD_ADD_FAR, - GTP5G_CMD_ADD_QER, - - GTP5G_CMD_DEL_PDR, - GTP5G_CMD_DEL_FAR, - GTP5G_CMD_DEL_QER, - - GTP5G_CMD_GET_PDR, - GTP5G_CMD_GET_FAR, - GTP5G_CMD_GET_QER, - - GTP5G_CMD_ADD_URR, - GTP5G_CMD_ADD_BAR, - GTP5G_CMD_DEL_URR, - GTP5G_CMD_DEL_BAR, - GTP5G_CMD_GET_URR, - GTP5G_CMD_GET_BAR, - - /* Add newly supported feature ON ABOVE - * for compatability with older version of - * free5GC's UPF or libgtp5gnl - * */ - - GTP5G_CMD_GET_VERSION, - - GTP5G_CMD_GET_REPORT, - - GTP5G_CMD_BUFFER_GTPU, - - GTP5G_CMD_GET_MULTI_REPORTS, - - __GTP5G_CMD_MAX, -}; -#define GTP5G_CMD_MAX (__GTP5G_CMD_MAX - 1) - -/* This const value need to bigger than the Layer 1 attr size, - * like GTP5G_PDR_ATTR_MAX and GTP5G_FAR_ATTR_MAX - */ -#define GTP5G_ATTR_MAX 0x10 - -enum gtp5g_device_attrs { - GTP5G_LINK = 1, - GTP5G_NET_NS_FD, -}; - -enum gtp5g_multicast_groups { - GTP5G_GENL_MCGRP, -}; - -extern struct genl_family gtp5g_genl_family; - -#endif // __GTP5G_GENL_H__ diff --git a/lib/gtp5g/include/genl_bar.h b/lib/gtp5g/include/genl_bar.h deleted file mode 100644 index c17b2ee4..00000000 --- a/lib/gtp5g/include/genl_bar.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __GENL_BAR_H__ -#define __GENL_BAR_H__ - -#include "genl.h" - -/* BAR attributes */ -enum gtp5g_bar_attrs { - GTP5G_BAR_ID = 3, - GTP5G_DOWNLINK_DATA_NOTIFICATION_DELAY, - GTP5G_BUFFERING_PACKETS_COUNT, - GTP5G_BAR_SEID, - - __GTP5G_BAR_ATTR_MAX, -}; -#define GTP5G_BAR_ATTR_MAX (__GTP5G_BAR_ATTR_MAX - 1) - -struct buffer_action { - u64 seid; - u16 notification_delay; - u32 buffer_packet_count; -} __attribute__((packed)); - -/* for kernel */ -extern int gtp5g_genl_add_bar(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_del_bar(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_get_bar(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_dump_bar(struct sk_buff *, struct netlink_callback *); - -#endif // __GENL_BAR_H__ diff --git a/lib/gtp5g/include/genl_far.h b/lib/gtp5g/include/genl_far.h deleted file mode 100644 index 66659ee7..00000000 --- a/lib/gtp5g/include/genl_far.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef __GENL_FAR_H__ -#define __GENL_FAR_H__ - -#include "genl.h" - -enum gtp5g_far_attrs { - /* gtp5g_device_attrs in this part */ - - GTP5G_FAR_ID = 3, - GTP5G_FAR_APPLY_ACTION, - GTP5G_FAR_FORWARDING_PARAMETER, - - /* Not IEs in 3GPP Spec, for other purpose */ - GTP5G_FAR_RELATED_TO_PDR, - - GTP5G_FAR_SEID, - GTP5G_FAR_BAR_ID, - __GTP5G_FAR_ATTR_MAX, -}; -#define GTP5G_FAR_ATTR_MAX (__GTP5G_FAR_ATTR_MAX - 1) - -/* Nest in GTP5G_FAR_FORWARDING_PARAMETER */ -enum gtp5g_forwarding_parameter_attrs { - GTP5G_FORWARDING_PARAMETER_OUTER_HEADER_CREATION = 1, - GTP5G_FORWARDING_PARAMETER_FORWARDING_POLICY, - GTP5G_FORWARDING_PARAMETER_PFCPSM_REQ_FLAGS, - - __GTP5G_FORWARDING_PARAMETER_ATTR_MAX, -}; -#define GTP5G_FORWARDING_PARAMETER_ATTR_MAX (__GTP5G_FORWARDING_PARAMETER_ATTR_MAX - 1) - -/* Nest in GTP5G_FORWARDING_PARAMETER_OUTER_HEADER_CREATION */ -enum gtp5g_outer_header_creation_attrs { - GTP5G_OUTER_HEADER_CREATION_DESCRIPTION = 1, - GTP5G_OUTER_HEADER_CREATION_O_TEID, - GTP5G_OUTER_HEADER_CREATION_PEER_ADDR_IPV4, - GTP5G_OUTER_HEADER_CREATION_PORT, - - __GTP5G_OUTER_HEADER_CREATION_ATTR_MAX, -}; -#define GTP5G_OUTER_HEADER_CREATION_ATTR_MAX (__GTP5G_OUTER_HEADER_CREATION_ATTR_MAX - 1) - -extern int gtp5g_genl_add_far(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_del_far(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_get_far(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_dump_far(struct sk_buff *, struct netlink_callback *); - -#endif // __GENL_FAR_H__ diff --git a/lib/gtp5g/include/genl_pdr.h b/lib/gtp5g/include/genl_pdr.h deleted file mode 100644 index 5e3f3d24..00000000 --- a/lib/gtp5g/include/genl_pdr.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef __GENL_PDR_H__ -#define __GENL_PDR_H__ - -#include "genl.h" - -enum gtp5g_pdr_attrs { - /* gtp5g_device_attrs in this part */ - - GTP5G_PDR_ID = 3, - GTP5G_PDR_PRECEDENCE, - GTP5G_PDR_PDI, - GTP5G_OUTER_HEADER_REMOVAL, - GTP5G_PDR_FAR_ID, - - /* Not in 3GPP spec, just used for routing */ - GTP5G_PDR_ROLE_ADDR_IPV4, - - /* Not in 3GPP spec, just used for buffering */ - GTP5G_PDR_UNIX_SOCKET_PATH, - - GTP5G_PDR_QER_ID, - - GTP5G_PDR_SEID, - GTP5G_PDR_URR_ID, - /* Add newly supported feature ON ABOVE - * for compatability with older version of - * free5GC's UPF or libgtp5gnl - * */ - - __GTP5G_PDR_ATTR_MAX, -}; -#define GTP5G_PDR_ATTR_MAX (__GTP5G_PDR_ATTR_MAX - 1) - -/* Nest in GTP5G_PDR_PDI */ -enum gtp5g_pdi_attrs { - GTP5G_PDI_UNSPEC, - GTP5G_PDI_UE_ADDR_IPV4, - GTP5G_PDI_F_TEID, - GTP5G_PDI_SDF_FILTER, - __GTP5G_PDI_ATTR_MAX, -}; -#define GTP5G_PDI_ATTR_MAX (__GTP5G_PDI_ATTR_MAX - 1) - -/* Nest in GTP5G_PDI_F_TEID */ -enum gtp5g_f_teid_attrs { - GTP5G_F_TEID_UNSPEC, - GTP5G_F_TEID_I_TEID, - GTP5G_F_TEID_GTPU_ADDR_IPV4, - __GTP5G_F_TEID_ATTR_MAX, -}; -#define GTP5G_F_TEID_ATTR_MAX (__GTP5G_F_TEID_ATTR_MAX - 1) - -/* Nest in GTP5G_PDI_SDF_FILTER */ -enum gtp5g_sdf_filter_attrs { - GTP5G_SDF_FILTER_FLOW_DESCRIPTION = 1, - GTP5G_SDF_FILTER_TOS_TRAFFIC_CLASS, - GTP5G_SDF_FILTER_SECURITY_PARAMETER_INDEX, - GTP5G_SDF_FILTER_FLOW_LABEL, - GTP5G_SDF_FILTER_SDF_FILTER_ID, - - __GTP5G_SDF_FILTER_ATTR_MAX, -}; -#define GTP5G_SDF_FILTER_ATTR_MAX (__GTP5G_SDF_FILTER_ATTR_MAX - 1) - -/* Nest in GTP5G_SDF_FILTER_FLOW_DESCRIPTION */ -enum gtp5g_flow_description_attrs { - GTP5G_FLOW_DESCRIPTION_ACTION = 1, // Only "permit" - GTP5G_FLOW_DESCRIPTION_DIRECTION, - GTP5G_FLOW_DESCRIPTION_PROTOCOL, - GTP5G_FLOW_DESCRIPTION_SRC_IPV4, - GTP5G_FLOW_DESCRIPTION_SRC_MASK, - GTP5G_FLOW_DESCRIPTION_DEST_IPV4, - GTP5G_FLOW_DESCRIPTION_DEST_MASK, - GTP5G_FLOW_DESCRIPTION_SRC_PORT, - GTP5G_FLOW_DESCRIPTION_DEST_PORT, - - __GTP5G_FLOW_DESCRIPTION_ATTR_MAX, -}; -#define GTP5G_FLOW_DESCRIPTION_ATTR_MAX (__GTP5G_FLOW_DESCRIPTION_ATTR_MAX - 1) - -enum { - GTP5G_SDF_FILTER_ACTION_UNSPEC = 0, - GTP5G_SDF_FILTER_PERMIT, - __GTP5G_SDF_FILTER_ACTION_MAX, -}; -#define GTP5G_SDF_FILTER_ACTION_MAX (__GTP5G_SDF_FILTER_ACTION_MAX - 1) - -enum { - GTP5G_SDF_FILTER_DIRECTION_UNSPEC = 0, - GTP5G_SDF_FILTER_IN, - GTP5G_SDF_FILTER_OUT, - __GTP5G_SDF_FILTER_DIRECTION_MAX, -}; -#define GTP5G_SDF_FILTER_DIRECTION_MAX (__GTP5G_SDF_FILTER_DIRECTION_MAX - 1) - -extern int gtp5g_genl_add_pdr(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_del_pdr(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_get_pdr(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_dump_pdr(struct sk_buff *, struct netlink_callback *); - -#endif // __GENL_PDR_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/genl_qer.h b/lib/gtp5g/include/genl_qer.h deleted file mode 100644 index add135fb..00000000 --- a/lib/gtp5g/include/genl_qer.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef __GENL_QER_H__ -#define __GENL_QER_H__ - -#include "genl.h" - -enum gtp5g_qer_attrs { - /* gtp5g_device_attrs in this part */ - - GTP5G_QER_ID = 3, - GTP5G_QER_GATE, - GTP5G_QER_MBR, - GTP5G_QER_GBR, - GTP5G_QER_CORR_ID, - GTP5G_QER_RQI, - GTP5G_QER_QFI, - GTP5G_QER_PPI, - GTP5G_QER_RCSR, - - /* Not IEs in 3GPP Spec, for other purpose */ - GTP5G_QER_RELATED_TO_PDR, - - GTP5G_QER_SEID, - __GTP5G_QER_ATTR_MAX, -}; -#define GTP5G_QER_ATTR_MAX (__GTP5G_QER_ATTR_MAX - 1) - -/* Nest in GTP5G_QER_MBR */ -enum gtp5g_mbr_attrs { - GTP5G_QER_MBR_UL_HIGH32 = 1, - GTP5G_QER_MBR_UL_LOW8, - GTP5G_QER_MBR_DL_HIGH32, - GTP5G_QER_MBR_DL_LOW8, - - __GTP5G_QER_MBR_ATTR_MAX, -}; -#define GTP5G_QER_MBR_ATTR_MAX (__GTP5G_QER_MBR_ATTR_MAX - 1) - -/* Nest in GTP5G_QER_QBR */ -enum gtp5g_qer_gbr_attrs { - GTP5G_QER_GBR_UL_HIGH32 = 1, - GTP5G_QER_GBR_UL_LOW8, - GTP5G_QER_GBR_DL_HIGH32, - GTP5G_QER_GBR_DL_LOW8, - - __GTP5G_QER_GBR_ATTR_MAX, -}; -#define GTP5G_QER_GBR_ATTR_MAX (__GTP5G_QER_GBR_ATTR_MAX - 1) - -extern int gtp5g_genl_add_qer(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_del_qer(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_get_qer(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_dump_qer(struct sk_buff *, struct netlink_callback *); - -#endif // __GENL_QER_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/genl_report.h b/lib/gtp5g/include/genl_report.h deleted file mode 100644 index 612260a4..00000000 --- a/lib/gtp5g/include/genl_report.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __GENL_REPORT_H__ -#define __GENL_REPORT_H__ - -#include "genl.h" -#include "urr.h" - -/* Nest in GTP5G_UR_VOLUME_MEASUREMENT */ -enum gtp5g_usage_report_volume_measurement_attrs { - GTP5G_UR_VOLUME_MEASUREMENT_FLAGS = 1, - - GTP5G_UR_VOLUME_MEASUREMENT_TOVOL, - GTP5G_UR_VOLUME_MEASUREMENT_UVOL, - GTP5G_UR_VOLUME_MEASUREMENT_DVOL, - - GTP5G_UR_VOLUME_MEASUREMENT_TOPACKET, - GTP5G_UR_VOLUME_MEASUREMENT_UPACKET, - GTP5G_UR_VOLUME_MEASUREMENT_DPACKET, - - __GTP5G_UR_VOLUME_MEASUREMENT_ATTR_MAX, -}; -#define GTP5G_UR_VOLUME_MEASUREMENT_ATTR_MAX (__GTP5G_UR_VOLUME_MEASUREMENT_ATTR_MAX - 1) - -enum gtp5g_usage_report_attrs { - GTP5G_UR_URRID = 3, - GTP5G_UR_USAGE_REPORT_TRIGGER, - GTP5G_UR_URSEQN, - GTP5G_UR_VOLUME_MEASUREMENT, - GTP5G_UR_QUERY_URR_REFERENCE, - GTP5G_UR_START_TIME, - GTP5G_UR_END_TIME, - GTP5G_UR_SEID, - - __GTP5G_UR_ATTR_MAX, -}; -#define GTP5G_UR_ATTR_MAX (__GTP5G_UR_ATTR_MAX - 1) - -enum gtp5g_multi_usage_report_attrs { - GTP5G_UR = 5, - - __GTP5G_URS_ATTR_MAX, -}; - -extern int gtp5g_genl_get_usage_report(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_get_multi_usage_reports(struct sk_buff *, struct genl_info *); - -extern int gtp5g_genl_fill_ur(struct sk_buff *, struct usage_report *); -extern int gtp5g_genl_fill_usage_report(struct sk_buff *, u32, u32, u32, struct usage_report *); -extern int gtp5g_genl_fill_multi_usage_reports(struct sk_buff *, u32, u32, u32, struct usage_report **, u32); - -extern void convert_urr_to_report(struct urr *, struct usage_report *); -#endif // __GENL_URR_H__ diff --git a/lib/gtp5g/include/genl_urr.h b/lib/gtp5g/include/genl_urr.h deleted file mode 100644 index 5e8f59b1..00000000 --- a/lib/gtp5g/include/genl_urr.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef __GENL_URR_H__ -#define __GENL_URR_H__ - -#include "genl.h" - -enum gtp5g_urr_attrs { - GTP5G_URR_ID = 3, - GTP5G_URR_MEASUREMENT_METHOD, - GTP5G_URR_REPORTING_TRIGGER, - GTP5G_URR_MEASUREMENT_PERIOD, - GTP5G_URR_MEASUREMENT_INFO, - GTP5G_URR_SEID, - - GTP5G_URR_VOLUME_THRESHOLD, - GTP5G_URR_VOLUME_QUOTA, - GTP5G_URR_MULTI_SEID_URRID, - GTP5G_URR_NUM, - - /* Not IEs in 3GPP Spec, for other purpose */ - GTP5G_URR_RELATED_TO_PDR, - - __GTP5G_URR_ATTR_MAX, -}; -#define GTP5G_URR_ATTR_MAX (__GTP5G_URR_ATTR_MAX - 1) - -/* Nest in GTP5G_URR_VOL_THRESHOLD */ -enum gtp5g_urr_volume_threshold_attrs { - GTP5G_URR_VOLUME_THRESHOLD_FLAG = 1, - - GTP5G_URR_VOLUME_THRESHOLD_TOVOL, - GTP5G_URR_VOLUME_THRESHOLD_UVOL, - GTP5G_URR_VOLUME_THRESHOLD_DVOL, - - __GTP5G_URR_VOLUME_THRESHOLD_ATTR_MAX, -}; -#define GTP5G_URR_VOLUME_THRESHOLD_ATTR_MAX (__GTP5G_URR_VOLUME_THRESHOLD_ATTR_MAX - 1) - -/* Nest in GTP5G_URR_VOL_QUOTA */ -enum gtp5g_urr_volume_quota_attrs { - GTP5G_URR_VOLUME_QUOTA_FLAG = 1, - - GTP5G_URR_VOLUME_QUOTA_TOVOL, - GTP5G_URR_VOLUME_QUOTA_UVOL, - GTP5G_URR_VOLUME_QUOTA_DVOL, - - __GTP5G_URR_VOLUME_QUOTA_ATTR_MAX, -}; -#define GTP5G_URR_VOLUME_QUOTA_ATTR_MAX (__GTP5G_URR_VOLUME_QUOTA_ATTR_MAX - 1) - -struct seid_urr { - u64 seid; - u32 urrid; -}; - -extern int gtp5g_genl_add_urr(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_del_urr(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_get_urr(struct sk_buff *, struct genl_info *); -extern int gtp5g_genl_dump_urr(struct sk_buff *, struct netlink_callback *); - -#endif // __GENL_URR_H__ diff --git a/lib/gtp5g/include/genl_version.h b/lib/gtp5g/include/genl_version.h deleted file mode 100644 index 042140bd..00000000 --- a/lib/gtp5g/include/genl_version.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __GENL_VERSION_H__ -#define __GENL_VERSION_H__ - -#include "genl.h" - -#define DRV_VERSION "0.8.2" - -enum gtp5g_version { - GTP5G_VERSION -}; - -extern int gtp5g_genl_get_version(struct sk_buff *, struct genl_info *); - -#endif // __GENL_VERSION_H__ diff --git a/lib/gtp5g/include/gtp.h b/lib/gtp5g/include/gtp.h deleted file mode 100644 index 40d25a3e..00000000 --- a/lib/gtp5g/include/gtp.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef __GTP5G_GTP_H__ -#define __GTP5G_GTP_H__ - -#include - -#define GTPV1 0x30 - -/* gtpv1_hdr flags */ -#define GTPV1_HDR_FLG_NPDU 0x01 -#define GTPV1_HDR_FLG_SEQ 0x02 -#define GTPV1_HDR_FLG_EXTHDR 0x04 -#define GTPV1_HDR_FLG_MASK 0x07 - -/* According to 3GPP TS 29.060. */ -struct gtpv1_hdr { - __u8 flags; - __u8 type; - __be16 length; - __be32 tid; -} __attribute__((packed)); - -typedef struct gtp1_hdr_opt { - __be16 seq_number; - __u8 NPDU; - __u8 next_ehdr_type; -} __attribute__((packed)) gtpv1_hdr_opt_t; - -struct recovery { - __u8 type_num; - __u8 cnt; -}__attribute__((packed)); - -struct gtpv1_echo_resp { - struct gtpv1_hdr gtpv1_h; - struct gtp1_hdr_opt gtpv1_opt_h; - struct recovery recov; -} __attribute__((packed)); - -/** 3GPP TS 29.281 - * From Figure 5.2.1-2 Definition of Extension Header Type - */ -#define GTPV1_NEXT_EXT_HDR_TYPE_00 0x00 /* No More extension */ -#define GTPV1_NEXT_EXT_HDR_TYPE_03 0x03 /* Long PDCP PDU Number */ -#define GTPV1_NEXT_EXT_HDR_TYPE_20 0x20 /* Service Class Indicator */ -#define GTPV1_NEXT_EXT_HDR_TYPE_40 0x40 /* UDP Port */ -#define GTPV1_NEXT_EXT_HDR_TYPE_81 0x81 /* RAN Container */ -#define GTPV1_NEXT_EXT_HDR_TYPE_82 0x82 /* Long PDCP PDU Number */ -#define GTPV1_NEXT_EXT_HDR_TYPE_83 0x83 /* Xw RAN Container */ -#define GTPV1_NEXT_EXT_HDR_TYPE_84 0x84 /* NR RAN Container */ -#define GTPV1_NEXT_EXT_HDR_TYPE_85 0x85 /* PDU Session Container */ -#define GTPV1_NEXT_EXT_HDR_TYPE_C0 0xc0 /* PDCP PDU Number */ - -#define GTP1U_PORT 2152 - -#define GTPV1_MSG_TYPE_ECHO_REQ 1 -#define GTPV1_MSG_TYPE_ECHO_RSP 2 -#define GTPV1_MSG_TYPE_EMARK 254 -#define GTPV1_MSG_TYPE_TPDU 255 - -#define GTPV1_IE_RECOVERY 14 - -typedef struct ul_pdu_sess_info { - __u8 spare_qfi; /* Spare(2b) + qfi(6b)*/ -} __attribute__((packed)) ul_pdu_sess_info_t; - -typedef struct dl_pdu_sess_info { - __u8 ppp_rqi_qfi; /* ppp(1b) + rqi(1b) + qfi(6) */ -} __attribute__((packed)) dl_pdu_sess_info_t; - -typedef struct dl_pdu_sess_info_ppi { - __u8 ppi_spare; /* ppi(3b) + spare(5b) */ - __u8 padding[3]; -} __attribute__((packed)) dl_pdu_sess_info_ppi_t; - -typedef struct pdu_sess_ctr { - __u8 type_spare; /* type(4b) + spare(4b) */ -#define PDU_SESSION_INFO_TYPE0 0x00 -#define PDU_SESSION_INFO_TYPE1 0x10 - union { - ul_pdu_sess_info_t ul; - dl_pdu_sess_info_t dl; - } u; - //dl_pdu_sess_info_ppi_t dl_ppi[0]; -} __attribute__((packed)) pdu_sess_ctr_t; - -typedef struct gtp1_hdr_ext_pdu_sess_ctr { - __u8 length; - pdu_sess_ctr_t pdu_sess_ctr; - __u8 next_ehdr_type; -} __attribute__((packed)) ext_pdu_sess_ctr_t; - -#endif // __GTP5G_GTP_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/hash.h b/lib/gtp5g/include/hash.h deleted file mode 100644 index c68f6146..00000000 --- a/lib/gtp5g/include/hash.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __HASH_H__ -#define __HASH_H__ - -#include - -#include - -extern u32 gtp5g_h_initval; - -static inline u32 u32_hashfn(u32 val) -{ - return jhash_1word(val, gtp5g_h_initval); -} - -static inline u32 str_hashfn(char *str) -{ - return jhash(str, strlen(str), 0); -} - -static inline u32 ipv4_hashfn(__be32 ip) -{ - return jhash_1word((__force u32)ip, gtp5g_h_initval); -} - -#endif // __HASH_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/link.h b/lib/gtp5g/include/link.h deleted file mode 100644 index 2b4ea0c9..00000000 --- a/lib/gtp5g/include/link.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __GTP5G_LINK_H__ -#define __GTP5G_LINK_H__ - -#include - -enum { - IFLA_GTP5G_UNSPEC, - - IFLA_GTP5G_FD1, - IFLA_GTP5G_PDR_HASHSIZE, - IFLA_GTP5G_ROLE, - - __IFLA_GTP5G_MAX, -}; -#define IFLA_GTP5G_MAX (__IFLA_GTP5G_MAX - 1) -/* end of part */ - -enum ifla_gtp5g_role { - GTP5G_ROLE_UPF = 0, - GTP5G_ROLE_RAN, -}; - -extern struct rtnl_link_ops gtp5g_link_ops; - -extern void gtp5g_link_all_del(struct list_head *); - -#endif // __GTP5G_LINK_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/log.h b/lib/gtp5g/include/log.h deleted file mode 100644 index 596d19db..00000000 --- a/lib/gtp5g/include/log.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __GTP5G_LOG_H__ -#define __GTP5G_LOG_H__ - -#include - -#define DBG(level, dev, fmt, args...) do { \ - if (level <= get_dbg_lvl()) { \ - if (dev) \ - printk_ratelimited("%s:[gtp5g] %s: "fmt, netdev_name(dev), __func__, ##args); \ - else \ - printk_ratelimited("[gtp5g] %s: " fmt, __func__, ##args); \ - } \ -} while(0) - -#define GTP5G_LOG(dev, fmt, args...) DBG(0, dev, fmt, ##args) -#define GTP5G_ERR(dev, fmt, args...) DBG(1, dev, fmt, ##args) -#define GTP5G_WAR(dev, fmt, args...) DBG(2, dev, fmt, ##args) -#define GTP5G_INF(dev, fmt, args...) DBG(3, dev, fmt, ##args) -#define GTP5G_TRC(dev, fmt, args...) DBG(4, dev, fmt, ##args) - -extern int get_dbg_lvl(void); -extern void set_dbg_lvl(int); - -#endif // __GTP5G_LOG_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/net.h b/lib/gtp5g/include/net.h deleted file mode 100644 index 3ed96301..00000000 --- a/lib/gtp5g/include/net.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __GTP5G_NET_H__ -#define __GTP5G_NET_H__ - -#include -#include - -struct gtp5g_net { - struct list_head gtp5g_dev_list; -}; - -extern struct pernet_operations gtp5g_net_ops; - -#define GTP5G_NET_ID() (*gtp5g_net_ops.id) - -#endif // __GTP5G_NET_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/pdr.h b/lib/gtp5g/include/pdr.h deleted file mode 100644 index c4e82b5f..00000000 --- a/lib/gtp5g/include/pdr.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef __PDR_H__ -#define __PDR_H__ - -#include -#include -#include -#include -#include -#include -#include - -#include "urr.h" - -#define SEID_U32ID_HEX_STR_LEN 24 - -struct local_f_teid { - u32 teid; - struct in_addr gtpu_addr_ipv4; -}; - -struct ip_filter_rule { - uint8_t action; - uint8_t direction; - uint8_t proto; - struct in_addr src; - struct in_addr smask; - struct in_addr dest; - struct in_addr dmask; - int sport_num; - struct range *sport; - int dport_num; - struct range *dport; -}; - -struct sdf_filter { - struct ip_filter_rule *rule; - uint16_t *tos_traffic_class; - u32 *security_param_idx; - u32 *flow_label; - u32 *bi_id; -}; - -struct pdi { - struct in_addr *ue_addr_ipv4; - struct local_f_teid *f_teid; - struct sdf_filter *sdf; -}; - -#define QER_ID_SIZE sizeof(u32) -#define URR_ID_SIZE sizeof(u32) - -struct pdr_node { - struct hlist_node hlist; - struct pdr *pdr; -}; - -struct pdr { - struct hlist_node hlist_id; - struct hlist_node hlist_i_teid; - struct hlist_node hlist_addr; - - u64 seid; - u16 id; - u32 precedence; - u8 *outer_header_removal; - struct pdi *pdi; - u32 *far_id; - struct far __rcu *far; - u32 *qer_ids; - u32 qer_num; - u8 qfi; - u32 *urr_ids; - u32 urr_num; - struct urr *urr; - - /* deprecated: AF_UNIX socket for buffer */ - struct sockaddr_un addr_unix; - struct socket *sock_for_buf; - - u16 af; - struct in_addr role_addr_ipv4; - struct sock *sk; - struct net_device *dev; - struct rcu_head rcu_head; - - /* Drop Counter */ - u64 ul_drop_cnt; - u64 dl_drop_cnt; - - /* Packet Statistics */ - u64 ul_pkt_cnt; - u64 dl_pkt_cnt; - u64 ul_byte_cnt; - u64 dl_byte_cnt; -}; - -extern void pdr_context_delete(struct pdr *); -extern struct pdr *find_pdr_by_id(struct gtp5g_dev *, u64, u16); -extern struct pdr *pdr_find_by_gtp1u(struct gtp5g_dev *, struct sk_buff *, - unsigned int, u32, u8); -extern struct pdr *pdr_find_by_ipv4(struct gtp5g_dev *, struct sk_buff *, - unsigned int, __be32); -extern int find_qer_id_in_pdr(struct pdr *, u32); -extern int find_urr_id_in_pdr(struct pdr *, u32); - -extern void pdr_append(u64, u16, struct pdr *, struct gtp5g_dev *); -extern void pdr_update_hlist_table(struct pdr *, struct gtp5g_dev *); - -extern void unix_sock_client_delete(struct pdr *); -extern int unix_sock_client_new(struct pdr *); -extern int unix_sock_client_update(struct pdr *, struct far *); - -static inline bool pdr_addr_is_netlink(struct pdr *pdr) -{ - return (pdr->addr_unix.sun_path[0] == '/' && pdr->addr_unix.sun_path[1] == 0); -} - -#endif // __PDR_H__ diff --git a/lib/gtp5g/include/pktinfo.h b/lib/gtp5g/include/pktinfo.h deleted file mode 100644 index f0f3fc22..00000000 --- a/lib/gtp5g/include/pktinfo.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef __PKTINFO_H__ -#define __PKTINFO_H__ - -#include -#include - -#include "qer.h" - -struct gtp5g_pktinfo { - struct sock *sk; - struct iphdr *iph; - struct flowi4 fl4; - struct rtable *rt; - struct outer_header_creation *hdr_creation; - u8 qfi; - struct net_device *dev; - __be16 gtph_port; -}; - -struct gtp5g_emark_pktinfo { - u32 teid; - u32 peer_addr; - u32 local_addr; - u32 role_addr; - - struct sock *sk; - struct flowi4 fl4; - struct rtable *rt; - struct net_device *dev; - __be16 gtph_port; -}; - -extern u64 ip4_rm_header(struct sk_buff *skb, unsigned int hdrlen); -extern struct rtable *ip4_find_route(struct sk_buff *, struct iphdr *, - struct sock *, struct net_device *, - __be32, __be32, struct flowi4 *); -extern void gtp5g_fwd_emark_skb_ipv4(struct sk_buff *, - struct net_device *, struct gtp5g_emark_pktinfo *); -extern int ip_xmit(struct sk_buff *, struct sock *, struct net_device *); -extern void gtp5g_xmit_skb_ipv4(struct sk_buff *, struct gtp5g_pktinfo *); - -extern void gtp5g_set_pktinfo_ipv4(struct gtp5g_pktinfo *, - struct sock *, struct iphdr *, - struct outer_header_creation *, - u8, struct rtable *, struct flowi4 *, - struct net_device *); -extern void gtp5g_push_header(struct sk_buff *, struct gtp5g_pktinfo *); - -#endif // __PKTINFO_H__ diff --git a/lib/gtp5g/include/proc.h b/lib/gtp5g/include/proc.h deleted file mode 100644 index b8f351bc..00000000 --- a/lib/gtp5g/include/proc.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __GTP5G_PROC_H__ -#define __GTP5G_PROC_H__ - -#include - -extern int create_proc(void); -extern void remove_proc(void); - -extern void init_proc_gtp5g_dev_list(void); -extern struct list_head * get_proc_gtp5g_dev_list_head(void); - -#endif // __GTP5G_PROC_H__ diff --git a/lib/gtp5g/include/qer.h b/lib/gtp5g/include/qer.h deleted file mode 100644 index 3e1d3f68..00000000 --- a/lib/gtp5g/include/qer.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __QER_H__ -#define __QER_H__ - -#include -#include -#include - -#include "dev.h" -#include "pdr.h" - -struct qer { - struct hlist_node hlist_id; - u64 seid; - u32 id; - uint8_t ul_dl_gate; - struct { - uint32_t ul_high; - uint8_t ul_low; - uint32_t dl_high; - uint8_t dl_low; - } mbr; - struct { - uint32_t ul_high; - uint8_t ul_low; - uint32_t dl_high; - uint8_t dl_low; - } gbr; - uint32_t qer_corr_id; - uint8_t rqi; - uint8_t qfi; - uint8_t ppi; - uint8_t rcsr; - struct net_device *dev; - struct rcu_head rcu_head; -}; - -extern void qer_context_delete(struct qer *); -extern struct qer *find_qer_by_id(struct gtp5g_dev *, u64, u32); -extern void qer_update(struct qer *, struct gtp5g_dev *); -extern void qer_append(u64, u32, struct qer *, struct gtp5g_dev *); -extern int qer_get_pdr_ids(u16 *, int, struct qer *, struct gtp5g_dev *); -extern int qer_set_pdr(struct pdr *, struct gtp5g_dev *); -extern void del_related_qer_hash(struct gtp5g_dev *, struct pdr *); - -#endif // __QER_H__ diff --git a/lib/gtp5g/include/report.h b/lib/gtp5g/include/report.h deleted file mode 100644 index 7e51df4d..00000000 --- a/lib/gtp5g/include/report.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef __REPORT_H__ -#define __REPORT_H__ - -#include -#include -#include - -#include "dev.h" - -#define USAR_TRIGGER_PERIO (1 << 0) -#define USAR_TRIGGER_VOLTH (1 << 1) -#define USAR_TRIGGER_TIMTH (1 << 2) -#define USAR_TRIGGER_QUHTI (1 << 3) -#define USAR_TRIGGER_START (1 << 4) -#define USAR_TRIGGER_STOPT (1 << 5) -#define USAR_TRIGGER_DROTH (1 << 6) -#define USAR_TRIGGER_IMMER (1 << 7) -#define USAR_TRIGGER_VOLQU (1 << 8) -#define USAR_TRIGGER_TIMQU (1 << 9) -#define USAR_TRIGGER_LIUSA (1 << 10) -#define USAR_TRIGGER_TERMR (1 << 11) -#define USAR_TRIGGER_MONIT (1 << 12) -#define USAR_TRIGGER_ENVCL (1 << 13) -#define USAR_TRIGGER_MACAR (1 << 14) -#define USAR_TRIGGER_EVETH (1 << 15) -#define USAR_TRIGGER_EVEQU (1 << 16) -#define USAR_TRIGGER_TEBUR (1 << 17) -#define USAR_TRIGGER_IPMJL (1 << 18) -#define USAR_TRIGGER_QUVTI (1 << 19) -#define USAR_TRIGGER_EMRRE (1 << 20) -#define USAR_TRIGGER_UPINT (1 << 21) - -struct VolumeMeasurement{ - u64 totalVolume; - u64 uplinkVolume; - u64 downlinkVolume; - u64 totalPktNum; - u64 uplinkPktNum; - u64 downlinkPktNum; -}__attribute__((packed)); - -struct usage_report { - u32 urrid; /* 8.2.54 URR_ID */ - u32 trigger ; - struct VolumeMeasurement volmeasurement; - - u32 queryUrrRef; - ktime_t start_time; - ktime_t end_time; - - u64 seid; -} __attribute__((packed)); - -#endif // __REPORT_H__ diff --git a/lib/gtp5g/include/seid.h b/lib/gtp5g/include/seid.h deleted file mode 100644 index 0fb5f84f..00000000 --- a/lib/gtp5g/include/seid.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __SEID_H__ -#define __SEID_H__ - -#include - -extern void seid_and_u32id_to_hex_str(u64, u32, char *); - -#endif // __SEID_H__ \ No newline at end of file diff --git a/lib/gtp5g/include/urr.h b/lib/gtp5g/include/urr.h deleted file mode 100644 index 7f4035a9..00000000 --- a/lib/gtp5g/include/urr.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef __URR_H__ -#define __URR_H__ - -#include -#include -#include - -#include "dev.h" -#include "report.h" - -#define DONT_SEND_UL_PACKET (-2) -#define SEID_U32ID_HEX_STR_LEN 24 -// Measurement Method -#define URR_METHOD_DURAT (1 << 0) -#define URR_METHOD_VOLUM (1 << 1) -#define URR_METHOD_EVENT (1 << 2) - -#define URR_VOLUME_TOVOL (1 << 0) -#define URR_VOLUME_ULVOL (1 << 1) -#define URR_VOLUME_DLVOL (1 << 2) - -// GTP5G_URR_VOLUME_QUOTA_FLAGS 8.2.50 -#define URR_VOLUME_QUOTA_TOVOL (1 << 0) -#define URR_VOLUME_QUOTA_ULVOL (1 << 1) -#define URR_VOLUME_QUOTA_DLVOL (1 << 2) - -// GTP5G_URR_VOLUME_THRESHOLD_FLAGS 8.2.13 -#define URR_VOLUME_THRESHOLD_TOVOL (1 << 0) -#define URR_VOLUME_THRESHOLD_ULVOL (1 << 1) -#define URR_VOLUME_THRESHOLD_DLVOL (1 << 2) - -// Measurement Information -#define URR_INFO_MBQE (1 << 0) -#define URR_INFO_INAM (1 << 1) -#define URR_INFO_RADI (1 << 2) -#define URR_INFO_ISTM (1 << 3) -#define URR_INFO_MNOP (1 << 4) -#define URR_INFO_SSPOC (1 << 5) -#define URR_INFO_ASPOC (1 << 6) -#define URR_INFO_CIAM (1 << 7) - -#define URR_RPT_TRIGGER_PERIO (1 << 0) -#define URR_RPT_TRIGGER_VOLTH (1 << 1) -#define URR_RPT_TRIGGER_TIMTH (1 << 2) -#define URR_RPT_TRIGGER_QUHTI (1 << 3) -#define URR_RPT_TRIGGER_START (1 << 4) -#define URR_RPT_TRIGGER_STOPT (1 << 5) -#define URR_RPT_TRIGGER_DROTH (1 << 6) -#define URR_RPT_TRIGGER_LIUSA (1 << 7) -#define URR_RPT_TRIGGER_VOLQU (1 << 8) -#define URR_RPT_TRIGGER_TIMQU (1 << 9) -#define URR_RPT_TRIGGER_ENVCL (1 << 10) -#define URR_RPT_TRIGGER_MACAR (1 << 11) -#define URR_RPT_TRIGGER_EVETH (1 << 12) -#define URR_RPT_TRIGGER_EVEQU (1 << 13) -#define URR_RPT_TRIGGER_IPMJL (1 << 14) -#define URR_RPT_TRIGGER_QUVTI (1 << 15) -#define URR_RPT_TRIGGER_REEMR (1 << 16) -#define URR_RPT_TRIGGER_UPINT (1 << 17) - -struct Volume{ - u8 flag; - - u64 totalVolume; - u64 uplinkVolume; - u64 downlinkVolume; -}; - -struct urr { - struct hlist_node hlist_id; - u64 seid; - u32 id; - u8 method; - u32 trigger; - u32 period; - u8 info; - - struct Volume volumethreshold; - struct Volume volumequota; - - // For usage report volume measurement - struct VolumeMeasurement bytes; - struct VolumeMeasurement consumed; - - // for report time - ktime_t start_time; - ktime_t end_time; - - // for quota exhausted - bool quota_exhausted; - u16 *pdrids; - u16 *actions; - u32 pdr_num; - - struct net_device *dev; - struct rcu_head rcu_head; -}; - -struct pdr; - -extern void urr_quota_exhaust_action(struct urr *, struct gtp5g_dev *); -extern void urr_reverse_quota_exhaust_action(struct urr *, struct gtp5g_dev *); - -extern void urr_context_delete(struct urr *); -extern struct urr *find_urr_by_id(struct gtp5g_dev *, u64, u32); -extern void urr_update(struct urr *, struct gtp5g_dev *); -extern void urr_append(u64, u32, struct urr *, struct gtp5g_dev *); -extern int urr_get_pdr_ids(u16 *, int, struct urr *, struct gtp5g_dev *); -extern int urr_set_pdr(struct pdr *, struct gtp5g_dev *); -extern void del_related_urr_hash(struct gtp5g_dev *, struct pdr *); - -#endif // __URR_H__ diff --git a/lib/gtp5g/include/util.h b/lib/gtp5g/include/util.h deleted file mode 100644 index b47e601f..00000000 --- a/lib/gtp5g/include/util.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __UTIL_H__ -#define __UTIL_H__ - -extern void ip_string(char *, int); - -#endif // __UTIL_H__ \ No newline at end of file diff --git a/lib/gtp5g/src/genl/genl.c b/lib/gtp5g/src/genl/genl.c deleted file mode 100644 index 54ec0241..00000000 --- a/lib/gtp5g/src/genl/genl.c +++ /dev/null @@ -1,182 +0,0 @@ -#include -#include - -#include "genl.h" -#include "genl_pdr.h" -#include "genl_far.h" -#include "genl_qer.h" -#include "genl_bar.h" -#include "genl_urr.h" -#include "genl_report.h" -#include "genl_version.h" - -static const struct nla_policy gtp5g_genl_pdr_policy[GTP5G_PDR_ATTR_MAX + 1] = { - [GTP5G_PDR_ID] = { .type = NLA_U32, }, - [GTP5G_PDR_PRECEDENCE] = { .type = NLA_U32, }, - [GTP5G_PDR_PDI] = { .type = NLA_NESTED, }, - [GTP5G_OUTER_HEADER_REMOVAL] = { .type = NLA_U8, }, - [GTP5G_PDR_FAR_ID] = { .type = NLA_U32, }, - [GTP5G_PDR_QER_ID] = { .type = NLA_U32, }, -}; - -static const struct nla_policy gtp5g_genl_far_policy[GTP5G_FAR_ATTR_MAX + 1] = { - [GTP5G_FAR_ID] = { .type = NLA_U32, }, - [GTP5G_FAR_APPLY_ACTION] = { .type = NLA_U8, }, - [GTP5G_FAR_FORWARDING_PARAMETER] = { .type = NLA_NESTED, }, -}; - -static const struct nla_policy gtp5g_genl_qer_policy[GTP5G_QER_ATTR_MAX + 1] = { - [GTP5G_QER_ID] = { .type = NLA_U32, }, - [GTP5G_QER_GATE] = { .type = NLA_U8, }, - [GTP5G_QER_MBR] = { .type = NLA_NESTED, }, - [GTP5G_QER_GBR] = { .type = NLA_NESTED, }, - [GTP5G_QER_CORR_ID] = { .type = NLA_U32, }, - [GTP5G_QER_RQI] = { .type = NLA_U8, }, - [GTP5G_QER_QFI] = { .type = NLA_U8, }, - [GTP5G_QER_PPI] = { .type = NLA_U8, }, - [GTP5G_QER_RCSR] = { .type = NLA_U8, }, -}; - -static const struct nla_policy gtp5g_genl_urr_policy[GTP5G_URR_ATTR_MAX + 1] = { - [GTP5G_URR_ID] = { .type = NLA_U32, }, - [GTP5G_URR_MEASUREMENT_METHOD] = { .type = NLA_U8, }, - [GTP5G_URR_REPORTING_TRIGGER] = { .type = NLA_U32, }, - [GTP5G_URR_MEASUREMENT_PERIOD] = { .type = NLA_U32, }, - [GTP5G_URR_MEASUREMENT_INFO] = { .type = NLA_U8, }, - [GTP5G_URR_SEID] = { .type = NLA_U64, }, - [GTP5G_URR_VOLUME_THRESHOLD] = { .type = NLA_NESTED, }, - [GTP5G_URR_VOLUME_QUOTA] = { .type = NLA_NESTED, }, -}; - -static const struct genl_ops gtp5g_genl_ops[] = { - { - .cmd = GTP5G_CMD_ADD_PDR, - // .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .doit = gtp5g_genl_add_pdr, - // .policy = gtp5g_genl_pdr_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_DEL_PDR, - // .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .doit = gtp5g_genl_del_pdr, - // .policy = gtp5g_genl_pdr_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_GET_PDR, - // .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .doit = gtp5g_genl_get_pdr, - .dumpit = gtp5g_genl_dump_pdr, - // .policy = gtp5g_genl_pdr_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_ADD_FAR, - // .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .doit = gtp5g_genl_add_far, - // .policy = gtp5g_genl_far_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_DEL_FAR, - // .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .doit = gtp5g_genl_del_far, - // .policy = gtp5g_genl_far_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_GET_FAR, - // .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .doit = gtp5g_genl_get_far, - .dumpit = gtp5g_genl_dump_far, - // .policy = gtp5g_genl_far_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_ADD_QER, - // .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .doit = gtp5g_genl_add_qer, - // .policy = gtp5g_genl_qer_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_DEL_QER, - // .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .doit = gtp5g_genl_del_qer, - // .policy = gtp5g_genl_qer_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_GET_QER, - // .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .doit = gtp5g_genl_get_qer, - .dumpit = gtp5g_genl_dump_qer, - // .policy = gtp5g_genl_qer_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_ADD_URR, - .doit = gtp5g_genl_add_urr, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_DEL_URR, - .doit = gtp5g_genl_del_urr, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_GET_URR, - .doit = gtp5g_genl_get_urr, - .dumpit = gtp5g_genl_dump_urr, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_ADD_BAR, - .doit = gtp5g_genl_add_bar, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_DEL_BAR, - .doit = gtp5g_genl_del_bar, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_GET_BAR, - .doit = gtp5g_genl_get_bar, - .dumpit = gtp5g_genl_dump_bar, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_GET_VERSION, - .doit = gtp5g_genl_get_version, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_GET_REPORT, - .doit = gtp5g_genl_get_usage_report, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = GTP5G_CMD_GET_MULTI_REPORTS, - .doit = gtp5g_genl_get_multi_usage_reports, - .flags = GENL_ADMIN_PERM, - }, -}; - -static const struct genl_multicast_group gtp5g_genl_mcgrps[] = { - [GTP5G_GENL_MCGRP] = { .name = "gtp5g" }, -}; - -struct genl_family gtp5g_genl_family __ro_after_init = { - .name = "gtp5g", - .version = 0, - .hdrsize = 0, - .maxattr = GTP5G_ATTR_MAX, - .netnsok = true, - .module = THIS_MODULE, - .ops = gtp5g_genl_ops, - .n_ops = ARRAY_SIZE(gtp5g_genl_ops), - .mcgrps = gtp5g_genl_mcgrps, - .n_mcgrps = ARRAY_SIZE(gtp5g_genl_mcgrps), -}; diff --git a/lib/gtp5g/src/genl/genl_bar.c b/lib/gtp5g/src/genl/genl_bar.c deleted file mode 100644 index 4a44dc4f..00000000 --- a/lib/gtp5g/src/genl/genl_bar.c +++ /dev/null @@ -1,336 +0,0 @@ -#include -#include -#include -#include - -#include "dev.h" -#include "genl.h" -#include "bar.h" -#include "genl_bar.h" -#include "net.h" - -static int bar_fill(struct bar *, struct gtp5g_dev *, struct genl_info *); -static int gtp5g_genl_fill_bar(struct sk_buff *, u32, u32, u32, struct bar *); - -int gtp5g_genl_add_bar(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct bar *bar; - int ifindex; - int netnsfd; - u64 seid; - u8 bar_id; - int err; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rtnl_lock(); - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - rcu_read_unlock(); - rtnl_unlock(); - return -ENODEV; - } - - if (info->attrs[GTP5G_BAR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_BAR_SEID]); - } else { - seid = 0; - } - - if (info->attrs[GTP5G_BAR_ID]) { - bar_id = nla_get_u8(info->attrs[GTP5G_BAR_ID]); - } else { - rcu_read_unlock(); - rtnl_unlock(); - return -ENODEV; - } - - bar = find_bar_by_id(gtp, seid, bar_id); - if (bar) { - if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) { - rcu_read_unlock(); - rtnl_unlock(); - return -EEXIST; - } - if (!(info->nlhdr->nlmsg_flags & NLM_F_REPLACE)) { - rcu_read_unlock(); - rtnl_unlock(); - return -EOPNOTSUPP; - } - err = bar_fill(bar, gtp, info); - if (err) { - bar_context_delete(bar); - return err; - } - return 0; - } - - if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE) { - rcu_read_unlock(); - rtnl_unlock(); - return -ENOENT; - } - - if (info->nlhdr->nlmsg_flags & NLM_F_APPEND) { - rcu_read_unlock(); - rtnl_unlock(); - return -EOPNOTSUPP; - } - - bar = kzalloc(sizeof(*bar), GFP_ATOMIC); - if (!bar) { - rcu_read_unlock(); - rtnl_unlock(); - return -ENOMEM; - } - - bar->dev = gtp->dev; - - err = bar_fill(bar, gtp, info); - if (err) { - bar_context_delete(bar); - rcu_read_unlock(); - rtnl_unlock(); - return err; - } - - bar_append(seid, bar_id, bar, gtp); - - rcu_read_unlock(); - rtnl_unlock(); - return 0; -} - -int gtp5g_genl_del_bar(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct bar *bar; - int ifindex; - int netnsfd; - u64 seid; - u8 bar_id; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - rcu_read_unlock(); - return -ENODEV; - } - - if (info->attrs[GTP5G_BAR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_BAR_SEID]); - } else { - seid = 0; - } - - if (info->attrs[GTP5G_BAR_ID]) { - bar_id = nla_get_u8(info->attrs[GTP5G_BAR_ID]); - } else { - rcu_read_unlock(); - return -ENODEV; - } - - bar = find_bar_by_id(gtp, seid, bar_id); - if (!bar) { - rcu_read_unlock(); - return -ENOENT; - } - - bar_context_delete(bar); - rcu_read_unlock(); - - return 0; -} - -int gtp5g_genl_get_bar(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct bar *bar; - int ifindex; - int netnsfd; - u64 seid; - u8 bar_id; - struct sk_buff *skb_ack; - int err; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - rcu_read_unlock(); - return -ENODEV; - } - - if (info->attrs[GTP5G_BAR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_BAR_SEID]); - } else { - seid = 0; - } - - if (info->attrs[GTP5G_BAR_ID]) { - bar_id = nla_get_u8(info->attrs[GTP5G_BAR_ID]); - } else { - rcu_read_unlock(); - return -ENODEV; - } - - bar = find_bar_by_id(gtp, seid, bar_id); - if (!bar) { - rcu_read_unlock(); - return -ENOENT; - } - - skb_ack = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); - if (!skb_ack) { - rcu_read_unlock(); - return -ENOMEM; - } - - err = gtp5g_genl_fill_bar(skb_ack, - NETLINK_CB(skb).portid, - info->snd_seq, - info->nlhdr->nlmsg_type, - bar); - if (err) { - kfree_skb(skb_ack); - rcu_read_unlock(); - return err; - } - rcu_read_unlock(); - - return genlmsg_unicast(genl_info_net(info), skb_ack, info->snd_portid); -} - -int gtp5g_genl_dump_bar(struct sk_buff *skb, struct netlink_callback *cb) -{ - /* netlink_callback->args - * args[0] : index of gtp5g dev id - * args[1] : index of gtp5g hash entry id in dev - * args[2] : index of gtp5g bar id - * args[5] : set non-zero means it is finished - */ - struct gtp5g_dev *gtp; - struct gtp5g_dev *last_gtp = (struct gtp5g_dev *)cb->args[0]; - struct net *net = sock_net(skb->sk); - struct gtp5g_net *gn = net_generic(net, GTP5G_NET_ID()); - int i; - int last_hash_entry_id = cb->args[1]; - int ret; - u8 bar_id = cb->args[2]; - struct bar *bar; - - if (cb->args[5]) - return 0; - - list_for_each_entry_rcu(gtp, &gn->gtp5g_dev_list, list) { - if (last_gtp && last_gtp != gtp) - continue; - else - last_gtp = NULL; - - for (i = last_hash_entry_id; i < gtp->hash_size; i++) { - hlist_for_each_entry_rcu(bar, >p->bar_id_hash[i], hlist_id) { - if (bar_id && bar_id != bar->id) - continue; - bar_id = 0; - ret = gtp5g_genl_fill_bar(skb, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - cb->nlh->nlmsg_type, - bar); - if (ret) { - cb->args[0] = (unsigned long)gtp; - cb->args[1] = i; - cb->args[2] = bar->id; - goto out; - } - } - } - } - - cb->args[5] = 1; -out: - return skb->len; -} - - -static int bar_fill(struct bar *bar, struct gtp5g_dev *gtp, struct genl_info *info) -{ - bar->id = nla_get_u8(info->attrs[GTP5G_BAR_ID]); - - if (info->attrs[GTP5G_BAR_SEID]) - bar->seid = nla_get_u64(info->attrs[GTP5G_BAR_SEID]); - else - bar->seid = 0; - - if (info->attrs[GTP5G_DOWNLINK_DATA_NOTIFICATION_DELAY]) - bar->delay = nla_get_u8(info->attrs[GTP5G_DOWNLINK_DATA_NOTIFICATION_DELAY]); - else - bar->delay = 0; - - if (info->attrs[GTP5G_BUFFERING_PACKETS_COUNT]) - bar->count = nla_get_u16(info->attrs[GTP5G_BUFFERING_PACKETS_COUNT]); - else - bar->count = 0; - - /* Update PDRs which has not linked to this BAR */ - bar_update(bar, gtp); - return 0; -} - -static int gtp5g_genl_fill_bar(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, - u32 type, struct bar *bar) -{ - void *genlh; - - genlh = genlmsg_put(skb, snd_portid, snd_seq, - >p5g_genl_family, 0, type); - if (!genlh) - goto genlmsg_fail; - - if (nla_put_u8(skb, GTP5G_BAR_ID, bar->id)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_DOWNLINK_DATA_NOTIFICATION_DELAY, bar->delay)) - goto genlmsg_fail; - if (nla_put_u16(skb, GTP5G_BUFFERING_PACKETS_COUNT, bar->count)) - goto genlmsg_fail; - if (bar->seid) { - if (nla_put_u64_64bit(skb, GTP5G_BAR_SEID, bar->seid, 0)) - goto genlmsg_fail; - } - - genlmsg_end(skb, genlh); - return 0; -genlmsg_fail: - genlmsg_cancel(skb, genlh); - return -EMSGSIZE; -} \ No newline at end of file diff --git a/lib/gtp5g/src/genl/genl_far.c b/lib/gtp5g/src/genl/genl_far.c deleted file mode 100644 index 1314a813..00000000 --- a/lib/gtp5g/src/genl/genl_far.c +++ /dev/null @@ -1,601 +0,0 @@ -#include -#include -#include - -#include "common.h" -#include "dev.h" -#include "genl.h" -#include "genl_far.h" -#include "far.h" -#include "pktinfo.h" -#include "api_version.h" - -#include -#include -#include "net.h" - -static int header_creation_fill(struct forwarding_parameter *, - struct nlattr **, u8 *, - struct gtp5g_emark_pktinfo *, - uint8_t sendEndmarker); -static int forwarding_parameter_fill(struct forwarding_parameter *, - struct nlattr **, u8 *, - struct gtp5g_emark_pktinfo *); -static int far_fill(struct far *, struct gtp5g_dev *, struct genl_info *, - u8 *, struct gtp5g_emark_pktinfo *); - -static int gtp5g_genl_fill_far(struct sk_buff *, u32, u32, u32, struct far *); - -int gtp5g_genl_add_far(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct far *far; - int ifindex; - int netnsfd; - u64 seid; - u32 far_id; - int err; - u8 flag; - struct gtp5g_emark_pktinfo epkt_info; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rtnl_lock(); - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - rcu_read_unlock(); - rtnl_unlock(); - return -ENODEV; - } - - if (info->attrs[GTP5G_FAR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_FAR_SEID]); - } else { - seid = 0; - } - - if (info->attrs[GTP5G_FAR_ID]) { - far_id = nla_get_u32(info->attrs[GTP5G_FAR_ID]); - } else { - rcu_read_unlock(); - rtnl_unlock(); - return -ENODEV; - } - - far = find_far_by_id(gtp, seid, far_id); - if (far) { - if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) { - rcu_read_unlock(); - rtnl_unlock(); - return -EEXIST; - } - if (!(info->nlhdr->nlmsg_flags & NLM_F_REPLACE)) { - rcu_read_unlock(); - rtnl_unlock(); - return -EOPNOTSUPP; - } - - flag = 0; - err = far_fill(far, gtp, info, &flag, &epkt_info); - if (err) { - far_context_delete(far); - rcu_read_unlock(); - rtnl_unlock(); - return err; - } - - // Send GTP-U End marker to gNB - if (flag) { - /* SKB size GTPU(8) + UDP(8) + IP(20) + Eth(14) - * + 2-Bytes align the IP header - * */ - struct sk_buff *skb = __netdev_alloc_skb(gtp->dev, 52, GFP_KERNEL); - if (!skb) { - rcu_read_unlock(); - rtnl_unlock(); - return 0; - } - skb_reserve(skb, 2); - skb->protocol = eth_type_trans(skb, gtp->dev); - gtp5g_fwd_emark_skb_ipv4(skb, gtp->dev, &epkt_info); - } - rcu_read_unlock(); - rtnl_unlock(); - return 0; - } - - if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE) { - rcu_read_unlock(); - rtnl_unlock(); - return -ENOENT; - } - - if (info->nlhdr->nlmsg_flags & NLM_F_APPEND) { - rcu_read_unlock(); - rtnl_unlock(); - return -EOPNOTSUPP; - } - - // Check only at the creation part - if (!info->attrs[GTP5G_FAR_APPLY_ACTION]) { - rcu_read_unlock(); - rtnl_unlock(); - return -EINVAL; - } - - far = kzalloc(sizeof(*far), GFP_ATOMIC); - if (!far) { - rcu_read_unlock(); - rtnl_unlock(); - return -ENOMEM; - } - far->dev = gtp->dev; - - err = far_fill(far, gtp, info, NULL, NULL); - if (err) { - far_context_delete(far); - rcu_read_unlock(); - rtnl_unlock(); - return err; - } - - far_append(seid, far_id, far, gtp); - - rcu_read_unlock(); - rtnl_unlock(); - return 0; -} - -int gtp5g_genl_del_far(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct far *far; - int ifindex; - int netnsfd; - u64 seid; - u32 far_id; - - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - rcu_read_unlock(); - return -ENODEV; - } - - if (info->attrs[GTP5G_FAR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_FAR_SEID]); - } else { - seid = 0; - } - - if (info->attrs[GTP5G_FAR_ID]) { - far_id = nla_get_u32(info->attrs[GTP5G_FAR_ID]); - } else { - rcu_read_unlock(); - return -ENODEV; - } - - far = find_far_by_id(gtp, seid, far_id); - if (!far) { - rcu_read_unlock(); - return -ENOENT; - } - - far_context_delete(far); - rcu_read_unlock(); - - return 0; -} - -int gtp5g_genl_get_far(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct far *far; - int ifindex; - int netnsfd; - u64 seid; - u32 far_id; - struct sk_buff *skb_ack; - int err; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - rcu_read_unlock(); - return -ENODEV; - } - - if (info->attrs[GTP5G_FAR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_FAR_SEID]); - } else { - seid = 0; - } - - if (info->attrs[GTP5G_FAR_ID]) { - far_id = nla_get_u32(info->attrs[GTP5G_FAR_ID]); - } else { - rcu_read_unlock(); - return -ENODEV; - } - - far = find_far_by_id(gtp, seid, far_id); - if (!far) { - rcu_read_unlock(); - return -ENOENT; - } - - skb_ack = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); - if (!skb_ack) { - rcu_read_unlock(); - return -ENOMEM; - } - - err = gtp5g_genl_fill_far(skb_ack, - NETLINK_CB(skb).portid, - info->snd_seq, - info->nlhdr->nlmsg_type, - far); - if (err) { - kfree_skb(skb_ack); - rcu_read_unlock(); - return err; - } - - rcu_read_unlock(); - - return genlmsg_unicast(genl_info_net(info), skb_ack, info->snd_portid); -} - -int gtp5g_genl_dump_far(struct sk_buff *skb, struct netlink_callback *cb) -{ - /* netlink_callback->args - * args[0] : index of gtp5g dev id - * args[1] : index of gtp5g hash entry id in dev - * args[2] : index of gtp5g far id - * args[5] : set non-zero means it is finished - */ - struct gtp5g_dev *gtp; - struct gtp5g_dev *last_gtp = (struct gtp5g_dev *)cb->args[0]; - struct net *net = sock_net(skb->sk); - struct gtp5g_net *gn = net_generic(net, GTP5G_NET_ID()); - int i; - int last_hash_entry_id = cb->args[1]; - int ret; - u32 far_id = cb->args[2]; - struct far *far; - - if (cb->args[5]) - return 0; - - list_for_each_entry_rcu(gtp, &gn->gtp5g_dev_list, list) { - if (last_gtp && last_gtp != gtp) - continue; - else - last_gtp = NULL; - - for (i = last_hash_entry_id; i < gtp->hash_size; i++) { - hlist_for_each_entry_rcu(far, >p->far_id_hash[i], hlist_id) { - if (far_id && far_id != far->id) - continue; - else - far_id = 0; - - ret = gtp5g_genl_fill_far(skb, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - cb->nlh->nlmsg_type, - far); - if (ret) { - cb->args[0] = (unsigned long)gtp; - cb->args[1] = i; - cb->args[2] = far->id; - goto out; - } - } - } - } - cb->args[5] = 1; -out: - return skb->len; -} - - -static int header_creation_fill(struct forwarding_parameter *param, - struct nlattr **attrs, u8 *flag, - struct gtp5g_emark_pktinfo *epkt_info, - uint8_t sendEndmarker) -{ - struct outer_header_creation *hdr_creation; - - if (!attrs[GTP5G_OUTER_HEADER_CREATION_DESCRIPTION] || - !attrs[GTP5G_OUTER_HEADER_CREATION_O_TEID] || - !attrs[GTP5G_OUTER_HEADER_CREATION_PEER_ADDR_IPV4] || - !attrs[GTP5G_OUTER_HEADER_CREATION_PORT]) { - return -EINVAL; - } - - if (!param->hdr_creation) { - param->hdr_creation = kzalloc(sizeof(*param->hdr_creation), - GFP_ATOMIC); - if (!param->hdr_creation) - return -ENOMEM; - hdr_creation = param->hdr_creation; - hdr_creation->description = nla_get_u16(attrs[GTP5G_OUTER_HEADER_CREATION_DESCRIPTION]); - hdr_creation->teid = htonl(nla_get_u32(attrs[GTP5G_OUTER_HEADER_CREATION_O_TEID])); - hdr_creation->peer_addr_ipv4.s_addr = nla_get_be32(attrs[GTP5G_OUTER_HEADER_CREATION_PEER_ADDR_IPV4]); - hdr_creation->port = htons(nla_get_u16(attrs[GTP5G_OUTER_HEADER_CREATION_PORT])); - } else { - u32 old_teid, old_peer_addr; - u16 old_port; - - hdr_creation = param->hdr_creation; - old_teid = hdr_creation->teid; - old_peer_addr = hdr_creation->peer_addr_ipv4.s_addr; - old_port = hdr_creation->port; - hdr_creation->description = nla_get_u16(attrs[GTP5G_OUTER_HEADER_CREATION_DESCRIPTION]); - hdr_creation->teid = htonl(nla_get_u32(attrs[GTP5G_OUTER_HEADER_CREATION_O_TEID])); - hdr_creation->peer_addr_ipv4.s_addr = nla_get_be32(attrs[GTP5G_OUTER_HEADER_CREATION_PEER_ADDR_IPV4]); - hdr_creation->port = htons(nla_get_u16(attrs[GTP5G_OUTER_HEADER_CREATION_PORT])); - /* For Downlink traffic from UPF to gNB - * In some cases, - * 1) SMF will send PFCP Msg filled with FAR's TEID and gNB N3 addr as 0 - * 2) Later time, SMF will send PFCP Msg filled with right value in 1) - - * 2.a) We should send the GTP-U EndMarker to gNB - * 2.b) SHOULD not set the flag as 1 - * 3) Xn Handover in b/w gNB then - * 3.a) SMF will send modification of PDR, FAR(TEID and GTP-U) - * 3.b) SHOULD set the flag as 1 and send GTP-U Marker for old gNB - - * */ - /* R15.3 29.281 - * 5.1 General format - * When setting up a GTP-U tunnel, the GTP-U entity shall not assign th - e value 'all zeros' to its own TEID. - * However, for backward compatibility, if a GTP-U entity receives (via - respective control plane message) a peer's - * TEID that is set to the value 'all zeros', the GTP-U entity shall ac - cept this value as valid and send the subsequent - * G-PDU with the TEID field in the header set to the value 'all zeros' - . - * */ - if ((flag != NULL && epkt_info != NULL)) { - if (sendEndmarker) { - *flag = 1; - epkt_info->teid = old_teid; - epkt_info->peer_addr = old_peer_addr; - epkt_info->gtph_port = old_port; - } - } - } - - return 0; -} - -static int forwarding_parameter_fill(struct forwarding_parameter *param, - struct nlattr **attrs, u8 *flag, - struct gtp5g_emark_pktinfo *epkt_info) -{ - struct nlattr *hdr_creation_attrs[GTP5G_OUTER_HEADER_CREATION_ATTR_MAX + 1]; - struct forwarding_policy *fwd_policy; - uint8_t sendEndmarker = 0; - int err; - - if (attrs[GTP5G_FORWARDING_PARAMETER_OUTER_HEADER_CREATION]) { - err = nla_parse_nested(hdr_creation_attrs, - GTP5G_OUTER_HEADER_CREATION_ATTR_MAX, - attrs[GTP5G_FORWARDING_PARAMETER_OUTER_HEADER_CREATION], - NULL, - NULL); - if (err) - return err; - - /* - TS 29.244 PFCPSMReq-Flags - SNDEM (Send End Marker Packets): - if this bit is set to "1", it indicates that the UP function - shall construct and send End Marker packets - */ - #define SNDEM 0x02 - if (attrs[GTP5G_FORWARDING_PARAMETER_PFCPSM_REQ_FLAGS]) { - sendEndmarker = nla_get_u8(attrs[GTP5G_FORWARDING_PARAMETER_PFCPSM_REQ_FLAGS]) & SNDEM; - } - err = header_creation_fill(param, hdr_creation_attrs, flag, epkt_info, sendEndmarker); - if (err) - return err; - } - - if (attrs[GTP5G_FORWARDING_PARAMETER_FORWARDING_POLICY]) { - if (!param->fwd_policy) { - param->fwd_policy = kzalloc(sizeof(*param->fwd_policy), GFP_ATOMIC); - if (!param->fwd_policy) - return -ENOMEM; - } - fwd_policy = param->fwd_policy; - fwd_policy->len = nla_len(attrs[GTP5G_FORWARDING_PARAMETER_FORWARDING_POLICY]); - if (fwd_policy->len >= sizeof(fwd_policy->identifier)) - return -EINVAL; - strncpy(fwd_policy->identifier, - nla_data(attrs[GTP5G_FORWARDING_PARAMETER_FORWARDING_POLICY]), fwd_policy->len); - - /* Exact value to handle forwarding policy */ - if (!(fwd_policy->mark = simple_strtol(fwd_policy->identifier, NULL, 10))) { - return -EINVAL; - } - } - - return 0; -} - - -static int far_fill(struct far *far, struct gtp5g_dev *gtp, struct genl_info *info, - u8 *flag, struct gtp5g_emark_pktinfo *epkt_info) -{ - struct nlattr *attrs[GTP5G_FORWARDING_PARAMETER_ATTR_MAX + 1]; - int err; - struct forwarding_parameter *fwd_param; - - if (!far) - return -EINVAL; - - far->id = nla_get_u32(info->attrs[GTP5G_FAR_ID]); - - if (info->attrs[GTP5G_FAR_SEID]) - far->seid = nla_get_u64(info->attrs[GTP5G_FAR_SEID]); - else - far->seid = 0; - - if (info->attrs[GTP5G_FAR_APPLY_ACTION]) - switch (nla_len(info->attrs[GTP5G_FAR_APPLY_ACTION])) - { - case FAR_ACTION_U16: - set_far_action_u16(true); - far->action = nla_get_u16(info->attrs[GTP5G_FAR_APPLY_ACTION]); - break; - case FAR_ACTION_U8: - set_far_action_u16(false); - far->action = nla_get_u8(info->attrs[GTP5G_FAR_APPLY_ACTION]); - break; - default: - break; - } - - if (info->attrs[GTP5G_FAR_FORWARDING_PARAMETER]) { - err = nla_parse_nested(attrs, - GTP5G_FORWARDING_PARAMETER_ATTR_MAX, - info->attrs[GTP5G_FAR_FORWARDING_PARAMETER], - NULL, - NULL); - if (err) - return err; - fwd_param = rcu_dereference(far->fwd_param); - if (!fwd_param) { - fwd_param = kzalloc(sizeof(*fwd_param), GFP_ATOMIC); - if (!fwd_param) - return -ENOMEM; - } - err = forwarding_parameter_fill(fwd_param, attrs, flag, epkt_info); - rcu_assign_pointer(far->fwd_param, fwd_param); - if (err) - return err; - } - - /* Update PDRs which has not linked to this FAR */ - far_update(far, gtp, flag, epkt_info); - - return 0; -} - - -static int gtp5g_genl_fill_far(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, - u32 type, struct far *far) -{ - struct gtp5g_dev *gtp = netdev_priv(far->dev); - void *genlh; - struct nlattr *nest_fwd_param; - struct nlattr *nest_hdr_creation; - struct forwarding_parameter *fwd_param; - struct outer_header_creation *hdr_creation; - struct forwarding_policy *fwd_policy; - u16 *ids = NULL; - int n; - - genlh = genlmsg_put(skb, snd_portid, snd_seq, >p5g_genl_family, 0, type); - if (!genlh) - goto genlmsg_fail; - - if (nla_put_u32(skb, GTP5G_FAR_ID, far->id)) - goto genlmsg_fail; - - if (far_action_is_u16()) { - if (nla_put_u16(skb, GTP5G_FAR_APPLY_ACTION, far->action)) - goto genlmsg_fail; - } else { - if (nla_put_u8(skb, GTP5G_FAR_APPLY_ACTION, far->action)) - goto genlmsg_fail; - } - - if (far->seid) { - if (nla_put_u64_64bit(skb, GTP5G_FAR_SEID, far->seid, 0)) - goto genlmsg_fail; - } - fwd_param = rcu_dereference(far->fwd_param); - if (fwd_param) { - nest_fwd_param = nla_nest_start(skb, GTP5G_FAR_FORWARDING_PARAMETER); - if (!nest_fwd_param) - goto genlmsg_fail; - - if (fwd_param->hdr_creation) { - nest_hdr_creation = nla_nest_start(skb, GTP5G_FORWARDING_PARAMETER_OUTER_HEADER_CREATION); - if (!nest_hdr_creation) - goto genlmsg_fail; - - hdr_creation = fwd_param->hdr_creation; - if (nla_put_u16(skb, GTP5G_OUTER_HEADER_CREATION_DESCRIPTION, hdr_creation->description)) - goto genlmsg_fail; - if (nla_put_u32(skb, GTP5G_OUTER_HEADER_CREATION_O_TEID, ntohl(hdr_creation->teid))) - goto genlmsg_fail; - if (nla_put_be32(skb, GTP5G_OUTER_HEADER_CREATION_PEER_ADDR_IPV4, hdr_creation->peer_addr_ipv4.s_addr)) - goto genlmsg_fail; - if (nla_put_u16(skb, GTP5G_OUTER_HEADER_CREATION_PORT, ntohs(hdr_creation->port))) - goto genlmsg_fail; - - nla_nest_end(skb, nest_hdr_creation); - } - - if ((fwd_policy = fwd_param->fwd_policy)) - if (nla_put(skb, GTP5G_FORWARDING_PARAMETER_FORWARDING_POLICY, fwd_policy->len, fwd_policy->identifier)) - goto genlmsg_fail; - - nla_nest_end(skb, nest_fwd_param); - } - - ids = kzalloc(MAX_PDR_PER_SESSION * sizeof(u16), GFP_KERNEL); - if (!ids) - goto genlmsg_fail; - n = far_get_pdr_ids(ids, MAX_PDR_PER_SESSION, far, gtp); - if (n) { - if (nla_put(skb, GTP5G_FAR_RELATED_TO_PDR, n * sizeof(u16), ids)) - goto genlmsg_fail; - } - - kfree(ids); - genlmsg_end(skb, genlh); - return 0; - -genlmsg_fail: - if (ids) - kfree(ids); - genlmsg_cancel(skb, genlh); - return -EMSGSIZE; -} diff --git a/lib/gtp5g/src/genl/genl_pdr.c b/lib/gtp5g/src/genl/genl_pdr.c deleted file mode 100644 index 86fb38a6..00000000 --- a/lib/gtp5g/src/genl/genl_pdr.c +++ /dev/null @@ -1,927 +0,0 @@ -#include -#include -#include - -#include -#include -#include - -#include "dev.h" -#include "genl.h" -#include "genl_pdr.h" -#include "pdr.h" -#include "api_version.h" - -#include -#include -#include "net.h" -#include "util.h" -#include "far.h" - -static int pdr_fill(struct pdr *, struct gtp5g_dev *, struct genl_info *); -static int parse_pdi(struct pdr *, struct nlattr *); -static int parse_f_teid(struct pdi *, struct nlattr *); -static int parse_sdf_filter(struct pdi *, struct nlattr *); -static int parse_ip_filter_rule(struct sdf_filter *, struct nlattr *); - -static int gtp5g_genl_fill_rule(struct sk_buff *, struct ip_filter_rule *); -static int gtp5g_genl_fill_sdf(struct sk_buff *, struct sdf_filter *); -static int gtp5g_genl_fill_f_teid(struct sk_buff *, struct local_f_teid *); -static int gtp5g_genl_fill_pdi(struct sk_buff *, struct pdi *); -static int gtp5g_genl_fill_pdr(struct sk_buff *, u32, u32, u32, struct pdr *); - -int gtp5g_genl_add_pdr(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct pdr *pdr; - int ifindex; - int netnsfd; - u64 seid = 0; - u16 pdr_id; - int err; - - if (info->attrs[GTP5G_LINK]) { - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - } else { - ifindex = -1; - } - - if (info->attrs[GTP5G_NET_NS_FD]) { - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - } else { - netnsfd = -1; - } - - rtnl_lock(); - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - rcu_read_unlock(); - rtnl_unlock(); - return -ENODEV; - } - - if (info->attrs[GTP5G_PDR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_PDR_SEID]); - } - - if (info->attrs[GTP5G_PDR_ID]) { - pdr_id = nla_get_u32(info->attrs[GTP5G_PDR_ID]); - } else { - rcu_read_unlock(); - rtnl_unlock(); - return -ENODEV; - } - - pdr = find_pdr_by_id(gtp, seid, pdr_id); - if (pdr) { - if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) { - rcu_read_unlock(); - rtnl_unlock(); - return -EEXIST; - } - if (!(info->nlhdr->nlmsg_flags & NLM_F_REPLACE)) { - rcu_read_unlock(); - rtnl_unlock(); - return -EOPNOTSUPP; - } - - err = pdr_fill(pdr, gtp, info); - if (err) { - pdr_context_delete(pdr); - return err; - } - - rcu_read_unlock(); - rtnl_unlock(); - return 0; - } - - if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE) { - rcu_read_unlock(); - rtnl_unlock(); - return -ENOENT; - } - - if (info->nlhdr->nlmsg_flags & NLM_F_APPEND) { - rcu_read_unlock(); - rtnl_unlock(); - return -EOPNOTSUPP; - } - - // Check only at the creation part - if (!info->attrs[GTP5G_PDR_PRECEDENCE]) { - rcu_read_unlock(); - rtnl_unlock(); - return -EINVAL; - } - - pdr = kzalloc(sizeof(*pdr), GFP_ATOMIC); - if (!pdr) { - rcu_read_unlock(); - rtnl_unlock(); - return -ENOMEM; - } - - sock_hold(gtp->sk1u); - pdr->sk = gtp->sk1u; - pdr->dev = gtp->dev; - - err = pdr_fill(pdr, gtp, info); - if (err) { - pdr_context_delete(pdr); - rcu_read_unlock(); - rtnl_unlock(); - return err; - } - - pdr_append(seid, pdr_id, pdr, gtp); - - rcu_read_unlock(); - rtnl_unlock(); - - return 0; -} - -int gtp5g_genl_del_pdr(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct pdr *pdr; - int ifindex; - int netnsfd; - u64 seid = 0; - u16 pdr_id; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - rcu_read_unlock(); - return -ENODEV; - } - - if (info->attrs[GTP5G_PDR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_PDR_SEID]); - } - - if (info->attrs[GTP5G_PDR_ID]) { - pdr_id = nla_get_u16(info->attrs[GTP5G_PDR_ID]); - } else { - rcu_read_unlock(); - return -ENODEV; - } - - pdr = find_pdr_by_id(gtp, seid, pdr_id); - if (!pdr) { - rcu_read_unlock(); - return -ENOENT; - } - - del_related_urr_hash(gtp, pdr); - del_related_qer_hash(gtp, pdr); - del_related_far_hash(gtp, pdr); - pdr_context_delete(pdr); - rcu_read_unlock(); - - return 0; -} - -int gtp5g_genl_get_pdr(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct pdr *pdr; - int ifindex; - int netnsfd; - u64 seid = 0; - u16 pdr_id; - struct sk_buff *skb_ack; - int err; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - rcu_read_unlock(); - return -ENODEV; - } - - if (info->attrs[GTP5G_PDR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_PDR_SEID]); - } - - if (info->attrs[GTP5G_PDR_ID]) { - pdr_id = nla_get_u16(info->attrs[GTP5G_PDR_ID]); - } else { - rcu_read_unlock(); - return -ENODEV; - } - - pdr = find_pdr_by_id(gtp, seid, pdr_id); - if (!pdr) { - rcu_read_unlock(); - return -ENOENT; - } - - skb_ack = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); - if (!skb_ack) { - rcu_read_unlock(); - return -ENOMEM; - } - - err = gtp5g_genl_fill_pdr(skb_ack, - NETLINK_CB(skb).portid, - info->snd_seq, - info->nlhdr->nlmsg_type, - pdr); - if (err) { - kfree_skb(skb_ack); - rcu_read_unlock(); - return err; - } - - rcu_read_unlock(); - - return genlmsg_unicast(genl_info_net(info), skb_ack, info->snd_portid); -} - -int gtp5g_genl_dump_pdr(struct sk_buff *skb, struct netlink_callback *cb) -{ - /* netlink_callback->args - * args[0] : index of gtp5g dev id - * args[1] : index of gtp5g hash entry id in dev - * args[2] : index of gtp5g pdr id - * args[5] : set non-zero means it is finished - */ - struct gtp5g_dev *gtp; - struct gtp5g_dev *last_gtp = (struct gtp5g_dev *)cb->args[0]; - struct net *net = sock_net(skb->sk); - struct gtp5g_net *gn = net_generic(net, GTP5G_NET_ID()); - int i; - int last_hash_entry_id = cb->args[1]; - int ret; - u16 pdr_id = cb->args[2]; - struct pdr *pdr; - - if (cb->args[5]) - return 0; - - list_for_each_entry_rcu(gtp, &gn->gtp5g_dev_list, list) { - if (last_gtp && last_gtp != gtp) - continue; - else - last_gtp = NULL; - - for (i = last_hash_entry_id; i < gtp->hash_size; i++) { - hlist_for_each_entry_rcu(pdr, >p->pdr_id_hash[i], hlist_id) { - if (pdr_id && pdr_id != pdr->id) - continue; - else - pdr_id = 0; - - ret = gtp5g_genl_fill_pdr(skb, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - cb->nlh->nlmsg_type, - pdr); - if (ret) { - cb->args[0] = (unsigned long)gtp; - cb->args[1] = i; - cb->args[2] = pdr->id; - goto out; - } - } - } - } - cb->args[5] = 1; -out: - return skb->len; -} - -int find_qer_id_in_pdr(struct pdr *pdr, u32 qer_id) -{ - int i = 0; - for (i = 0; i < pdr->qer_num; i++) { - if (pdr->qer_ids[i] == qer_id) - return 1; - } - return 0; -} - -static void set_pdr_qfi(struct pdr *pdr, struct gtp5g_dev *gtp){ - int i; - struct qer *qer; - - // TS 38.415 QFI range {0..2^6-1} - for (i = 0; i < pdr->qer_num; i++) { - qer = find_qer_by_id(gtp, pdr->seid, pdr->qer_ids[i]); - if (qer && qer->qfi > 0) { - pdr->qfi = qer->qfi; - break; - } - } -} - -static int set_pdr_qer_ids(struct pdr *pdr, u32 qer_id) -{ - u32 *new_qer_ids; - - if (find_qer_id_in_pdr(pdr, qer_id)) - return 0; - - new_qer_ids = kzalloc((++pdr->qer_num) * QER_ID_SIZE, GFP_ATOMIC); - if (!new_qer_ids) - return -ENOMEM; - - if (pdr->qer_ids) { - memcpy(new_qer_ids, pdr->qer_ids, (pdr->qer_num - 1) * QER_ID_SIZE); - kfree(pdr->qer_ids); - } - - new_qer_ids[pdr->qer_num - 1] = qer_id; - pdr->qer_ids = new_qer_ids; - - return 0; -} - -int find_urr_id_in_pdr(struct pdr *pdr, u32 urr_id) -{ - int i = 0; - - if (!pdr) - return 0; - - for (i = 0; i < pdr->urr_num; i++) { - if (pdr->urr_ids[i] == urr_id) - return 1; - } - return 0; -} - -static int set_pdr_urr_ids(struct pdr *pdr, u32 urr_id) -{ - u32 *new_urr_ids; - - if (find_urr_id_in_pdr(pdr, urr_id)) - return 0; - - new_urr_ids = kzalloc((++pdr->urr_num) * URR_ID_SIZE, GFP_ATOMIC); - if (!new_urr_ids) - return -ENOMEM; - - if (pdr->urr_ids) { - memcpy(new_urr_ids, pdr->urr_ids, (pdr->urr_num - 1) * URR_ID_SIZE); - kfree(pdr->urr_ids); - } - - new_urr_ids[pdr->urr_num - 1] = urr_id; - pdr->urr_ids = new_urr_ids; - - return 0; -} - -static int pdr_fill(struct pdr *pdr, struct gtp5g_dev *gtp, struct genl_info *info) -{ - char *str; - int err; - struct nlattr *hdr = nlmsg_attrdata(info->nlhdr, 0); - int remaining = nlmsg_attrlen(info->nlhdr, 0); - struct far *far; - - pdr->seid = 0; - - hdr = nla_next(hdr, &remaining); - while (nla_ok(hdr, remaining)) { - switch (nla_type(hdr)) { - case GTP5G_PDR_SEID: - pdr->seid = nla_get_u64(hdr); - break; - case GTP5G_PDR_ID: - pdr->id = nla_get_u16(hdr); - break; - case GTP5G_PDR_PRECEDENCE: - pdr->precedence = nla_get_u32(hdr); - break; - case GTP5G_OUTER_HEADER_REMOVAL: - if (!pdr->outer_header_removal) { - pdr->outer_header_removal = kzalloc(sizeof(*pdr->outer_header_removal), GFP_ATOMIC); - if (!pdr->outer_header_removal) - return -ENOMEM; - } - *pdr->outer_header_removal = nla_get_u8(hdr); - break; - case GTP5G_PDR_ROLE_ADDR_IPV4: - /* Not in 3GPP spec, just used for routing */ - pdr->role_addr_ipv4.s_addr = nla_get_u32(hdr); - break; - case GTP5G_PDR_UNIX_SOCKET_PATH: - /* Not in 3GPP spec, just used for buffering */ - str = nla_data(hdr); - pdr->addr_unix.sun_family = AF_UNIX; - strncpy(pdr->addr_unix.sun_path, str, nla_len(hdr)); - break; - case GTP5G_PDR_FAR_ID: - if (!pdr->far_id) { - pdr->far_id = kzalloc(sizeof(*pdr->far_id), GFP_ATOMIC); - if (!pdr->far_id) - return -ENOMEM; - } - *pdr->far_id = nla_get_u32(hdr); - break; - case GTP5G_PDR_QER_ID: - err = set_pdr_qer_ids(pdr, nla_get_u32(hdr)); - if (err) - return err; - break; - case GTP5G_PDR_PDI: - err = parse_pdi(pdr, hdr); - if (err) - return err; - break; - case GTP5G_PDR_URR_ID: - err = set_pdr_urr_ids(pdr, nla_get_u32(hdr)); - if (err) - return err; - break; - } - hdr = nla_next(hdr, &remaining); - } - - if (!pdr) - return -EINVAL; - - pdr->af = AF_INET; - far = find_far_by_id(gtp, pdr->seid, *pdr->far_id); - rcu_assign_pointer(pdr->far, far); - - err = far_set_pdr(pdr, gtp); - if (err) - return err; - - err = urr_set_pdr(pdr, gtp); - if (err) - return err; - - err = qer_set_pdr(pdr, gtp); - if (err) - return err; - - set_pdr_qfi(pdr, gtp); - - if (unix_sock_client_update(pdr, far) < 0) - return -EINVAL; - - // Update hlist table - pdr_update_hlist_table(pdr, gtp); - - return 0; -} - -static int parse_pdi(struct pdr *pdr, struct nlattr *a) -{ - struct nlattr *attrs[GTP5G_PDI_ATTR_MAX + 1]; - struct pdi *pdi; - int err; - char ip_str[40]; - - err = nla_parse_nested(attrs, GTP5G_PDI_ATTR_MAX, a, NULL, NULL); - if (err) - return err; - - if (!pdr->pdi) { - pdr->pdi = kzalloc(sizeof(*pdr->pdi), GFP_ATOMIC); - if (!pdr->pdi) - return -ENOMEM; - } - pdi = pdr->pdi; - - if (attrs[GTP5G_PDI_UE_ADDR_IPV4]) { - if (!pdi->ue_addr_ipv4) { - pdi->ue_addr_ipv4 = kzalloc(sizeof(*pdi->ue_addr_ipv4), GFP_ATOMIC); - if (!pdi->ue_addr_ipv4) - return -ENOMEM; - } - pdi->ue_addr_ipv4->s_addr = nla_get_be32(attrs[GTP5G_PDI_UE_ADDR_IPV4]); - - ip_string(ip_str, pdi->ue_addr_ipv4->s_addr); - } - - if (attrs[GTP5G_PDI_F_TEID]) { - err = parse_f_teid(pdi, attrs[GTP5G_PDI_F_TEID]); - if (err) - return err; - } - - if (attrs[GTP5G_PDI_SDF_FILTER]) { - err = parse_sdf_filter(pdi, attrs[GTP5G_PDI_SDF_FILTER]); - if (err) - return err; - } - - return 0; -} - -static int parse_f_teid(struct pdi *pdi, struct nlattr *a) -{ - struct nlattr *attrs[GTP5G_F_TEID_ATTR_MAX + 1]; - struct local_f_teid *f_teid; - int err; - - err = nla_parse_nested(attrs, GTP5G_F_TEID_ATTR_MAX, a, NULL, NULL); - if (err) - return err; - - if (!attrs[GTP5G_F_TEID_I_TEID]) - return -EINVAL; - - if (!attrs[GTP5G_F_TEID_GTPU_ADDR_IPV4]) - return -EINVAL; - - if (!pdi->f_teid) { - pdi->f_teid = kzalloc(sizeof(*pdi->f_teid), GFP_ATOMIC); - if (!pdi->f_teid) - return -ENOMEM; - } - f_teid = pdi->f_teid; - - f_teid->teid = htonl(nla_get_u32(attrs[GTP5G_F_TEID_I_TEID])); - - f_teid->gtpu_addr_ipv4.s_addr = nla_get_be32(attrs[GTP5G_F_TEID_GTPU_ADDR_IPV4]); - - return 0; -} - -static int parse_sdf_filter(struct pdi *pdi, struct nlattr *a) -{ - struct nlattr *attrs[GTP5G_SDF_FILTER_ATTR_MAX + 1]; - struct sdf_filter *sdf; - int err; - - err = nla_parse_nested(attrs, GTP5G_SDF_FILTER_ATTR_MAX, a, NULL, NULL); - if (err) - return err; - - if (!pdi->sdf) { - pdi->sdf = kzalloc(sizeof(*pdi->sdf), GFP_ATOMIC); - if (!pdi->sdf) - return -ENOMEM; - } - sdf = pdi->sdf; - - if (attrs[GTP5G_SDF_FILTER_FLOW_DESCRIPTION]) { - err = parse_ip_filter_rule(sdf, attrs[GTP5G_SDF_FILTER_FLOW_DESCRIPTION]); - if (err) - return err; - } - - if (attrs[GTP5G_SDF_FILTER_TOS_TRAFFIC_CLASS]) { - if (!sdf->tos_traffic_class) { - sdf->tos_traffic_class = kzalloc(sizeof(*sdf->tos_traffic_class), GFP_ATOMIC); - if (!sdf->tos_traffic_class) - return -ENOMEM; - } - *sdf->tos_traffic_class = nla_get_u16(attrs[GTP5G_SDF_FILTER_TOS_TRAFFIC_CLASS]); - } - - if (attrs[GTP5G_SDF_FILTER_SECURITY_PARAMETER_INDEX]) { - if (!sdf->security_param_idx) { - sdf->security_param_idx = kzalloc(sizeof(*sdf->security_param_idx), GFP_ATOMIC); - if (!sdf->security_param_idx) - return -ENOMEM; - } - *sdf->security_param_idx = nla_get_u32(attrs[GTP5G_SDF_FILTER_SECURITY_PARAMETER_INDEX]); - } - - if (attrs[GTP5G_SDF_FILTER_FLOW_LABEL]) { - if (!sdf->flow_label) { - sdf->flow_label = kzalloc(sizeof(*sdf->flow_label), GFP_ATOMIC); - if (!sdf->flow_label) - return -ENOMEM; - } - *sdf->flow_label = nla_get_u32(attrs[GTP5G_SDF_FILTER_FLOW_LABEL]); - } - - if (attrs[GTP5G_SDF_FILTER_SDF_FILTER_ID]) { - if (!sdf->bi_id) { - sdf->bi_id = kzalloc(sizeof(*sdf->bi_id), GFP_ATOMIC); - if (!sdf->bi_id) { - return -ENOMEM; - } - } - *sdf->bi_id = nla_get_u32(attrs[GTP5G_SDF_FILTER_SDF_FILTER_ID]); - } - - return 0; -} - -static int parse_ip_filter_rule(struct sdf_filter *sdf, struct nlattr *a) -{ - struct nlattr *attrs[GTP5G_FLOW_DESCRIPTION_ATTR_MAX + 1]; - struct ip_filter_rule *rule; - int err; - int i; - - err = nla_parse_nested(attrs, GTP5G_FLOW_DESCRIPTION_ATTR_MAX, a, NULL, NULL); - if (err) - return err; - - if (!attrs[GTP5G_FLOW_DESCRIPTION_ACTION]) - return -EINVAL; - if (!attrs[GTP5G_FLOW_DESCRIPTION_DIRECTION]) - return -EINVAL; - if (!attrs[GTP5G_FLOW_DESCRIPTION_PROTOCOL]) - return -EINVAL; - if (!attrs[GTP5G_FLOW_DESCRIPTION_SRC_IPV4]) - return -EINVAL; - if (!attrs[GTP5G_FLOW_DESCRIPTION_DEST_IPV4]) - return -EINVAL; - - if (!sdf->rule) { - sdf->rule = kzalloc(sizeof(*sdf->rule), GFP_ATOMIC); - if (!sdf->rule) - return -ENOMEM; - } - rule = sdf->rule; - - rule->action = nla_get_u8(attrs[GTP5G_FLOW_DESCRIPTION_ACTION]); - rule->direction = nla_get_u8(attrs[GTP5G_FLOW_DESCRIPTION_DIRECTION]); - rule->proto = nla_get_u8(attrs[GTP5G_FLOW_DESCRIPTION_PROTOCOL]); - rule->src.s_addr = nla_get_be32(attrs[GTP5G_FLOW_DESCRIPTION_SRC_IPV4]); - rule->dest.s_addr = nla_get_be32(attrs[GTP5G_FLOW_DESCRIPTION_DEST_IPV4]); - if (attrs[GTP5G_FLOW_DESCRIPTION_SRC_MASK]) - rule->smask.s_addr = nla_get_be32(attrs[GTP5G_FLOW_DESCRIPTION_SRC_MASK]); - else - rule->smask.s_addr = -1; - - if (attrs[GTP5G_FLOW_DESCRIPTION_DEST_MASK]) - rule->dmask.s_addr = nla_get_be32(attrs[GTP5G_FLOW_DESCRIPTION_DEST_MASK]); - else - rule->dmask.s_addr = -1; - - if (attrs[GTP5G_FLOW_DESCRIPTION_SRC_PORT]) { - u32 *sport_encode = nla_data(attrs[GTP5G_FLOW_DESCRIPTION_SRC_PORT]); - rule->sport_num = nla_len(attrs[GTP5G_FLOW_DESCRIPTION_SRC_PORT]) / sizeof(u32); - if (rule->sport) - kfree(rule->sport); - rule->sport = kzalloc(rule->sport_num * sizeof(*rule->sport), GFP_ATOMIC); - if (!rule->sport) - return -ENOMEM; - - for (i = 0; i < rule->sport_num; i++) { - u16 port1 = (u16)(sport_encode[i] & 0xFFFF); - u16 port2 = (u16)(sport_encode[i] >> 16); - if (port1 <= port2) { - rule->sport[i].start = port1; - rule->sport[i].end = port2; - } else { - rule->sport[i].start = port2; - rule->sport[i].end = port1; - } - } - } - - if (attrs[GTP5G_FLOW_DESCRIPTION_DEST_PORT]) { - u32 *dport_encode = nla_data(attrs[GTP5G_FLOW_DESCRIPTION_DEST_PORT]); - rule->dport_num = nla_len(attrs[GTP5G_FLOW_DESCRIPTION_DEST_PORT]) / sizeof(u32); - - if (rule->dport) - kfree(rule->dport); - - rule->dport = kzalloc(rule->dport_num * sizeof(*rule->dport), GFP_ATOMIC); - if (!rule->dport) - return -ENOMEM; - - for (i = 0; i < rule->dport_num; i++) { - u16 port1 = (u16)(dport_encode[i] & 0xFFFF); - u16 port2 = (u16)(dport_encode[i] >> 16); - if (port1 <= port2) { - rule->dport[i].start = port1; - rule->dport[i].end = port2; - } else { - rule->dport[i].start = port2; - rule->dport[i].end = port1; - } - } - } - - return 0; -} - -static int gtp5g_genl_fill_rule(struct sk_buff *skb, struct ip_filter_rule *rule) -{ - struct nlattr *nest_rule; - int max_port_num = rule->sport_num; - u32 *port_buf = NULL; - int i; - - if (rule->dport_num > max_port_num) - max_port_num = rule->dport_num; - - port_buf = kzalloc(max_port_num * sizeof(u32), GFP_KERNEL); - if (!port_buf) - goto genlmsg_fail; - - nest_rule = nla_nest_start(skb, GTP5G_SDF_FILTER_FLOW_DESCRIPTION); - if (!nest_rule) - goto genlmsg_fail; - - if (nla_put_u8(skb, GTP5G_FLOW_DESCRIPTION_ACTION, rule->action)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_FLOW_DESCRIPTION_DIRECTION, rule->direction)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_FLOW_DESCRIPTION_PROTOCOL, rule->proto)) - goto genlmsg_fail; - if (nla_put_be32(skb, GTP5G_FLOW_DESCRIPTION_SRC_IPV4, rule->src.s_addr)) - goto genlmsg_fail; - if (nla_put_be32(skb, GTP5G_FLOW_DESCRIPTION_DEST_IPV4, rule->dest.s_addr)) - goto genlmsg_fail; - - if (rule->smask.s_addr != -1) - if (nla_put_be32(skb, GTP5G_FLOW_DESCRIPTION_SRC_MASK, rule->smask.s_addr)) - goto genlmsg_fail; - - if (rule->dmask.s_addr != -1) - if (nla_put_be32(skb, GTP5G_FLOW_DESCRIPTION_DEST_MASK, rule->dmask.s_addr)) - goto genlmsg_fail; - - if (rule->sport_num && rule->sport) { - for (i = 0; i < rule->sport_num; i++) - port_buf[i] = (u32)(rule->sport[i].start | (rule->sport[i].end << 16)); - if (nla_put(skb, GTP5G_FLOW_DESCRIPTION_SRC_PORT, - rule->sport_num * sizeof(u32), port_buf)) - goto genlmsg_fail; - } - - if (rule->dport_num && rule->dport) { - for (i = 0; i < rule->dport_num; i++) - port_buf[i] = (u32)(rule->dport[i].start | (rule->dport[i].end << 16)); - if (nla_put(skb, GTP5G_FLOW_DESCRIPTION_DEST_PORT, - rule->dport_num * sizeof(u32), port_buf)) - goto genlmsg_fail; - } - - nla_nest_end(skb, nest_rule); - kfree(port_buf); - return 0; - -genlmsg_fail: - if (port_buf) - kfree(port_buf); - return -EMSGSIZE; -} - - -static int gtp5g_genl_fill_sdf(struct sk_buff *skb, struct sdf_filter *sdf) -{ - struct nlattr *nest_sdf; - - nest_sdf = nla_nest_start(skb, GTP5G_PDI_SDF_FILTER); - if (!nest_sdf) - return -EMSGSIZE; - - if (sdf->rule) { - if (gtp5g_genl_fill_rule(skb, sdf->rule)) - return -EMSGSIZE; - } - - if (sdf->tos_traffic_class) - if (nla_put_u16(skb, GTP5G_SDF_FILTER_TOS_TRAFFIC_CLASS, *sdf->tos_traffic_class)) - return -EMSGSIZE; - - if (sdf->security_param_idx) - if (nla_put_u32(skb, GTP5G_SDF_FILTER_SECURITY_PARAMETER_INDEX, *sdf->security_param_idx)) - return -EMSGSIZE; - - if (sdf->flow_label) - if (nla_put_u32(skb, GTP5G_SDF_FILTER_FLOW_LABEL, *sdf->flow_label)) - return -EMSGSIZE; - - if (sdf->bi_id) - if (nla_put_u32(skb, GTP5G_SDF_FILTER_SDF_FILTER_ID, *sdf->bi_id)) - return -EMSGSIZE; - - nla_nest_end(skb, nest_sdf); - return 0; -} - - -static int gtp5g_genl_fill_f_teid(struct sk_buff *skb, struct local_f_teid *f_teid) -{ - struct nlattr *nest_f_teid; - - nest_f_teid = nla_nest_start(skb, GTP5G_PDI_F_TEID); - if (!nest_f_teid) - return -EMSGSIZE; - - if (nla_put_u32(skb, GTP5G_F_TEID_I_TEID, ntohl(f_teid->teid))) - return -EMSGSIZE; - if (nla_put_be32(skb, GTP5G_F_TEID_GTPU_ADDR_IPV4, f_teid->gtpu_addr_ipv4.s_addr)) - return -EMSGSIZE; - - nla_nest_end(skb, nest_f_teid); - return 0; -} - -static int gtp5g_genl_fill_pdi(struct sk_buff *skb, struct pdi *pdi) -{ - struct nlattr *nest_pdi; - - nest_pdi = nla_nest_start(skb, GTP5G_PDR_PDI); - if (!nest_pdi) - return -EMSGSIZE; - - if (pdi->ue_addr_ipv4) { - if (nla_put_be32(skb, GTP5G_PDI_UE_ADDR_IPV4, pdi->ue_addr_ipv4->s_addr)) - return -EMSGSIZE; - } - - if (pdi->f_teid) { - if (gtp5g_genl_fill_f_teid(skb, pdi->f_teid)) - return -EMSGSIZE; - } - - if (pdi->sdf) { - if (gtp5g_genl_fill_sdf(skb, pdi->sdf)) - return -EMSGSIZE; - } - - nla_nest_end(skb, nest_pdi); - return 0; -} - - -static int gtp5g_genl_fill_pdr(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, - u32 type, struct pdr *pdr) -{ - void *genlh; - int i; - - genlh = genlmsg_put(skb, snd_portid, snd_seq, >p5g_genl_family, 0, type); - if (!genlh) - goto genlmsg_fail; - - if (nla_put_u16(skb, GTP5G_PDR_ID, pdr->id)) - goto genlmsg_fail; - - if (nla_put_u32(skb, GTP5G_PDR_PRECEDENCE, pdr->precedence)) - goto genlmsg_fail; - - if (pdr->seid) { - if (nla_put_u64_64bit(skb, GTP5G_PDR_SEID, pdr->seid, 0)) - goto genlmsg_fail; - } - - if (pdr->outer_header_removal) { - if (nla_put_u8(skb, GTP5G_OUTER_HEADER_REMOVAL, *pdr->outer_header_removal)) - goto genlmsg_fail; - } - - if (pdr->far_id) { - if (nla_put_u32(skb, GTP5G_PDR_FAR_ID, *pdr->far_id)) - goto genlmsg_fail; - } - - for (i = 0; i < pdr->qer_num; i++) { - if (nla_put_u32(skb, GTP5G_PDR_QER_ID, pdr->qer_ids[i])) - goto genlmsg_fail; - } - - for (i = 0; i < pdr->urr_num; i++) { - if (nla_put_u32(skb, GTP5G_PDR_URR_ID, pdr->urr_ids[i])) - goto genlmsg_fail; - } - - if (pdr->role_addr_ipv4.s_addr) { - if (nla_put_u32(skb, GTP5G_PDR_ROLE_ADDR_IPV4, pdr->role_addr_ipv4.s_addr)) - goto genlmsg_fail; - } - - if (pdr->pdi) { - if (gtp5g_genl_fill_pdi(skb, pdr->pdi)) - goto genlmsg_fail; - } - - genlmsg_end(skb, genlh); - return 0; -genlmsg_fail: - genlmsg_cancel(skb, genlh); - return -EMSGSIZE; -} diff --git a/lib/gtp5g/src/genl/genl_qer.c b/lib/gtp5g/src/genl/genl_qer.c deleted file mode 100644 index a1dc2b7c..00000000 --- a/lib/gtp5g/src/genl/genl_qer.c +++ /dev/null @@ -1,426 +0,0 @@ -#include -#include - -#include "common.h" -#include "dev.h" -#include "genl.h" -#include "genl_qer.h" -#include "qer.h" - -#include -#include -#include "net.h" - -static int qer_fill(struct qer *, struct gtp5g_dev *, struct genl_info *); -static int gtp5g_genl_fill_qer(struct sk_buff *, u32, u32, u32, struct qer *); - -int gtp5g_genl_add_qer(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct qer *qer; - int ifindex; - int netnsfd; - u64 seid; - u32 qer_id; - int err; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rtnl_lock(); - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - rcu_read_unlock(); - rtnl_unlock(); - return -ENODEV; - } - - if (info->attrs[GTP5G_QER_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_QER_SEID]); - } else { - seid = 0; - } - - if (info->attrs[GTP5G_QER_ID]) { - qer_id = nla_get_u32(info->attrs[GTP5G_QER_ID]); - } else { - rcu_read_unlock(); - rtnl_unlock(); - return -ENODEV; - } - - qer = find_qer_by_id(gtp, seid, qer_id); - if (qer) { - if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) { - rcu_read_unlock(); - rtnl_unlock(); - return -EEXIST; - } - if (!(info->nlhdr->nlmsg_flags & NLM_F_REPLACE)) { - rcu_read_unlock(); - rtnl_unlock(); - return -EOPNOTSUPP; - } - err = qer_fill(qer, gtp, info); - if (err) { - qer_context_delete(qer); - return err; - } - return 0; - } - - if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE) { - rcu_read_unlock(); - rtnl_unlock(); - return -ENOENT; - } - - if (info->nlhdr->nlmsg_flags & NLM_F_APPEND) { - rcu_read_unlock(); - rtnl_unlock(); - return -EOPNOTSUPP; - } - - qer = kzalloc(sizeof(*qer), GFP_ATOMIC); - if (!qer) { - rcu_read_unlock(); - rtnl_unlock(); - return -ENOMEM; - } - - qer->dev = gtp->dev; - - err = qer_fill(qer, gtp, info); - if (err) { - qer_context_delete(qer); - rcu_read_unlock(); - rtnl_unlock(); - return err; - } - - qer_append(seid, qer_id, qer, gtp); - - rcu_read_unlock(); - rtnl_unlock(); - return 0; -} - -int gtp5g_genl_del_qer(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct qer *qer; - int ifindex; - int netnsfd; - u64 seid; - u32 qer_id; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - rcu_read_unlock(); - return -ENODEV; - } - - if (info->attrs[GTP5G_QER_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_QER_SEID]); - } else { - seid = 0; - } - - if (info->attrs[GTP5G_QER_ID]) { - qer_id = nla_get_u32(info->attrs[GTP5G_QER_ID]); - } else { - rcu_read_unlock(); - return -ENODEV; - } - - qer = find_qer_by_id(gtp, seid, qer_id); - if (!qer) { - rcu_read_unlock(); - return -ENOENT; - } - - qer_context_delete(qer); - rcu_read_unlock(); - - return 0; -} - -int gtp5g_genl_get_qer(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct qer *qer; - int ifindex; - int netnsfd; - u64 seid; - u32 qer_id; - struct sk_buff *skb_ack; - int err; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - rcu_read_unlock(); - return -ENODEV; - } - - if (info->attrs[GTP5G_QER_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_QER_SEID]); - } else { - seid = 0; - } - - if (info->attrs[GTP5G_QER_ID]) { - qer_id = nla_get_u32(info->attrs[GTP5G_QER_ID]); - } else { - rcu_read_unlock(); - return -ENODEV; - } - - qer = find_qer_by_id(gtp, seid, qer_id); - if (!qer) { - rcu_read_unlock(); - return -ENOENT; - } - - skb_ack = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); - if (!skb_ack) { - rcu_read_unlock(); - return -ENOMEM; - } - - err = gtp5g_genl_fill_qer(skb_ack, - NETLINK_CB(skb).portid, - info->snd_seq, - info->nlhdr->nlmsg_type, - qer); - if (err) { - kfree_skb(skb_ack); - rcu_read_unlock(); - return err; - } - rcu_read_unlock(); - - return genlmsg_unicast(genl_info_net(info), skb_ack, info->snd_portid); -} - -int gtp5g_genl_dump_qer(struct sk_buff *skb, struct netlink_callback *cb) -{ - /* netlink_callback->args - * args[0] : index of gtp5g dev id - * args[1] : index of gtp5g hash entry id in dev - * args[2] : index of gtp5g qer id - * args[5] : set non-zero means it is finished - */ - struct gtp5g_dev *gtp; - struct gtp5g_dev *last_gtp = (struct gtp5g_dev *)cb->args[0]; - struct net *net = sock_net(skb->sk); - struct gtp5g_net *gn = net_generic(net, GTP5G_NET_ID()); - int i; - int last_hash_entry_id = cb->args[1]; - int ret; - u32 qer_id = cb->args[2]; - struct qer *qer; - - if (cb->args[5]) - return 0; - - list_for_each_entry_rcu(gtp, &gn->gtp5g_dev_list, list) { - if (last_gtp && last_gtp != gtp) - continue; - else - last_gtp = NULL; - - for (i = last_hash_entry_id; i < gtp->hash_size; i++) { - hlist_for_each_entry_rcu(qer, >p->qer_id_hash[i], hlist_id) { - if (qer_id && qer_id != qer->id) - continue; - qer_id = 0; - ret = gtp5g_genl_fill_qer(skb, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - cb->nlh->nlmsg_type, - qer); - if (ret) { - cb->args[0] = (unsigned long)gtp; - cb->args[1] = i; - cb->args[2] = qer->id; - goto out; - } - } - } - } - - cb->args[5] = 1; -out: - return skb->len; -} - - -static int qer_fill(struct qer *qer, struct gtp5g_dev *gtp, struct genl_info *info) -{ - struct nlattr *mbr_param_attrs[GTP5G_QER_MBR_ATTR_MAX + 1]; - struct nlattr *gbr_param_attrs[GTP5G_QER_GBR_ATTR_MAX + 1]; - - qer->id = nla_get_u32(info->attrs[GTP5G_QER_ID]); - - if (info->attrs[GTP5G_QER_SEID]) - qer->seid = nla_get_u64(info->attrs[GTP5G_QER_SEID]); - else - qer->seid = 0; - - if (info->attrs[GTP5G_QER_GATE]) - qer->ul_dl_gate = nla_get_u8(info->attrs[GTP5G_QER_GATE]); - - /* MBR */ - if (info->attrs[GTP5G_QER_MBR] && - !nla_parse_nested(mbr_param_attrs, GTP5G_QER_MBR_ATTR_MAX, info->attrs[GTP5G_QER_MBR], NULL, NULL)) { - qer->mbr.ul_high = nla_get_u32(mbr_param_attrs[GTP5G_QER_MBR_UL_HIGH32]); - qer->mbr.ul_low = nla_get_u8(mbr_param_attrs[GTP5G_QER_MBR_UL_LOW8]); - qer->mbr.dl_high = nla_get_u32(mbr_param_attrs[GTP5G_QER_MBR_DL_HIGH32]); - qer->mbr.dl_low = nla_get_u8(mbr_param_attrs[GTP5G_QER_MBR_DL_LOW8]); - } - - /* GBR */ - if (info->attrs[GTP5G_QER_GBR] && - !nla_parse_nested(gbr_param_attrs, GTP5G_QER_GBR_ATTR_MAX, info->attrs[GTP5G_QER_GBR], NULL, NULL)) { - qer->gbr.ul_high = nla_get_u32(gbr_param_attrs[GTP5G_QER_GBR_UL_HIGH32]); - qer->gbr.ul_low = nla_get_u8(gbr_param_attrs[GTP5G_QER_GBR_UL_LOW8]); - qer->gbr.dl_high = nla_get_u32(gbr_param_attrs[GTP5G_QER_GBR_DL_HIGH32]); - qer->gbr.dl_low = nla_get_u8(gbr_param_attrs[GTP5G_QER_GBR_DL_LOW8]); - } - - if (info->attrs[GTP5G_QER_CORR_ID]) - qer->qer_corr_id = nla_get_u32(info->attrs[GTP5G_QER_CORR_ID]); - - if (info->attrs[GTP5G_QER_RQI]) - qer->rqi = nla_get_u8(info->attrs[GTP5G_QER_RQI]); - - if (info->attrs[GTP5G_QER_QFI]) - qer->qfi = nla_get_u8(info->attrs[GTP5G_QER_QFI]); - - if (info->attrs[GTP5G_QER_PPI]) - qer->ppi = nla_get_u8(info->attrs[GTP5G_QER_PPI]); - - if (info->attrs[GTP5G_QER_RCSR]) - qer->rcsr = nla_get_u8(info->attrs[GTP5G_QER_RCSR]); - - /* Update PDRs which has not linked to this QER */ - qer_update(qer, gtp); - return 0; -} - - -static int gtp5g_genl_fill_qer(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, - u32 type, struct qer *qer) -{ - struct gtp5g_dev *gtp = netdev_priv(qer->dev); - void *genlh; - struct nlattr *nest_mbr_param; - struct nlattr *nest_gbr_param; - u16 *ids = NULL; - int n; - - genlh = genlmsg_put(skb, snd_portid, snd_seq, - >p5g_genl_family, 0, type); - if (!genlh) - goto genlmsg_fail; - - if (nla_put_u32(skb, GTP5G_QER_ID, qer->id)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_QER_GATE, qer->ul_dl_gate)) - goto genlmsg_fail; - if (qer->seid) { - if (nla_put_u64_64bit(skb, GTP5G_QER_SEID, qer->seid, 0)) - goto genlmsg_fail; - } - - /* MBR */ - if (!(nest_mbr_param = nla_nest_start(skb, GTP5G_QER_MBR))) - goto genlmsg_fail; - - if (nla_put_u32(skb, GTP5G_QER_MBR_UL_HIGH32, qer->mbr.ul_high)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_QER_MBR_UL_LOW8, qer->mbr.ul_low)) - goto genlmsg_fail; - if (nla_put_u32(skb, GTP5G_QER_MBR_DL_HIGH32, qer->mbr.dl_high)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_QER_MBR_DL_LOW8, qer->mbr.dl_low)) - goto genlmsg_fail; - - nla_nest_end(skb, nest_mbr_param); - - /* GBR */ - if (!(nest_gbr_param = nla_nest_start(skb, GTP5G_QER_GBR))) - goto genlmsg_fail; - - if (nla_put_u32(skb, GTP5G_QER_GBR_UL_HIGH32, qer->gbr.ul_high)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_QER_GBR_UL_LOW8, qer->gbr.ul_low)) - goto genlmsg_fail; - if (nla_put_u32(skb, GTP5G_QER_GBR_DL_HIGH32, qer->gbr.dl_high)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_QER_GBR_DL_LOW8, qer->gbr.dl_low)) - goto genlmsg_fail; - - nla_nest_end(skb, nest_gbr_param); - - /* CORR_ID, RQI, QFI, PPI, RCSR */ - if (nla_put_u32(skb, GTP5G_QER_CORR_ID, qer->qer_corr_id)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_QER_RQI, qer->rqi)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_QER_QFI, qer->qfi)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_QER_PPI, qer->ppi)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_QER_RCSR, qer->rcsr)) - goto genlmsg_fail; - - ids = kzalloc(MAX_PDR_PER_SESSION * sizeof(u16), GFP_KERNEL); - if (!ids) - goto genlmsg_fail; - n = qer_get_pdr_ids(ids, MAX_PDR_PER_SESSION, qer, gtp); - if (n) { - if (nla_put(skb, GTP5G_QER_RELATED_TO_PDR, n * sizeof(u16), ids)) - goto genlmsg_fail; - } - - kfree(ids); - genlmsg_end(skb, genlh); - return 0; - -genlmsg_fail: - if (ids) - kfree(ids); - genlmsg_cancel(skb, genlh); - return -EMSGSIZE; -} diff --git a/lib/gtp5g/src/genl/genl_report.c b/lib/gtp5g/src/genl/genl_report.c deleted file mode 100644 index 97a2900b..00000000 --- a/lib/gtp5g/src/genl/genl_report.c +++ /dev/null @@ -1,355 +0,0 @@ -#include -#include -#include -#include - -#include "dev.h" -#include "genl.h" -#include "report.h" -#include "genl_report.h" -#include "genl_urr.h" -#include "hash.h" - -#include "net.h" -#include "log.h" -#include "pdr.h" -#include "urr.h" - -static int gtp5g_genl_fill_volume_measurement(struct sk_buff *, struct VolumeMeasurement); -static int parse_seid_urr(struct seid_urr *, struct nlattr *); - -int gtp5g_genl_get_usage_report(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct urr *urr; - int ifindex; - int netnsfd; - u64 seid; - u32 urr_id; - struct sk_buff *skb_ack = NULL; - int err = 0; - struct usage_report *report = NULL; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - err = -ENODEV; - goto fail; - } - - if (info->attrs[GTP5G_URR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_URR_SEID]); - } else { - seid = 0; - } - - if (!info->attrs[GTP5G_URR_ID]) { - err = -ENODEV; - goto fail; - } - urr_id = nla_get_u32(info->attrs[GTP5G_URR_ID]); - - urr = find_urr_by_id(gtp, seid, urr_id); - if (!urr) { - err = -ENOENT; - goto fail; - } - - skb_ack = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); - if (!skb_ack) { - err = -ENOMEM; - goto fail; - } - - report = kzalloc(sizeof(struct usage_report), GFP_KERNEL); - if (!report) { - err = -ENOMEM; - goto fail; - } - - convert_urr_to_report(urr, report); - - err = gtp5g_genl_fill_usage_report(skb_ack, - NETLINK_CB(skb).portid, - info->snd_seq, - info->nlhdr->nlmsg_type, - report); - - kfree(report); - -fail: - if (err) { - if (skb_ack) { - kfree_skb(skb_ack); - } - rcu_read_unlock(); - return err; - } - - rcu_read_unlock(); - return genlmsg_unicast(genl_info_net(info), skb_ack, info->snd_portid); -} - -int gtp5g_genl_get_multi_usage_reports(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct urr *urr = NULL; - int ifindex; - int netnsfd; - u32 urr_num, report_num = 0, i = 0; - struct sk_buff *skb_ack = NULL; - int err = 0; - struct nlattr *hdr = nlmsg_attrdata(info->nlhdr, 0); - int remaining = nlmsg_attrlen(info->nlhdr, 0); - struct seid_urr **seid_urrs; - struct usage_report **reports = NULL; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - if (!info->attrs[GTP5G_URR_NUM]) - return -EINVAL; - urr_num = nla_get_u32(info->attrs[GTP5G_URR_NUM]); - - rcu_read_lock(); - - seid_urrs = kzalloc(sizeof(struct seid_urr *) * urr_num , GFP_KERNEL); - hdr = nla_next(hdr, &remaining); - while (nla_ok(hdr,remaining)) { - switch (nla_type(hdr)) { - case GTP5G_URR_MULTI_SEID_URRID: - seid_urrs[i] = kzalloc(sizeof(struct seid_urr), GFP_KERNEL); - err = parse_seid_urr(seid_urrs[i++], hdr); - if (err) { - goto fail; - } - break; - } - hdr = nla_next(hdr, &remaining); - } - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - err = -ENODEV; - goto fail; - } - - reports = kzalloc(sizeof(struct usage_report *) * urr_num , GFP_KERNEL); - if (!reports) { - err = -ENOMEM; - goto fail; - } - - for (i = 0; i < urr_num; i++) { - urr = find_urr_by_id(gtp, seid_urrs[i]->seid, seid_urrs[i]->urrid); - if (!urr) { - err = -ENOENT; - goto fail; - } - - reports[i] = kzalloc(sizeof(struct usage_report), GFP_KERNEL); - if (!reports[i]) { - err = -ENOMEM; - goto fail; - } - - convert_urr_to_report(urr, reports[report_num++]); - } - - skb_ack = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); - if (!skb_ack) { - err = -ENOMEM; - goto fail; - } - - err = gtp5g_genl_fill_multi_usage_reports(skb_ack, - NETLINK_CB(skb).portid, - info->snd_seq, - info->nlhdr->nlmsg_type, - reports, report_num); - -fail: - if (reports) { - for (i = 0; i < report_num; i++) { - if (reports[i]) - kfree(reports[i]); - } - kfree(reports); - } - if (seid_urrs) { - for (i = 0; i < urr_num; i++) { - if (seid_urrs[i]) - kfree(seid_urrs[i]); - } - kfree(seid_urrs); - } - - if (err) { - if (skb_ack) - kfree_skb(skb_ack); - rcu_read_unlock(); - return err; - } - - rcu_read_unlock(); - return genlmsg_unicast(genl_info_net(info), skb_ack, info->snd_portid); -} - -static int gtp5g_genl_fill_volume_measurement(struct sk_buff *skb, struct VolumeMeasurement bytes) -{ - struct nlattr *nest_volume_measurement; - - nest_volume_measurement = nla_nest_start(skb, GTP5G_UR_VOLUME_MEASUREMENT); - if (!nest_volume_measurement) - return -EMSGSIZE; - - if (nla_put_u64_64bit(skb, GTP5G_UR_VOLUME_MEASUREMENT_TOVOL, bytes.totalVolume , 0)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_UR_VOLUME_MEASUREMENT_UVOL, bytes.uplinkVolume, 0)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_UR_VOLUME_MEASUREMENT_DVOL, bytes.downlinkVolume, 0)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_UR_VOLUME_MEASUREMENT_TOPACKET, bytes.totalPktNum, 0)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_UR_VOLUME_MEASUREMENT_UPACKET, bytes.uplinkPktNum, 0)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_UR_VOLUME_MEASUREMENT_DPACKET, bytes.downlinkPktNum, 0)) - return -EMSGSIZE; - - nla_nest_end(skb, nest_volume_measurement); - - memset(&bytes, 0, sizeof(struct VolumeMeasurement)); - - return 0; -} - -int gtp5g_genl_fill_ur(struct sk_buff *skb, struct usage_report *report) -{ - struct nlattr *nest_usage_report; - - nest_usage_report = nla_nest_start(skb, GTP5G_UR); - if (!nest_usage_report) - return -EMSGSIZE; - - if (nla_put_u32(skb, GTP5G_UR_URRID, report->urrid)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_UR_START_TIME, report->start_time, 0)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_UR_END_TIME, report->end_time, 0)) - return -EMSGSIZE; - if (gtp5g_genl_fill_volume_measurement(skb, report->volmeasurement)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_UR_SEID, report->seid, 0)) - return -EMSGSIZE; - - if (report->trigger) { - if (nla_put_be32(skb, GTP5G_UR_USAGE_REPORT_TRIGGER, report->trigger)) - return -EMSGSIZE; - } - - nla_nest_end(skb, nest_usage_report); - - return 0; -} - -static int parse_seid_urr(struct seid_urr *seid_urr, struct nlattr *a) -{ - struct nlattr *attrs[GTP5G_URR_ATTR_MAX + 1]; - int err; - - if (!seid_urr) { - return -ENOMEM; - } - - err = nla_parse_nested(attrs, GTP5G_URR_ATTR_MAX, a, NULL, NULL); - if (err){ - return err; - } - - if (attrs[GTP5G_URR_ID]) { - seid_urr->urrid = nla_get_u32(attrs[GTP5G_URR_ID]); - } - - if (attrs[GTP5G_URR_SEID]) { - seid_urr->seid = nla_get_u64(attrs[GTP5G_URR_SEID]); - } - - return 0; -} - -int gtp5g_genl_fill_usage_report(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, - u32 type, struct usage_report *report) -{ - void *genlh; - genlh = genlmsg_put(skb, snd_portid, snd_seq, - >p5g_genl_family, 0, type); - if (!genlh) - goto genlmsg_fail; - - gtp5g_genl_fill_ur(skb, report); - - genlmsg_end(skb, genlh); - - return 0; - -genlmsg_fail: - genlmsg_cancel(skb, genlh); - return -EMSGSIZE; -} - -int gtp5g_genl_fill_multi_usage_reports(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, - u32 type, struct usage_report **reports, u32 report_num) -{ - int i; - void *genlh; - genlh = genlmsg_put(skb, snd_portid, snd_seq, - >p5g_genl_family, 0, type); - if (!genlh) - goto genlmsg_fail; - - for (i = 0; i < report_num; i++) { - gtp5g_genl_fill_ur(skb, reports[i]); - } - - genlmsg_end(skb, genlh); - - return 0; - -genlmsg_fail: - genlmsg_cancel(skb, genlh); - return -EMSGSIZE; -} - -void convert_urr_to_report(struct urr *urr, struct usage_report *report) -{ - urr->end_time = ktime_get_real(); - *report = (struct usage_report ) { - urr->id, - 0, - urr->bytes, - 0, - urr->start_time, - urr->end_time, - urr->seid - }; - - memset(&urr->bytes, 0, sizeof(struct VolumeMeasurement)); - - urr->start_time = ktime_get_real(); -} \ No newline at end of file diff --git a/lib/gtp5g/src/genl/genl_urr.c b/lib/gtp5g/src/genl/genl_urr.c deleted file mode 100644 index 409d2692..00000000 --- a/lib/gtp5g/src/genl/genl_urr.c +++ /dev/null @@ -1,522 +0,0 @@ -#include -#include -#include -#include - -#include "common.h" -#include "dev.h" -#include "genl.h" -#include "urr.h" -#include "genl_urr.h" -#include "genl_report.h" - -#include "net.h" -#include "log.h" - -static int urr_fill(struct urr *, struct gtp5g_dev *, struct genl_info *); -static int gtp5g_genl_fill_urr(struct sk_buff *, u32, u32, u32, struct urr *); -static int parse_volumethreshold(struct urr *urr, struct nlattr *a); -static int parse_volumeqouta(struct urr *urr, struct nlattr *a); - -int gtp5g_genl_add_urr(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct urr *urr; - int ifindex; - int netnsfd; - u64 seid; - u32 urr_id; - int err = 0; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rtnl_lock(); - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - err = -ENODEV; - goto end; - } - - if (info->attrs[GTP5G_URR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_URR_SEID]); - } else { - seid = 0; - } - - if (!info->attrs[GTP5G_URR_ID]) { - err = -ENODEV; - goto end; - } - urr_id = nla_get_u32(info->attrs[GTP5G_URR_ID]); - - urr = find_urr_by_id(gtp, seid, urr_id); - if (urr) { - if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) { - err = -EEXIST; - goto end; - } - if (!(info->nlhdr->nlmsg_flags & NLM_F_REPLACE)) { - err = -EOPNOTSUPP; - goto end; - } - err = urr_fill(urr, gtp, info); - if (err) { - urr_context_delete(urr); - goto end; - } - - goto end; - } - - if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE) { - err = -ENOENT; - goto end; - } - - if (info->nlhdr->nlmsg_flags & NLM_F_APPEND) { - err = -EOPNOTSUPP; - goto end; - } - - urr = kzalloc(sizeof(*urr), GFP_ATOMIC); - if (!urr) { - err = -ENOMEM; - goto end; - } - - urr->dev = gtp->dev; - urr->start_time = ktime_get_real(); - - err = urr_fill(urr, gtp, info); - if (err) { - urr_context_delete(urr); - goto end; - } - - urr_append(seid, urr_id, urr, gtp); - -end: - rcu_read_unlock(); - rtnl_unlock(); - return err; -} - -int gtp5g_genl_del_urr(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct urr *urr = NULL; - int ifindex; - int netnsfd; - u64 seid; - u32 urr_id; - struct sk_buff *skb_ack = NULL; - int err = 0; - struct usage_report *report = NULL; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - err = -ENODEV; - goto fail; - } - - if (info->attrs[GTP5G_URR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_URR_SEID]); - } else { - seid = 0; - } - - if (!info->attrs[GTP5G_URR_ID]) { - err = -ENODEV; - goto fail; - } - urr_id = nla_get_u32(info->attrs[GTP5G_URR_ID]); - - urr = find_urr_by_id(gtp, seid, urr_id); - if (!urr) { - err = -ENOENT; - goto fail; - } - - skb_ack = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); - if (!skb_ack) { - err = -ENOMEM; - goto fail; - } - - report = kzalloc(sizeof(struct usage_report), GFP_KERNEL); - if (!report) { - err = -ENOMEM; - goto fail; - } - - convert_urr_to_report(urr, report); - - err = gtp5g_genl_fill_usage_report(skb_ack, - NETLINK_CB(skb).portid, - info->snd_seq, - info->nlhdr->nlmsg_type, - report); - - kfree(report); - -fail: - if (err) { - if (skb_ack) { - kfree_skb(skb_ack); - } - rcu_read_unlock(); - return err; - } - - urr_context_delete(urr); - rcu_read_unlock(); - return genlmsg_unicast(genl_info_net(info), skb_ack, info->snd_portid); -} - -int gtp5g_genl_get_urr(struct sk_buff *skb, struct genl_info *info) -{ - struct gtp5g_dev *gtp; - struct urr *urr; - int ifindex; - int netnsfd; - u64 seid; - u32 urr_id; - struct sk_buff *skb_ack = NULL; - int err = 0; - - if (!info->attrs[GTP5G_LINK]) - return -EINVAL; - ifindex = nla_get_u32(info->attrs[GTP5G_LINK]); - - if (info->attrs[GTP5G_NET_NS_FD]) - netnsfd = nla_get_u32(info->attrs[GTP5G_NET_NS_FD]); - else - netnsfd = -1; - - rcu_read_lock(); - - gtp = gtp5g_find_dev(sock_net(skb->sk), ifindex, netnsfd); - if (!gtp) { - err = -ENODEV; - goto fail; - } - - if (info->attrs[GTP5G_URR_SEID]) { - seid = nla_get_u64(info->attrs[GTP5G_URR_SEID]); - } else { - seid = 0; - } - - if (!info->attrs[GTP5G_URR_ID]) { - err = -ENODEV; - goto fail; - } - urr_id = nla_get_u32(info->attrs[GTP5G_URR_ID]); - - urr = find_urr_by_id(gtp, seid, urr_id); - if (!urr) { - err = -ENOENT; - goto fail; - } - - skb_ack = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); - if (!skb_ack) { - err = -ENOMEM; - goto fail; - } - - err = gtp5g_genl_fill_urr(skb_ack, - NETLINK_CB(skb).portid, - info->snd_seq, - info->nlhdr->nlmsg_type, - urr); - -fail: - if (err) { - if (skb_ack) { - kfree_skb(skb_ack); - } - rcu_read_unlock(); - return err; - } - - rcu_read_unlock(); - return genlmsg_unicast(genl_info_net(info), skb_ack, info->snd_portid); -} - -int gtp5g_genl_dump_urr(struct sk_buff *skb, struct netlink_callback *cb) -{ - /* netlink_callback->args - * args[0] : index of gtp5g dev id - * args[1] : index of gtp5g hash entry id in dev - * args[2] : index of gtp5g urr id - * args[5] : set non-zero means it is finished - */ - struct gtp5g_dev *gtp; - struct gtp5g_dev *last_gtp = (struct gtp5g_dev *)cb->args[0]; - struct net *net = sock_net(skb->sk); - struct gtp5g_net *gn = net_generic(net, GTP5G_NET_ID()); - int i; - int last_hash_entry_id = cb->args[1]; - int ret; - u32 urr_id = cb->args[2]; - struct urr *urr; - - if (cb->args[5]) - return 0; - - list_for_each_entry_rcu(gtp, &gn->gtp5g_dev_list, list) { - if (last_gtp && last_gtp != gtp) - continue; - else - last_gtp = NULL; - - for (i = last_hash_entry_id; i < gtp->hash_size; i++) { - hlist_for_each_entry_rcu(urr, >p->urr_id_hash[i], hlist_id) { - if (urr_id && urr_id != urr->id) - continue; - urr_id = 0; - ret = gtp5g_genl_fill_urr(skb, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - cb->nlh->nlmsg_type, - urr); - if (ret) { - cb->args[0] = (unsigned long)gtp; - cb->args[1] = i; - cb->args[2] = urr->id; - goto out; - } - } - } - } - - cb->args[5] = 1; -out: - return skb->len; -} - - -static int urr_fill(struct urr *urr, struct gtp5g_dev *gtp, struct genl_info *info) -{ - urr->id = nla_get_u32(info->attrs[GTP5G_URR_ID]); - - if (info->attrs[GTP5G_URR_SEID]) - urr->seid = nla_get_u64(info->attrs[GTP5G_URR_SEID]); - else - urr->seid = 0; - - if (info->attrs[GTP5G_URR_MEASUREMENT_METHOD]) - urr->method = nla_get_u8(info->attrs[GTP5G_URR_MEASUREMENT_METHOD]); - - if (info->attrs[GTP5G_URR_REPORTING_TRIGGER]) { - urr->trigger = nla_get_u32(info->attrs[GTP5G_URR_REPORTING_TRIGGER]); - if (urr->trigger == URR_RPT_TRIGGER_START) { - // Clean bytes to make sure the bytes are counted after the start of service data flow - // TODO: Should send the previous stroed bytes to CP first - memset(&urr->bytes, 0, sizeof(struct VolumeMeasurement)); - } - } - - if (info->attrs[GTP5G_URR_MEASUREMENT_PERIOD]) - urr->period = nla_get_u32(info->attrs[GTP5G_URR_MEASUREMENT_PERIOD]); - - if (info->attrs[GTP5G_URR_MEASUREMENT_INFO]) - urr->info = nla_get_u8(info->attrs[GTP5G_URR_MEASUREMENT_INFO]); - - if (info->attrs[GTP5G_URR_VOLUME_THRESHOLD]) - parse_volumethreshold(urr, info->attrs[GTP5G_URR_VOLUME_THRESHOLD]); - - if (info->attrs[GTP5G_URR_VOLUME_QUOTA]) { - parse_volumeqouta(urr, info->attrs[GTP5G_URR_VOLUME_QUOTA]); - urr->consumed = urr->bytes; - - if (urr->volumequota.totalVolume == 0 && urr->trigger == URR_RPT_TRIGGER_VOLQU) { - urr_quota_exhaust_action(urr, gtp); - GTP5G_INF(NULL, "URR (%u) Receive zero quota, stop measure", urr->id); - } else if (urr->quota_exhausted) { - urr_reverse_quota_exhaust_action(urr, gtp); - GTP5G_INF(NULL, "URR (%u) Receive New quota, continue measure", urr->id); - } - } - - /* Update PDRs which has not linked to this URR */ - urr_update(urr, gtp); - - return 0; -} - -static int parse_volumethreshold(struct urr *urr, struct nlattr *a) -{ - struct nlattr *attrs[GTP5G_URR_ATTR_MAX + 1]; - int err; - - err = nla_parse_nested(attrs, GTP5G_URR_VOLUME_THRESHOLD_ATTR_MAX, a, NULL, NULL); - if (err) - return err; - - if (attrs[GTP5G_URR_VOLUME_THRESHOLD_FLAG]) { - urr->volumethreshold.flag = nla_get_u8(attrs[GTP5G_URR_VOLUME_THRESHOLD_FLAG]); - } - - if (attrs[GTP5G_URR_VOLUME_THRESHOLD_TOVOL]) { - urr->volumethreshold.totalVolume = nla_get_u64(attrs[GTP5G_URR_VOLUME_THRESHOLD_TOVOL]); - } - - if (attrs[GTP5G_URR_VOLUME_THRESHOLD_UVOL]) { - urr->volumethreshold.uplinkVolume = nla_get_u64(attrs[GTP5G_URR_VOLUME_THRESHOLD_UVOL]); - } - - if (attrs[GTP5G_URR_VOLUME_THRESHOLD_DVOL]) { - urr->volumethreshold.downlinkVolume = nla_get_u64(attrs[GTP5G_URR_VOLUME_THRESHOLD_DVOL]); - } - - return 0; -} - -static int parse_volumeqouta(struct urr *urr, struct nlattr *a) -{ - struct nlattr *attrs[GTP5G_URR_ATTR_MAX + 1]; - int err; - - err = nla_parse_nested(attrs, GTP5G_URR_VOLUME_QUOTA_ATTR_MAX, a, NULL, NULL); - if (err) - return err; - - if (attrs[GTP5G_URR_VOLUME_QUOTA_FLAG]) { - urr->volumequota.flag = nla_get_u8(attrs[GTP5G_URR_VOLUME_QUOTA_FLAG]); - } - - if (attrs[GTP5G_URR_VOLUME_QUOTA_TOVOL]) { - urr->volumequota.totalVolume = nla_get_u64(attrs[GTP5G_URR_VOLUME_QUOTA_TOVOL]); - } - - if (attrs[GTP5G_URR_VOLUME_QUOTA_UVOL]) { - urr->volumequota.uplinkVolume = nla_get_u64(attrs[GTP5G_URR_VOLUME_QUOTA_UVOL]); - } - - if (attrs[GTP5G_URR_VOLUME_QUOTA_DVOL]) { - urr->volumequota.downlinkVolume = nla_get_u64(attrs[GTP5G_URR_VOLUME_QUOTA_DVOL]); - } - - return 0; -} - -static int gtp5g_genl_fill_volume_threshold(struct sk_buff *skb, struct Volume volumethreshold) -{ - struct nlattr *nest_volume_threshold; - - nest_volume_threshold = nla_nest_start(skb, GTP5G_URR_VOLUME_THRESHOLD); - if (!nest_volume_threshold) - return -EMSGSIZE; - - if (nla_put_u8(skb, GTP5G_URR_VOLUME_THRESHOLD_FLAG, volumethreshold.flag)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_URR_VOLUME_THRESHOLD_TOVOL, volumethreshold.totalVolume, 0)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_URR_VOLUME_THRESHOLD_UVOL, volumethreshold.uplinkVolume, 0)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_URR_VOLUME_THRESHOLD_DVOL, volumethreshold.downlinkVolume, 0)) - return -EMSGSIZE; - - nla_nest_end(skb, nest_volume_threshold); - return 0; -} - -static int gtp5g_genl_fill_volume_quota(struct sk_buff *skb, struct Volume volumequota) -{ - struct nlattr *nest_volume_quota; - - nest_volume_quota = nla_nest_start(skb, GTP5G_URR_VOLUME_QUOTA); - if (!nest_volume_quota) - return -EMSGSIZE; - - if (nla_put_u8(skb, GTP5G_URR_VOLUME_QUOTA_FLAG, volumequota.flag)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_URR_VOLUME_QUOTA_TOVOL, volumequota.totalVolume, 0)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_URR_VOLUME_QUOTA_UVOL, volumequota.uplinkVolume, 0)) - return -EMSGSIZE; - if (nla_put_u64_64bit(skb, GTP5G_URR_VOLUME_QUOTA_DVOL, volumequota.downlinkVolume, 0)) - return -EMSGSIZE; - - nla_nest_end(skb, nest_volume_quota); - return 0; -} - -static int gtp5g_genl_fill_urr(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, - u32 type, struct urr *urr) -{ - struct gtp5g_dev *gtp = netdev_priv(urr->dev); - void *genlh; - u16 *ids = NULL; - int n; - - genlh = genlmsg_put(skb, snd_portid, snd_seq, - >p5g_genl_family, 0, type); - if (!genlh) - goto genlmsg_fail; - - if (nla_put_u32(skb, GTP5G_URR_ID, urr->id)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_URR_MEASUREMENT_METHOD, urr->method)) - goto genlmsg_fail; - if (nla_put_u32(skb, GTP5G_URR_REPORTING_TRIGGER, urr->trigger)) - goto genlmsg_fail; - if (nla_put_u32(skb, GTP5G_URR_MEASUREMENT_PERIOD, urr->period)) - goto genlmsg_fail; - if (nla_put_u8(skb, GTP5G_URR_MEASUREMENT_INFO, urr->info)) - goto genlmsg_fail; - if (urr->seid) { - if (nla_put_u64_64bit(skb, GTP5G_URR_SEID, urr->seid, 0)) - goto genlmsg_fail; - } - if (urr->volumethreshold.flag != 0) { - if (gtp5g_genl_fill_volume_threshold(skb, urr->volumethreshold)) - goto genlmsg_fail; - } - - if (urr->volumequota.flag != 0) { - if (gtp5g_genl_fill_volume_quota(skb, urr->volumequota)) - goto genlmsg_fail; - } - ids = kzalloc(MAX_PDR_PER_SESSION * sizeof(u16), GFP_KERNEL); - if (!ids) - goto genlmsg_fail; - n = urr_get_pdr_ids(ids, MAX_PDR_PER_SESSION, urr, gtp); - if (n) { - if (nla_put(skb, GTP5G_URR_RELATED_TO_PDR, n * sizeof(u16), ids)) - goto genlmsg_fail; - } - - kfree(ids); - genlmsg_end(skb, genlh); - return 0; - -genlmsg_fail: - if (ids) { - kfree(ids); - } - genlmsg_cancel(skb, genlh); - return -EMSGSIZE; -} diff --git a/lib/gtp5g/src/genl/genl_version.c b/lib/gtp5g/src/genl/genl_version.c deleted file mode 100644 index 97cc3dd6..00000000 --- a/lib/gtp5g/src/genl/genl_version.c +++ /dev/null @@ -1,43 +0,0 @@ -#include "genl_version.h" - -static int gtp5g_genl_fill_ver(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, - u32 type) -{ - void *genlh; - - genlh = genlmsg_put(skb, snd_portid, snd_seq, >p5g_genl_family, 0, type); - if (!genlh) - goto genlmsg_fail; - - if (nla_put_string(skb, GTP5G_VERSION, DRV_VERSION)) - goto genlmsg_fail; - - genlmsg_end(skb, genlh); - return 0; - -genlmsg_fail: - genlmsg_cancel(skb, genlh); - return -EMSGSIZE; -} - -int gtp5g_genl_get_version(struct sk_buff *skb, struct genl_info *info) -{ - struct sk_buff *skb_ack; - int err; - - skb_ack = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); - if (!skb_ack) { - return -ENOMEM; - } - - err = gtp5g_genl_fill_ver(skb_ack, - NETLINK_CB(skb).portid, - info->snd_seq, - info->nlhdr->nlmsg_type); - if (err) { - kfree_skb(skb_ack); - return err; - } - - return genlmsg_unicast(genl_info_net(info), skb_ack, info->snd_portid); -} diff --git a/lib/gtp5g/src/gtp5g.c b/lib/gtp5g/src/gtp5g.c deleted file mode 100644 index 3d132979..00000000 --- a/lib/gtp5g/src/gtp5g.c +++ /dev/null @@ -1,77 +0,0 @@ -#include - -#include "genl.h" -#include "link.h" -#include "net.h" -#include "proc.h" -#include "hash.h" -#include "log.h" -#include "genl_version.h" - -static int __init gtp5g_init(void) -{ - int err; - - GTP5G_LOG(NULL, "Gtp5g Module initialization Ver: %s\n", DRV_VERSION); - - init_proc_gtp5g_dev_list(); - - // set hash initial value - get_random_bytes(>p5g_h_initval, sizeof(gtp5g_h_initval)); - - err = rtnl_link_register(>p5g_link_ops); - if (err < 0) { - GTP5G_ERR(NULL, "Failed to register rtnl\n"); - goto error_out; - } - - err = genl_register_family(>p5g_genl_family); - if (err < 0) { - GTP5G_ERR(NULL, "Failed to register generic\n"); - goto unreg_rtnl_link; - } - - err = register_pernet_subsys(>p5g_net_ops); - if (err < 0) { - GTP5G_ERR(NULL, "Failed to register namespace\n"); - goto unreg_genl_family; - } - - err = create_proc(); - if (err < 0) { - goto unreg_pernet; - } - GTP5G_LOG(NULL, "5G GTP module loaded\n"); - - return 0; -unreg_pernet: - unregister_pernet_subsys(>p5g_net_ops); -unreg_genl_family: - genl_unregister_family(>p5g_genl_family); -unreg_rtnl_link: - rtnl_link_unregister(>p5g_link_ops); -error_out: - return err; -} - -static void __exit gtp5g_fini(void) -{ - genl_unregister_family(>p5g_genl_family); - rtnl_link_unregister(>p5g_link_ops); - unregister_pernet_subsys(>p5g_net_ops); - - remove_proc(); - - GTP5G_LOG(NULL, "5G GTP module unloaded\n"); -} - -late_initcall(gtp5g_init); -module_exit(gtp5g_fini); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yao-Wen Chang "); -MODULE_AUTHOR("Muthuraman "); -MODULE_DESCRIPTION("Interface for 5G GTP encapsulated traffic"); -MODULE_VERSION(DRV_VERSION); -MODULE_ALIAS_RTNL_LINK("gtp5g"); -MODULE_ALIAS_GENL_FAMILY("gtp5g"); diff --git a/lib/gtp5g/src/gtpu/dev.c b/lib/gtp5g/src/gtpu/dev.c deleted file mode 100644 index bd9a8556..00000000 --- a/lib/gtp5g/src/gtpu/dev.c +++ /dev/null @@ -1,252 +0,0 @@ -#include -#include -#include - -#include "dev.h" -#include "genl.h" -#include "encap.h" -#include "pdr.h" -#include "far.h" -#include "qer.h" -#include "bar.h" -#include "urr.h" -#include "pktinfo.h" - -struct gtp5g_dev *gtp5g_find_dev(struct net *src_net, int ifindex, int netnsfd) -{ - struct gtp5g_dev *gtp = NULL; - struct net_device *dev; - struct net *net; - - /* Examine the link attributes and figure out which network namespace - * we are talking about. - */ - if (netnsfd == -1) - net = get_net(src_net); - else - net = get_net_ns_by_fd(netnsfd); - - if (IS_ERR(net)) - return NULL; - - /* Check if there's an existing gtp5g device to configure */ - dev = dev_get_by_index_rcu(net, ifindex); - if (dev && dev->netdev_ops == >p5g_netdev_ops) - gtp = netdev_priv(dev); - else - gtp = NULL; - - put_net(net); - - return gtp; -} - -static int gtp5g_dev_init(struct net_device *dev) -{ - struct gtp5g_dev *gtp = netdev_priv(dev); - - gtp->dev = dev; - - dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!dev->tstats) { - return -ENOMEM; - } - - return 0; -} - -static void gtp5g_dev_uninit(struct net_device *dev) -{ - struct gtp5g_dev *gtp = netdev_priv(dev); - - gtp5g_encap_disable(gtp->sk1u); - free_percpu(dev->tstats); -} - -/** - * Entry function for Downlink packets - * */ -static netdev_tx_t gtp5g_dev_xmit(struct sk_buff *skb, struct net_device *dev) -{ - unsigned int proto = ntohs(skb->protocol); - struct gtp5g_pktinfo pktinfo; - int ret = 0; - - /* Ensure there is sufficient headroom */ - if (skb_cow_head(skb, dev->needed_headroom)) { - goto tx_err; - } - - skb_reset_inner_headers(skb); - - /* PDR lookups in gtp5g_build_skb_*() need rcu read-side lock. - * */ - rcu_read_lock(); - switch (proto) { - case ETH_P_IP: - ret = gtp5g_handle_skb_ipv4(skb, dev, &pktinfo); - break; - default: - ret = -EOPNOTSUPP; - } - rcu_read_unlock(); - - if (ret < 0) - goto tx_err; - - if (ret == FAR_ACTION_FORW) - gtp5g_xmit_skb_ipv4(skb, &pktinfo); - - return NETDEV_TX_OK; - -tx_err: - dev->stats.tx_errors++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -const struct net_device_ops gtp5g_netdev_ops = { - .ndo_init = gtp5g_dev_init, - .ndo_uninit = gtp5g_dev_uninit, - .ndo_start_xmit = gtp5g_dev_xmit, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) - .ndo_get_stats64 = dev_get_tstats64, -#else - .ndo_get_stats64 = ip_tunnel_get_stats64, -#endif -}; - -int dev_hashtable_new(struct gtp5g_dev *gtp, int hsize) -{ - int i; - - gtp->addr_hash = kmalloc_array(hsize, sizeof(struct hlist_head), - GFP_KERNEL); - if (gtp->addr_hash == NULL) - return -ENOMEM; - - gtp->i_teid_hash = kmalloc_array(hsize, sizeof(struct hlist_head), - GFP_KERNEL); - if (gtp->i_teid_hash == NULL) - goto err1; - - gtp->pdr_id_hash = kmalloc_array(hsize, sizeof(struct hlist_head), - GFP_KERNEL); - if (gtp->pdr_id_hash == NULL) - goto err2; - - gtp->far_id_hash = kmalloc_array(hsize, sizeof(struct hlist_head), - GFP_KERNEL); - if (gtp->far_id_hash == NULL) - goto err3; - - gtp->qer_id_hash = kmalloc_array(hsize, sizeof(struct hlist_head), - GFP_KERNEL); - if (gtp->qer_id_hash == NULL) - goto err4; - - gtp->bar_id_hash = kmalloc_array(hsize, sizeof(struct hlist_head), - GFP_KERNEL); - if (!gtp->bar_id_hash) - goto err5; - - gtp->urr_id_hash = kmalloc_array(hsize, sizeof(struct hlist_head), - GFP_KERNEL); - if (!gtp->urr_id_hash) - goto err6; - - gtp->related_far_hash = kmalloc_array(hsize, sizeof(struct hlist_head), - GFP_KERNEL); - if (gtp->related_far_hash == NULL) - goto err7; - - gtp->related_qer_hash = kmalloc_array(hsize, sizeof(struct hlist_head), - GFP_KERNEL); - if (gtp->related_qer_hash == NULL) - goto err8; - - gtp->related_bar_hash = kmalloc_array(hsize, sizeof(struct hlist_head), - GFP_KERNEL); - if (!gtp->related_bar_hash) - goto err9; - - gtp->related_urr_hash = kmalloc_array(hsize, sizeof(struct hlist_head), - GFP_KERNEL); - if (!gtp->related_urr_hash) - goto err10; - - gtp->hash_size = hsize; - - for (i = 0; i < hsize; i++) { - INIT_HLIST_HEAD(>p->addr_hash[i]); - INIT_HLIST_HEAD(>p->i_teid_hash[i]); - INIT_HLIST_HEAD(>p->pdr_id_hash[i]); - INIT_HLIST_HEAD(>p->far_id_hash[i]); - INIT_HLIST_HEAD(>p->qer_id_hash[i]); - INIT_HLIST_HEAD(>p->bar_id_hash[i]); - INIT_HLIST_HEAD(>p->urr_id_hash[i]); - INIT_HLIST_HEAD(>p->related_far_hash[i]); - INIT_HLIST_HEAD(>p->related_qer_hash[i]); - INIT_HLIST_HEAD(>p->related_bar_hash[i]); - INIT_HLIST_HEAD(>p->related_urr_hash[i]); - } - - return 0; -err10: - kfree(gtp->related_bar_hash); -err9: - kfree(gtp->related_qer_hash); -err8: - kfree(gtp->related_far_hash); -err7: - kfree(gtp->urr_id_hash); -err6: - kfree(gtp->bar_id_hash); -err5: - kfree(gtp->qer_id_hash); -err4: - kfree(gtp->far_id_hash); -err3: - kfree(gtp->pdr_id_hash); -err2: - kfree(gtp->i_teid_hash); -err1: - kfree(gtp->addr_hash); - return -ENOMEM; -} - -void gtp5g_hashtable_free(struct gtp5g_dev *gtp) -{ - struct pdr *pdr; - struct far *far; - struct qer *qer; - struct bar *bar; - struct urr *urr; - int i; - - for (i = 0; i < gtp->hash_size; i++) { - hlist_for_each_entry_rcu(far, >p->far_id_hash[i], hlist_id) - far_context_delete(far); - hlist_for_each_entry_rcu(qer, >p->qer_id_hash[i], hlist_id) - qer_context_delete(qer); - hlist_for_each_entry_rcu(pdr, >p->pdr_id_hash[i], hlist_id) - pdr_context_delete(pdr); - hlist_for_each_entry_rcu(bar, >p->bar_id_hash[i], hlist_id) - bar_context_delete(bar); - hlist_for_each_entry_rcu(urr, >p->urr_id_hash[i], hlist_id) - urr_context_delete(urr); - } - - synchronize_rcu(); - kfree(gtp->addr_hash); - kfree(gtp->i_teid_hash); - kfree(gtp->pdr_id_hash); - kfree(gtp->far_id_hash); - kfree(gtp->qer_id_hash); - kfree(gtp->bar_id_hash); - kfree(gtp->urr_id_hash); - kfree(gtp->related_far_hash); - kfree(gtp->related_qer_hash); - kfree(gtp->related_bar_hash); - kfree(gtp->related_urr_hash); -} \ No newline at end of file diff --git a/lib/gtp5g/src/gtpu/encap.c b/lib/gtp5g/src/gtpu/encap.c deleted file mode 100644 index 836ec4d3..00000000 --- a/lib/gtp5g/src/gtpu/encap.c +++ /dev/null @@ -1,989 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "dev.h" -#include "link.h" -#include "encap.h" -#include "gtp.h" -#include "pdr.h" -#include "far.h" -#include "qer.h" -#include "urr.h" -#include "report.h" - -#include "genl.h" -#include "genl_report.h" - -#include "log.h" -#include "api_version.h" -#include "pktinfo.h" - -/* used to compatible with api with/without seid */ -#define MSG_KOV_LEN 4 - -enum msg_type { - TYPE_BUFFER = 1, - TYPE_URR_REPORT, - TYPE_BAR_INFO, -}; - -static void gtp5g_encap_disable_locked(struct sock *); -static int gtp5g_encap_recv(struct sock *, struct sk_buff *); -static int gtp1u_udp_encap_recv(struct gtp5g_dev *, struct sk_buff *); -static int gtp5g_rx(struct pdr *, struct sk_buff *, unsigned int, unsigned int); -static int gtp5g_fwd_skb_encap(struct sk_buff *, struct net_device *, - unsigned int, struct pdr *, struct far *, uint64_t); -static int netlink_send(struct pdr *, struct far *, struct sk_buff *, struct net *, struct usage_report *, u32); -static int unix_sock_send(struct pdr *, struct far *, void *, u32, u32); -static int gtp5g_fwd_skb_ipv4(struct sk_buff *, - struct net_device *, struct gtp5g_pktinfo *, - struct pdr *, struct far *, uint64_t); - -/* When gtp5g newlink, establish the udp tunnel used in N3 interface */ -struct sock *gtp5g_encap_enable(int fd, int type, struct gtp5g_dev *gtp){ - struct udp_tunnel_sock_cfg tuncfg = {NULL}; - struct socket *sock; - struct sock *sk; - int err; - - GTP5G_LOG(NULL, "enable gtp5g for the fd(%d) type(%d)\n", fd, type); - - sock = sockfd_lookup(fd, &err); - if (!sock) { - GTP5G_ERR(NULL, "Failed to find the socket fd(%d)\n", fd); - return NULL; - } - - if (sock->sk->sk_protocol != IPPROTO_UDP) { - GTP5G_ERR(NULL, "socket fd(%d) is not a UDP\n", fd); - sk = ERR_PTR(-EINVAL); - goto out_sock; - } - - lock_sock(sock->sk); - if (sock->sk->sk_user_data) { - GTP5G_ERR(NULL, "Failed to set sk_user_datat of socket fd(%d)\n", fd); - sk = ERR_PTR(-EBUSY); - goto out_sock; - } - - sk = sock->sk; - sock_hold(sk); - - tuncfg.sk_user_data = gtp; - tuncfg.encap_type = type; - tuncfg.encap_rcv = gtp5g_encap_recv; - tuncfg.encap_destroy = gtp5g_encap_disable_locked; - - setup_udp_tunnel_sock(sock_net(sock->sk), sock, &tuncfg); - -out_sock: - release_sock(sock->sk); - sockfd_put(sock); - return sk; -} - - -void gtp5g_encap_disable(struct sock *sk) -{ - struct gtp5g_dev *gtp; - - if (!sk) { - return; - } - - lock_sock(sk); - gtp = sk->sk_user_data; - if (gtp) { - gtp->sk1u = NULL; - udp_sk(sk)->encap_type = 0; - // sk_user_data was protected by RCU - rcu_assign_sk_user_data(sk, NULL); - sock_put(sk); - } - release_sock(sk); -} - -static void gtp5g_encap_disable_locked(struct sock *sk) -{ - rtnl_lock(); - gtp5g_encap_disable(sk); - rtnl_unlock(); -} - -/** - * Entry function for Uplink packets - * */ -static int gtp5g_encap_recv(struct sock *sk, struct sk_buff *skb) -{ - struct gtp5g_dev *gtp; - int ret = 0; - - gtp = rcu_dereference_sk_user_data(sk); - if (!gtp) { - return 1; - } - - switch (udp_sk(sk)->encap_type) { - case UDP_ENCAP_GTP1U: - ret = gtp1u_udp_encap_recv(gtp, skb); - break; - default: - ret = -1; // Should not happen - } - - switch (ret) { - case 1: - GTP5G_ERR(gtp->dev, "Pass up to the process\n"); - break; - case 0: - break; - case -1: - GTP5G_ERR(gtp->dev, "GTP packet has been dropped\n"); - kfree_skb(skb); - ret = 0; - break; - } - - return ret; -} - -static int gtp1c_handle_echo_req(struct sk_buff *skb, struct gtp5g_dev *gtp) -{ - struct gtpv1_hdr *req_gtp1; - struct gtp1_hdr_opt *req_gtpOptHdr; - - struct gtpv1_echo_resp *gtp_pkt; - - struct rtable *rt; - struct flowi4 fl4; - struct iphdr *iph; - struct udphdr *udph; - - __u8 flags = 0; - __be16 seq_number = 0; - - req_gtp1 = (struct gtpv1_hdr *)(skb->data + sizeof(struct udphdr)); - - flags = req_gtp1->flags; - if (flags & GTPV1_HDR_FLG_SEQ) { - req_gtpOptHdr = (struct gtp1_hdr_opt *)(skb->data + sizeof(struct udphdr) - + sizeof(struct gtpv1_hdr)); - seq_number = req_gtpOptHdr->seq_number; - } else { - GTP5G_ERR(gtp->dev, "GTP echo request shall bring sequence number\n"); - seq_number = 0; - } - - pskb_pull(skb, skb->len); - - gtp_pkt = skb_push(skb, sizeof(struct gtpv1_echo_resp)); - if (!gtp_pkt) { - GTP5G_ERR(gtp->dev, "can not construct GTP Echo Response\n"); - return 1; - } - memset(gtp_pkt, 0, sizeof(struct gtpv1_echo_resp)); - - /* gtp header*/ - gtp_pkt->gtpv1_h.flags = GTPV1 | GTPV1_HDR_FLG_SEQ; - gtp_pkt->gtpv1_h.type = GTPV1_MSG_TYPE_ECHO_RSP; - gtp_pkt->gtpv1_h.length = - htons(sizeof(struct gtpv1_echo_resp) - sizeof(struct gtpv1_hdr)); - gtp_pkt->gtpv1_h.tid = 0; - - /* gtp opt header*/ - gtp_pkt->gtpv1_opt_h.seq_number = seq_number; - - /* gtp recovery*/ - gtp_pkt->recov.type_num = GTPV1_IE_RECOVERY; - gtp_pkt->recov.cnt = 0; - - iph = ip_hdr(skb); - udph = udp_hdr(skb); - - rt = ip4_find_route(skb, iph, gtp->sk1u, gtp->dev, - iph->daddr , - iph->saddr, - &fl4); - if (IS_ERR(rt)) { - GTP5G_ERR(gtp->dev, "no route for GTP echo response from %pI4\n", - &iph->saddr); - return 1; - } - - udp_tunnel_xmit_skb(rt, gtp->sk1u, skb, - fl4.saddr, fl4.daddr, - iph->tos, - ip4_dst_hoplimit(&rt->dst), - 0, - udph->dest, udph->source, - !net_eq(sock_net(gtp->sk1u), - dev_net(gtp->dev)), - false); - - return 0; -} - -static int gtp1u_udp_encap_recv(struct gtp5g_dev *gtp, struct sk_buff *skb) -{ - unsigned int hdrlen = sizeof(struct udphdr) + sizeof(struct gtpv1_hdr); - struct gtpv1_hdr *gtpv1; - struct pdr *pdr; - unsigned int pull_len = hdrlen; - u8 gtp_type; - u32 teid; - - if (!pskb_may_pull(skb, pull_len)) { - GTP5G_ERR(gtp->dev, "Failed to pull skb length %#x\n", pull_len); - return -1; - } - - gtpv1 = (struct gtpv1_hdr *)(skb->data + sizeof(struct udphdr)); - if ((gtpv1->flags >> 5) != GTP_V1) { - GTP5G_ERR(gtp->dev, "GTP version is not v1: %#x\n", - gtpv1->flags); - return 1; - } - - gtp_type = gtpv1->type; - teid = gtpv1->tid; - if (gtp_type == GTPV1_MSG_TYPE_ECHO_REQ) { - GTP5G_INF(gtp->dev, "GTP-C message type is GTP echo request: %#x\n", - gtp_type); - - return gtp1c_handle_echo_req(skb, gtp); - } - - if (gtp_type != GTPV1_MSG_TYPE_TPDU && gtp_type != GTPV1_MSG_TYPE_EMARK) { - GTP5G_ERR(gtp->dev, "GTP-U message type is not a TPDU or End Marker: %#x\n", - gtp_type); - return 1; - } - - /** TS 29.281 Chapter 5.1 and Figure 5.1-1 - * GTP-U header at least 8 byte - * - * This field shall be present if and only if any one or more of the S, PN and E flags are set. - * This field means seq number (2 Octect), N-PDU number (1 Octet) and Next ext hdr type (1 Octet). - * - * TODO: Validate the Reserved flag set or not, if it is set then protocol error - */ - if (gtpv1->flags & GTPV1_HDR_FLG_MASK) { - u8 *ext_hdr = NULL; - hdrlen += sizeof(struct gtp1_hdr_opt); - pull_len = hdrlen; - if (!pskb_may_pull(skb, pull_len)) { - GTP5G_ERR(gtp->dev, "Failed to pull skb length %#x\n", pull_len); - return -1; - } - - /** TS 29.281 Chapter 5.2 and Figure 5.2.1-1 - * The length of the Extension header shall be defined in a variable length of 4 octets, - * i.e. m+1 = n*4 octets, where n is a positive integer. - */ - while (*(ext_hdr = (u8 *)(skb->data + hdrlen - 1))) { - u8 ext_hdr_type = *ext_hdr; - unsigned int extlen; - pull_len = hdrlen + 1; // 1 byte for the length of extension hdr - if (!pskb_may_pull(skb, pull_len)) { - GTP5G_ERR(gtp->dev, "Failed to pull skb length %#x\n", pull_len); - return -1; - } - extlen = (*((u8 *)(skb->data + hdrlen))) * 4; // total length of extension hdr - if (extlen == 0) { - GTP5G_ERR(gtp->dev, "Invalid extention header length\n"); - return -1; - } - hdrlen += extlen; - pull_len = hdrlen; - if (!pskb_may_pull(skb, pull_len)) { - GTP5G_ERR(gtp->dev, "Failed to pull skb length %#x\n", pull_len); - return -1; - } - switch (ext_hdr_type) { - case GTPV1_NEXT_EXT_HDR_TYPE_85: - { - // ext_pdu_sess_ctr_t *etype85 = (ext_pdu_sess_ctr_t *) (skb->data + hdrlen); - // pdu_sess_ctr_t *pdu_sess_info = &etype85->pdu_sess_ctr; - - // Commented the below code due to support N9 packet downlink - // if (pdu_sess_info->type_spare == PDU_SESSION_INFO_TYPE0) - // return -1; - - //TODO: validate pdu_sess_ctr - break; - } - } - } - } - - pdr = pdr_find_by_gtp1u(gtp, skb, hdrlen, teid, gtp_type); - if (!pdr) { - GTP5G_ERR(gtp->dev, "No PDR match this skb : teid[%d]\n", ntohl(teid)); - return -1; - } - - return gtp5g_rx(pdr, skb, hdrlen, gtp->role); -} - -static int gtp5g_drop_skb_encap(struct sk_buff *skb, struct net_device *dev, - struct pdr *pdr) -{ - struct gtpv1_hdr *gtp1 = (struct gtpv1_hdr *)(skb->data + sizeof(struct udphdr)); - if (gtp1->type == GTPV1_MSG_TYPE_TPDU) { - pdr->ul_drop_cnt++; - GTP5G_INF(NULL, "PDR (%u) UL_DROP_CNT (%llu)", pdr->id, pdr->ul_drop_cnt); - } - dev_kfree_skb(skb); - return 0; -} - -static int gtp5g_buf_skb_encap(struct sk_buff *skb, struct net_device *dev, - unsigned int hdrlen, struct pdr *pdr, struct far *far) -{ - struct gtpv1_hdr *gtp1 = (struct gtpv1_hdr *)(skb->data + sizeof(struct udphdr)); - if (gtp1->type == GTPV1_MSG_TYPE_TPDU) { - // Get rid of the GTP-U + UDP headers. - if (iptunnel_pull_header(skb, - hdrlen, - skb->protocol, - !net_eq(sock_net(pdr->sk), dev_net(dev)))) { - GTP5G_ERR(dev, "Failed to pull GTP-U and UDP headers\n"); - return -1; - } - - if (pdr_addr_is_netlink(pdr)) { - if (netlink_send(pdr, far, skb, dev_net(dev), NULL, 0) < 0) { - GTP5G_ERR(dev, "Failed to send skb to netlink socket PDR(%u)", pdr->id); - ++pdr->ul_drop_cnt; - } - } else { - if (unix_sock_send(pdr, far, skb->data, skb_headlen(skb), 0) < 0) { - GTP5G_ERR(dev, "Failed to send skb to unix domain socket PDR(%u)", pdr->id); - ++pdr->ul_drop_cnt; - } - } - } - dev_kfree_skb(skb); - return 0; -} - -/* Function netlink_{...} are used to handle buffering */ -// Send PDR ID, FAR action and buffered packet to user space -static int netlink_send(struct pdr *pdr, struct far *far, struct sk_buff *skb_in, struct net *net, struct usage_report *reports, u32 report_num) -{ - struct sk_buff *skb; - static atomic_t seq_counter; - u32 seq; - void *header; - struct nlattr *attr; - int i, err; - struct nlattr *nest_msg_type; - - if (reports != NULL) { - skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); - } else { - skb = genlmsg_new( - nla_total_size_64bit(8) + - nla_total_size(2) + - nla_total_size(2) + - nla_total_size(skb_in->len), - GFP_ATOMIC); - } - - if (!skb) - return -ENOMEM; - - seq = atomic_inc_return(&seq_counter); - header = genlmsg_put(skb, 0, seq, >p5g_genl_family, 0, GTP5G_CMD_BUFFER_GTPU); - if (!header) - { - nlmsg_free(skb); - return -ENOMEM; - } - - if (reports != NULL) { - nest_msg_type = nla_nest_start(skb, GTP5G_REPORT); - - for (i = 0; i < report_num; i++) { - gtp5g_genl_fill_ur(skb, &reports[i]); - } - - nla_nest_end(skb, nest_msg_type); - } else { - nest_msg_type = nla_nest_start(skb, GTP5G_BUFFER); - - err = nla_put_u16(skb, GTP5G_BUFFER_ID, pdr->id); - if (err != 0) { - nlmsg_free(skb); - return err; - } - - err = nla_put_u64_64bit(skb, GTP5G_BUFFER_SEID, pdr->seid, GTP5G_BUFFER_PAD); - if (err != 0) { - nlmsg_free(skb); - return err; - } - - err = nla_put_u16(skb, GTP5G_BUFFER_ACTION, far->action); - if (err != 0) { - nlmsg_free(skb); - return err; - } - - attr = nla_reserve(skb, GTP5G_BUFFER_PACKET, skb_in->len); - if (!attr) { - nlmsg_free(skb); - return -EINVAL; - } - skb_copy_bits(skb_in, 0, nla_data(attr), skb_in->len); - - nla_nest_end(skb, nest_msg_type); - } - - genlmsg_end(skb, header); - genlmsg_multicast_netns(>p5g_genl_family, net, skb, 0, GTP5G_GENL_MCGRP, GFP_ATOMIC); - return 0; -} - -/* Function unix_sock_{...} are used to handle buffering */ -// Send PDR ID, FAR action and buffered packet to user space -static int unix_sock_send(struct pdr *pdr, struct far *far, void *buf, u32 len, u32 report_num) -{ - struct msghdr msg; - struct kvec *kov; - struct socket *sock = pdr->sock_for_buf; - int msg_kovlen; - int total_kov_len = 0; - int i, rt; - u8 type_hdr[1] = {TYPE_BUFFER}; - u64 self_seid_hdr[1] = {pdr->seid}; - u16 self_hdr[2] = {pdr->id, far->action}; - u32 self_num_hdr[1] = {report_num}; - - if (pdr_addr_is_netlink(pdr)) { - return -EINVAL; - } - - if (!sock) { - GTP5G_ERR(NULL, "Failed Socket is NULL\n"); - return -EINVAL; - } - - memset(&msg, 0, sizeof(msg)); - if (report_num > 0) { - type_hdr[0] = TYPE_URR_REPORT; - } - - msg_kovlen = MSG_KOV_LEN; - kov = kmalloc_array(msg_kovlen, sizeof(struct kvec), - GFP_KERNEL); - if (kov == NULL) - return -ENOMEM; - - memset(kov, 0, sizeof(struct kvec) * msg_kovlen); - - kov[0].iov_base = type_hdr; - kov[0].iov_len = sizeof(type_hdr); - kov[1].iov_base = self_seid_hdr; - kov[1].iov_len = sizeof(self_seid_hdr); - - //buf is report in this case - if (report_num > 0) { - kov[2].iov_base = self_num_hdr; - kov[2].iov_len = sizeof(self_num_hdr); - } - else { - kov[2].iov_base = self_hdr; - kov[2].iov_len = sizeof(self_hdr); - } - - kov[3].iov_base = buf; - kov[3].iov_len = len; - - for (i = 0; i < msg_kovlen; i++) - total_kov_len += kov[i].iov_len; - - msg.msg_name = 0; - msg.msg_namelen = 0; - iov_iter_kvec(&msg.msg_iter, WRITE, kov, msg_kovlen, total_kov_len); - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = MSG_DONTWAIT; - - rt = sock_sendmsg(sock, &msg); - kfree(kov); - - return rt; -} - -bool increment_and_check_counter(struct VolumeMeasurement *volmeasure, struct Volume *volume, u64 vol, bool uplink, bool mnop){ - if (!volmeasure) { - return false; - } - - if (mnop) { - if (uplink) { - volmeasure->uplinkPktNum++; - } else { - volmeasure->downlinkPktNum++; - } - volmeasure->totalPktNum = volmeasure->uplinkPktNum + volmeasure->downlinkPktNum; - } - - if (uplink) { - volmeasure->uplinkVolume += vol; - } else { - volmeasure->downlinkVolume += vol; - } - - volmeasure->totalVolume = volmeasure->uplinkVolume + volmeasure->downlinkVolume; - - if (!volume) { - return false; - } - - if (volume->totalVolume && (volmeasure->totalVolume >= volume->totalVolume) && (volume->flag & URR_VOLUME_TOVOL)) { - return true; - } else if (volume->uplinkVolume && (volmeasure->uplinkVolume >= volume->uplinkVolume) && (volume->flag & URR_VOLUME_ULVOL)) { - return true; - } else if (volume->downlinkVolume && (volmeasure->downlinkVolume >= volume->downlinkVolume) && (volume->flag & URR_VOLUME_DLVOL)) { - return true; - } - - return false; -} - -int check_urr(struct pdr *pdr, struct far *far, u64 vol, u64 vol_mbqe, bool uplink) { - struct gtp5g_dev *gtp = netdev_priv(pdr->dev); - int i; - int ret = 1; - u64 volume; - u64 len; - u32 report_num = 0; - u32 *triggers = NULL; - struct urr *urr, **urrs = NULL; - struct usage_report *report = NULL; - bool mnop; - struct sk_buff *skb; - - urrs = kzalloc(sizeof(struct urr *) * pdr->urr_num , GFP_ATOMIC); - triggers = kzalloc(sizeof(u32) * pdr->urr_num , GFP_ATOMIC); - if (!urrs || !triggers) { - ret = -1; - goto err1; - } - - for (i = 0; i < pdr->urr_num; i++) { - urr = find_urr_by_id(gtp, pdr->seid, pdr->urr_ids[i]); - - mnop = false; - if (urr->info & URR_INFO_MNOP) - mnop = true; - - if (!(urr->info & URR_INFO_INAM)) { - if (urr->method & URR_METHOD_VOLUM) { - if (urr->trigger == 0) { - GTP5G_ERR(pdr->dev, "no supported trigger(%u) in URR(%u) and related to PDR(%u)", - urr->trigger, urr->id, pdr->id); - ret = 0; - goto err1; - } - - if (urr->trigger & URR_RPT_TRIGGER_START && uplink) { - triggers[report_num] = USAR_TRIGGER_START; - urrs[report_num++] = urr; - urr_quota_exhaust_action(urr, gtp); - GTP5G_TRC(NULL, "URR (%u) Start of Service Data Flow, stop measure until recieve quota", urr->id); - continue; - } - - if (urr->info & URR_INFO_MBQE) { - // TODO: gtp5g isn't support QoS enforcement yet - // Currently MBQE Volume = MAQE Volume - vol_mbqe = vol; - volume = vol_mbqe; - } else { - volume = vol; - } - // Caculate Volume measurement for each trigger - if (urr->trigger & URR_RPT_TRIGGER_VOLTH) { - if (increment_and_check_counter(&urr->bytes, &urr->volumethreshold, volume, uplink, mnop)) { - triggers[report_num] = USAR_TRIGGER_VOLTH; - urrs[report_num++] = urr; - } - } else { - // For other triggers, only increment bytes - increment_and_check_counter(&urr->bytes, NULL, volume, uplink,mnop); - } - if (urr->trigger & URR_RPT_TRIGGER_VOLQU) { - if (increment_and_check_counter(&urr->consumed, &urr->volumequota, volume, uplink, mnop)) { - triggers[report_num] = USAR_TRIGGER_VOLQU; - urrs[report_num++] = urr; - urr_quota_exhaust_action(urr, gtp); - GTP5G_INF(NULL, "URR (%u) Quota Exhaust, stop measure", urr->id); - } - } - } - } else { - GTP5G_TRC(pdr->dev, "URR stop measurement"); - } - } - if (report_num > 0) { - len = sizeof(*report) * report_num; - - report = kzalloc(len, GFP_ATOMIC); - if (!report) { - ret = -1; - goto err1; - } - - for (i = 0; i < report_num; i++) { - // TODO: FAR ID for Quota Action IE for indicating the action while no quota is granted - if (triggers[i] == USAR_TRIGGER_START){ - ret = DONT_SEND_UL_PACKET; - } - convert_urr_to_report(urrs[i], &report[i]); - - report[i].trigger = triggers[i]; - } - - if (pdr_addr_is_netlink(pdr)) { - if (netlink_send(pdr, far, skb, dev_net(pdr->dev), report, report_num) < 0) { - GTP5G_ERR(pdr->dev, "Failed to send report to netlink socket PDR(%u)", pdr->id); - ret = -1; - goto err1; - } - } else { - if (unix_sock_send(pdr, far, report, len, report_num) < 0) { - GTP5G_ERR(pdr->dev, "Failed to send report to unix domain socket PDR(%u)", pdr->id); - ret = -1; - goto err1; - } - } - } - -err1: - if (report) { - kfree(report); - } - if (urrs) { - kfree(urrs); - } - if (triggers) { - kfree(triggers); - } - return ret; -} - -static int gtp5g_rx(struct pdr *pdr, struct sk_buff *skb, - unsigned int hdrlen, unsigned int role) -{ - int rt = -1; - u64 volume_mbqe = 0; - struct far *far = rcu_dereference(pdr->far); - // struct qer *qer = rcu_dereference(pdr->qer); - - if (!far) { - GTP5G_ERR(pdr->dev, "FAR not exists for PDR(%u)\n", pdr->id); - goto out; - } - - //TODO: QER - //if (qer) { - // printk_ratelimited("%s:%d QER Rule found, id(%#x) qfi(%#x)\n", __func__, __LINE__, - // qer->id, qer->qfi); - //} - - // TODO: not reading the value of outer_header_removal now, - // just check if it is assigned. - if (pdr->outer_header_removal) { - // One and only one of the DROP, FORW and BUFF flags shall be set to 1. - // The NOCP flag may only be set if the BUFF flag is set. - // The DUPL flag may be set with any of the DROP, FORW, BUFF and NOCP flags. - switch(far->action & FAR_ACTION_MASK) { - case FAR_ACTION_DROP: - rt = gtp5g_drop_skb_encap(skb, pdr->dev, pdr); - break; - case FAR_ACTION_FORW: - rt = gtp5g_fwd_skb_encap(skb, pdr->dev, hdrlen, pdr, far, volume_mbqe); - break; - case FAR_ACTION_BUFF: - rt = gtp5g_buf_skb_encap(skb, pdr->dev, hdrlen, pdr, far); - break; - default: - GTP5G_ERR(pdr->dev, "Unhandled apply action(%u) in FAR(%u) and related to PDR(%u)\n", - far->action, far->id, pdr->id); - } - goto out; - } - - // TODO: this action is not supported - GTP5G_ERR(pdr->dev, "Uplink: PDR(%u) didn't has a OHR information " - "(which routed to the gtp interface and matches a PDR)\n", pdr->id); - -out: - return rt; -} - -static int gtp5g_fwd_skb_encap(struct sk_buff *skb, struct net_device *dev, - unsigned int hdrlen, struct pdr *pdr, struct far *far, uint64_t volume_mbqe) -{ - struct forwarding_parameter *fwd_param = rcu_dereference(far->fwd_param); - struct outer_header_creation *hdr_creation; - struct forwarding_policy *fwd_policy; - struct gtpv1_hdr *gtp1 = (struct gtpv1_hdr *)(skb->data + sizeof(struct udphdr)); - struct iphdr *iph; - struct udphdr *uh; - struct pcpu_sw_netstats *stats; - int ret; - u64 volume = 0; - - if (gtp1->type == GTPV1_MSG_TYPE_TPDU) - volume = ip4_rm_header(skb, hdrlen); - - if (fwd_param) { - if ((fwd_policy = fwd_param->fwd_policy)) - skb->mark = fwd_policy->mark; - - if ((hdr_creation = fwd_param->hdr_creation)) { - // Just modify the teid and packet dest ip - gtp1->tid = hdr_creation->teid; - - skb_push(skb, 20); // L3 Header Length - iph = ip_hdr(skb); - - if (!pdr->pdi->f_teid) { - GTP5G_ERR(dev, "Failed to hdr removal + creation " - "due to pdr->pdi->f_teid not exist\n"); - return -1; - } - - iph->saddr = pdr->pdi->f_teid->gtpu_addr_ipv4.s_addr; - iph->daddr = hdr_creation->peer_addr_ipv4.s_addr; - iph->check = 0; - - uh = udp_hdr(skb); - uh->check = 0; - - if (pdr->urr_num != 0) { - ret = check_urr(pdr, far, volume, volume_mbqe, true); - if (ret < 0) { - if (ret == DONT_SEND_UL_PACKET) { - GTP5G_ERR(pdr->dev, "Should not foward the first uplink packet"); - return -1; - } else { - GTP5G_ERR(pdr->dev, "Fail to send Usage Report"); - } - } - } - - if (ip_xmit(skb, pdr->sk, dev) < 0) { - GTP5G_ERR(dev, "Failed to transmit skb through ip_xmit\n"); - return -1; - } - - return 0; - } - } - - if (gtp1->type != GTPV1_MSG_TYPE_TPDU) { - GTP5G_WAR(dev, "Uplink: GTPv1 msg type is not TPDU\n"); - return -1; - } - - // Get rid of the GTP-U + UDP headers. - if (iptunnel_pull_header(skb, - hdrlen, - skb->protocol, - !net_eq(sock_net(pdr->sk), - dev_net(dev)))) { - GTP5G_ERR(dev, "Failed to pull GTP-U and UDP headers\n"); - return -1; - } - - /* Now that the UDP and the GTP header have been removed, set up the - * new network header. This is required by the upper layer to - * calculate the transport header. - * */ - skb_reset_network_header(skb); - - skb->dev = dev; - - stats = this_cpu_ptr(skb->dev->tstats); - u64_stats_update_begin(&stats->syncp); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) - u64_stats_inc(&stats->rx_packets); - u64_stats_add(&stats->rx_bytes, skb->len); -#else - stats->rx_packets++; - stats->rx_bytes += skb->len; -#endif - u64_stats_update_end(&stats->syncp); - - pdr->ul_pkt_cnt++; - pdr->ul_byte_cnt += skb->len; /* length without GTP header */ - GTP5G_INF(NULL, "PDR (%u) UL_PKT_CNT (%llu) UL_BYTE_CNT (%llu)", pdr->id, pdr->ul_pkt_cnt, pdr->ul_byte_cnt); - - ret = netif_rx(skb); - if (ret != NET_RX_SUCCESS) { - GTP5G_ERR(dev, "Uplink: Packet got dropped\n"); - } - - if (pdr->urr_num != 0) { - if (check_urr(pdr, far, volume, volume_mbqe, true) < 0) - GTP5G_ERR(pdr->dev, "Fail to send Usage Report"); - } - - return 0; -} - -static int gtp5g_drop_skb_ipv4(struct sk_buff *skb, struct net_device *dev, - struct pdr *pdr) -{ - ++pdr->dl_drop_cnt; - GTP5G_INF(NULL, "PDR (%u) DL_DROP_CNT (%llu)", pdr->id, pdr->dl_drop_cnt); - dev_kfree_skb(skb); - return FAR_ACTION_DROP; -} - -static int gtp5g_fwd_skb_ipv4(struct sk_buff *skb, - struct net_device *dev, struct gtp5g_pktinfo *pktinfo, - struct pdr *pdr, struct far *far, uint64_t volume_mbqe) -{ - struct rtable *rt; - struct flowi4 fl4; - struct iphdr *iph = ip_hdr(skb); - struct outer_header_creation *hdr_creation; - u64 volume; - struct forwarding_parameter *fwd_param; - - if (!far) { - GTP5G_ERR(dev, "Unknown RAN address\n"); - goto err; - } - - fwd_param = rcu_dereference(far->fwd_param); - if (!(fwd_param && - fwd_param->hdr_creation)) { - GTP5G_ERR(dev, "Unknown RAN address\n"); - goto err; - } - - hdr_creation = fwd_param->hdr_creation; - rt = ip4_find_route(skb, - iph, - pdr->sk, - dev, - pdr->role_addr_ipv4.s_addr, - hdr_creation->peer_addr_ipv4.s_addr, - &fl4); - if (IS_ERR(rt)) - goto err; - - gtp5g_set_pktinfo_ipv4(pktinfo, - pdr->sk, - iph, - hdr_creation, - pdr->qfi, - rt, - &fl4, - dev); - - pdr->dl_pkt_cnt++; - pdr->dl_byte_cnt += skb->len; - GTP5G_INF(NULL, "PDR (%u) DL_PKT_CNT (%llu) DL_BYTE_CNT (%llu)", pdr->id, pdr->dl_pkt_cnt, pdr->dl_byte_cnt); - - volume = ip4_rm_header(skb, 0); - - gtp5g_push_header(skb, pktinfo); - - if (pdr->urr_num != 0) { - if (check_urr(pdr, far, volume, volume_mbqe, false) < 0) - GTP5G_ERR(pdr->dev, "Fail to send Usage Report"); - } - - return FAR_ACTION_FORW; -err: - return -EBADMSG; -} - -static int gtp5g_buf_skb_ipv4(struct sk_buff *skb, struct net_device *dev, - struct pdr *pdr, struct far *far) -{ - if (pdr_addr_is_netlink(pdr)) { - if (netlink_send(pdr, far, skb, dev_net(dev), NULL, 0) < 0) { - GTP5G_ERR(dev, "Failed to send skb to netlink socket PDR(%u)", pdr->id); - ++pdr->dl_drop_cnt; - } - } else { - // TODO: handle nonlinear part - if (unix_sock_send(pdr, far, skb->data, skb_headlen(skb), 0) < 0) { - GTP5G_ERR(dev, "Failed to send skb to unix domain socket PDR(%u)", pdr->id); - ++pdr->dl_drop_cnt; - } - } - - dev_kfree_skb(skb); - return FAR_ACTION_BUFF; -} - -int gtp5g_handle_skb_ipv4(struct sk_buff *skb, struct net_device *dev, - struct gtp5g_pktinfo *pktinfo) -{ - struct gtp5g_dev *gtp = netdev_priv(dev); - struct pdr *pdr; - struct far *far; - //struct gtp5g_qer *qer; - struct iphdr *iph; - u64 volume_mbqe = 0; - - /* Read the IP destination address and resolve the PDR. - * Prepend PDR header with TEI/TID from PDR. - */ - iph = ip_hdr(skb); - if (gtp->role == GTP5G_ROLE_UPF) - pdr = pdr_find_by_ipv4(gtp, skb, 0, iph->daddr); - else - pdr = pdr_find_by_ipv4(gtp, skb, 0, iph->saddr); - - if (!pdr) { - GTP5G_INF(dev, "no PDR found for %pI4, skip\n", &iph->daddr); - return -ENOENT; - } - - /* TODO: QoS rule have to apply before apply FAR - * */ - //qer = rcu_dereference(pdr->qer); - //if (qer) { - // GTP5G_ERR(dev, "%s:%d QER Rule found, id(%#x) qfi(%#x) TODO\n", - // __func__, __LINE__, qer->id, qer->qfi); - //} - - far = rcu_dereference(pdr->far); - if (far) { - // One and only one of the DROP, FORW and BUFF flags shall be set to 1. - // The NOCP flag may only be set if the BUFF flag is set. - // The DUPL flag may be set with any of the DROP, FORW, BUFF and NOCP flags. - switch (far->action & FAR_ACTION_MASK) { - case FAR_ACTION_DROP: - return gtp5g_drop_skb_ipv4(skb, dev, pdr); - case FAR_ACTION_FORW: - return gtp5g_fwd_skb_ipv4(skb, dev, pktinfo, pdr, far, volume_mbqe); - case FAR_ACTION_BUFF: - return gtp5g_buf_skb_ipv4(skb, dev, pdr, far); - default: - GTP5G_ERR(dev, "Unspec apply action(%u) in FAR(%u) and related to PDR(%u)", - far->action, far->id, pdr->id); - } - } - - return -ENOENT; -} diff --git a/lib/gtp5g/src/gtpu/hash.c b/lib/gtp5g/src/gtpu/hash.c deleted file mode 100644 index e473d8ec..00000000 --- a/lib/gtp5g/src/gtpu/hash.c +++ /dev/null @@ -1,5 +0,0 @@ -#include - -#include "hash.h" - -u32 gtp5g_h_initval; diff --git a/lib/gtp5g/src/gtpu/link.c b/lib/gtp5g/src/gtpu/link.c deleted file mode 100644 index c45ab02f..00000000 --- a/lib/gtp5g/src/gtpu/link.c +++ /dev/null @@ -1,178 +0,0 @@ -#include -#include -#include -#include - -#include "dev.h" -#include "link.h" -#include "net.h" -#include "encap.h" -#include "gtp.h" -#include "log.h" -#include "proc.h" - -const struct nla_policy gtp5g_policy[IFLA_GTP5G_MAX + 1] = { - [IFLA_GTP5G_FD1] = { .type = NLA_U32 }, - [IFLA_GTP5G_PDR_HASHSIZE] = { .type = NLA_U32 }, - [IFLA_GTP5G_ROLE] = { .type = NLA_U32 }, -}; - -static void gtp5g_link_setup(struct net_device *dev) -{ - dev->netdev_ops = >p5g_netdev_ops; - dev->needs_free_netdev = true; - - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->mtu = ETH_DATA_LEN - - (sizeof(struct iphdr) + - sizeof(struct udphdr) + - sizeof(struct gtpv1_hdr)); - - /* Zero header length. */ - dev->type = ARPHRD_NONE; - dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - - dev->priv_flags |= IFF_NO_QUEUE; - dev->features |= NETIF_F_LLTX; - netif_keep_dst(dev); - - /* TODO: Modify the headroom size based on - * what are the extension header going to support - * */ - dev->needed_headroom = LL_MAX_HEADER + - sizeof(struct iphdr) + - sizeof(struct udphdr) + - sizeof(struct gtpv1_hdr); -} - -static int gtp5g_validate(struct nlattr *tb[], struct nlattr *data[], - struct netlink_ext_ack *extack) -{ - if (!data) - return -EINVAL; - - return 0; -} - -static int gtp5g_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[], - struct netlink_ext_ack *extack) -{ - struct gtp5g_dev *gtp; - struct gtp5g_net *gn; - struct sock *sk; - unsigned int role = GTP5G_ROLE_UPF; - u32 fd1; - int hashsize, err; - - gtp = netdev_priv(dev); - - if (!data[IFLA_GTP5G_FD1]) { - GTP5G_ERR(NULL, "Failed to create a new link\n"); - return -EINVAL; - } - fd1 = nla_get_u32(data[IFLA_GTP5G_FD1]); - sk = gtp5g_encap_enable(fd1, UDP_ENCAP_GTP1U, gtp); - if (IS_ERR(sk)) - return PTR_ERR(sk); - gtp->sk1u = sk; - - if (data[IFLA_GTP5G_ROLE]) { - role = nla_get_u32(data[IFLA_GTP5G_ROLE]); - if (role > GTP5G_ROLE_RAN) { - if (sk) - gtp5g_encap_disable(sk); - return -EINVAL; - } - } - gtp->role = role; - - if (!data[IFLA_GTP5G_PDR_HASHSIZE]) - hashsize = 1024; - else - hashsize = nla_get_u32(data[IFLA_GTP5G_PDR_HASHSIZE]); - - err = dev_hashtable_new(gtp, hashsize); - if (err < 0) { - gtp5g_encap_disable(gtp->sk1u); - GTP5G_ERR(dev, "Failed to create a hash table\n"); - goto out_encap; - } - - err = register_netdevice(dev); - if (err < 0) { - netdev_dbg(dev, "failed to register new netdev %d\n", err); - gtp5g_hashtable_free(gtp); - gtp5g_encap_disable(gtp->sk1u); - goto out_hashtable; - } - - gn = net_generic(dev_net(dev), GTP5G_NET_ID()); - list_add_rcu(>p->list, &gn->gtp5g_dev_list); - list_add_rcu(>p->proc_list, get_proc_gtp5g_dev_list_head()); - - GTP5G_LOG(dev, "Registered a new 5G GTP interface\n"); - return 0; -out_hashtable: - gtp5g_hashtable_free(gtp); -out_encap: - gtp5g_encap_disable(gtp->sk1u); - return err; -} - -static void gtp5g_dellink(struct net_device *dev, struct list_head *head) -{ - struct gtp5g_dev *gtp = netdev_priv(dev); - - gtp5g_hashtable_free(gtp); - list_del_rcu(>p->list); - list_del_rcu(>p->proc_list); - unregister_netdevice_queue(dev, head); - - GTP5G_LOG(dev, "De-registered 5G GTP interface\n"); -} - -static size_t gtp5g_get_size(const struct net_device *dev) -{ - /* IFLA_UPF_PDR_HASHSIZE */ - return nla_total_size(sizeof(__u32)); -} - -static int gtp5g_fill_info(struct sk_buff *skb, const struct net_device *dev) -{ - struct gtp5g_dev *gtp = netdev_priv(dev); - - if (nla_put_u32(skb, IFLA_GTP5G_PDR_HASHSIZE, gtp->hash_size)) - goto nla_put_failure; - - return 0; -nla_put_failure: - return -EMSGSIZE; -} - -struct rtnl_link_ops gtp5g_link_ops __read_mostly = { - .kind = "gtp5g", - .maxtype = IFLA_GTP5G_MAX, - .policy = gtp5g_policy, - .priv_size = sizeof(struct gtp5g_dev), - .setup = gtp5g_link_setup, - .validate = gtp5g_validate, - .newlink = gtp5g_newlink, - .dellink = gtp5g_dellink, - .get_size = gtp5g_get_size, - .fill_info = gtp5g_fill_info, -}; - -void gtp5g_link_all_del(struct list_head *dev_list) -{ - struct gtp5g_dev *gtp; - LIST_HEAD(list); - - rtnl_lock(); - list_for_each_entry(gtp, dev_list, list) - gtp5g_dellink(gtp->dev, &list); - - unregister_netdevice_many(&list); - rtnl_unlock(); -} \ No newline at end of file diff --git a/lib/gtp5g/src/gtpu/net.c b/lib/gtp5g/src/gtpu/net.c deleted file mode 100644 index 8ef91372..00000000 --- a/lib/gtp5g/src/gtpu/net.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include - -#include "dev.h" -#include "net.h" -#include "link.h" - -static unsigned int gtp5g_net_id __read_mostly; - -static int __net_init gtp5g_net_init(struct net *net) -{ - struct gtp5g_net *gn = net_generic(net, gtp5g_net_id); - - INIT_LIST_HEAD(&gn->gtp5g_dev_list); - return 0; -} - -static void __net_exit gtp5g_net_exit(struct net *net) -{ - struct gtp5g_net *gn = net_generic(net, gtp5g_net_id); - - gtp5g_link_all_del(&gn->gtp5g_dev_list); -} - -struct pernet_operations gtp5g_net_ops = { - .init = gtp5g_net_init, - .exit = gtp5g_net_exit, - .id = >p5g_net_id, - .size = sizeof(struct gtp5g_net), -}; diff --git a/lib/gtp5g/src/gtpu/pktinfo.c b/lib/gtp5g/src/gtpu/pktinfo.c deleted file mode 100644 index 2cbfd9b5..00000000 --- a/lib/gtp5g/src/gtpu/pktinfo.c +++ /dev/null @@ -1,323 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gtp.h" -#include "far.h" -#include "qer.h" -#include "pktinfo.h" -#include "log.h" - -u64 network_and_transport_header_len(struct sk_buff *skb) { - u64 hdrlen; - struct iphdr *iph; - struct tcphdr *tcp; - - iph = (struct iphdr *)skb->data; - hdrlen = iph->ihl * 4; - - switch (iph->protocol) { - case IPPROTO_TCP: - // tcp = (struct tcphdr *)(skb_transport_header(skb) + (iph->ihl << 2)); - skb->len -= iph->ihl * 4; - skb->data += iph->ihl * 4; - - tcp = (struct tcphdr *)skb->data; - hdrlen += tcp->doff * 4; - break; - case IPPROTO_UDP: - hdrlen += 8; // udp header len = 8B - break; - default: - break; - } - - return hdrlen; -} - -u64 ip4_rm_header(struct sk_buff *skb, unsigned int hdrlen) { - struct sk_buff *skb_copy, tmp; - u64 volume; - - // To make sure cacaluting the len of skb will not move the data & len value - // of the original skb - tmp = *skb; - skb_copy = &tmp; - - volume = skb->len; - if (hdrlen > 0) { - // packets with gtp header - volume -= hdrlen; - skb_copy->len -= hdrlen; - skb_copy->data += hdrlen; - } - - // packets without gtp header - volume -= network_and_transport_header_len(skb_copy); - return volume; -} - -struct rtable *ip4_find_route(struct sk_buff *skb, struct iphdr *iph, - struct sock *sk, struct net_device *gtp_dev, - __be32 saddr, __be32 daddr, struct flowi4 *fl4) -{ - struct rtable *rt; - __be16 df; - int mtu; - - memset(fl4, 0, sizeof(*fl4)); - fl4->flowi4_oif = sk->sk_bound_dev_if; - fl4->daddr = daddr; - fl4->saddr = (saddr ? saddr : inet_sk(sk)->inet_saddr); - fl4->flowi4_tos = RT_CONN_FLAGS(sk); - fl4->flowi4_proto = sk->sk_protocol; - - rt = ip_route_output_key(dev_net(gtp_dev), fl4); - if (IS_ERR(rt)) { - GTP5G_ERR(gtp_dev, "no route to %pI4\n", &iph->daddr); - gtp_dev->stats.tx_carrier_errors++; - goto err; - } - - if (rt->dst.dev == gtp_dev) { - GTP5G_ERR(gtp_dev, "circular route to %pI4\n", &iph->daddr); - gtp_dev->stats.collisions++; - goto err_rt; - } - - skb_dst_drop(skb); - - /* This is similar to tnl_update_pmtu(). */ - df = iph->frag_off; - if (df) { - mtu = dst_mtu(&rt->dst) - gtp_dev->hard_header_len - - sizeof(struct iphdr) - sizeof(struct udphdr); - // GTPv1 - mtu -= sizeof(struct gtpv1_hdr); - } - else { - mtu = dst_mtu(&rt->dst); - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 8) || defined(RHEL8) - rt->dst.ops->update_pmtu(&rt->dst, NULL, skb, mtu, false); -#else - rt->dst.ops->update_pmtu(&rt->dst, NULL, skb, mtu); -#endif - - if (!skb_is_gso(skb) && (iph->frag_off & htons(IP_DF)) && - mtu < ntohs(iph->tot_len)) { - GTP5G_ERR(gtp_dev, "packet too big, fragmentation needed\n"); - memset(IPCB(skb), 0, sizeof(*IPCB(skb))); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, - htonl(mtu)); - goto err_rt; - } - - return rt; -err_rt: - ip_rt_put(rt); -err: - return ERR_PTR(-ENOENT); -} - -struct rtable *ip4_find_route_simple(struct sk_buff *skb, - struct sock *sk, struct net_device *gtp_dev, - __be32 saddr, __be32 daddr, struct flowi4 *fl4) -{ - struct rtable *rt; - - memset(fl4, 0, sizeof(*fl4)); - fl4->flowi4_oif = sk->sk_bound_dev_if; - fl4->daddr = daddr; - fl4->saddr = (saddr ? saddr : inet_sk(sk)->inet_saddr); - fl4->flowi4_tos = RT_CONN_FLAGS(sk); - fl4->flowi4_proto = sk->sk_protocol; - - rt = ip_route_output_key(dev_net(gtp_dev), fl4); - if (IS_ERR(rt)) { - GTP5G_ERR(gtp_dev, "no route from %#x to %#x\n", saddr, daddr); - gtp_dev->stats.tx_carrier_errors++; - goto err; - } - - if (rt->dst.dev == gtp_dev) { - GTP5G_ERR(gtp_dev, "Packet colllisions from %#x to %#x\n", - saddr, daddr); - gtp_dev->stats.collisions++; - goto err_rt; - } - - skb_dst_drop(skb); - - return rt; - -err_rt: - ip_rt_put(rt); -err: - return ERR_PTR(-ENOENT); -} - -int ip_xmit(struct sk_buff *skb, struct sock *sk, struct net_device *gtp_dev) -{ - struct iphdr *iph = ip_hdr(skb); - struct flowi4 fl4; - struct rtable *rt; - __be32 src; - - rt = ip4_find_route_simple(skb, sk, gtp_dev, 0, iph->daddr, &fl4); - if (IS_ERR(rt)) { - GTP5G_ERR(gtp_dev, "Failed to find route\n"); - return -EBADMSG; - } - - skb_dst_set(skb, &rt->dst); - /* - fill in correct source address of the outgoing interface. - Support multiple IP address configured on outgoing interface. - */ - src = inet_select_addr(rt->dst.dev, - rt_nexthop(rt, iph->daddr), - RT_SCOPE_UNIVERSE); - if (src != 0) { - iph->saddr = src; - } - - if (ip_local_out(dev_net(gtp_dev), sk, skb) < 0) { - GTP5G_ERR(gtp_dev, "Failed to send skb to ip layer\n"); - return -1; - } - return 0; -} - -void gtp5g_fwd_emark_skb_ipv4(struct sk_buff *skb, - struct net_device *dev, struct gtp5g_emark_pktinfo *epkt_info) -{ - struct rtable *rt; - struct flowi4 fl4; - struct gtpv1_hdr *gtp1; - - /* Reset all headers */ - skb_reset_transport_header(skb); - skb_reset_network_header(skb); - skb_reset_mac_header(skb); - - /* Fill GTP-U Header */ - gtp1 = skb_push(skb, sizeof(*gtp1)); - gtp1->flags = GTPV1; /* v1, GTP-non-prime. */ - gtp1->type = GTPV1_MSG_TYPE_EMARK; - gtp1->tid = epkt_info->teid; - - rt = ip4_find_route_simple(skb, epkt_info->sk, dev, - epkt_info->role_addr /* Src Addr */ , - epkt_info->peer_addr /* Dst Addr*/, - &fl4); - if (IS_ERR(rt)) { - GTP5G_ERR(dev, "Failed to send GTP-U end-marker due to routing\n"); - dev_kfree_skb(skb); - return; - } - - udp_tunnel_xmit_skb(rt, - epkt_info->sk, - skb, - fl4.saddr, - fl4.daddr, - 0, - ip4_dst_hoplimit(&rt->dst), - 0, - epkt_info->gtph_port, - epkt_info->gtph_port, - true, - true); -} - -void gtp5g_xmit_skb_ipv4(struct sk_buff *skb, struct gtp5g_pktinfo *pktinfo) -{ - udp_tunnel_xmit_skb(pktinfo->rt, - pktinfo->sk, - skb, - pktinfo->fl4.saddr, - pktinfo->fl4.daddr, - pktinfo->iph->tos, - ip4_dst_hoplimit(&pktinfo->rt->dst), - 0, - pktinfo->gtph_port, - pktinfo->gtph_port, - true, - true); -} - -inline void gtp5g_set_pktinfo_ipv4(struct gtp5g_pktinfo *pktinfo, - struct sock *sk, struct iphdr *iph, struct outer_header_creation *hdr_creation, - u8 qfi, struct rtable *rt, struct flowi4 *fl4, - struct net_device *dev) -{ - pktinfo->sk = sk; - pktinfo->iph = iph; - pktinfo->hdr_creation = hdr_creation; - pktinfo->qfi = qfi; - pktinfo->rt = rt; - pktinfo->fl4 = *fl4; - pktinfo->dev = dev; -} - -void gtp5g_push_header(struct sk_buff *skb, struct gtp5g_pktinfo *pktinfo) -{ - int payload_len = skb->len; - struct gtpv1_hdr *gtp1; - gtpv1_hdr_opt_t *gtp1opt; - ext_pdu_sess_ctr_t *dl_pdu_sess; - int ext_flag = 0; - - GTP5G_TRC(NULL, "SKBLen(%u) GTP-U V1(%zu) Opt(%zu) DL_PDU(%zu)\n", - payload_len, sizeof(*gtp1), sizeof(*gtp1opt), sizeof(*dl_pdu_sess)); - - pktinfo->gtph_port = pktinfo->hdr_creation->port; - - /* Suppport for extension header, sequence number and N-PDU. - * Update the length field if any of them is available. - */ - if (pktinfo->qfi > 0) { - ext_flag = 1; - - /* Push PDU Session container information */ - dl_pdu_sess = skb_push(skb, sizeof(*dl_pdu_sess)); - /* Multiple of 4 (TODO include PPI) */ - dl_pdu_sess->length = 1; - dl_pdu_sess->pdu_sess_ctr.type_spare = 0; /* For DL */ - dl_pdu_sess->pdu_sess_ctr.u.dl.ppp_rqi_qfi = pktinfo->qfi; - //TODO: PPI - dl_pdu_sess->next_ehdr_type = 0; /* No more extension Header */ - - /* Push optional header information */ - gtp1opt = skb_push(skb, sizeof(*gtp1opt)); - gtp1opt->seq_number = 0; - gtp1opt->NPDU = 0; - gtp1opt->next_ehdr_type = 0x85; /* PDU Session Container */ - // Increment the GTP-U payload length by size of optional headers length - payload_len += (sizeof(*gtp1opt) + sizeof(*dl_pdu_sess)); - } - - /* Bits 8 7 6 5 4 3 2 1 - * +--+--+--+--+--+--+--+--+ - * |version |PT| 0| E| S|PN| - * +--+--+--+--+--+--+--+--+ - * 0 0 1 1 0 0 0 0 - */ - gtp1 = skb_push(skb, sizeof(*gtp1)); - gtp1->flags = GTPV1; /* v1, GTP-non-prime. */ - if (ext_flag) - gtp1->flags |= GTPV1_HDR_FLG_EXTHDR; /* v1, Extension header enabled */ - gtp1->type = GTPV1_MSG_TYPE_TPDU; - gtp1->tid = pktinfo->hdr_creation->teid; - gtp1->length = htons(payload_len); /* Excluded the header length of gtpv1 */ - - GTP5G_TRC(NULL, "QER Found GTP-U Flg(%u) GTPU-L(%u) SkbLen(%u)\n", - gtp1->flags, ntohs(gtp1->length), skb->len); -} diff --git a/lib/gtp5g/src/log.c b/lib/gtp5g/src/log.c deleted file mode 100644 index dcd520f2..00000000 --- a/lib/gtp5g/src/log.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "log.h" - -int dbg_trace_lvl = 1; - -int get_dbg_lvl(){ - return dbg_trace_lvl; -} - -void set_dbg_lvl(int val){ - dbg_trace_lvl = val; -} \ No newline at end of file diff --git a/lib/gtp5g/src/pfcp/api_version.c b/lib/gtp5g/src/pfcp/api_version.c deleted file mode 100644 index 2c36745d..00000000 --- a/lib/gtp5g/src/pfcp/api_version.c +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include "api_version.h" - -bool api_far_action_u16 = false; - -void set_far_action_u16(bool val){ - api_far_action_u16 = val; -} - -bool far_action_is_u16(){ - return api_far_action_u16; -} \ No newline at end of file diff --git a/lib/gtp5g/src/pfcp/bar.c b/lib/gtp5g/src/pfcp/bar.c deleted file mode 100644 index d87b5847..00000000 --- a/lib/gtp5g/src/pfcp/bar.c +++ /dev/null @@ -1,119 +0,0 @@ -#include - -#include "dev.h" -#include "bar.h" -#include "far.h" -#include "seid.h" -#include "hash.h" - -static void seid_bar_id_to_hex_str(u64 seid_int, u32 bar_id, char *buff) -{ - seid_and_u32id_to_hex_str(seid_int, bar_id, buff); -} - -static void bar_context_free(struct rcu_head *head) -{ - struct bar *bar = container_of(head, struct bar, rcu_head); - - if (!bar) - return; - - kfree(bar); -} - -void bar_context_delete(struct bar *bar) -{ - struct gtp5g_dev *gtp = netdev_priv(bar->dev); - struct hlist_head *head; - struct far *far; - char seid_bar_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - if (!bar) - return; - - if (!hlist_unhashed(&bar->hlist_id)) - hlist_del_rcu(&bar->hlist_id); - - seid_bar_id_to_hex_str(bar->seid, bar->id, seid_bar_id_hexstr); - head = >p->related_bar_hash[str_hashfn(seid_bar_id_hexstr) % gtp->hash_size]; - hlist_for_each_entry_rcu(far, head, hlist_related_bar) { - if (*far->bar_id == bar->id) { - far->bar = NULL; - } - } - - call_rcu(&bar->rcu_head, bar_context_free); -} - -struct bar *find_bar_by_id(struct gtp5g_dev *gtp, u64 seid, u32 bar_id) -{ - struct hlist_head *head; - struct bar *bar; - char seid_bar_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_bar_id_to_hex_str(seid, bar_id, seid_bar_id_hexstr); - head = >p->bar_id_hash[str_hashfn(seid_bar_id_hexstr) % gtp->hash_size]; - hlist_for_each_entry_rcu(bar, head, hlist_id) { - if (bar->seid == seid && bar->id == bar_id) - return bar; - } - - return NULL; -} - -void bar_update(struct bar *bar, struct gtp5g_dev *gtp) -{ - struct far *far; - struct hlist_head *head; - char seid_bar_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_bar_id_to_hex_str(bar->seid, bar->id, seid_bar_id_hexstr); - head = >p->related_bar_hash[str_hashfn(seid_bar_id_hexstr) % gtp->hash_size]; - hlist_for_each_entry_rcu(far, head, hlist_related_bar) { - if (*far->bar_id == bar->id) { - far->bar = bar; - } - } -} - -void bar_append(u64 seid, u32 bar_id, struct bar *bar, struct gtp5g_dev *gtp) -{ - char seid_bar_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - u32 i; - - seid_bar_id_to_hex_str(seid, bar_id, seid_bar_id_hexstr); - i = str_hashfn(seid_bar_id_hexstr) % gtp->hash_size; - hlist_add_head_rcu(&bar->hlist_id, >p->bar_id_hash[i]); -} - -int bar_get_far_ids(u32 *ids, int n, struct bar *bar, struct gtp5g_dev *gtp) -{ - struct hlist_head *head; - struct far *far; - char seid_bar_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - int i; - - seid_bar_id_to_hex_str(bar->seid, bar->id, seid_bar_id_hexstr); - head = >p->related_bar_hash[str_hashfn(seid_bar_id_hexstr) % gtp->hash_size]; - i = 0; - hlist_for_each_entry_rcu(far, head, hlist_related_bar) { - if (i >= n) - break; - if (*far->bar_id == bar->id) - ids[i++] = far->id; - } - return i; -} - -void bar_set_far(u64 seid, u32 bar_id, struct hlist_node *node, struct gtp5g_dev *gtp) -{ - char seid_bar_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - u32 i; - - if (!hlist_unhashed(node)) - hlist_del_rcu(node); - - seid_bar_id_to_hex_str(seid, bar_id, seid_bar_id_hexstr); - i = str_hashfn(seid_bar_id_hexstr) % gtp->hash_size; - hlist_add_head_rcu(node, >p->related_bar_hash[i]); -} diff --git a/lib/gtp5g/src/pfcp/far.c b/lib/gtp5g/src/pfcp/far.c deleted file mode 100644 index 3f628300..00000000 --- a/lib/gtp5g/src/pfcp/far.c +++ /dev/null @@ -1,172 +0,0 @@ -#include "dev.h" -#include "far.h" -#include "pdr.h" -#include "seid.h" -#include "hash.h" - -static void seid_far_id_to_hex_str(u64 seid_int, u32 far_id, char *buff) -{ - seid_and_u32id_to_hex_str(seid_int, far_id, buff); -} - -static void far_context_free(struct rcu_head *head) -{ - struct far *far = container_of(head, struct far, rcu_head); - struct forwarding_parameter *fwd_param; - - if (!far) - return; - - fwd_param = rcu_dereference(far->fwd_param); - if (fwd_param) { - if (fwd_param->hdr_creation) - kfree(fwd_param->hdr_creation); - if (fwd_param->fwd_policy) - kfree(fwd_param->fwd_policy); - kfree(fwd_param); - } - - kfree(far); -} - -void far_context_delete(struct far *far) -{ - struct gtp5g_dev *gtp = netdev_priv(far->dev); - struct hlist_head *head; - struct pdr_node *pdr_node; - - char seid_far_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0};; - - if (!far) - return; - - if (!hlist_unhashed(&far->hlist_id)) - hlist_del_rcu(&far->hlist_id); - - seid_far_id_to_hex_str(far->seid, far->id, seid_far_id_hexstr); - head = >p->related_far_hash[str_hashfn(seid_far_id_hexstr) % gtp->hash_size]; - hlist_for_each_entry_rcu(pdr_node, head, hlist) { - if (pdr_node->pdr->seid == far->seid && - *pdr_node->pdr->far_id == far->id) { - rcu_assign_pointer(pdr_node->pdr->far, NULL); - unix_sock_client_delete(pdr_node->pdr); - } - } - - call_rcu(&far->rcu_head, far_context_free); -} - -struct far *find_far_by_id(struct gtp5g_dev *gtp, u64 seid, u32 far_id) -{ - struct hlist_head *head; - struct far *far; - char seid_far_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_far_id_to_hex_str(seid, far_id, seid_far_id_hexstr); - head = >p->far_id_hash[str_hashfn(seid_far_id_hexstr) % gtp->hash_size]; - hlist_for_each_entry_rcu(far, head, hlist_id) { - if (far->seid == seid && far->id == far_id) - return far; - } - - return NULL; -} - -void far_update(struct far *far, struct gtp5g_dev *gtp, u8 *flag, - struct gtp5g_emark_pktinfo *epkt_info) -{ - struct pdr_node *pdr_node; - struct hlist_head *head; - char seid_far_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_far_id_to_hex_str(far->seid, far->id, seid_far_id_hexstr); - head = >p->related_far_hash[str_hashfn(seid_far_id_hexstr) % gtp->hash_size]; - hlist_for_each_entry_rcu(pdr_node, head, hlist) { - if (pdr_node->pdr->seid == far->seid && - *pdr_node->pdr->far_id == far->id) { - if (flag != NULL && *flag == 1) { - epkt_info->role_addr = pdr_node->pdr->role_addr_ipv4.s_addr; - epkt_info->sk = pdr_node->pdr->sk; - } - rcu_assign_pointer(pdr_node->pdr->far, far); - unix_sock_client_update(pdr_node->pdr, far); - } - } -} - -void far_append(u64 seid, u32 far_id, struct far *far, struct gtp5g_dev *gtp) -{ - char seid_far_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - u32 i; - - seid_far_id_to_hex_str(seid, far_id, seid_far_id_hexstr); - i = str_hashfn(seid_far_id_hexstr) % gtp->hash_size; - hlist_add_head_rcu(&far->hlist_id, >p->far_id_hash[i]); -} - -int far_get_pdr_ids(u16 *ids, int n, struct far *far, struct gtp5g_dev *gtp) -{ - struct hlist_head *head; - struct pdr_node *pdr_node; - char seid_far_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - int i; - - seid_far_id_to_hex_str(far->seid, far->id, seid_far_id_hexstr); - head = >p->related_far_hash[str_hashfn(seid_far_id_hexstr) % gtp->hash_size]; - i = 0; - hlist_for_each_entry_rcu(pdr_node, head, hlist) { - if (i >= n) - break; - if (pdr_node->pdr->seid == far->seid && - *pdr_node->pdr->far_id == far->id) - ids[i++] = pdr_node->pdr->id; - } - return i; -} - -void del_related_far_hash(struct gtp5g_dev *gtp, struct pdr *pdr) -{ - u32 i; - struct pdr_node *pdr_node = NULL ; - struct pdr_node *to_be_del = NULL ; - char seid_far_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_far_id_to_hex_str(pdr->seid, *pdr->far_id, seid_far_id_hexstr); - i = str_hashfn(seid_far_id_hexstr) % gtp->hash_size; - hlist_for_each_entry_rcu(pdr_node, >p->related_far_hash[i], hlist) { - if (pdr_node->pdr != NULL && - pdr_node->pdr->seid == pdr->seid && - pdr_node->pdr->id == pdr->id) { - to_be_del = pdr_node; - break; - } - } - if (to_be_del){ - hlist_del(&to_be_del->hlist); - kfree(to_be_del); - } -} - -int far_set_pdr(struct pdr *pdr, struct gtp5g_dev *gtp) -{ - char seid_far_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - struct pdr_node *pdr_node = NULL; - u32 i; - - if (!pdr) - return -1; - - del_related_far_hash(gtp, pdr); - - seid_far_id_to_hex_str(pdr->seid, *pdr->far_id, seid_far_id_hexstr); - i = str_hashfn(seid_far_id_hexstr) % gtp->hash_size; - - pdr_node = kzalloc(sizeof(*pdr_node), GFP_ATOMIC); - if (!pdr_node) { - return -ENOMEM; - } - pdr_node->pdr = pdr; - hlist_add_head_rcu(&pdr_node->hlist, >p->related_far_hash[i]); - - return 0; -} diff --git a/lib/gtp5g/src/pfcp/pdr.c b/lib/gtp5g/src/pfcp/pdr.c deleted file mode 100644 index 98f513bb..00000000 --- a/lib/gtp5g/src/pfcp/pdr.c +++ /dev/null @@ -1,394 +0,0 @@ -#include - -#include "dev.h" -#include "link.h" -#include "pdr.h" -#include "far.h" -#include "gtp.h" -#include "genl_pdr.h" -#include "genl_far.h" -#include "seid.h" -#include "hash.h" -#include "genl.h" -#include "log.h" -#include - - -static void seid_pdr_id_to_hex_str(u64 seid_int, u16 pdr_id, char *buff) -{ - seid_and_u32id_to_hex_str(seid_int, (u32)(pdr_id), buff); -} - -static void pdr_context_free(struct rcu_head *head) -{ - struct pdr *pdr = container_of(head, struct pdr, rcu_head); - struct pdi *pdi; - struct sdf_filter *sdf; - - if (!pdr) - return; - - sock_put(pdr->sk); - - if (pdr->outer_header_removal) - kfree(pdr->outer_header_removal); - - pdi = pdr->pdi; - if (pdi) { - if (pdi->ue_addr_ipv4) - kfree(pdi->ue_addr_ipv4); - if (pdi->f_teid) - kfree(pdi->f_teid); - if (pdr->far_id) - kfree(pdr->far_id); - if (pdr->qer_ids) - kfree(pdr->qer_ids); - if (pdr->urr_ids) - kfree(pdr->urr_ids); - - sdf = pdi->sdf; - if (sdf) { - if (sdf->rule) { - if (sdf->rule->sport) - kfree(sdf->rule->sport); - if (sdf->rule->dport) - kfree(sdf->rule->dport); - kfree(sdf->rule); - } - if (sdf->tos_traffic_class) - kfree(sdf->tos_traffic_class); - if (sdf->security_param_idx) - kfree(sdf->security_param_idx); - if (sdf->flow_label) - kfree(sdf->flow_label); - if (sdf->bi_id) - kfree(sdf->bi_id); - - kfree(sdf); - } - kfree(pdi); - } - - unix_sock_client_delete(pdr); - kfree(pdr); -} - -void pdr_context_delete(struct pdr *pdr) -{ - if (!pdr) - return; - - if (!hlist_unhashed(&pdr->hlist_id)) - hlist_del_rcu(&pdr->hlist_id); - - if (!hlist_unhashed(&pdr->hlist_i_teid)) - hlist_del_rcu(&pdr->hlist_i_teid); - - if (!hlist_unhashed(&pdr->hlist_addr)) - hlist_del_rcu(&pdr->hlist_addr); - - call_rcu(&pdr->rcu_head, pdr_context_free); -} - -// Delete the AF_UNIX client -void unix_sock_client_delete(struct pdr *pdr) -{ - if (!pdr || pdr_addr_is_netlink(pdr)) - return; - - if (pdr->sock_for_buf) - sock_release(pdr->sock_for_buf); - - pdr->sock_for_buf = NULL; -} - -// Create a AF_UNIX client by specific name sent from user space -int unix_sock_client_new(struct pdr *pdr) -{ - struct socket **psock = &pdr->sock_for_buf; - struct sockaddr_un *addr = &pdr->addr_unix; - int err; - - if (strlen(addr->sun_path) == 0) { - return -EINVAL; - } - - if (pdr_addr_is_netlink(pdr)) { - return 0; - } - - err = sock_create(AF_UNIX, SOCK_DGRAM, 0, psock); - if (err) { - return err; - } - - err = (*psock)->ops->connect(*psock, (struct sockaddr *)addr, - sizeof(addr->sun_family) + strlen(addr->sun_path), 0); - if (err) { - unix_sock_client_delete(pdr); - return err; - } - - return 0; -} - -// Handle PDR/FAR changed and affect buffering -int unix_sock_client_update(struct pdr *pdr, struct far *far) -{ - if (!pdr || pdr_addr_is_netlink(pdr)) - return 0; - - unix_sock_client_delete(pdr); - - if ((far && (far->action & FAR_ACTION_BUFF)) || pdr->urr_num > 0) - return unix_sock_client_new(pdr); - - return 0; -} - -struct pdr *find_pdr_by_id(struct gtp5g_dev *gtp, u64 seid, u16 pdr_id) -{ - struct hlist_head *head; - struct pdr *pdr; - char seid_pdr_id[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_pdr_id_to_hex_str(seid, pdr_id, seid_pdr_id); - head = >p->pdr_id_hash[str_hashfn(seid_pdr_id) % gtp->hash_size]; - hlist_for_each_entry_rcu(pdr, head, hlist_id) { - if (pdr->seid == seid && pdr->id == pdr_id) - return pdr; - } - - return NULL; -} - -static int ipv4_match(__be32 target_addr, __be32 ifa_addr, __be32 ifa_mask) -{ - return !((target_addr ^ ifa_addr) & ifa_mask); -} - -static bool ports_match(struct range *match_list, int list_len, __be16 port) -{ - int i; - - if (!list_len) - return true; - - for (i = 0; i < list_len; i++) { - if (match_list[i].start <= port && match_list[i].end >= port) - return true; - } - return false; -} - -static int sdf_filter_match(struct sdf_filter *sdf, struct sk_buff *skb, - unsigned int hdrlen, u8 direction) -{ - #define IP_PROTO_RESERVED 0xff - struct iphdr *iph; - struct ip_filter_rule *rule; - const __be16 *pptr; - __be16 _ports[2]; - - if (!sdf) - return 1; - - if (!pskb_may_pull(skb, hdrlen + sizeof(struct iphdr))) - goto mismatch; - - iph = (struct iphdr *)(skb->data + hdrlen); - - if (sdf->rule) { - rule = sdf->rule; - if (rule->direction != direction) - goto mismatch; - - if (rule->proto != IP_PROTO_RESERVED && rule->proto != iph->protocol) - goto mismatch; - - if (!ipv4_match(iph->saddr, rule->src.s_addr, rule->smask.s_addr)) - goto mismatch; - - if (!ipv4_match(iph->daddr, rule->dest.s_addr, rule->dmask.s_addr)) - goto mismatch; - - if (rule->sport_num + rule->dport_num > 0) { - if (!(pptr = skb_header_pointer(skb, hdrlen + sizeof(struct iphdr), sizeof(_ports), _ports))) - goto mismatch; - - if (!ports_match(rule->sport, rule->sport_num, ntohs(pptr[0]))) - goto mismatch; - - if (!ports_match(rule->dport, rule->dport_num, ntohs(pptr[1]))) - goto mismatch; - } - } - -/* - if (sdf->tos_traffic_class) - GTP5G_ERR(NULL, "TODO: SDF's ToS traffic class\n"); - - if (sdf->security_param_idx) - GTP5G_ERR(NULL, "TODO: SDF's Security parameter index\n"); - - if (sdf->flow_label) - GTP5G_ERR(NULL, "TODO: SDF's Flow label\n"); - - if (sdf->bi_id) - GTP5G_ERR(NULL, "TODO: SDF's SDF filter id\n"); -*/ - - return 1; -mismatch: - return 0; -} - -struct pdr *pdr_find_by_gtp1u(struct gtp5g_dev *gtp, struct sk_buff *skb, - unsigned int hdrlen, u32 teid, u8 type) -{ -#ifdef MATCH_IP - struct iphdr *outer_iph; -#endif - struct iphdr *iph; - __be32 *target_addr = NULL; - struct hlist_head *head; - struct pdr *pdr; - struct pdi *pdi; - - if (!gtp) - return NULL; - - if (ntohs(skb->protocol) != ETH_P_IP) - return NULL; - - if (type == GTPV1_MSG_TYPE_TPDU) { - if (!pskb_may_pull(skb, hdrlen + sizeof(struct iphdr))) - return NULL; - iph = (struct iphdr *)(skb->data + hdrlen); - target_addr = (gtp->role == GTP5G_ROLE_UPF ? &iph->saddr : &iph->daddr); - } - - head = >p->i_teid_hash[u32_hashfn(teid) % gtp->hash_size]; - hlist_for_each_entry_rcu(pdr, head, hlist_i_teid) { - pdi = pdr->pdi; - if (!pdi) - continue; - - // GTP-U packet must check teid - if (!(pdi->f_teid && pdi->f_teid->teid == teid)) - continue; - - if (type != GTPV1_MSG_TYPE_TPDU) - return pdr; - - // check outer IP dest addr to distinguish between N3 and N9 packet whil e act as i-upf -#ifdef MATCH_IP - #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) - outer_iph = (struct iphdr *)(skb->head + skb->network_header); - if (!(pdi->f_teid && pdi->f_teid->gtpu_addr_ipv4.s_addr == outer_iph->daddr)) - continue; - #else - outer_iph = (struct iphdr *)(skb->network_header); - if (!(pdi->f_teid && pdi->f_teid->gtpu_addr_ipv4.s_addr == outer_iph->daddr)) - continue; - #endif -#endif - if (pdi->ue_addr_ipv4) - if (!(pdr->af == AF_INET && target_addr && *target_addr == pdi->ue_addr_ipv4->s_addr)) - continue; - - if (pdi->sdf) - if (!sdf_filter_match(pdi->sdf, skb, hdrlen, GTP5G_SDF_FILTER_OUT)) - continue; - - GTP5G_INF(NULL, "Match PDR ID:%d\n", pdr->id); - - return pdr; - } - - return NULL; -} - -struct pdr *pdr_find_by_ipv4(struct gtp5g_dev *gtp, struct sk_buff *skb, - unsigned int hdrlen, __be32 addr) -{ - struct hlist_head *head; - struct pdr *pdr; - struct pdi *pdi; - - head = >p->addr_hash[ipv4_hashfn(addr) % gtp->hash_size]; - - hlist_for_each_entry_rcu(pdr, head, hlist_addr) { - pdi = pdr->pdi; - - // TODO: Move the value we check into first level - if (!(pdr->af == AF_INET && pdi->ue_addr_ipv4->s_addr == addr)) - continue; - - if (pdi->sdf) - if (!sdf_filter_match(pdi->sdf, skb, hdrlen, GTP5G_SDF_FILTER_OUT)) - continue; - - return pdr; - } - - return NULL; -} - -void pdr_append(u64 seid, u16 pdr_id, struct pdr *pdr, struct gtp5g_dev *gtp) -{ - u32 i; - char seid_pdr_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_pdr_id_to_hex_str(seid, pdr_id, seid_pdr_id_hexstr); - i = str_hashfn(seid_pdr_id_hexstr) % gtp->hash_size; - hlist_add_head_rcu(&pdr->hlist_id, >p->pdr_id_hash[i]); -} - -void pdr_update_hlist_table(struct pdr *pdr, struct gtp5g_dev *gtp) -{ - struct hlist_head *head; - struct pdr *ppdr; - struct pdr *last_ppdr; - struct pdi *pdi; - struct local_f_teid *f_teid; - - if (!hlist_unhashed(&pdr->hlist_i_teid)) - hlist_del_rcu(&pdr->hlist_i_teid); - - if (!hlist_unhashed(&pdr->hlist_addr)) - hlist_del_rcu(&pdr->hlist_addr); - - pdi = pdr->pdi; - if (!pdi) - return; - - f_teid = pdi->f_teid; - if (f_teid) { - last_ppdr = NULL; - head = >p->i_teid_hash[u32_hashfn(f_teid->teid) % gtp->hash_size]; - hlist_for_each_entry_rcu(ppdr, head, hlist_i_teid) { - if (pdr->precedence > ppdr->precedence) - last_ppdr = ppdr; - else - break; - } - if (!last_ppdr) - hlist_add_head_rcu(&pdr->hlist_i_teid, head); - else - hlist_add_behind_rcu(&pdr->hlist_i_teid, &last_ppdr->hlist_i_teid); - } else if (pdi->ue_addr_ipv4) { - last_ppdr = NULL; - head = >p->addr_hash[u32_hashfn(pdi->ue_addr_ipv4->s_addr) % gtp->hash_size]; - hlist_for_each_entry_rcu(ppdr, head, hlist_addr) { - if (pdr->precedence > ppdr->precedence) - last_ppdr = ppdr; - else - break; - } - if (!last_ppdr) - hlist_add_head_rcu(&pdr->hlist_addr, head); - else - hlist_add_behind_rcu(&pdr->hlist_addr, &last_ppdr->hlist_addr); - } -} diff --git a/lib/gtp5g/src/pfcp/qer.c b/lib/gtp5g/src/pfcp/qer.c deleted file mode 100644 index 809ee23f..00000000 --- a/lib/gtp5g/src/pfcp/qer.c +++ /dev/null @@ -1,161 +0,0 @@ -#include - -#include "dev.h" -#include "qer.h" -#include "pdr.h" -#include "far.h" -#include "seid.h" -#include "hash.h" - -static void seid_qer_id_to_hex_str(u64 seid_int, u32 qer_id, char *buff) -{ - seid_and_u32id_to_hex_str(seid_int, qer_id, buff); -} - -static void qer_context_free(struct rcu_head *head) -{ - struct qer *qer = container_of(head, struct qer, rcu_head); - - if (!qer) - return; - - kfree(qer); -} - -void qer_context_delete(struct qer *qer) -{ - struct gtp5g_dev *gtp = netdev_priv(qer->dev); - struct hlist_head *head; - struct pdr_node *pdr_node; - char seid_qer_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - if (!qer) - return; - - if (!hlist_unhashed(&qer->hlist_id)) - hlist_del_rcu(&qer->hlist_id); - - seid_qer_id_to_hex_str(qer->seid, qer->id, seid_qer_id_hexstr); - head = >p->related_qer_hash[str_hashfn(seid_qer_id_hexstr) % gtp->hash_size]; - hlist_for_each_entry_rcu(pdr_node, head, hlist) { - if (pdr_node->pdr != NULL && - find_qer_id_in_pdr(pdr_node->pdr, qer->id)) { - unix_sock_client_delete(pdr_node->pdr); - } - } - - call_rcu(&qer->rcu_head, qer_context_free); -} - -struct qer *find_qer_by_id(struct gtp5g_dev *gtp, u64 seid, u32 qer_id) -{ - struct hlist_head *head; - struct qer *qer; - char seid_qer_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_qer_id_to_hex_str(seid, qer_id, seid_qer_id_hexstr); - head = >p->qer_id_hash[str_hashfn(seid_qer_id_hexstr) % gtp->hash_size]; - hlist_for_each_entry_rcu(qer, head, hlist_id) { - if (qer->seid == seid && qer->id == qer_id) - return qer; - } - - return NULL; -} - -void qer_update(struct qer *qer, struct gtp5g_dev *gtp) -{ - struct pdr_node *pdr_node; - struct hlist_head *head; - char seid_qer_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_qer_id_to_hex_str(qer->seid, qer->id, seid_qer_id_hexstr); - head = >p->related_qer_hash[str_hashfn(seid_qer_id_hexstr) % gtp->hash_size]; - hlist_for_each_entry_rcu(pdr_node, head, hlist) { - if (pdr_node->pdr != NULL && find_qer_id_in_pdr(pdr_node->pdr, qer->id)) { - unix_sock_client_update(pdr_node->pdr, rcu_dereference(pdr_node->pdr->far)); - } - } -} - -void qer_append(u64 seid, u32 qer_id, struct qer *qer, struct gtp5g_dev *gtp) -{ - u32 i; - char seid_qer_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_qer_id_to_hex_str(seid, qer_id, seid_qer_id_hexstr); - i = str_hashfn(seid_qer_id_hexstr) % gtp->hash_size; - hlist_add_head_rcu(&qer->hlist_id, >p->qer_id_hash[i]); -} - -int qer_get_pdr_ids(u16 *ids, int n, struct qer *qer, struct gtp5g_dev *gtp) -{ - struct hlist_head *head; - struct pdr_node *pdr_node; - int i; - char seid_qer_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_qer_id_to_hex_str(qer->seid, qer->id, seid_qer_id_hexstr); - head = >p->related_qer_hash[str_hashfn(seid_qer_id_hexstr) % gtp->hash_size]; - i = 0; - hlist_for_each_entry_rcu(pdr_node, head, hlist) { - if (i >= n) - break; - if (pdr_node->pdr != NULL && find_qer_id_in_pdr(pdr_node->pdr, qer->id)) { - ids[i++] = pdr_node->pdr->id; - } - } - return i; -} - -void del_related_qer_hash(struct gtp5g_dev *gtp, struct pdr *pdr) -{ - u32 i, j; - struct pdr_node *pdr_node = NULL ; - struct pdr_node *to_be_del = NULL ; - char seid_qer_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - for (j = 0; j < pdr->qer_num; j++) { - to_be_del = NULL; - seid_qer_id_to_hex_str(pdr->seid, pdr->qer_ids[j], seid_qer_id_hexstr); - i = str_hashfn(seid_qer_id_hexstr) % gtp->hash_size; - hlist_for_each_entry_rcu(pdr_node, >p->related_qer_hash[i], hlist) { - if (pdr_node->pdr != NULL && - pdr_node->pdr->seid == pdr->seid && - pdr_node->pdr->id == pdr->id) { - to_be_del = pdr_node; - break; - } - } - if (to_be_del){ - hlist_del(&to_be_del->hlist); - kfree(to_be_del); - } - } -} - -int qer_set_pdr(struct pdr *pdr, struct gtp5g_dev *gtp) -{ - char seid_qer_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - u32 i, j; - struct pdr_node *pdr_node = NULL; - - if (!pdr) - return -1; - - // clean old pdr_node - del_related_qer_hash(gtp, pdr); - - for (j = 0; j < pdr->qer_num; j++) { - seid_qer_id_to_hex_str(pdr->seid, pdr->qer_ids[j], seid_qer_id_hexstr); - i = str_hashfn(seid_qer_id_hexstr) % gtp->hash_size; - - pdr_node = kzalloc(sizeof(*pdr_node), GFP_ATOMIC); - if (!pdr_node) { - return -ENOMEM; - } - pdr_node->pdr = pdr; - hlist_add_head_rcu(&pdr_node->hlist, >p->related_qer_hash[i]); - } - return 0; -} diff --git a/lib/gtp5g/src/pfcp/seid.c b/lib/gtp5g/src/pfcp/seid.c deleted file mode 100644 index 7fe7e830..00000000 --- a/lib/gtp5g/src/pfcp/seid.c +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include - -#include "seid.h" - -#define SEID_HEX_STR_LEN 16 -#define U32_ID_HEX_STR_LEN 8 - -void seid_and_u32id_to_hex_str(u64 seid_int, u32 id, char *seid_u32id_hexstr) -{ - char seid_hexstr[SEID_HEX_STR_LEN]; - char id_hexstr[U32_ID_HEX_STR_LEN]; - - snprintf(seid_hexstr, SEID_HEX_STR_LEN, "%llx", seid_int); - snprintf(id_hexstr, U32_ID_HEX_STR_LEN, "%x", id); - strcpy(seid_u32id_hexstr, seid_hexstr); - strcat(seid_u32id_hexstr, id_hexstr); -} \ No newline at end of file diff --git a/lib/gtp5g/src/pfcp/urr.c b/lib/gtp5g/src/pfcp/urr.c deleted file mode 100644 index 1913c7ea..00000000 --- a/lib/gtp5g/src/pfcp/urr.c +++ /dev/null @@ -1,255 +0,0 @@ -#include - -#include "common.h" -#include "dev.h" -#include "urr.h" -#include "pdr.h" -#include "far.h" -#include "seid.h" -#include "hash.h" -#include "log.h" - -void seid_urr_id_to_hex_str(u64 seid_int, u32 urr_id, char *buff) -{ - seid_and_u32id_to_hex_str(seid_int, urr_id, buff); -} - -static void urr_context_free(struct rcu_head *head) -{ - struct urr *urr = container_of(head, struct urr, rcu_head); - if (!urr) - return; - - kfree(urr); -} - -void urr_context_delete(struct urr *urr) -{ - struct gtp5g_dev *gtp = netdev_priv(urr->dev); - struct hlist_head *head; - struct pdr_node *pdr_node; - char seid_urr_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - if (!urr) - return; - - if (!hlist_unhashed(&urr->hlist_id)) - hlist_del_rcu(&urr->hlist_id); - - seid_urr_id_to_hex_str(urr->seid, urr->id, seid_urr_id_hexstr); - head = >p->related_urr_hash[str_hashfn(seid_urr_id_hexstr) % gtp->hash_size]; - hlist_for_each_entry_rcu(pdr_node, head, hlist) { - if (pdr_node->pdr != NULL && - find_urr_id_in_pdr(pdr_node->pdr, urr->id)) { - unix_sock_client_delete(pdr_node->pdr); - } - } - - call_rcu(&urr->rcu_head, urr_context_free); -} - -struct urr *find_urr_by_id(struct gtp5g_dev *gtp, u64 seid, u32 urr_id) -{ - struct hlist_head *head; - struct urr *urr; - char seid_urr_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_urr_id_to_hex_str(seid, urr_id, seid_urr_id_hexstr); - head = >p->urr_id_hash[str_hashfn(seid_urr_id_hexstr) % gtp->hash_size]; - hlist_for_each_entry_rcu(urr, head, hlist_id) { - if (urr->seid == seid && urr->id == urr_id) - return urr; - } - - return NULL; -} - -void urr_update(struct urr *urr, struct gtp5g_dev *gtp) -{ - struct pdr_node *pdr_node; - struct hlist_head *head; - char seid_urr_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - seid_urr_id_to_hex_str(urr->seid, urr->id, seid_urr_id_hexstr); - head = >p->related_urr_hash[str_hashfn(seid_urr_id_hexstr) % gtp->hash_size]; - hlist_for_each_entry_rcu(pdr_node, head, hlist) { - if (pdr_node->pdr != NULL && - find_urr_id_in_pdr(pdr_node->pdr, urr->id)) { - unix_sock_client_update(pdr_node->pdr, rcu_dereference(pdr_node->pdr->far)); - } - } -} - -// TODO: FAR ID for Quota Action IE for indicating the action while no quota is granted -void urr_quota_exhaust_action(struct urr *urr, struct gtp5g_dev *gtp) -{ - struct hlist_head *head; - struct pdr_node *pdr_node; - char seid_urr_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - u16 *actions = NULL, *pdrids = NULL; - struct far *far; - - if (urr->quota_exhausted) { - GTP5G_WAR(NULL, "URR (%u) quota was already exhausted\n", urr->id); - return; - } - - // urr stop measurement - urr->pdr_num = 0; - - pdrids = kzalloc(MAX_PDR_PER_SESSION * sizeof(u16), GFP_KERNEL); - actions = kzalloc(MAX_PDR_PER_SESSION * sizeof(u16), GFP_KERNEL); - if (!pdrids || !actions) - goto fail; - - seid_urr_id_to_hex_str(urr->seid, urr->id, seid_urr_id_hexstr); - head = >p->related_urr_hash[str_hashfn(seid_urr_id_hexstr) % gtp->hash_size]; - //each pdr that associate with the urr drop pkt - hlist_for_each_entry_rcu(pdr_node, head, hlist) { - if (find_urr_id_in_pdr(pdr_node->pdr, urr->id)) { - pdrids[urr->pdr_num] = pdr_node->pdr->id; - far = rcu_dereference(pdr_node->pdr->far); - if (far != NULL) { - actions[urr->pdr_num++] = far->action; - - far->action = FAR_ACTION_DROP; - } - } - } - - if (urr->pdr_num > 0) { - urr->pdrids = kzalloc(urr->pdr_num * sizeof(u16), GFP_KERNEL); - urr->actions = kzalloc(urr->pdr_num * sizeof(u16), GFP_KERNEL); - - memcpy(urr->pdrids, pdrids, urr->pdr_num * sizeof(u16)); - memcpy(urr->actions, actions, urr->pdr_num * sizeof(u16)); - } - - urr->info |= URR_INFO_INAM; - urr->quota_exhausted = true; - -fail: - if (pdrids) - kfree(pdrids); - if (actions) - kfree(actions); -} - -void urr_reverse_quota_exhaust_action(struct urr *urr, struct gtp5g_dev *gtp) -{ - struct hlist_head *head; - struct pdr_node *pdr_node; - char seid_urr_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - int i; - struct far *far; - - if (!urr->quota_exhausted) { - GTP5G_WAR(NULL, "URR (%u) quota is not exhausted; should not reverse\n", urr->id); - return; - } - - seid_urr_id_to_hex_str(urr->seid, urr->id, seid_urr_id_hexstr); - head = >p->related_urr_hash[str_hashfn(seid_urr_id_hexstr) % gtp->hash_size]; - - //each pdr that associate with the urr resume it's normal action - hlist_for_each_entry_rcu(pdr_node, head, hlist) { - if (find_urr_id_in_pdr(pdr_node->pdr, urr->id)) { - for (i = 0; i < urr->pdr_num; i++) { - if (urr->pdrids[i] == pdr_node->pdr->id) { - far = rcu_dereference(pdr_node->pdr->far); - if (far != NULL) { - far->action = urr->actions[i]; - } - } - } - } - } - - urr->quota_exhausted = false; - - if (urr->pdrids) - kfree(urr->pdrids); - if (urr->actions) - kfree(urr->actions); -} - -void urr_append(u64 seid, u32 urr_id, struct urr *urr, struct gtp5g_dev *gtp) -{ - char seid_urr_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - u32 i; - - seid_urr_id_to_hex_str(seid, urr_id, seid_urr_id_hexstr); - i = str_hashfn(seid_urr_id_hexstr) % gtp->hash_size; - hlist_add_head_rcu(&urr->hlist_id, >p->urr_id_hash[i]); -} - -int urr_get_pdr_ids(u16 *ids, int n, struct urr *urr, struct gtp5g_dev *gtp) -{ - struct hlist_head *head; - struct pdr_node *pdr_node; - char seid_urr_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - int i; - - seid_urr_id_to_hex_str(urr->seid, urr->id, seid_urr_id_hexstr); - head = >p->related_urr_hash[str_hashfn(seid_urr_id_hexstr) % gtp->hash_size]; - i = 0; - hlist_for_each_entry_rcu(pdr_node, head, hlist) { - if (i >= n) - break; - if (pdr_node->pdr != NULL && find_urr_id_in_pdr(pdr_node->pdr, urr->id)) { - ids[i++] = pdr_node->pdr->id; - } - } - return i; -} - -void del_related_urr_hash(struct gtp5g_dev *gtp, struct pdr *pdr) -{ - u32 i, j; - struct pdr_node *pdr_node = NULL ; - struct pdr_node *to_be_del = NULL ; - char seid_urr_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - - for (j = 0; j < pdr->urr_num; j++) { - to_be_del = NULL; - seid_urr_id_to_hex_str(pdr->seid, pdr->urr_ids[j], seid_urr_id_hexstr); - i = str_hashfn(seid_urr_id_hexstr) % gtp->hash_size; - hlist_for_each_entry_rcu(pdr_node, >p->related_urr_hash[i], hlist) { - if (pdr_node->pdr != NULL && - pdr_node->pdr->seid == pdr->seid && - pdr_node->pdr->id == pdr->id) { - to_be_del = pdr_node; - break; - } - } - if (to_be_del){ - hlist_del(&to_be_del->hlist); - kfree(to_be_del); - } - } -} - -int urr_set_pdr(struct pdr *pdr, struct gtp5g_dev *gtp) -{ - char seid_urr_id_hexstr[SEID_U32ID_HEX_STR_LEN] = {0}; - u32 i, j; - struct pdr_node *pdr_node = NULL; - - if (!pdr) - return -1; - - // clean old pdr_node - del_related_urr_hash(gtp, pdr); - - for (j = 0; j < pdr->urr_num; j++) { - seid_urr_id_to_hex_str(pdr->seid, pdr->urr_ids[j], seid_urr_id_hexstr); - i = str_hashfn(seid_urr_id_hexstr) % gtp->hash_size; - - pdr_node = kzalloc(sizeof(*pdr_node), GFP_ATOMIC); - if (!pdr_node) { - return -ENOMEM; - } - pdr_node->pdr = pdr; - hlist_add_head_rcu(&pdr_node->hlist, >p->related_urr_hash[i]); - } - return 0; -} diff --git a/lib/gtp5g/src/proc.c b/lib/gtp5g/src/proc.c deleted file mode 100644 index 2cb50759..00000000 --- a/lib/gtp5g/src/proc.c +++ /dev/null @@ -1,702 +0,0 @@ -#include -#include -#include -#include - -#include "proc.h" -#include "log.h" -#include "pdr.h" -#include "far.h" - -#include "util.h" - -struct list_head proc_gtp5g_dev; -struct proc_gtp5g_pdr { - u16 id; - u64 seid; - u32 precedence; - u8 ohr; - u32 role_addr4; - - u32 pdi_ue_addr4; - u32 pdi_fteid; - u32 pdi_gtpu_addr4; - - u32 far_id; - u32 *qer_ids; - u32 qer_num; - - u32 *urr_ids; - u32 urr_num; - - u64 ul_drop_cnt; - u64 dl_drop_cnt; - - /* Packet Statistics */ - u64 ul_pkt_cnt; - u64 dl_pkt_cnt; - u64 ul_byte_cnt; - u64 dl_byte_cnt; -}; - -struct proc_gtp5g_far { - u32 id; - u64 seid; - u16 action; - - //OHC - u16 description; - u32 teid; - u32 peer_addr4; -}; - -struct proc_gtp5g_qer { - u32 id; - u64 seid; - u8 qfi; -}; - -struct proc_gtp5g_urr { - u32 id; - u64 seid; - u8 method; - u32 trigger; - u32 period; - u8 info; - - u8 volth_flag; - u64 volth_tolvol; - u64 volth_ulvol; - u64 volth_dlvol; - - u8 volqu_flag; - u64 volqu_tolvol; - u64 volqu_ulvol; - u64 volqu_dlvol; - - s64 start_time; - s64 end_time; -}; - -struct proc_dir_entry *proc_gtp5g = NULL; -struct proc_dir_entry *proc_gtp5g_dbg = NULL; -struct proc_dir_entry *proc_gtp5g_pdr = NULL; -struct proc_dir_entry *proc_gtp5g_far = NULL; -struct proc_dir_entry *proc_gtp5g_qer = NULL; -struct proc_dir_entry *proc_gtp5g_urr = NULL; -struct proc_gtp5g_pdr proc_pdr; -struct proc_gtp5g_far proc_far; -struct proc_gtp5g_qer proc_qer; -struct proc_gtp5g_urr proc_urr; - -u64 proc_seid = 0; -u16 proc_pdr_id = 0; -u32 proc_far_id = 0; -u32 proc_qer_id = 0; -u32 proc_urr_id = 0; - -struct list_head * get_proc_gtp5g_dev_list_head(){ - return &proc_gtp5g_dev; -} - -void init_proc_gtp5g_dev_list(){ - INIT_LIST_HEAD(&proc_gtp5g_dev); -} - -static int gtp5g_dbg_read(struct seq_file *s, void *v) -{ - seq_printf(s, "gtp5g kerenl debug level range: 0~4\n"); - seq_printf(s, "\t 0 -> Logging\n"); - seq_printf(s, "\t 1 -> Error(default)\n"); - seq_printf(s, "\t 2 -> Warning\n"); - seq_printf(s, "\t 3 -> Information\n"); - seq_printf(s, "\t 4 -> Trace\n"); - seq_printf(s, "Current: %d\n", get_dbg_lvl()); - return 0; -} - -static ssize_t proc_dbg_write(struct file *filp, const char __user *buffer, - size_t len, loff_t *dptr) -{ - char buf[16]; - unsigned long buf_len = min(len, sizeof(buf) - 1); - int dbg; - - if (copy_from_user(buf, buffer, buf_len)) { - GTP5G_ERR(NULL, "Failed to read buffer: %s\n", buffer); - goto err; - } - - buf[buf_len] = 0; - if (sscanf(buf, "%d", &dbg) != 1) { - GTP5G_ERR(NULL, "Failed to read debug level: %s\n", buffer); - goto err; - } - - if (dbg < 0 || dbg > 4) { - GTP5G_ERR(NULL, "Failed to set debug level: %d <0 or >4\n", dbg); - goto err; - } - - set_dbg_lvl(dbg); - return strnlen(buf, buf_len); -err: - return -1; -} - -static int proc_dbg_read(struct inode *inode, struct file *file) -{ - return single_open(file, gtp5g_dbg_read, NULL); -} - -static void set_pdr_qer_ids(char *pdr_qer_ids, struct proc_gtp5g_pdr *proc_pdr) -{ - int i = 0, len = 0; - for (i = 0; i < proc_pdr->qer_num; i++) { - len += sprintf(&pdr_qer_ids[len], "0x%x, ", proc_pdr->qer_ids[i]); - } -} - -static void set_pdr_urr_ids(char *pdr_urr_ids, struct proc_gtp5g_pdr *proc_pdr) -{ - int i = 0, len = 0; - for (i = 0; i < proc_pdr->urr_num; i++) { - len += sprintf(&pdr_urr_ids[len], "0x%x, ", proc_pdr->urr_ids[i]); - } -} - -static int gtp5g_pdr_read(struct seq_file *s, void *v) -{ - char role_addr[35]; - char pdi_ue_addr[35]; - char pdu_gtpu_addr[35]; - char pdr_qer_ids[64]; - char pdr_urr_ids[64]; - - if (!proc_pdr_id) { - seq_printf(s, "Given PDR ID does not exists\n"); - return -1; - } - - seq_printf(s, "PDR: \n"); - seq_printf(s, "\t SEID : %llu\n", proc_pdr.seid); - seq_printf(s, "\t ID : %u\n", proc_pdr.id); - seq_printf(s, "\t Precedence: %u\n", proc_pdr.precedence); - seq_printf(s, "\t OHR: %u\n", proc_pdr.ohr); - ip_string(role_addr, proc_pdr.role_addr4); - seq_printf(s, "\t Role Addr4: %s(%#08x)\n", role_addr, ntohl(proc_pdr.role_addr4)); - ip_string(pdi_ue_addr, proc_pdr.pdi_ue_addr4); - seq_printf(s, "\t PDI UE Addr4: %s(%#08x)\n", pdi_ue_addr, ntohl(proc_pdr.pdi_ue_addr4)); - seq_printf(s, "\t PDI TEID: %#08x\n", ntohl(proc_pdr.pdi_fteid)); - ip_string(pdu_gtpu_addr, proc_pdr.pdi_gtpu_addr4); - seq_printf(s, "\t PDU GTPU Addr4: %s(%#08x)\n", pdu_gtpu_addr, ntohl(proc_pdr.pdi_gtpu_addr4)); - seq_printf(s, "\t FAR ID: %u\n", proc_pdr.far_id); - set_pdr_qer_ids(pdr_qer_ids, &proc_pdr); - seq_printf(s, "\t QER IDs: %s\n", pdr_qer_ids); - set_pdr_urr_ids(pdr_urr_ids, &proc_pdr); - seq_printf(s, "\t URR IDs: %s\n", pdr_urr_ids); - seq_printf(s, "\t UL Drop Count: %#llx\n", proc_pdr.ul_drop_cnt); - seq_printf(s, "\t DL Drop Count: %#llx\n", proc_pdr.dl_drop_cnt); - seq_printf(s, "\t UL Packet Count: %llu\n", proc_pdr.ul_pkt_cnt); - seq_printf(s, "\t DL Packet Count: %llu\n", proc_pdr.dl_pkt_cnt); - seq_printf(s, "\t UL Byte Count: %llu\n", proc_pdr.ul_byte_cnt); - seq_printf(s, "\t DL Byte Count: %llu\n", proc_pdr.dl_byte_cnt); - return 0; -} - -static int gtp5g_far_read(struct seq_file *s, void *v) -{ - if (!proc_far_id) { - seq_printf(s, "Given FAR ID does not exists\n"); - return -1; - } - - seq_printf(s, "FAR: \n"); - seq_printf(s, "\t SEID : %llu\n", proc_far.seid); - seq_printf(s, "\t ID : %u\n", proc_far.id); - seq_printf(s, "\t Apply Action: %#x\n", proc_far.action); - seq_printf(s, "\t OHC Description: %#x\n", proc_far.description); - seq_printf(s, "\t OHC TEID : %#08x\n", ntohl(proc_far.teid)); - seq_printf(s, "\t OHC Peer Addr4: %#08x\n", ntohl(proc_far.peer_addr4)); - return 0; -} - -static int gtp5g_qer_read(struct seq_file *s, void *v) -{ - if (!proc_qer_id) { - seq_printf(s, "Given QER ID does not exists\n"); - return -1; - } - - seq_printf(s, "QER: \n"); - seq_printf(s, "\t SEID : %llu\n", proc_qer.seid); - seq_printf(s, "\t ID : %u\n", proc_qer.id); - seq_printf(s, "\t QFI: %u\n", proc_qer.qfi); - return 0; -} - -static int gtp5g_urr_read(struct seq_file *s, void *v) -{ - if (!proc_urr_id) { - seq_printf(s, "Given URR ID does not exists\n"); - return -1; - } - - seq_printf(s, "URR: \n"); - seq_printf(s, "\t SEID : %llu\n", proc_urr.seid); - seq_printf(s, "\t ID : %u\n", proc_urr.id); - seq_printf(s, "\t Measurement method : 0x%02x\n", proc_urr.method); - seq_printf(s, "\t Reporting trigger : 0x%06x\n", proc_urr.trigger); - seq_printf(s, "\t Measurement period : %d\n", proc_urr.period); - seq_printf(s, "\t Measurement information : 0x%02x\n", proc_urr.info); - seq_printf(s, "\t Volume threshold flag: 0x%02x\n", proc_urr.volth_flag); - seq_printf(s, "\t Volume threshold toltal volume: %llu\n", proc_urr.volth_tolvol); - seq_printf(s, "\t Volume threshold uplink volume: %llu\n", proc_urr.volth_ulvol); - seq_printf(s, "\t Volume threshold downlink volume: %llu\n", proc_urr.volth_dlvol); - - seq_printf(s, "\t Volume quota flag: %02x\n", proc_urr.volqu_flag); - seq_printf(s, "\t Volume quota toltal volume: %llu\n", proc_urr.volqu_tolvol); - seq_printf(s, "\t Volume quota uplink volume: %llu\n", proc_urr.volqu_ulvol); - seq_printf(s, "\t Volume quota downlink volume: %llu\n", proc_urr.volqu_dlvol); - - seq_printf(s, "\t Start time: %lld\n", proc_urr.start_time); - seq_printf(s, "\t End time: %lld\n", proc_urr.end_time); - - return 0; -} - -static ssize_t proc_pdr_write(struct file *filp, const char __user *buffer, - size_t len, loff_t *dptr) -{ - char buf[128], dev_name[32]; - u8 found = 0; - unsigned long buf_len = min(sizeof(buf) - 1, len); - struct pdr *pdr; - struct gtp5g_dev *gtp; - - if (copy_from_user(buf, buffer, buf_len)) { - GTP5G_ERR(NULL, "Failed to read buffer: %s\n", buf); - goto err; - } - - buf[buf_len] = 0; - if (sscanf(buf, "%s %llu %hu", dev_name, &proc_seid, &proc_pdr_id) != 3) { - GTP5G_ERR(NULL, "proc write of PDR Dev & ID: %s is not valid\n", buf); - goto err; - } - - list_for_each_entry_rcu(gtp, &proc_gtp5g_dev, proc_list) { - if (strcmp(dev_name, netdev_name(gtp->dev)) == 0) { - found = 1; - break; - } - } - if (!found) { - GTP5G_ERR(NULL, "Given dev: %s not exists\n", dev_name); - goto err; - } - - pdr = find_pdr_by_id(gtp, proc_seid, proc_pdr_id); - if (!pdr) { - GTP5G_ERR(NULL, "Given SEID : %llu PDR ID : %u not exists\n", proc_seid, proc_pdr_id); - goto err; - } - - memset(&proc_pdr, 0, sizeof(proc_pdr)); - proc_pdr.id = pdr->id; - proc_pdr.seid = pdr->seid; - proc_pdr.precedence = pdr->precedence; - - if (pdr->outer_header_removal) - proc_pdr.ohr = *pdr->outer_header_removal; - - if (pdr->role_addr_ipv4.s_addr) - proc_pdr.role_addr4 = pdr->role_addr_ipv4.s_addr; - - if (pdr->pdi) { - if (pdr->pdi->ue_addr_ipv4) - proc_pdr.pdi_ue_addr4 = pdr->pdi->ue_addr_ipv4->s_addr; - if (pdr->pdi->f_teid) { - proc_pdr.pdi_fteid = pdr->pdi->f_teid->teid; - proc_pdr.pdi_gtpu_addr4 = pdr->pdi->f_teid->gtpu_addr_ipv4.s_addr; - } - } - - if (pdr->far_id) - proc_pdr.far_id = *pdr->far_id; - - if (pdr->qer_ids) { - proc_pdr.qer_ids = pdr->qer_ids; - proc_pdr.qer_num = pdr->qer_num; - } - - if (pdr->urr_ids) { - proc_pdr.urr_ids = pdr->urr_ids; - proc_pdr.urr_num = pdr->urr_num; - } - - proc_pdr.ul_drop_cnt = pdr->ul_drop_cnt; - proc_pdr.dl_drop_cnt = pdr->dl_drop_cnt; - - proc_pdr.ul_pkt_cnt = pdr->ul_pkt_cnt; - proc_pdr.dl_pkt_cnt = pdr->dl_pkt_cnt; - proc_pdr.ul_byte_cnt = pdr->ul_byte_cnt; - proc_pdr.dl_byte_cnt = pdr->dl_byte_cnt; - - return strnlen(buf, buf_len); -err: - proc_pdr_id = 0; - return -1; -} - -static ssize_t proc_far_write(struct file *filp, const char __user *buffer, - size_t len, loff_t *dptr) -{ - char buf[128], dev_name[32]; - u8 found = 0; - unsigned long buf_len = min(sizeof(buf) - 1, len); - struct far *far; - struct gtp5g_dev *gtp; - struct forwarding_parameter *fwd_param; - - if (copy_from_user(buf, buffer, buf_len)) { - GTP5G_ERR(NULL, "Failed to read buffer: %s\n", buf); - goto err; - } - - buf[buf_len] = 0; - if (sscanf(buf, "%s %llu %u", dev_name, &proc_seid, &proc_far_id) != 3) { - GTP5G_ERR(NULL, "proc write of FAR Dev & ID: %s is not valid\n", buf); - goto err; - } - - list_for_each_entry_rcu(gtp, &proc_gtp5g_dev, proc_list) { - if (strcmp(dev_name, netdev_name(gtp->dev)) == 0) { - found = 1; - break; - } - } - if (!found) { - GTP5G_ERR(NULL, "Given dev: %s not exists\n", dev_name); - goto err; - } - - far = find_far_by_id(gtp, proc_seid, proc_far_id); - if (!far) { - GTP5G_ERR(NULL, "Given FAR ID : %u not exists\n", proc_far_id); - goto err; - } - - memset(&proc_far, 0, sizeof(proc_far)); - proc_far.id = far->id; - proc_far.seid = far->seid; - proc_far.action = far->action; - - fwd_param = rcu_dereference(far->fwd_param); - if (fwd_param) { - if (fwd_param->hdr_creation) { - proc_far.description = fwd_param->hdr_creation->description; - proc_far.teid = fwd_param->hdr_creation->teid; - proc_far.peer_addr4 = fwd_param->hdr_creation->peer_addr_ipv4.s_addr; - } - } - - return strnlen(buf, buf_len); -err: - proc_far_id = 0; - return -1; -} - -static ssize_t proc_qer_write(struct file *filp, const char __user *buffer, - size_t len, loff_t *dptr) -{ - char buf[128], dev_name[32]; - u8 found = 0; - unsigned long buf_len = min(sizeof(buf) - 1, len); - struct qer *qer; - struct gtp5g_dev *gtp; - - if (copy_from_user(buf, buffer, buf_len)) { - GTP5G_ERR(NULL, "Failed to read buffer: %s\n", buf); - goto err; - } - - buf[buf_len] = 0; - if (sscanf(buf, "%s %llu %u", dev_name, &proc_seid, &proc_qer_id) != 3) { - GTP5G_ERR(NULL, "proc write of QER Dev & ID: %s is not valid\n", buf); - goto err; - } - - list_for_each_entry_rcu(gtp, &proc_gtp5g_dev, proc_list) { - if (strcmp(dev_name, netdev_name(gtp->dev)) == 0) { - found = 1; - break; - } - } - if (!found) { - GTP5G_ERR(NULL, "Given dev: %s not exists\n", dev_name); - goto err; - } - - qer = find_qer_by_id(gtp, proc_seid, proc_qer_id); - if (!qer) { - GTP5G_ERR(NULL, "Given QER ID : %u not exists\n", proc_qer_id); - goto err; - } - - memset(&proc_qer, 0, sizeof(proc_qer)); - proc_qer.id = qer->id; - proc_qer.seid = qer->seid; - proc_qer.qfi = qer->qfi; - - return strnlen(buf, buf_len); -err: - proc_qer_id = 0; - return -1; -} - -static ssize_t proc_urr_write(struct file *filp, const char __user *buffer, - size_t len, loff_t *dptr) -{ - char buf[128], dev_name[32]; - u8 found = 0; - unsigned long buf_len = min(sizeof(buf) - 1, len); - struct urr *urr; - struct gtp5g_dev *gtp; - - if (copy_from_user(buf, buffer, buf_len)) { - GTP5G_ERR(NULL, "Failed to read buffer: %s\n", buf); - goto err; - } - - buf[buf_len] = 0; - if (sscanf(buf, "%s %llu %u", dev_name, &proc_seid, &proc_urr_id) != 3) { - GTP5G_ERR(NULL, "proc write of URR Dev & ID: %s is not valid\n", buf); - goto err; - } - - list_for_each_entry_rcu(gtp, &proc_gtp5g_dev, proc_list) { - if (strcmp(dev_name, netdev_name(gtp->dev)) == 0) { - found = 1; - break; - } - } - if (!found) { - GTP5G_ERR(NULL, "Given dev: %s not exists\n", dev_name); - goto err; - } - - urr = find_urr_by_id(gtp, proc_seid, proc_urr_id); - if (!urr) { - GTP5G_ERR(NULL, "Given URR ID : %u not exists\n", proc_urr_id); - goto err; - } - - memset(&proc_urr, 0, sizeof(proc_urr)); - proc_urr.id = urr->id; - proc_urr.seid = urr->seid; - proc_urr.method = urr->method; - proc_urr.trigger = urr->trigger; - proc_urr.period = urr->period; - proc_urr.info = urr->info; - - proc_urr.volth_flag = urr->volumethreshold.flag; - proc_urr.volth_tolvol = urr->volumethreshold.totalVolume; - proc_urr.volth_ulvol = urr->volumethreshold.uplinkVolume; - proc_urr.volth_dlvol = urr->volumethreshold.downlinkVolume; - - proc_urr.volqu_flag = urr->volumequota.flag; - proc_urr.volqu_tolvol = urr->volumequota.totalVolume; - proc_urr.volqu_ulvol = urr->volumequota.uplinkVolume; - proc_urr.volqu_dlvol = urr->volumequota.downlinkVolume; - - proc_urr.start_time = urr->start_time; - proc_urr.end_time = urr->end_time; - - return strnlen(buf, buf_len); -err: - proc_urr_id = 0; - return -1; -} - -static int proc_pdr_read(struct inode *inode, struct file *file) -{ - return single_open(file, gtp5g_pdr_read, NULL); -} - -static int proc_far_read(struct inode *inode, struct file *file) -{ - return single_open(file, gtp5g_far_read, NULL); -} - -static int proc_qer_read(struct inode *inode, struct file *file) -{ - return single_open(file, gtp5g_qer_read, NULL); -} - -static int proc_urr_read(struct inode *inode, struct file *file) -{ - return single_open(file, gtp5g_urr_read, NULL); -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) -static const struct proc_ops proc_gtp5g_dbg_ops = { - .proc_open = proc_dbg_read, - .proc_read = seq_read, - .proc_write = proc_dbg_write, - .proc_lseek = seq_lseek, - .proc_release = single_release, -}; -#else -static const struct file_operations proc_gtp5g_dbg_ops = { - .owner = THIS_MODULE, - .open = proc_dbg_read, - .read = seq_read, - .write = proc_dbg_write, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) -static const struct proc_ops proc_gtp5g_pdr_ops = { - .proc_open = proc_pdr_read, - .proc_read = seq_read, - .proc_write = proc_pdr_write, - .proc_lseek = seq_lseek, - .proc_release = single_release, -}; -#else -static const struct file_operations proc_gtp5g_pdr_ops = { - .owner = THIS_MODULE, - .open = proc_pdr_read, - .read = seq_read, - .write = proc_pdr_write, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) -static const struct proc_ops proc_gtp5g_far_ops = { - .proc_open = proc_far_read, - .proc_read = seq_read, - .proc_write = proc_far_write, - .proc_lseek = seq_lseek, - .proc_release = single_release, -}; -#else -static const struct file_operations proc_gtp5g_far_ops = { - .owner = THIS_MODULE, - .open = proc_far_read, - .read = seq_read, - .write = proc_far_write, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) -static const struct proc_ops proc_gtp5g_qer_ops = { - .proc_open = proc_qer_read, - .proc_read = seq_read, - .proc_write = proc_qer_write, - .proc_lseek = seq_lseek, - .proc_release = single_release, -}; -#else -static const struct file_operations proc_gtp5g_qer_ops = { - .owner = THIS_MODULE, - .open = proc_qer_read, - .read = seq_read, - .write = proc_qer_write, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) -static const struct proc_ops proc_gtp5g_urr_ops = { - .proc_open = proc_urr_read, - .proc_read = seq_read, - .proc_write = proc_urr_write, - .proc_lseek = seq_lseek, - .proc_release = single_release, -}; -#else -static const struct file_operations proc_gtp5g_urr_ops = { - .owner = THIS_MODULE, - .open = proc_urr_read, - .read = seq_read, - .write = proc_urr_write, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - -int create_proc(void) -{ - proc_gtp5g = proc_mkdir("gtp5g", NULL); - if (!proc_gtp5g) { - GTP5G_ERR(NULL, "Failed to create /proc/gtp5g\n"); - } - - proc_gtp5g_dbg = proc_create("dbg", (S_IFREG | S_IRUGO | S_IWUGO), - proc_gtp5g, &proc_gtp5g_dbg_ops); - if (!proc_gtp5g_dbg) { - GTP5G_ERR(NULL, "Failed to create /proc/gtp5g/dbg\n"); - goto remove_gtp5g_proc; - } - - proc_gtp5g_pdr = proc_create("pdr", (S_IFREG | S_IRUGO | S_IWUGO), - proc_gtp5g, &proc_gtp5g_pdr_ops); - if (!proc_gtp5g_pdr) { - GTP5G_ERR(NULL, "Failed to create /proc/gtp5g/pdr\n"); - goto remove_dbg_proc; - } - - proc_gtp5g_far = proc_create("far", (S_IFREG | S_IRUGO | S_IWUGO), - proc_gtp5g, &proc_gtp5g_far_ops); - if (!proc_gtp5g_far) { - GTP5G_ERR(NULL, "Failed to create /proc/gtp5g/far\n"); - goto remove_pdr_proc; - } - - proc_gtp5g_qer = proc_create("qer", (S_IFREG | S_IRUGO | S_IWUGO), - proc_gtp5g, &proc_gtp5g_qer_ops); - if (!proc_gtp5g_qer) { - GTP5G_ERR(NULL, "Failed to create /proc/gtp5g/qer\n"); - goto remove_far_proc; - } - - proc_gtp5g_urr = proc_create("urr", (S_IFREG | S_IRUGO | S_IWUGO), - proc_gtp5g, &proc_gtp5g_urr_ops); - if (!proc_gtp5g_urr) { - GTP5G_ERR(NULL, "Failed to create /proc/gtp5g/urr\n"); - goto remove_qer_proc; - } - - return 0; - - remove_qer_proc: - remove_proc_entry("qer", proc_gtp5g); - remove_far_proc: - remove_proc_entry("far", proc_gtp5g); - remove_pdr_proc: - remove_proc_entry("pdr", proc_gtp5g); - remove_dbg_proc: - remove_proc_entry("dbg", proc_gtp5g); - remove_gtp5g_proc: - remove_proc_entry("gtp5g", NULL); - return -1; -} - -void remove_proc() -{ - remove_proc_entry("urr", proc_gtp5g); - remove_proc_entry("qer", proc_gtp5g); - remove_proc_entry("far", proc_gtp5g); - remove_proc_entry("pdr", proc_gtp5g); - remove_proc_entry("dbg", proc_gtp5g); - remove_proc_entry("gtp5g", NULL); -} diff --git a/lib/gtp5g/src/util.c b/lib/gtp5g/src/util.c deleted file mode 100644 index b44c8535..00000000 --- a/lib/gtp5g/src/util.c +++ /dev/null @@ -1,11 +0,0 @@ -#include - -#include "util.h" - -void ip_string(char * ip_str, int ip_int){ - sprintf(ip_str, "%i.%i.%i.%i", - (ip_int) & 0xFF, - (ip_int >> 8) & 0xFF, - (ip_int >> 16) & 0xFF, - (ip_int >> 24) & 0xFF); -} \ No newline at end of file