Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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).
Expand Down
16 changes: 16 additions & 0 deletions conf/open5gs_dbconf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}

Expand Down Expand Up @@ -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
119 changes: 64 additions & 55 deletions python/colteconf_cn_4g.py
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down Expand Up @@ -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())
Expand All @@ -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
Expand All @@ -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"]
Expand All @@ -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
Expand Down Expand Up @@ -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")
18 changes: 18 additions & 0 deletions python/coltedb.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")


Expand Down Expand Up @@ -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()
3 changes: 3 additions & 0 deletions python/coltedb_cn_4g.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
71 changes: 71 additions & 0 deletions webadmin/views/home.hbs-es
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<main role="main" class="container">

<div class="card mb-3">
<div class="card-header">
{{translate "Recargar Saldo Usuario"}}
</div>
<div class="card-body">
<form method="post" action="/home/topup">
<div class="form-group">
<label for="recipient">IMSI</label>
<input
type="tel"
id="formnumber"
class="form-control"
placeholder="{{translate 'IMSI'}}"
name="imsi"
/>
</div>
<div class="form-group">
<label for="amount">{{translate "Cantidad a Recargar"}}</label>
<input type="text" id="formamount" class="form-control" name="amount" />
</div>
<button
type="submit"
class="btn btn-primary"
onclick="return confirm('Esta seguro de que desea recargar ' + document.getElementById('formamount').value + ' pesos a la persona usuaria ' + document.getElementById('formnumber').value + '?');"
>{{translate "Recargar"}}</button>
</form>
</div>
</div>

<div class="card mb-3">
<div class="card-header">
{{translate "Transferencia entre Usuarixs"}}
</div>
<div class="card-body">
<form method="post" action="/home/transfer">
<div class="form-group">
<label for="recipient">{{translate "IMSI que Envia"}}</label>
<input
type="tel"
id="formsend"
class="form-control"
placeholder="{{translate 'Numero Telefonico'}}"
name="source"
/>
<label for="recipient">{{translate "IMSI que Recibe"}}</label>
<input
type="tel"
id="formreceive"
class="form-control"
placeholder="{{translate 'Numero Telefonico'}}"
name="dest"
/>
</div>
<div class="form-group">
<label for="amount">{{translate "Cantidad a transferir"}}</label>
<input type="text" id="formtransferamount" class="form-control" name="amount" />
</div>
<button
type="submit"
class="btn btn-primary"
onclick="return confirm({{translate
"'Estas seguro que quieres transferir ' + document.getElementById('formtransferamount').value + ' pesos del usuario ' + document.getElementById('formsend').value + ' al usuario ' + document.getElementById('formreceive').value + '?'"
}});"
>{{translate "Transferir"}}</button>
</form>
</div>
</div>
</main>

Loading