#/*
# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# * contributor license agreements.  See the NOTICE file distributed with
# * this work for additional information regarding copyright ownership.
# * The OpenAirInterface Software Alliance licenses this file to You under
# * the OAI Public License, Version 1.1  (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.openairinterface.org/?page_id=698
# *
# * 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.
# *-------------------------------------------------------------------------------
# * For more information about the OpenAirInterface (OAI) Software Alliance:
# *      contact@openairinterface.org
# */
#---------------------------------------------------------------------

import os
import re
import sys
import ipaddress

class spgwcConfigGen():
	def __init__(self):
		self.kind = ''
		self.s11c_name = ''
		self.sxc_name = ''
		self.prefix = ''
		self.fromDockerFile = False
		self.apn_list = ''
		self.pdn_list = ''
		self.dns1 = ''
		self.dns2 = ''
		self.s5p5 = 'auto'

	def GenerateSpgwcConfigurer(self):
		apns = self.apn_list.split();
		pdns = self.pdn_list.split();
		conf_file = open('./spgw_c.conf', 'w')
		conf_file.write('# generated by generate_spgwc_config_script.py\n')
		conf_file.write('S-GW =\n')
		conf_file.write('{\n')
		conf_file.write('    INSTANCE = 0; # 0 is the default\n')
		conf_file.write('    PID_DIRECTORY  = "/var/run";  # /var/run is the default\n')
		conf_file.write('    #ITTI_TASKS :\n')
		conf_file.write('    #{\n')
		conf_file.write('	#ITTI_TIMER_SCHED_PARAMS :\n')
		conf_file.write('	#{\n')
		conf_file.write('	    #CPU_ID       = 1;\n')
		conf_file.write('	    #SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('	    #SCHED_PRIORITY = 85;\n')
		conf_file.write('	#};\n')
		conf_file.write('	#S11_SCHED_PARAMS :\n')
		conf_file.write('	#{\n')
		conf_file.write('	    #CPU_ID       = 1;\n')
		conf_file.write('	    #SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('	    #SCHED_PRIORITY = 84;\n')
		conf_file.write('	#};\n')
		conf_file.write('	#S5S8_SCHED_PARAMS :\n')
		conf_file.write('	#{\n')
		conf_file.write('	    #CPU_ID       = 1;\n')
		conf_file.write('	    #SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('	    #SCHED_PRIORITY = 84;\n')
		conf_file.write('	#};\n')
		conf_file.write('	#SX_SCHED_PARAMS :\n')
		conf_file.write('	#{\n')
		conf_file.write('	    #CPU_ID       = 1;\n')
		conf_file.write('	    #SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('	    #SCHED_PRIORITY = 84;\n')
		conf_file.write('	#};\n')
		conf_file.write('	#SGW_APP_SCHED_PARAMS :\n')
		conf_file.write('	#{\n')
		conf_file.write('	    #CPU_ID       = 1;\n')
		conf_file.write('	    #SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('	    #SCHED_PRIORITY = 84;\n')
		conf_file.write('	#};\n')
		conf_file.write('	#ASYNC_CMD_SCHED_PARAMS :\n')
		conf_file.write('	#{\n')
		conf_file.write('	    #CPU_ID       = 1;\n')
		conf_file.write('	    #SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('	    #SCHED_PRIORITY = 84;\n')
		conf_file.write('	#};\n')
		conf_file.write('    #};\n')

		conf_file.write('    INTERFACES :\n')
		conf_file.write('    {\n')
		conf_file.write('	S11_CP :\n')
		conf_file.write('	{\n')
		conf_file.write('	    # S-GW binded interface for S11 communication (GTPV2-C), if none selected the ITTI message interface is used\n')
		conf_file.write('	    INTERFACE_NAME	 = "'+self.s11c_name+'";       # STRING, interface name, YOUR NETWORK CONFIG HERE\n')
		conf_file.write('	    IPV4_ADDRESS	   = "read";	  # STRING, CIDR or "read" to let app read interface configured IP address, YOUR NETWORK CONFIG HERE\n')
		conf_file.write('	    #PORT		   = 2123;	   # INTEGER, port number, PREFER NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING\n')
		conf_file.write('	    #SCHED_PARAMS :			   # SCHEADULING PARAMS OF THE LOOPING RECEIVER THREAD BOUND TO THIS INTERFACE/PROTOCOL\n')
		conf_file.write('	    #{\n')
		conf_file.write('		#CPU_ID       = 1;\n')
		conf_file.write('		#SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('		#SCHED_PRIORITY = 95;\n')
		conf_file.write('	    #};\n')
		conf_file.write('	};\n')
		conf_file.write('	S5_S8_CP :\n')
		conf_file.write('	{\n')
		conf_file.write('	    # S-GW binded interface for S5 or S8 communication\n')
		if self.s5p5 == 'auto':
			conf_file.write('	    INTERFACE_NAME	 = "lo"; # STRING, interface name\n')
			conf_file.write('	    IPV4_ADDRESS	   = "127.0.8.1/8";	  # STRING, CIDR or "read" to let app read interface configured IP address\n')
		else:
			conf_file.write('	    INTERFACE_NAME	 = "lo:s5c"; # STRING, interface name\n')
			conf_file.write('	    IPV4_ADDRESS	   = "read";	  # STRING, CIDR or "read" to let app read interface configured IP address\n')
		conf_file.write('	    #PORT		   = 2123;	   # INTEGER, port number, PREFER NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING\n')
		conf_file.write('	    #SCHED_PARAMS :			   # SCHEADULING PARAMS OF THE LOOPING RECEIVER THREAD BOUND TO THIS INTERFACE/PROTOCOL\n')
		conf_file.write('	    #{\n')
		conf_file.write('		#CPU_ID       = 1;\n')
		conf_file.write('		#SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('		#SCHED_PRIORITY = 95;\n')
		conf_file.write('	    #};\n')
		conf_file.write('	};\n')
		conf_file.write('    };\n')
		conf_file.write('};\n')

		conf_file.write('P-GW =\n')
		conf_file.write('{\n')
		conf_file.write('    INSTANCE = 0;	  # 0 is the default\n')
		conf_file.write('    PID_DIRECTORY = "/var/run"; # /var/run is the default\n')

		conf_file.write('    #ITTI_TASKS :\n')
		conf_file.write('    #{\n')
		conf_file.write('	#ITTI_TIMER_SCHED_PARAMS :\n')
		conf_file.write('	#{\n')
		conf_file.write('	    #CPU_ID       = 1;\n')
		conf_file.write('	    #SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('	    #SCHED_PRIORITY = 85;\n')
		conf_file.write('	#};\n')
		conf_file.write('	#S11_SCHED_PARAMS :\n')
		conf_file.write('	#{\n')
		conf_file.write('	    #CPU_ID       = 1;\n')
		conf_file.write('	    #SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('	    #SCHED_PRIORITY = 84;\n')
		conf_file.write('	#};\n')
		conf_file.write('	#S5S8_SCHED_PARAMS :\n')
		conf_file.write('	#{\n')
		conf_file.write('	    #CPU_ID       = 1;\n')
		conf_file.write('	    #SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('	    #SCHED_PRIORITY = 84;\n')
		conf_file.write('	#};\n')
		conf_file.write('	#SX_SCHED_PARAMS :\n')
		conf_file.write('	#{\n')
		conf_file.write('	    #CPU_ID       = 1;\n')
		conf_file.write('	    #SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('	    #SCHED_PRIORITY = 84;\n')
		conf_file.write('	#};\n')
		conf_file.write('	#PGW_APP_SCHED_PARAMS :\n')
		conf_file.write('	#{\n')
		conf_file.write('	    #CPU_ID       = 1;\n')
		conf_file.write('	    #SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('	    #SCHED_PRIORITY = 84;\n')
		conf_file.write('	#};\n')
		conf_file.write('	#ASYNC_CMD_SCHED_PARAMS :\n')
		conf_file.write('	#{\n')
		conf_file.write('	    #CPU_ID       = 1;\n')
		conf_file.write('	    #SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('	    #SCHED_PRIORITY = 84;\n')
		conf_file.write('	#};\n')
		conf_file.write('    #};\n')

		conf_file.write('    INTERFACES :\n')
		conf_file.write('    {\n')
		conf_file.write('	S5_S8_CP :\n')
		conf_file.write('	{\n')
		conf_file.write('	    # P-GW binded interface for S5 or S8 communication\n')
		if self.s5p5 == 'auto':
			conf_file.write('	    INTERFACE_NAME	 = "lo"; # STRING, interface name\n')
			conf_file.write('	    IPV4_ADDRESS	   = "127.0.8.2/8";			      # STRING, CIDR or "read" to let app read interface configured IP address\n')
		else:
			conf_file.write('	    INTERFACE_NAME	 = "lo:p5c"; # STRING, interface name\n')
			conf_file.write('	    IPV4_ADDRESS	   = "read";			      # STRING, CIDR or "read" to let app read interface configured IP address\n')
		conf_file.write('	    #PORT		   = 2123;\n')
		conf_file.write('	    #SCHED_PARAMS :			   # SCHEADULING PARAMS OF THE LOOPING RECEIVER THREAD BOUND TO THIS INTERFACE/PROTOCOL\n')
		conf_file.write('	    #{\n')
		conf_file.write('		#CPU_ID       = 1;\n')
		conf_file.write('		#SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('		#SCHED_PRIORITY = 95;\n')
		conf_file.write('	    #};\n')
		conf_file.write('	};\n')
		conf_file.write('	SX :\n')
		conf_file.write('	{\n')
		conf_file.write('	    # P-GW binded interface for SX communication\n')
		conf_file.write('	    INTERFACE_NAME	 = "'+self.sxc_name+'"; # STRING, interface name\n')
		conf_file.write('	    IPV4_ADDRESS	   = "read";			# STRING, CIDR or "read" to let app read interface configured IP address\n')
		conf_file.write('	    #PORT		   = 8805;\n')
		conf_file.write('	    #SCHED_PARAMS :			   # SCHEADULING PARAMS OF THE LOOPING RECEIVER THREAD BOUND TO THIS INTERFACE/PROTOCOL\n')
		conf_file.write('	    #{\n')
		conf_file.write('		#CPU_ID       = 1;\n')
		conf_file.write('		#SCHED_POLICY = "SCHED_FIFO"; # Values in { SCHED_OTHER, SCHED_IDLE, SCHED_BATCH, SCHED_FIFO, SCHED_RR }\n')
		conf_file.write('		#SCHED_PRIORITY = 95;\n')
		conf_file.write('	    #};\n')
		conf_file.write('	};\n')
		conf_file.write('    };\n')
		conf_file.write('    # Pool of UE assigned IP addresses\n')
		conf_file.write('    # Do not make IP pools overlap\n')
		conf_file.write('    # first IPv4 address X.Y.Z.1 is reserved for GTP network device on SPGW\n')
		conf_file.write('    # Normally no more than 96 pools allowed, but for non OVS GTP solution, only one pool allowed (TODO).\n')
		conf_file.write('    IP_ADDRESS_POOL :\n')
		conf_file.write('    {\n')
		conf_file.write('	IPV4_LIST = (\n')
		for pdn in pdns[ 0:len(pdns)-1 ]:
			hosts = list(ipaddress.ip_network(pdn).hosts())
			conf_file.write('		      {RANGE = "'+str(hosts[1])+' - '+str(hosts[-2])+'";}, # STRING, IPv4 RANGE IP_start - IP_end, YOUR NETWORK CONFIG HERE.\n')
		pdn = pdns[len(pdns) - 1]
		hosts = list(ipaddress.ip_network(pdn).hosts())
		conf_file.write('		      {RANGE = "'+str(hosts[1])+' - '+str(hosts[-2])+'";}  # STRING, IPv4 RANGE IP_start - IP_end, YOUR NETWORK CONFIG HERE.\n')
		conf_file.write('		    );\n')
		conf_file.write('	IPV6_LIST = (\n')
		conf_file.write('		      {PREFIX = "2001:1:2::/64";}, # STRING, IPv6 prefix, YOUR NETWORK CONFIG HERE.\n')
		conf_file.write('		      {PREFIX = "3001:1:2::/64";}, # STRING, IPv6 prefix, YOUR NETWORK CONFIG HERE.\n')
		conf_file.write('		      {PREFIX = "4001:1:2::/64";}  # STRING, IPv6 prefix, YOUR NETWORK CONFIG HERE.\n')
		conf_file.write('		    );\n')
		conf_file.write('    };\n')
		conf_file.write('    APN_LIST = (\n')
		conf_file.write('       # IPV4_POOL, IPV6_POOL are index in IPV4_LIST, IPV6_LIST, PDN_TYPE choice in {IPv4, IPv6, IPv4v6}\n')
		i = 0
		for apn in apns[ 0:len(apns)-1 ]:
			conf_file.write('      {APN_NI = "'+apn+'"; PDN_TYPE = "IPv4"; IPV4_POOL  = '+str(i)+'; IPV6_POOL = -1},\n')
			i += 1
		apn = apns[len(apns) - 1]
		conf_file.write('      {APN_NI = "'+apn+'"; PDN_TYPE = "IPv4"; IPV4_POOL  = '+str(i)+'; IPV6_POOL = -1}\n')
		conf_file.write('    );\n')
		conf_file.write('    # DNS address communicated to UEs\n')
		conf_file.write('    DEFAULT_DNS_IPV4_ADDRESS     = "'+self.dns1+'"; # YOUR NETWORK CONFIG HERE\n')
		conf_file.write('    DEFAULT_DNS_SEC_IPV4_ADDRESS = "'+self.dns2+'"; # YOUR NETWORK CONFIG HERE\n')
		conf_file.write('    DEFAULT_DNS_IPV6_ADDRESS     = "2001:4860:4860::8888"; # FFU\n')
		conf_file.write('    DEFAULT_DNS_SEC_IPV6_ADDRESS = "2001:4860:4860::8844"; # FFU\n')
		conf_file.write('    # Non standard feature, normally should be set to "no", but you may need to set to yes for UE that do not explicitly request a PDN address through NAS signalling\n')
		conf_file.write('    FORCE_PUSH_PROTOCOL_CONFIGURATION_OPTIONS = "no";  # STRING, {"yes", "no"}.\n')
		conf_file.write('    PCEF :\n')
		conf_file.write('    {\n')
		conf_file.write('      # Waiting for HSS APN-AMBR IE ...\n')
		conf_file.write('      APN_AMBR_UL			     = 500000; # Maximum UL bandwidth that can be used by non guaranteed bit rate traffic in Kbits/seconds.\n')
		conf_file.write('      APN_AMBR_DL			     = 500000; # Maximum DL bandwidth that can be used by non guaranteed bit rate traffic in Kbits/seconds.\n')
		conf_file.write('    };\n')
		conf_file.write('};\n')
		conf_file.close()

		if self.s5p5 == 'prod':
			spgwcFile = open('./spgwc-cfg.sh', 'w')
			spgwcFile.write('#!/bin/bash\n')
			spgwcFile.write('\n')
			spgwcFile.write('ifconfig lo:s5c 127.0.0.15 up\n')
			spgwcFile.write('echo "ifconfig lo:s5c 127.0.0.15 up --> OK"\n')
			spgwcFile.write('ifconfig lo:p5c 127.0.0.16 up\n')
			spgwcFile.write('echo "ifconfig lo:p5c 127.0.0.16 up --> OK"\n')
			spgwcFile.write('exit 0\n')
			spgwcFile.close()


#-----------------------------------------------------------
# Usage()
#-----------------------------------------------------------
def Usage():
	print('----------------------------------------------------------------------------------------------------------------------')
	print('generate_spgwc_config_script.py')
	print('   Prepare a bash script to be run in the workspace where SPGW-C is being built.')
	print('   That bash script will copy configuration template files and adapt to your configuration.')
	print('----------------------------------------------------------------------------------------------------------------------')
	print('Usage: python3 generate_spgwc_config_script.py [options]')
	print('  --help  Show this help.')
	print('------------------------------------------------------------------------------------------------- SPGW-C Options -----')
	print('  --kind=SPGW-C')
	print('  --s11c=[SPGW-C S11 Interface Name]')
	print('  --sxc=[SPGW-C SX Interface Name]')
	print('  --apn_list=["APNs"]')
	print('  --pdn_list=["PDNs"]')
	print('  --prefix=["Prefix for configuration files"]')
	print('  --from_docker_file')

argvs = sys.argv
argc = len(argvs)
cwd = os.getcwd()

mySpgwcCfg =  spgwcConfigGen()

while len(argvs) > 1:
	myArgv = argvs.pop(1)
	if re.match('^\-\-help$', myArgv, re.IGNORECASE):
		Usage()
		sys.exit(0)
	elif re.match('^\-\-kind=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-kind=(.+)$', myArgv, re.IGNORECASE)
		mySpgwcCfg.kind = matchReg.group(1)
	elif re.match('^\-\-s11c=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-s11c=(.+)$', myArgv, re.IGNORECASE)
		mySpgwcCfg.s11c_name = matchReg.group(1)
	elif re.match('^\-\-sxc=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-sxc=(.+)$', myArgv, re.IGNORECASE)
		mySpgwcCfg.sxc_name = matchReg.group(1)
	elif re.match('^\-\-dns1=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-dns1=(.+)$', myArgv, re.IGNORECASE)
		mySpgwcCfg.dns1 = matchReg.group(1)
	elif re.match('^\-\-dns2=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-dns2=(.+)$', myArgv, re.IGNORECASE)
		mySpgwcCfg.dns2 = matchReg.group(1)
	elif re.match('^\-\-apn_list=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-apn_list=(.+)$', myArgv, re.IGNORECASE)
		mySpgwcCfg.apn_list = str(matchReg.group(1))
	elif re.match('^\-\-pdn_list=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-pdn_list=(.+)$', myArgv, re.IGNORECASE)
		mySpgwcCfg.pdn_list = str(matchReg.group(1))
	elif re.match('^\-\-prefix=(.+)$', myArgv, re.IGNORECASE):
		matchReg = re.match('^\-\-prefix=(.+)$', myArgv, re.IGNORECASE)
		mySpgwcCfg.prefix = matchReg.group(1)
	elif re.match('^\-\-from_docker_file', myArgv, re.IGNORECASE):
		mySpgwcCfg.fromDockerFile = True
	elif re.match('^\-\-s5p5_production', myArgv, re.IGNORECASE):
		mySpgwcCfg.s5p5 = 'prod'
	else:
		Usage()
		sys.exit('Invalid Parameter: ' + myArgv)

if mySpgwcCfg.kind == '':
	Usage()
	sys.exit('missing kind parameter')

if mySpgwcCfg.kind == 'SPGW-C':
	if mySpgwcCfg.s11c_name == '':
		Usage()
		sys.exit('missing S11 Interface Name on SPGW-C container')
	elif mySpgwcCfg.sxc_name == '':
		Usage()
		sys.exit('missing SX Interface Name on SPGW-C container')
	elif mySpgwcCfg.apn_list == '':
		Usage()
		sys.exit('missing apn_list')
	elif mySpgwcCfg.pdn_list == '':
		Usage()
		sys.exit('missing pdn_list')
	elif mySpgwcCfg.dns1 == '':
		Usage()
		sys.exit('missing primary DNS')
	elif mySpgwcCfg.dns2 == '':
		Usage()
		sys.exit('missing secondary DNS')
	elif mySpgwcCfg.prefix == '':
		Usage()
		sys.exit('missing prefix')
	else:
		mySpgwcCfg.GenerateSpgwcConfigurer()
		sys.exit(0)
else:
	Usage()
	sys.exit('invalid kind parameter')
