From b1637a9d5f0b89e4f89fb812075b22cf980d40d7 Mon Sep 17 00:00:00 2001 From: Marko Mecina <marko.mecina@univie.ac.at> Date: Tue, 8 Nov 2022 16:07:09 +0100 Subject: [PATCH] add GRESB parser/router --- Ccs/ccs_function_lib.py | 176 +++++++++++++++++++++++++++++++++++++- Ccs/tools/gresb_router.py | 31 +++++++ 2 files changed, 206 insertions(+), 1 deletion(-) create mode 100755 Ccs/tools/gresb_router.py diff --git a/Ccs/ccs_function_lib.py b/Ccs/ccs_function_lib.py index e21c8a7..8e9bc54 100644 --- a/Ccs/ccs_function_lib.py +++ b/Ccs/ccs_function_lib.py @@ -67,6 +67,8 @@ try: pc.CUC_OFFSET, pc.CUC_EPOCH, pc.puscrc, pc.PLM_PKT_PREFIX_TC_SEND, pc.PLM_PKT_SUFFIX, pc.FMT_TYPE_PARAM] s13_unpack_data_header = pc.s13_unpack_data_header + SPW_PROTOCOL_IDS_R = {pc.SPW_PROTOCOL_IDS[key]: key for key in pc.SPW_PROTOCOL_IDS} + except AttributeError as err: logger.critical(err) raise err @@ -3916,7 +3918,13 @@ def get_spw_from_plm_gw(sock_plm, sock_gnd, strip_spw=4): def setup_gw_spw_routing(gw_hp, gnd_hp, tc_hp=None, spw_head=b'\xfe\x02\x00\x00'): - + """ + A router for the single-port HVS SpW Brick that handles the HVS and SpW protocol for the CCS + @param gw_hp: + @param gnd_hp: + @param tc_hp: + @param spw_head: + """ gw = socket.socket() gw.settimeout(10) gw.connect(gw_hp) @@ -3973,6 +3981,172 @@ def setup_gw_spw_routing(gw_hp, gnd_hp, tc_hp=None, spw_head=b'\xfe\x02\x00\x00' gw.close() +def _gresb_unpack(raw, hdr_endianess='big'): + pid = raw[0] + pktlen = int.from_bytes(raw[1:4], hdr_endianess) + return raw[4:], pktlen, pid + + +def _gresb_pack(pkt, protocol_id=0, hdr_endianess='big'): + return protocol_id.to_bytes(1, hdr_endianess) + len(pkt).to_bytes(3, hdr_endianess) + pkt + + +def get_gresb_pkt(gresb, gnd_s, hdr_endianess='big'): + + data = b'' + while len(data) < 4: + data += gresb.recv(4 - len(data)) + + spwdata, plen, pid = _gresb_unpack(data, hdr_endianess=hdr_endianess) + while len(spwdata) < plen: + spwdata += gresb.recv(plen - len(spwdata)) + + gnd_s.send(spwdata) + + logger.debug(plen, len(spwdata), spwdata.hex()) + print(plen, len(spwdata), spwdata.hex()) + + +def setup_gresb_routing(gresb_hp, gnd_hp, tc_hp=None, protocol_id=0, hdr_endianess='big'): + """ + Handle GRESB protocol for CCS + @param gresb_hp: + @param gnd_hp: + @param tc_hp: + @param protocol_id: + @param hdr_endianess: + """ + gresb = socket.socket() + gresb.settimeout(10) + gresb.connect(gresb_hp) + + gnd = socket.socket() + gnd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + gnd.bind(gnd_hp) + gnd.listen() + + if tc_hp is not None: + tcsock = socket.socket() + tcsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + tcsock.bind(tc_hp) + tcsock.listen() + else: + tcsock = gnd + + while gresb.fileno() > 0: + logger.info(gresb, gnd) + gnd_s, addr = gnd.accept() + tc_s, addr2 = tcsock.accept() + + while True: + try: + print('START') + r, w, e = select.select([gresb, tc_s], [], []) + print(r) + for sockfd in r: + if sockfd == gresb: + while select.select([gresb], [], [], 0)[0]: + get_gresb_pkt(gresb, gnd_s, hdr_endianess=hdr_endianess) + elif sockfd == tc_s: + while select.select([tc_s], [], [], 0)[0]: + rawtc = tc_s.recv(1024) + if rawtc == b'': + raise socket.error('Lost connection to port '.format(tc_s.getsockname())) + else: + logger.info('# TC:', rawtc) + print('# TC:', rawtc) + msg = _gresb_pack(rawtc, protocol_id=protocol_id, hdr_endianess=hdr_endianess) + print(gresb) + gresb.send(msg) + print(msg) + + except socket.timeout: + continue + except socket.error: + gnd_s.close() + tc_s.close() + logger.info('Closed TM/TC ports. Reopening...') + break + print('########') + time.sleep(1) + + gnd.close() + tcsock.close() + gresb.close() + + +def extract_spw(stream): + """ + Read SpW packets from a byte stream + @param stream: + @return: + """ + + pkt_size_stream = b'' + pckts = [] + headers = [] + + while True: + pkt_size_stream += stream.read(2) + if len(pkt_size_stream) < 2: + break + tla, pid = pkt_size_stream[:2] + logger.debug(pid) + + # if (tla == pc.SPW_DPU_LOGICAL_ADDRESS) and (pid in SPW_PROTOCOL_IDS_R): + if pid in SPW_PROTOCOL_IDS_R: + buf = pkt_size_stream + else: + pkt_size_stream = pkt_size_stream[1:] + continue + + if SPW_PROTOCOL_IDS_R[pid] == "FEEDATA": + header = pc.FeeDataTransferHeader() + elif SPW_PROTOCOL_IDS_R[pid] == "RMAP": + while len(buf) < 3: + instruction = stream.read(1) + if not instruction: + return pckts, buf + buf += instruction + + instruction = buf[2] + + if (instruction >> 6) & 1: + header = pc.RMapCommandHeader() + elif (instruction >> 5) & 0b11 == 0b01: + header = pc.RMapReplyWriteHeader() + elif (instruction >> 5) & 0b11 == 0b00: + header = pc.RMapReplyReadHeader() + + hsize = header.__class__.bits.size + + while len(buf) < hsize: + buf += stream.read(hsize - len(buf)) + + header.bin[:] = buf[:hsize] + + if SPW_PROTOCOL_IDS_R[pid] == "FEEDATA": + pktsize = header.bits.DATA_LEN + elif (header.bits.PKT_TYPE == 1 and header.bits.WRITE == 0) or ( + header.bits.PKT_TYPE == 0 and header.bits.WRITE == 1): + pktsize = hsize + else: + pktsize = hsize + header.bits.DATA_LEN# + pc.RMAP_PEC_LEN # TODO: no data CRC from FEEsim? + + while len(buf) < pktsize: + data = stream.read(pktsize - len(buf)) + if not data: + return headers, pckts, pkt_size_stream + buf += data + + buf = buf[:pktsize] + pkt_size_stream = buf[pktsize:] + pckts.append(buf) + headers.append(header) + + return headers, pckts, pkt_size_stream + + ## # Save pool # diff --git a/Ccs/tools/gresb_router.py b/Ccs/tools/gresb_router.py new file mode 100755 index 0000000..c2a0e8e --- /dev/null +++ b/Ccs/tools/gresb_router.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 + +""" +Handle packets prepended with GRESB header +""" + +import sys +sys.path.insert(0, '..') + +from ccs_function_lib import setup_gresb_routing + +if __name__ == "__main__": + + if len(sys.argv) < 3: + print("USAGE: ./gresb_router.py <GRESB host:port> <TM host:port> [<TC host:port>]") + sys.exit() + + gw, tm = sys.argv[1:3] + + gw_hp = (gw.split(":")[0], int(gw.split(":")[1])) + tm_hp = (tm.split(":")[0], int(tm.split(":")[1])) + + if len(sys.argv) == 4: + tc = sys.argv[3] + tc_hp = (tc.split(":")[0], int(tc.split(":")[1])) + else: + tc = None + tc_hp = None + + print("Routing between GRESB:{} and TM:{},TC:{}. Adding/removing 4-byte GRESB header".format(gw, tm, tc)) + setup_gresb_routing(gw_hp, tm_hp, tc_hp=tc_hp) -- GitLab