diff --git a/README.md b/README.md index f2338b84..ef629e42 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ core networks. colte packages. This should be installed automatically as a dependency via apt if any of the other component packages are installed. + + ## Apt Packages To ease deployment, we host pre-compiled apt packages on our server for x86_64 @@ -51,19 +53,42 @@ repository to get colte and haulage, and you will also need to add the open5gs repository separately. To do this, use the following commands according to your distribution: -### Debian 10 (buster) (**Recommended**) +## Nodejs version recommendations +A Ubuntu/Debian basic installation use nodejs at version 10, open5gs and CoLTE need +nodejs version 14 or latest (this solve npm takes long time to install), so we need to install it following next steps: +```shell +sudo apt update +sudo apt install curl +curl -fsSL https://deb.nodesource.com/setup_21.x | sudo -E bash - +sudo apt install nodejs +``` + +MongoDB v6 is the latest version that open5gs uses. + +### Debian 10 (buster) (**Recommended**) ```shell echo "deb [signed-by=/usr/share/keyrings/colte-archive-keyring.gpg] http://colte.cs.washington.edu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/colte.list sudo wget -O /usr/share/keyrings/colte-archive-keyring.gpg http://colte.cs.washington.edu/colte-archive-keyring.gpg -wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | sudo apt-key add - -echo "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/4.2 main" | sudo tee /etc/apt/sources.list.d/mongodb-org.list +curl -fsSL https://pgp.mongodb.com/server-6.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-6.0.gpg --dearmor +echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg] https://repo.mongodb.org/apt/debian bullseye/mongodb-org/6.0 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list +sudo apt update +sudo apt upgrade -y +sudo apt install -y mongodb-org +sudo systemctl start mongod +sudo systemctl enable mongod wget -qO - https://download.opensuse.org/repositories/home:/acetcom:/open5gs:/latest/Debian_10/Release.key | sudo apt-key add - sudo sh -c "echo 'deb http://download.opensuse.org/repositories/home:/acetcom:/open5gs:/latest/Debian_10/ ./' > /etc/apt/sources.list.d/open5gs.list" sudo apt update sudo apt install colte-cn-4g colte-prepaid ``` +You can install under Debian 11 +```shell +wget -qO - https://download.opensuse.org/repositories/home:/acetcom:/open5gs:/latest/Debian_10/Release.key | sudo apt-key add - +sudo sh -c "echo 'deb http://download.opensuse.org/repositories/home:/acetcom:/open5gs:/latest/Debian_11/ ./' > /etc/apt/sources.list.d/open5gs.list" +``` + ### Ubuntu 18.04 or 20.04 (bionic or focal) ```shell @@ -91,6 +116,8 @@ npm install npm start ``` +If you want to use a translated template, at the directory views/ from each web interface, you need to change the .hbs-es files to .hbs + # Configuration After installation, pointers to all the various config files can be found in `/etc/colte/`. The main config file is `config.yml`. After you edit this file, run `colteconf` to reconfigure all components and restart them as necessary. Note that you **must** run colteconf at least once after installing CoLTE, because there is no way for us to know some of the options (e.g. upstream and downstream interfaces). diff --git a/conf/open5gs_dbconf.sh b/conf/open5gs_dbconf.sh index 1e3b0ff2..129f1cd3 100755 --- a/conf/open5gs_dbconf.sh +++ b/conf/open5gs_dbconf.sh @@ -12,6 +12,7 @@ display_help() { echo " static_ip6 {imsi ip6}: adds a static IPv6 assignment to an already-existing user" echo " type {imsi type}: changes the PDN-Type of the first PDN: 0 = IPv4, 1 = IPv6, 2 = IPv4v6, 3 = v4 OR v6" echo " help: displays this message and exits" + echo " speed {imsi dl_value dl_unit ul_value ul_unit}: dl_unit 0=bps 1=Kbps 2=Mbps 3=Gbps 4=Tbps " echo " default values are as follows: APN \"internet\", dl_bw/ul_bw 1 Gbps, PGW address is 127.0.0.3, IPv4 only" } @@ -283,4 +284,19 @@ if [ "$1" = "type" ]; then exit 0 fi +if [ "$1" = "speed" ]; then + if [ "$#" -ne 6 ]; then + echo "dbconf.sh: incorrect number of args, format is \"open5gs_dbconf.sh speed imsi dl_value dl_unit_value ul_value ul_unit_value \"" + exit 1 + fi + IMSI=$2 + DL_VALUE=$3 + DL_UNIT=$4 + UL_VALUE=$5 + UL_UNIT=$6 + mongo --eval "db.subscribers.update({\"imsi\": \"$IMSI\"},{\$set : { \"ambr\": {\"downlink\": {\"value\": NumberInt($DL_VALUE), \"unit\": NumberInt($DL_UNIT)}, \"uplink\": {\"value\": NumberInt($UL_VALUE),\"unit\": ($UL_UNIT) } } }});" open5gs + exit 0 +fi + + display_help diff --git a/python/colteconf_cn_4g.py b/python/colteconf_cn_4g.py index 3cb809a9..227f9331 100644 --- a/python/colteconf_cn_4g.py +++ b/python/colteconf_cn_4g.py @@ -126,41 +126,43 @@ def _update_mme(colte_data): with open(mme, "r+") as file: mme_data = yaml.load(file.read()) - + yaml.dump(mme_data['mme']['gummei'][0]['plmn_id'], sys.stdout) + print ("MMC",mme_data['mme']['gummei'][0]['plmn_id']['mcc']) + print (mme_data['mme']['gummei'][0]['plmn_id']['mnc']) + #print (len(mme_data['mme']['gummei']['plmn_id'])) # Create fields in the data if they do not yet exist _create_field_if_not_exist(mme_data, ["mme"], CommentedMap()) _create_field_if_not_exist(mme_data, ["mme", "gummei"], CommentedMap()) - _create_field_if_not_exist( - mme_data, ["mme", "gummei", "plmn_id"], CommentedMap() - ) - mme_data["mme"]["gummei"]["plmn_id"]["mcc"] = colte_data["mcc"] - mme_data["mme"]["gummei"]["plmn_id"]["mnc"] = colte_data["mnc"] + _create_field_if_not_exist(mme_data, ['mme','gummei',0,'plmn_id'], CommentedMap()) + + mme_data["mme"]["gummei"][0]["plmn_id"]["mcc"] = colte_data["mcc"] + mme_data["mme"]["gummei"][0]["plmn_id"]["mnc"] = colte_data["mnc"] _create_field_if_not_exist(mme_data, ["mme", "tai"], CommentedMap()) - _create_field_if_not_exist(mme_data, ["mme", "tai", "plmn_id"], CommentedMap()) - mme_data["mme"]["tai"]["plmn_id"]["mcc"] = colte_data["mcc"] - mme_data["mme"]["tai"]["plmn_id"]["mnc"] = colte_data["mnc"] + _create_field_if_not_exist(mme_data, ["mme", "tai",0, "plmn_id"], CommentedMap()) + mme_data["mme"]["tai"][0]["plmn_id"]["mcc"] = colte_data["mcc"] + mme_data["mme"]["tai"][0]["plmn_id"]["mnc"] = colte_data["mnc"] - mme_data["mme"]["s1ap"] = CommentedSeq() - mme_data["mme"]["s1ap"].append({"addr": colte_data["enb_iface_addr"]}) + _create_field_if_not_exist(mme_data, ["mme", "s1ap"], CommentedMap()) + mme_data["mme"]["s1ap"]["server"] = CommentedSeq() + mme_data["mme"]["s1ap"]["server"].append({"address": colte_data["enb_iface_addr"]}) _create_field_if_not_exist(mme_data, ["mme", "network_name"], CommentedMap()) mme_data["mme"]["network_name"]["full"] = colte_data["network_name"] - mme_data["mme"]["gtpc"] = CommentedSeq() - mme_data["mme"]["gtpc"].append({"addr": "127.0.0.2"}) + _create_field_if_not_exist(mme_data, ["mme", "gtpc"], CommentedMap()) + mme_data["mme"]["gtpc"]["server"] = CommentedSeq() + mme_data["mme"]["gtpc"]["server"].append({"address": "127.0.0.2"}) - _create_field_if_not_exist(mme_data, ["sgwc"], CommentedMap()) + _create_field_if_not_exist(mme_data, ["mme", "gtpc", "client"], CommentedMap()) - mme_data["sgwc"]["gtpc"] = CommentedSeq() - mme_data["sgwc"]["gtpc"].append({"addr": "127.0.0.3"}) + mme_data["mme"]["gtpc"]["client"]["sgwc"] = CommentedSeq() + mme_data["mme"]["gtpc"]["client"]["sgwc"].append({"address": "127.0.0.3"}) - _create_field_if_not_exist(mme_data, ["smf"], CommentedMap()) - - mme_data["smf"]["gtpc"] = CommentedSeq() - mme_data["smf"]["gtpc"].append({"addr": "127.0.0.4"}) - mme_data["smf"]["gtpc"].append({"addr": "::1"}) + mme_data["mme"]["gtpc"]["client"]["smf"] = CommentedSeq() + mme_data["mme"]["gtpc"]["client"]["smf"].append({"address": "127.0.0.4"}) + mme_data["mme"]["gtpc"]["client"]["smf"].append({"address": "::1"}) # Disable internal file logging since journald is capturing stdout _create_field_if_not_exist(mme_data, ["logger"], CommentedMap()) @@ -194,17 +196,18 @@ def _update_sgwc(colte_data): # Create fields in the data if they do not yet exist _create_field_if_not_exist(sgwc_data, ["sgwc"], CommentedMap()) - sgwc_data["sgwc"]["gtpc"] = CommentedSeq() - sgwc_data["sgwc"]["gtpc"].append({"addr": "127.0.0.3"}) + _create_field_if_not_exist(sgwc_data, ["sgwc", "gtpc"], CommentedMap()) + sgwc_data["sgwc"]["gtpc"]["server"] = CommentedSeq() + sgwc_data["sgwc"]["gtpc"]["server"].append({"address": "127.0.0.3"}) - sgwc_data["sgwc"]["pfcp"] = CommentedSeq() - sgwc_data["sgwc"]["pfcp"].append({"addr": "127.0.0.3"}) + _create_field_if_not_exist(sgwc_data, ["sgwc", "pfcp"], CommentedMap()) + sgwc_data["sgwc"]["pfcp"]["server"] = CommentedSeq() + sgwc_data["sgwc"]["pfcp"]["server"].append({"address": "127.0.0.3"}) # Link towards the SGW-U - _create_field_if_not_exist(sgwc_data, ["sgwu"], CommentedMap()) - - sgwc_data["sgwu"]["pfcp"] = CommentedSeq() - sgwc_data["sgwu"]["pfcp"].append({"addr": "127.0.0.6"}) + _create_field_if_not_exist(sgwc_data, ["sgwc", "pfcp", "client"], CommentedMap()) + sgwc_data["sgwc"]["pfcp"]["client"]["sgwu"] = CommentedSeq() + sgwc_data["sgwc"]["pfcp"]["client"]["sgwu"].append({"address": "127.0.0.6"}) # Disable internal file logging since journald is capturing stdout _create_field_if_not_exist(sgwc_data, ["logger"], CommentedMap()) @@ -223,11 +226,13 @@ def _update_sgwu(colte_data): # Create fields in the data if they do not yet exist _create_field_if_not_exist(sgwu_data, ["sgwu"], CommentedMap()) - sgwu_data["sgwu"]["gtpu"] = CommentedSeq() - sgwu_data["sgwu"]["gtpu"].append({"addr": colte_data["enb_iface_addr"]}) + _create_field_if_not_exist(sgwu_data, ["sgwu", "gtpu"], CommentedMap()) + sgwu_data["sgwu"]["gtpu"]["server"] = CommentedSeq() + sgwu_data["sgwu"]["gtpu"]["server"].append({"address": colte_data["enb_iface_addr"]}) - sgwu_data["sgwu"]["pfcp"] = CommentedSeq() - sgwu_data["sgwu"]["pfcp"].append({"addr": "127.0.0.6"}) + _create_field_if_not_exist(sgwu_data, ["sgwu", "pfcp"], CommentedMap()) + sgwu_data["sgwu"]["pfcp"]["server"] = CommentedSeq() + sgwu_data["sgwu"]["pfcp"]["server"].append({"address": "127.0.0.6"}) # Link towards the SGW-C # TODO(matt9j) This might be the wrong address! Not included in the default @@ -251,30 +256,33 @@ def _update_smf(colte_data): # Create fields in the data if they do not yet exist _create_field_if_not_exist(smf_data, ["smf"], CommentedMap()) - smf_data["smf"]["gtpc"] = CommentedSeq() - smf_data["smf"]["gtpc"].append({"addr": "127.0.0.4"}) - smf_data["smf"]["gtpc"].append({"addr": "::1"}) + _create_field_if_not_exist(smf_data, ["smf", "gtpc"], CommentedMap()) + smf_data["smf"]["gtpc"]["server"] = CommentedSeq() + smf_data["smf"]["gtpc"]["server"].append({"address": "127.0.0.4"}) + smf_data["smf"]["gtpc"]["server"].append({"address": "::1"}) - smf_data["smf"]["pfcp"] = CommentedSeq() - smf_data["smf"]["pfcp"].append({"addr": "127.0.0.4"}) - smf_data["smf"]["pfcp"].append({"addr": "::1"}) + _create_field_if_not_exist(smf_data, ["smf", "pfcp"], CommentedMap()) + smf_data["smf"]["pfcp"]["server"] = CommentedSeq() + smf_data["smf"]["pfcp"]["server"].append({"address": "127.0.0.4"}) + smf_data["smf"]["pfcp"]["server"].append({"address": "::1"}) - smf_data["smf"]["subnet"] = CommentedSeq() + # Create link to UPF + _create_field_if_not_exist(smf_data, ["smf", "pfcp", "client"], CommentedMap()) + + smf_data["smf"]["pfcp"]["client"]["upf"] = CommentedSeq() + smf_data["smf"]["pfcp"]["client"]["upf"].append({"address": "127.0.0.7"}) + + # Add Subnets, DNS, and MTU + smf_data["smf"]["session"] = CommentedSeq() net = IPNetwork(colte_data["lte_subnet"]) netstr = str(net[1]) + "/" + str(net.prefixlen) - smf_data["smf"]["subnet"].append({"addr": netstr}) + smf_data["smf"]["session"].append({"subnet": netstr}) smf_data["smf"]["dns"] = CommentedSeq() smf_data["smf"]["dns"].append(colte_data["dns"]) smf_data["smf"]["mtu"] = 1400 - # Create link to UPF - _create_field_if_not_exist(smf_data, ["upf"], CommentedMap()) - - smf_data["upf"]["pfcp"] = CommentedSeq() - smf_data["upf"]["pfcp"].append({"addr": "127.0.0.7"}) - # Disable 5GC NRF link while operating EPC only if "nrf" in smf_data: del smf_data["nrf"] @@ -296,16 +304,18 @@ def _update_upf(colte_data): # Create fields in the data if they do not yet exist _create_field_if_not_exist(upf_data, ["upf"], CommentedMap()) - upf_data["upf"]["pfcp"] = CommentedSeq() - upf_data["upf"]["pfcp"].append({"addr": "127.0.0.7"}) + _create_field_if_not_exist(upf_data, ["upf", "pfcp"], CommentedMap()) + upf_data["upf"]["pfcp"]["server"] = CommentedSeq() + upf_data["upf"]["pfcp"]["server"].append({"address": "127.0.0.7"}) - upf_data["upf"]["gtpu"] = CommentedSeq() - upf_data["upf"]["gtpu"].append({"addr": "127.0.0.7"}) + _create_field_if_not_exist(upf_data, ["upf", "gtpu"], CommentedMap()) + upf_data["upf"]["gtpu"]["server"] = CommentedSeq() + upf_data["upf"]["gtpu"]["server"].append({"address": "127.0.0.7"}) - upf_data["upf"]["subnet"] = CommentedSeq() + upf_data["upf"]["session"] = CommentedSeq() net = IPNetwork(colte_data["lte_subnet"]) netstr = str(net[1]) + "/" + str(net.prefixlen) - upf_data["upf"]["subnet"].append({"addr": netstr}) + upf_data["upf"]["session"].append({"subnet": netstr}) # Link to the SMF # TODO(matt9j) Might not be needed @@ -368,5 +378,4 @@ def _control_epc_services(action): # Restart everything to pick up new configurations, and don't restart # networkd while the EPC or metering are running. stop_all_services() - os.system("systemctl restart systemd-networkd") - sync_service_state(colte_data) + os.system("systemctl restart systemd-networkd") \ No newline at end of file diff --git a/python/coltedb.py b/python/coltedb.py index 5044709a..effb614f 100644 --- a/python/coltedb.py +++ b/python/coltedb.py @@ -20,6 +20,8 @@ def display_help(): print(" topup_data {imsi} {data}: adds bytes to a user's account") print(" admin {imsi}: gives a user administrative privileges") print(" noadmin {imsi}: removes a user's administrative privileges") + print(" speed {imsi dl_value dl_unit ul_value ul_unit}: Change bandwith per UE unit values 0=bps 1=Kbps 2=Mbps 3=Gbps 4=Tbps") + print(" default values are as follows: APN \"internet\", dl_bw/ul_bw 1 Gbps, PGW address is 127.0.0.3, IPv4 only ") print(" help: displays this message and exits") @@ -212,5 +214,21 @@ def display_help(): db_name=dbname, db_user=db_user, db_pass=db_pass, imsi=sys.argv[2] ) + elif command == "speed": + if len(sys.argv) != 7 : + log.error( + 'coltedb: incorrect number of args, format is "coltedb speed imsi dl_value dl_unit ul_value dl_unit units values are 0=bps 1=Kbps 2=Mbps 3=Gbps 4=Gbps"' + ) + else: + if core_network is not None: + core_network.speed_user( + imsi=sys.argv[2], + dl_value=sys.argv[3], + dl_unit=sys.argv[4], + ul_value=sys.argv[5], + ul_unit=sys.argv[6], + ) + + else: display_help() diff --git a/python/coltedb_cn_4g.py b/python/coltedb_cn_4g.py index a539d897..6ace60aa 100644 --- a/python/coltedb_cn_4g.py +++ b/python/coltedb_cn_4g.py @@ -16,6 +16,9 @@ def add_user(imsi, ip, ki, opc, apn): def remove_user(imsi): subprocess.run(["/etc/colte/colte_open5gsdb", "remove", str(imsi)], check=True) +def speed_user(imsi, dl_value, dl_unit, ul_value, ul_unit): + open5gs_entry = [str(imsi), str(dl_value), str(dl_unit), str(ul_value), str(ul_unit)] + subprocess.run(["/etc/colte/colte_open5gsdb", "speed"] + open5gs_entry, check=True) if __name__ == "__main__": logging.basicConfig(level=logging.INFO) diff --git a/webadmin/views/home.hbs-es b/webadmin/views/home.hbs-es new file mode 100644 index 00000000..3dd1ea35 --- /dev/null +++ b/webadmin/views/home.hbs-es @@ -0,0 +1,71 @@ +
+ +
+
+ {{translate "Recargar Saldo Usuario"}} +
+
+
+
+ + +
+
+ + +
+ +
+
+
+ +
+
+ {{translate "Transferencia entre Usuarixs"}} +
+
+
+
+ + + + +
+
+ + +
+ +
+
+
+
+ diff --git a/webadmin/views/layout.hbs-es b/webadmin/views/layout.hbs-es new file mode 100644 index 00000000..1f15bbd4 --- /dev/null +++ b/webadmin/views/layout.hbs-es @@ -0,0 +1,46 @@ + + + + + + + + + + + {{title}} + + + + + {{{body}}} + + + + + + diff --git a/webadmin/views/users.hbs-es b/webadmin/views/users.hbs-es new file mode 100644 index 00000000..2e894b71 --- /dev/null +++ b/webadmin/views/users.hbs-es @@ -0,0 +1,170 @@ + +
+ +
+
+ {{translate "Busqueda de Usuarixs por IMSI"}} +
+
+
+
+ + +
+
+
+
+ +
+
+ + + + + + + + + + + + + + {{#each customers_list}} + + + + + + + + + + + + + + {{/each}} + +
IMSINombreNumero telefonicoSaldo de DatosSaldo en pesosAcceso a Internet Acceso Local -CoLTE
{{this.imsi}} + {{username}} + + {{this.msisdn}} + {{convertBytes this.data_balance}} + + + {{{renderCurrency this.balance}}} + + + {{ this.current_policy_name }} + + + + + {{#if this.enabled}} + + {{else}} + + {{/if}} +
+
+ +
+
+ + + + diff --git a/webgui/views/layout.hbs-es b/webgui/views/layout.hbs-es new file mode 100644 index 00000000..90b37230 --- /dev/null +++ b/webgui/views/layout.hbs-es @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + {{title}} + + + + + + + {{{body}}} + + + + + diff --git a/webgui/views/purchase.hbs-es b/webgui/views/purchase.hbs-es new file mode 100644 index 00000000..7814e727 --- /dev/null +++ b/webgui/views/purchase.hbs-es @@ -0,0 +1,40 @@ +
+
+
+ {{translate "Account"}} +
+
+

{{translate "Saldo actual: $"}}{{{renderCurrency balance}}}

+

{{translate "Datos Disponibles: "}}{{data_balance_str}}

+
+
+ +
+
+ {{translate "Comprar"}} +
+
+
+ {{#each pack}} +

+ {{this.currency_symbol}} + {{{renderCurrency this.print_cost}}}

+ {{/each}} +
+

+ +

+
+
+
diff --git a/webgui/views/services.hbs-es b/webgui/views/services.hbs-es new file mode 100644 index 00000000..1d1b2790 --- /dev/null +++ b/webgui/views/services.hbs-es @@ -0,0 +1,13 @@ +
+
+
+ {{! TODO: Add translation of this term! }} + {{translate "Servicios Web Gratuitos"}} +
+
+ {{#each services}} +

{{this.serviceName}}

+ {{/each}} +
+
+
\ No newline at end of file diff --git a/webgui/views/status.hbs-es b/webgui/views/status.hbs-es new file mode 100644 index 00000000..775b1bcf --- /dev/null +++ b/webgui/views/status.hbs-es @@ -0,0 +1,29 @@ +
+ +
+
+ {{translate "Información de la Cuenta"}} +
+
+

{{translate "Número de Teléfono"}}: {{msisdn}}

+

{{translate "Saldo Actual: $"}}{{{renderCurrency balance}}}

+

{{translate "Datos Disponibles: "}}{{data_balance_str}}

+

{{translate "Total Descarga: "}}{{raw_down_str}}

+

{{translate "Total Enviado: "}}{{raw_up_str}}

+
+
+ + + +
diff --git a/webgui/views/transfer.hbs-es b/webgui/views/transfer.hbs-es new file mode 100644 index 00000000..5ba0fcb4 --- /dev/null +++ b/webgui/views/transfer.hbs-es @@ -0,0 +1,39 @@ +
+
+
+ {{translate "Transfer"}} +
+
+

{{translate "Saldo actual: $"}}{{{renderCurrency balance}}}

+
+
+ + +
+
+ + +
+ +
+
+
+