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
Branches
Tags
1 merge request!1093Resolve COB-328 "Multicast destinations"
Pipeline #118387 failed
Pipeline: tango

#118389

    Pipeline: tango

    #118388

      ...@@ -133,15 +133,18 @@ render_CDB_environment_ilt: ...@@ -133,15 +133,18 @@ render_CDB_environment_ilt:
      python -m pip install . python -m pip install .
      # fetch IPs from netbox (netbox.astron.nl) # 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 mkdir -p generated/CDB/environments
      for STATION in ${LOFAR2_STATIONS}; do 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}" DATA_NETWORK=`jq < netbox-data-networks.json '.results[] | select(.description | test("'${STATION}' multicast range"; "i")) | .prefix' -r`
      l2ss-generate-cdb-datastreams -s ${STATION} -l ${LCU_IP} > generated/CDB/environments/${STATION}-ilt.json
      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 done
      artifacts: artifacts:
      expire_in: 4 weeks expire_in: 4 weeks
      ......
      ...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
      # Copyright (C) 2025 ASTRON (Netherlands Institute for Radio Astronomy) # Copyright (C) 2025 ASTRON (Netherlands Institute for Radio Astronomy)
      # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
      from ipaddress import IPv4Address from ipaddress import IPv4Address, IPv4Network
      from typing import Dict, List from typing import Dict, List
      from tangostationcontrol.toolkit._cdb import CDB from tangostationcontrol.toolkit._cdb import CDB
      ...@@ -10,10 +10,22 @@ from tangostationcontrol.toolkit._cdb import CDB ...@@ -10,10 +10,22 @@ from tangostationcontrol.toolkit._cdb import CDB
      N_pol = 2 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: 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.station = station
      self.lcu_ip = lcu_ip self.lcu_ip = lcu_ip
      self.data_network = data_network
      @property @property
      def station_nr(self) -> int: def station_nr(self) -> int:
      ...@@ -41,7 +53,15 @@ class StationData: ...@@ -41,7 +53,15 @@ class StationData:
      # using the 00:22:86 prefix, see https://maclookup.app/vendors/astron # 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}" 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 raise NotImplementedError
      def properties_Beamlet(self, antenna_field: str) -> Dict[str, List[str]]: def properties_Beamlet(self, antenna_field: str) -> Dict[str, List[str]]:
      ...@@ -55,12 +75,16 @@ class StationData: ...@@ -55,12 +75,16 @@ class StationData:
      "FPGA_beamlet_output_hdr_udp_source_port_RW_default": [ "FPGA_beamlet_output_hdr_udp_source_port_RW_default": [
      50000 + n for n in range(16) 50000 + n for n in range(16)
      ], ],
      # "FPGA_beamlet_output_multiple_hdr_eth_destination_mac_RW_default_shorthand": [ "FPGA_beamlet_output_multiple_hdr_eth_destination_mac_RW_default_shorthand": [
      # ], multicast_mac(self._beamlet_destination_ip(antenna_field, n))
      # "FPGA_beamlet_output_multiple_hdr_ip_destination_address_RW_default_shorthand": [ for n in range(4)
      # ], ],
      # "FPGA_beamlet_output_multiple_hdr_udp_destination_port_RW_default_shorthand": [ "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: def CDB(self) -> CDB:
      ...@@ -73,7 +97,7 @@ class CSStationData(StationData): ...@@ -73,7 +97,7 @@ class CSStationData(StationData):
      def antenna_fields(self) -> list[str]: def antenna_fields(self) -> list[str]:
      return ["LBA", "HBA0", "HBA1"] 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 # defined as per IP plan
      match antenna_field: match antenna_field:
      case "LBA": case "LBA":
      ...@@ -85,6 +109,27 @@ class CSStationData(StationData): ...@@ -85,6 +109,27 @@ class CSStationData(StationData):
      raise ValueError(f"Unknown antenna field: {antenna_field}") 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: def CDB(self) -> CDB:
      cdb = super().CDB() cdb = super().CDB()
      cdb.add_device_properties( cdb.add_device_properties(
      ...@@ -104,7 +149,7 @@ class RSStationData(StationData): ...@@ -104,7 +149,7 @@ class RSStationData(StationData):
      def antenna_fields(self) -> list[str]: def antenna_fields(self) -> list[str]:
      return ["LBA", "HBA"] 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 # defined as per IP plan
      match antenna_field: match antenna_field:
      case "LBA": case "LBA":
      ...@@ -114,6 +159,23 @@ class RSStationData(StationData): ...@@ -114,6 +159,23 @@ class RSStationData(StationData):
      raise ValueError(f"Unknown antenna field: {antenna_field}") 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: def CDB(self) -> CDB:
      cdb = super().CDB() cdb = super().CDB()
      cdb.add_device_properties( cdb.add_device_properties(
      ...@@ -156,10 +218,17 @@ def main(**kwargs): ...@@ -156,10 +218,17 @@ def main(**kwargs):
      required=True, required=True,
      help="LCU IP for this station", 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() 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())) 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