{#- Package ru/libinstance provides common instance code for handling Radio Units and cells. Use buildout() macro to emit instance-level code to handle configured RUs. NOTE: before importing package slaplte.jinja2 needs to already loaded as {%- import 'slaplte.jinja2' as slaplte with context %} NOTE: driver-specific logic is implemented in rudrv.buildout_ru() . #} {#- cell_list keeps cell registry #} {%- set cell_list = {} %} {%- do slaplte.load_cell(cell_list) %} {%- macro buildout() %} {#- part emits new buildout section and registers it into buildout.parts #} {%- set parts_list = [] %} {%- macro part(name) %} {%- do parts_list.append(name) %} [{{ name }}] {%- endmacro %} {#- promise emits new buildout section for a promise #} {%- macro promise(name) %} {{ part('promise-'+name) }} <= monitor-promise-base name = {{ name }}.py config-testing = {{ slapparameter_dict.get("testing", False) }} config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }} {%- endmacro %} {#- import RU drivers #} {%- import 'ru_sdr_libinstance.jinja2.cfg' as rudrv_sdr with context %} {%- import 'ru_lopcomm_libinstance.jinja2.cfg' as rudrv_lopcomm with context %} {%- import 'ru_sunwave_libinstance.jinja2.cfg' as rudrv_sunwave with context %} {%- set rudrv_dict = namespace(sdr=rudrv_sdr, lopcomm=rudrv_lopcomm, sunwave=rudrv_sunwave) %} {#- split slapos tap interface for each RU fallback to non-split approach for ntap <= 1 to avoid hard-dependecy on setcap/tapsplit TODO Relying on setcap and tapsplit should be removed once SlapOS is improved to provide several TAP interfaces to instances. See discussion at https://lab.nexedi.com/nexedi/slapos/merge_requests/1471#note_194356 for details. #} {%- set ntap = len(list(cell_list|dictsort)) %} {%- set vtap_list = [] %} [vtap] recipe = plone.recipe.command ntap = {{ ntap }} command = {{ netcapdo }} {{ pythonwitheggs }} {{ ru_tapsplit }} {{ slaplte.tap }} ${:ntap} update-command = ${:command} stop-on-error = true {%- if ntap <= 1 %} [vtap] ntap = 0 stop-on-error = false {%- if ntap == 1 %} {%- do vtap_list.append(slaplte.tap) %} [vtap.{{ slaplte.tap }}] network = {{ slap_configuration['tap-ipv6-network'] }} gateway = {{ slap_configuration['tap-ipv6-gateway'] }} addr = {{ slap_configuration['tap-ipv6-addr'] }} {%- endif %} {%- else %} {%- for i in range(1,1+ntap) %} {%- set tap = '%s-%d' % (slaplte.tap, i) %} {%- do vtap_list.append(tap) %} [vtap.{{ tap }}] recipe = slapos.recipe.build depends = ${vtap:recipe} init = import types def readfile(path): with open(path) as f: return f.read() # ~ import tapsplit tapsplit = types.ModuleType('tapsplit') exec(readfile('{{ ru_tapsplit }}'), tapsplit.__dict__) # simulate what tapsplit would assign to the tap # ( tap subinterface will be created for real later at install time - when it # is too late to update section options ) slapnet = tapsplit.ifnet6('{{ slaplte.tap }}') tapnet = tapsplit.netsplit(slapnet, {{ 1+ntap }}) [{{ i }}] options['network'] = str(tapnet) options['gateway'] = str(tapnet[1]) options['addr'] = str(tapnet[-1]) {%- endfor %} {%- endif %} # vtap_jdict maps tapname -> json(interface-info) [vtap_jdict] recipe = slapos.recipe.build depends = {% for tap in vtap_list %} ${vtap.{{tap}}:addr} {% endfor %} init = import json {%- for tap in vtap_list %} tap = self.buildout['vtap.{{tap}}'] tap = {k: tap[k] for k in ('network', 'gateway', 'addr')} options['{{tap}}'] = json.dumps(tap) {%- endfor %} {#- provide CPRI-based RUs IP address via DHCP #} {%- if trx == 'cpri' %} [dnsmasq-config] recipe = slapos.recipe.template:jinja2 url = {{ru_dnsmasq_template}} filename = dnsmasq.cfg extensions = jinja2.ext.do output = ${directory:etc}/${:filename} context = import json_module json import netaddr netaddr section directory directory section vtap_jdict vtap_jdict json cell_list {{ cell_list | tojson }} {{ part('dnsmasq-service') }} recipe = slapos.cookbook:wrapper port = 5353 ip = ${slap-configuration:tun-ipv4-addr} command-line = {{ dnsmasq_location }}/sbin/dnsmasq --conf-file=${dnsmasq-config:output} -x ${directory:run}/dnsmasq.pid --local-service --keep-in-foreground wrapper-path = ${directory:service}/dnsmasq mode = 0775 hash-files = ${dnsmasq-config:output} # {# promise('dnsmasq-listen') #} #promise = check_socket_listening #config-host = ${dnsmasq-service:ip} #config-port = ${dnsmasq-service:port} {%- endif %} {#- go through all RUs and for each RU emit generic promises and invoke RU-specific buildout handler #} {%- set ru_type = {'lopcomm': 'lopcomm', 'm2ru': 'sunwave'}.get(ru, 'sdr') %} {%- set rudrv = rudrv_dict[ru_type] %} {%- for i, (cell_ref, cell) in enumerate(cell_list|dictsort) %} {%- set ru_ref = cell_ref if cell_ref != 'default' else 'RU' %} {%- set n_antenna_ul = int(slapparameter_dict.get('n_antenna_ul', default_n_antenna_ul)) %} # {{ ru_ref }} ({{ ru_type}}) {%- if trx == 'sdr' %} {{ promise('%s-sdr-busy' % ru_ref) }} promise = check_sdr_busy config-sdr = {{ sdr }} config-sdr_dev = 0 config-dma_chan = 0 {%- elif trx == 'cpri' %} {{ promise('%s-sdr-busy' % ru_ref) }} promise = check_sdr_busy config-sdr = {{ sdr }} config-sdr_dev = {{ slapparameter_dict.get('sdr_number', 0) }} config-dma_chan = {{ cell.cpri_port_number }} {{ promise('%s-cpri-lock' % ru_ref) }} promise = check_cpri_lock config-sdr_dev = {{ slapparameter_dict.get('sdr_number', 0) }} config-sfp_port = {{ cell.cpri_port_number }} config-amarisoft-rf-info-log = ${amarisoft-rf-info-template:log-output} {%- else %} {%- do bug('unreachable') %} {%- endif %} {{ promise('%s-rx-saturated' % ru_ref) }} promise = check_rx_saturated config-rf-rx-chan-list = {{ list(range(i*n_antenna_ul, (i+1)*n_antenna_ul)) }} config-amarisoft-stats-log = ${amarisoft-stats-template:log-output} config-max-rx-sample-db = {{ slapparameter_dict.get("max_rx_sample_db", 0) }} {#- driver-specific part #} {{ rudrv.buildout_ru(ru_ref, cell) }} {%- endfor %} [buildout] parts += {%- for part in parts_list %} {{ part }} {%- endfor %} {%- endmacro %}