--- accesspoint_wired_interface: eth0 accesspoint_wireless_frequency_bands: - 2g - 5g accesspoint_wifi_device_htmode: 2g: "HT20" 5g: "VHT80" accesspoint_wireless_device_paths: 2g: "platform/ahb/18100000.wmac" 5g: "pci0000:00/0000:00:00.0" accesspoint_network_base: "{{ accesspoint_network_base_yaml | from_yaml }}" accesspoint_network_base_yaml: | - name: globals 'globals' options: ula_prefix: "fc{{ '%02x:%04x:%04x' | format((255 | random(seed=inventory_hostname + '0')), (65535 | random(seed=inventory_hostname + '1')), (65535 | random(seed=inventory_hostname + '2'))) }}::/48" - name: interface 'loopback' options: device: lo proto: static ipaddr: 127.0.0.1 netmask: 255.0.0.0 {% if 'vlan' in network_mgmt_zone %} - name: device options: type: 8021q ifname: "{{ accesspoint_wired_interface }}" vid: {{ network_mgmt_zone.vlan }} name: "{{ accesspoint_wired_interface }}.{{ network_mgmt_zone.vlan }}" {% endif %} - name: interface 'mgmt' options: device: "{{ accesspoint_wired_interface }}{% if 'vlan' in network_mgmt_zone %}.{{ network_mgmt_zone.vlan }}{% endif %}" accept_ra: 0 proto: static ipaddr: "{{ network_mgmt_zone.prefix | ansible.utils.ipaddr(network_mgmt_zone.offsets[inventory_hostname]) }}" accesspoint_network_zones: "{{ accesspoint_network_zones_yaml | from_yaml }}" accesspoint_network_zones_yaml: | {% for zone_name in accesspoint_zones.keys() %} - name: device options: type: 8021q ifname: "{{ accesspoint_wired_interface }}" vid: {{ network_zones[zone_name].vlan }} name: "{{ accesspoint_wired_interface }}.{{ network_zones[zone_name].vlan }}" - name: device options: type: bridge name: "br-{{ zone_name }}" ports: - "{{ accesspoint_wired_interface }}.{{ network_zones[zone_name].vlan }}" - name: "interface '{{ zone_name }}'" options: device: "br-{{ zone_name }}" accept_ra: 0 proto: none {% endfor %} accesspoint_wireless_devices: "{{ accesspoint_wireless_devices_yaml | from_yaml }}" accesspoint_wireless_devices_yaml: | {% for band in accesspoint_wireless_frequency_bands %} - name: wifi-device 'radio{{ band }}' options: type: 'mac80211' channel: "{{ accesspoint_wifi_channels[band][inventory_hostname] }}" band: '{{ band }}' country: AT path: "{{ accesspoint_wireless_device_paths[band] }}" htmode: '{{ accesspoint_wifi_device_htmode[band] }}' cell_density: '0' {% set txpower = accesspoint_wifi_txpower[band][inventory_hostname] %} {% if txpower is defined %} txpower: '{{ txpower }}' {% endif %} {% endfor %} accesspoint_wireless_ifaces: "{{ accesspoint_wireless_ifaces_yaml | from_yaml }}" accesspoint_wireless_ifaces_yaml: | {% for zone in accesspoint_zones.keys() %} {% set outer_loop = loop %} {% for band in accesspoint_wireless_frequency_bands %} - name: wifi-iface '{{ zone }}{{ band }}' options: device: 'radio{{ band }}' network: '{{ zone }}' mode: 'ap' ssid: '{{ accesspoint_zones[zone].ssid }}' encryption: '{{ accesspoint_zones[zone].encryption }}' key: '{{ accesspoint_zones[zone].key }}' disassoc_low_ack: '1' rsn_preauth: '1' {% if accesspoint_80211r is defined %} ieee80211r: '1' mobility_domain: '{{ "%04x" % (accesspoint_80211r.mobility_domain_base + outer_loop.index0) }}' ft_over_ds: '1' {% endif %} {% if accesspoint_client_steering is defined %} bss_transition: '1' wnm_sleep_mode: '1' time_advertisement: '2' time_zone: 'CET-1CEST,M3.5.0,M10.5.0/3' ieee80211k: '1' rrm_neighbor_report: '1' rrm_beacon_report: '1' {% endif %} {% endfor %} {% endfor %} openwrt_arch: ath79 openwrt_target: generic openwrt_profile: ubnt_unifiac-lite openwrt_output_image_suffixes: - "{{ openwrt_target }}-{{ openwrt_profile }}-squashfs-sysupgrade.bin" openwrt_packages_remove: - ppp - ppp-mod-pppoe - dnsmasq - firewall - firewall4 - odhcpd - odhcpd-ipv6only - wpad-basic-mbedtls openwrt_packages_add: - hostapd-mbedtls - haveged - htop - ip - nftables - less - nano - tcpdump-mini - horst - prometheus-node-exporter-lua - prometheus-node-exporter-lua-netstat - prometheus-node-exporter-lua-openwrt ## we will install a custom version of these collectors, see below #- prometheus-node-exporter-lua-wifi #- prometheus-node-exporter-lua-wifi_stations ## manually install dependencies for wifi-collectors - libiwinfo-lua - libubus-lua _accesspoint_client_steering_packages_extra_: none: [] dawn: - dawn usteer: - usteer openwrt_packages_extra: "{{ _accesspoint_client_steering_packages_extra_[accesspoint_client_steering.kind | default('none')] }}" openwrt_mixin: /etc/sysctl.conf: content: | # Defaults are configured in /etc/sysctl.d/* and can be customized in this file # # disable IP forwarding, we don't need it since we are # only an AP that bridges VLANs to Wifi SSIDs net.ipv4.conf.default.forwarding=0 net.ipv4.conf.all.forwarding=0 net.ipv4.ip_forward=0 net.ipv6.conf.default.forwarding=0 net.ipv6.conf.all.forwarding=0 /etc/dropbear/authorized_keys: content: "{{ ssh_keys_root | join('\n') }}\n" /etc/htoprc: file: "{{ global_files_dir }}/common/htoprc" /etc/rc.d/S21nftables: link: "../init.d/nftables" /etc/rc.d/K89nftables: link: "../init.d/nftables" /etc/init.d/nftables: mode: "0755" content: | #!/bin/sh /etc/rc.common START=21 STOP=89 start() { nft -f /etc/nftables.conf } stop() { nft flush ruleset } /etc/nftables.conf: content: | flush ruleset define nic_mgmt = {{ accesspoint_wired_interface }}.{{ network_zones.mgmt.vlan }} table inet global { chain input { type filter hook input priority filter; policy drop; ct state vmap { established: accept, related: accept, invalid: drop } iifname vmap { lo: accept, $nic_mgmt: accept } } chain forward { type filter hook forward priority filter; policy drop; } } /usr/lib/lua/prometheus-collectors/wifi.lua: mode: "0755" content: | -- This is a custom version of the upstream wifi and wifi_stations collectors. We want -- to know the number of stations connected but for privacy and metric cardinality -- reasons we don't care for MAC addresses and other details of all connected stations. local ubus = require "ubus" local iwinfo = require "iwinfo" local function scrape() local metric_wifi_network_quality = metric("wifi_network_quality","gauge") local metric_wifi_network_bitrate = metric("wifi_network_bitrate","gauge") local metric_wifi_network_noise = metric("wifi_network_noise_dbm","gauge") local metric_wifi_network_signal = metric("wifi_network_signal_dbm","gauge") local metric_wifi_stations = metric("wifi_stations", "gauge") local u = ubus.connect() local status = u:call("network.wireless", "status", {}) for dev, dev_table in pairs(status) do for _, intf in ipairs(dev_table['interfaces']) do local ifname = intf['ifname'] if ifname ~= nil then local iw = iwinfo[iwinfo.type(ifname)] local labels = { channel = iw.channel(ifname), ssid = iw.ssid(ifname), bssid = string.lower(iw.bssid(ifname)), mode = iw.mode(ifname), ifname = ifname, country = iw.country(ifname), frequency = iw.frequency(ifname), device = dev, } local qc = iw.quality(ifname) or 0 local qm = iw.quality_max(ifname) or 0 local quality = 0 if qc > 0 and qm > 0 then quality = math.floor((100 / qm) * qc) end local stations = 0 local assoclist = iw.assoclist(ifname) for _, _ in pairs(assoclist) do stations = stations + 1 end metric_wifi_network_quality(labels, quality) metric_wifi_network_noise(labels, iw.noise(ifname) or 0) metric_wifi_network_bitrate(labels, iw.bitrate(ifname) or 0) metric_wifi_network_signal(labels, iw.signal(ifname) or -255) metric_wifi_stations(labels, stations) end end end end return { scrape = scrape } /usr/bin/list-stations: mode: "0755" file: "{{ global_files_dir }}/common/openwrt/list-stations" openwrt_uci_base: system: - name: system options: hostname: '{{ inventory_hostname }}' timezone: 'CET-1CEST,M3.5.0,M10.5.0/3' ttylogin: '0' log_size: '64' urandom_seed: '0' - name: timeserver 'ntp' options: enabled: '{{ accesspoint_ntp_servers is defined | ternary("1", "0") }}' enable_server: '0' server: "{{ accesspoint_ntp_servers | default([]) }}" - name: led options: sysfs: blue:dome trigger: none - name: led options: sysfs: white:dome trigger: default-on default: 0 dropbear: - name: dropbear options: PasswordAuth: 'off' RootPasswordAuth: 'off' Port: '{{ ansible_port }}' uhttpd: - name: uhttpd main options: enabled: '0' prometheus-node-exporter-lua: - name: prometheus-node-exporter-lua 'main' options: listen_interface: 'mgmt' listen_port: '9100' network: "{{ accesspoint_network_base + accesspoint_network_zones }}" wireless: "{{ accesspoint_wireless_devices + accesspoint_wireless_ifaces }}" _accesspoint_client_steering_options_default_: dawn: network: broadcast_ip: "{{ network_mgmt_zone.prefix | ansible.utils.ipaddr('broadcast') }}" usteer: network: 'mgmt' syslog: '1' local_mode: '0' ipv6: '0' debug_level: '2' openwrt_uci_client_steering: "{{ openwrt_uci_client_steering_yaml | from_yaml }}" openwrt_uci_client_steering_yaml: | {% if accesspoint_client_steering is defined %} {% if accesspoint_client_steering.kind == 'dawn' %} umdns: - name: umds options: jail: '1' network: - mgmt dawn: {% for section, options in (_accesspoint_client_steering_options_default_.dawn | combine(accesspoint_client_steering.options | default({}))).items() %} - name: {{ section }} options: {% for option, value in options.items() %} {{ option }}: {{ value }} {% endfor %} {% endfor %} {% elif accesspoint_client_steering.kind == 'usteer' %} usteer: - name: usteer options: {% for option,value in (_accesspoint_client_steering_options_default_.usteer | combine(accesspoint_client_steering.options | default({}))).items() %} {{ option }}: {{ value }} {% endfor %} {% endif %} {% endif %} openwrt_uci: "{{ openwrt_uci_base | combine(accesspoint_client_steering is defined | ternary(openwrt_uci_client_steering, {})) }}"