Skip to content
Snippets Groups Projects
Commit 7a5ee44c authored by Reinder Kraaij's avatar Reinder Kraaij :eye:
Browse files

Merge branch 'COB-328-multicast-destinations' into 'master'

Resolve COB-328 "Multicast destinations"

Closes COB-328

See merge request !1093
parents e5706383 ce94a86f
No related branches found
No related tags found
1 merge request!1093Resolve COB-328 "Multicast destinations"
......@@ -133,15 +133,18 @@ render_CDB_environment_ilt:
python -m pip install .
# fetch IPs from netbox (netbox.astron.nl)
curl -X GET -k 'https://10.87.2.131/api/ipam/ip-addresses/?dns_name__isw=lcu-&limit=100' -H 'Accept: application/json' -H "Authorization: Token ${NETBOX_TOKEN}" > netbox.json
curl -X GET -k 'https://10.87.2.131/api/ipam/ip-addresses/?dns_name__isw=lcu-&limit=100' -H 'Accept: application/json' -H "Authorization: Token ${NETBOX_TOKEN}" > netbox-lcu-ips.json
curl -X GET -k 'https://10.87.2.131/api/ipam/prefixes/?description__ic=multicast%20range' -H 'accept: application/json' -H "Authorization: Token ${NETBOX_TOKEN}" > netbox-data-networks.json
mkdir -p generated/CDB/environments
for STATION in ${LOFAR2_STATIONS}; do
LCU_IP=`jq < netbox.json '.results[] | select(.dns_name == "lcu-'${STATION}'.data.lofar.eu") | .address | split("/") | .[0]' -r`
LCU_IP=`jq < netbox-lcu-ips.json '.results[] | select(.dns_name == "lcu-'${STATION}'.data.lofar.eu") | .address | split("/") | .[0]' -r`
echo "Generating CDB for ${STATION} using LCU IP ${LCU_IP}"
l2ss-generate-cdb-datastreams -s ${STATION} -l ${LCU_IP} > generated/CDB/environments/${STATION}-ilt.json
DATA_NETWORK=`jq < netbox-data-networks.json '.results[] | select(.description | test("'${STATION}' multicast range"; "i")) | .prefix' -r`
echo "Generating CDB for ${STATION} using LCU IP ${LCU_IP} DATA NETWORK ${DATA_NETWORK}"
l2ss-generate-cdb-datastreams -s ${STATION} -l ${LCU_IP} -d ${DATA_NETWORK} > generated/CDB/environments/${STATION}-ilt.json
done
artifacts:
expire_in: 4 weeks
......
......@@ -2,7 +2,7 @@
# Copyright (C) 2025 ASTRON (Netherlands Institute for Radio Astronomy)
# SPDX-License-Identifier: Apache-2.0
from ipaddress import IPv4Address
from ipaddress import IPv4Address, IPv4Network
from typing import Dict, List
from tangostationcontrol.toolkit._cdb import CDB
......@@ -10,10 +10,22 @@ from tangostationcontrol.toolkit._cdb import CDB
N_pol = 2
def multicast_mac(multicast_ip: IPv4Address) -> str:
"""Compute the Multicast destination MAC address from its IP address"""
# see f.e. https://technet.microsoft.com/en-us/library/cc957928.aspx
lower_23bits = int(multicast_ip) & 0x7FF
lower_hex = f"{lower_23bits:06x}"
return f"01:00:5e:{lower_hex[0:2]}:{lower_hex[2:4]}:{lower_hex[4:6]}"
class StationData:
def __init__(self, station, lcu_ip: IPv4Address, resolver=None):
def __init__(
self, station, lcu_ip: IPv4Address, data_network: IPv4Network, resolver=None
):
self.station = station
self.lcu_ip = lcu_ip
self.data_network = data_network
@property
def station_nr(self) -> int:
......@@ -41,7 +53,15 @@ class StationData:
# using the 00:22:86 prefix, see https://maclookup.app/vendors/astron
return f"00:22:86:{self.station_8bit_id:02x}:{antenna_field_idx:02x}:{fpga_nr // 4:01}{fpga_nr % 4:01}"
def _fpga_source_ip(self, antenna_field: str, fpga_nr: int):
def _fpga_source_ip(self, antenna_field: str, fpga_nr: int) -> IPv4Address:
raise NotImplementedError
def _beamlet_destination_ip(
self, antenna_field: str, stream_nr: int
) -> IPv4Address:
raise NotImplementedError
def _beamlet_destination_port(self, antenna_field: str, stream_nr: int) -> int:
raise NotImplementedError
def properties_Beamlet(self, antenna_field: str) -> Dict[str, List[str]]:
......@@ -55,12 +75,16 @@ class StationData:
"FPGA_beamlet_output_hdr_udp_source_port_RW_default": [
50000 + n for n in range(16)
],
# "FPGA_beamlet_output_multiple_hdr_eth_destination_mac_RW_default_shorthand": [
# ],
# "FPGA_beamlet_output_multiple_hdr_ip_destination_address_RW_default_shorthand": [
# ],
# "FPGA_beamlet_output_multiple_hdr_udp_destination_port_RW_default_shorthand": [
# ],
"FPGA_beamlet_output_multiple_hdr_eth_destination_mac_RW_default_shorthand": [
multicast_mac(self._beamlet_destination_ip(antenna_field, n))
for n in range(4)
],
"FPGA_beamlet_output_multiple_hdr_ip_destination_address_RW_default_shorthand": [
self._beamlet_destination_ip(antenna_field, n) for n in range(4)
],
"FPGA_beamlet_output_multiple_hdr_udp_destination_port_RW_default_shorthand": [
self._beamlet_destination_port(antenna_field, n) for n in range(4)
],
}
def CDB(self) -> CDB:
......@@ -73,7 +97,7 @@ class CSStationData(StationData):
def antenna_fields(self) -> list[str]:
return ["LBA", "HBA0", "HBA1"]
def _fpga_source_ip(self, antenna_field: str, fpga_nr: int):
def _fpga_source_ip(self, antenna_field: str, fpga_nr: int) -> IPv4Address:
# defined as per IP plan
match antenna_field:
case "LBA":
......@@ -85,6 +109,27 @@ class CSStationData(StationData):
raise ValueError(f"Unknown antenna field: {antenna_field}")
def _beamlet_destination_ip(
self, antenna_field: str, stream_nr: int
) -> IPv4Address:
# defined as per IP plan
match antenna_field:
case "LBA":
return list(self.data_network.hosts())[0 + stream_nr]
case "HBA0":
return list(self.data_network.hosts())[32 + stream_nr]
case "HBA1":
return list(self.data_network.hosts())[64 + stream_nr]
def _beamlet_destination_port(self, antenna_field: str, stream_nr: int) -> int:
match antenna_field:
case "LBA":
return 10000 + stream_nr
case "HBA0":
return 10100 + stream_nr
case "HBA1":
return 10200 + stream_nr
def CDB(self) -> CDB:
cdb = super().CDB()
cdb.add_device_properties(
......@@ -104,7 +149,7 @@ class RSStationData(StationData):
def antenna_fields(self) -> list[str]:
return ["LBA", "HBA"]
def _fpga_source_ip(self, antenna_field: str, fpga_nr: int):
def _fpga_source_ip(self, antenna_field: str, fpga_nr: int) -> IPv4Address:
# defined as per IP plan
match antenna_field:
case "LBA":
......@@ -114,6 +159,23 @@ class RSStationData(StationData):
raise ValueError(f"Unknown antenna field: {antenna_field}")
def _beamlet_destination_ip(
self, antenna_field: str, stream_nr: int
) -> IPv4Address:
# defined as per IP plan
match antenna_field:
case "LBA":
return list(self.data_network.hosts())[0 + stream_nr]
case "HBA":
return list(self.data_network.hosts())[32 + stream_nr]
def _beamlet_destination_port(self, antenna_field: str, stream_nr: int) -> int:
match antenna_field:
case "LBA":
return 10000 + stream_nr
case "HBA":
return 10100 + stream_nr
def CDB(self) -> CDB:
cdb = super().CDB()
cdb.add_device_properties(
......@@ -156,10 +218,17 @@ def main(**kwargs):
required=True,
help="LCU IP for this station",
)
parser.add_argument(
"-d",
"--data-network",
type=IPv4Network,
required=True,
help="IP range for FPGA data stream destinations",
)
args = parser.parse_args()
station_data = StationDataFactory(args.station, args.lcu_ip)
station_data = StationDataFactory(args.station, args.lcu_ip, args.data_network)
print(str(station_data.CDB()))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment