Now working version of private call routing, on a per-system basis, with the ability to overload OBP with TS information for unit calls.

This commit is contained in:
Cort Buffington 2020-03-16 02:20:24 +00:00
parent f00d29e8a0
commit b48e522f85
5 changed files with 35 additions and 31 deletions

View File

@ -207,7 +207,7 @@ def stream_trimmer_loop():
_stream = systems[system].STATUS[stream_id]
_sysconfig = CONFIG['SYSTEMS'][system]
if systems[system].STATUS[stream_id]['ACTIVE']:
logger.info('(%s) *TIME OUT* STREAM ID: %s SUB: %s PEER: %s TYPE: %s DST ID: %s TS 1 Duration: %.2f', \
logger.info('(%s) *TIME OUT* STREAM ID: %s SUB: %s PEER: %s TYPE: %s DST ID: %s TS 1 Duration: %.2f', \
system, int_id(stream_id), get_alias(int_id(_stream['RFS']), subscriber_ids), get_alias(int_id(_sysconfig['NETWORK_ID']), peer_ids), _stream['TYPE'], get_alias(int_id(_stream['DST']), talkgroup_ids), _stream['LAST'] - _stream['START'])
if CONFIG['REPORTS']['REPORT']:
if _stream['TYPE'] == 'GROUP':
@ -225,8 +225,8 @@ class routerOBP(OPENBRIDGE):
self.name = _name
self.STATUS = {}
# list of targets for unit (subscriber, private) calls
self.targets = []
# list of self._targets for unit (subscriber, private) calls
self._targets = []
def group_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _frame_type, _dtype_vseq, _stream_id, _data):
pkt_time = time()
@ -418,7 +418,7 @@ class routerOBP(OPENBRIDGE):
self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, call_duration)
if CONFIG['REPORTS']['REPORT']:
self._report.send_bridgeEvent('GROUP VOICE,END,RX,{},{},{},{},{},{},{:.2f}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id), call_duration).encode(encoding='utf-8', errors='ignore'))
_target_status[_stream_id]['ACTIVE']: False
self.STATUS[_stream_id]['ACTIVE']: False
logger.debug('(%s) OpenBridge sourced call stream end, remove terminated Stream ID: %s', self._system, int_id(_stream_id))
@ -448,21 +448,20 @@ class routerOBP(OPENBRIDGE):
if _dst_id in UNIT_MAP:
if UNIT_MAP[_dst_id][0] != self._system:
self._targets = [UNIT_MAP[_dst_id][0]]
_target_route = UNIT_MAP[_dst_id][0]
else:
self._targets = []
logger.debug('UNIT call to a subscriber on the same system, send nothing')
logger.error('UNIT call to a subscriber on the same system, send nothing')
else:
self._targets = list(systems)
self._targets = list(UNIT)
self._targets.remove(self._system)
_target_route = 'FLOOD'
# This is a new call stream, so log & report
self.STATUS['START'] = pkt_time
logger.info('(%s) *UNIT CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) UNIT: %s (%s), TS: %s, FORWARD: %s', \
self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, _target_route)
self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, self._targets)
if CONFIG['REPORTS']['REPORT']:
self._report.send_bridgeEvent('UNIT VOICE,START,RX,{},{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id), _target_route).encode(encoding='utf-8', errors='ignore'))
self._report.send_bridgeEvent('UNIT VOICE,START,RX,{},{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id), self._targets).encode(encoding='utf-8', errors='ignore'))
for _target in self._targets:
_target_status = systems[_target].STATUS
@ -480,18 +479,19 @@ class routerOBP(OPENBRIDGE):
'ACTIVE': True
}
logger.info('(%s) Unit call bridged to OBP System: %s TS: %s, TGID: %s', self._system, _target, _slot, int_id(_dst_id))
logger.info('(%s) Unit call bridged to OBP System: %s TS: %s, TGID: %s', self._system, _target, _slot if _target_system['BOTH_SLOTS'] else 1, int_id(_dst_id))
if CONFIG['REPORTS']['REPORT']:
systems[_target]._report.send_bridgeEvent('UNIT VOICE,START,TX,{},{},{},{},{},{}'.format(_target, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore'))
# Record the time of this packet so we can later identify a stale stream
_target_status[_stream_id]['LAST'] = pkt_time
# Clear the TS bit -- all OpenBridge streams are effectively on TS1
_tmp_bits = _bits & ~(1 << 7)
# Clear the TS bit and follow propper OBP definition, unless "BOTH_SLOTS" is set. This only works for unit calls.
if not _target_system['BOTH_SLOTS']:
_tmp_bits = _bits & ~(1 << 7)
# Assemble transmit HBP packet
_tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]])
_data = b''.join([_tmp_data, dmrpkt])
# Assemble transmit HBP packet
_tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]])
_data = b''.join([_tmp_data, dmrpkt])
if (_frame_type == HBPF_DATA_SYNC) and (_dtype_vseq == HBPF_SLT_VTERM):
_target_status[_stream_id]['ACTIVE']: False
@ -583,8 +583,8 @@ class routerHBP(HBSYSTEM):
HBSYSTEM.__init__(self, _name, _config, _report)
self.name = _name
# list of targets for unit (subscriber, private) calls
self.targets = []
# list of self._targets for unit (subscriber, private) calls
self._targets = []
# Status information for the system, TS1 & TS2
# 1 & 2 are "timeslot"
@ -931,7 +931,7 @@ class routerHBP(HBSYSTEM):
logger.info('(%s) *UNIT CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) UNIT: %s (%s), TS: %s, FORWARD: %s', \
self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, self._targets)
if CONFIG['REPORTS']['REPORT']:
self._report.send_bridgeEvent('UNIT VOICE,START,RX,{},{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id), _target_route).encode(encoding='utf-8', errors='ignore'))
self._report.send_bridgeEvent('UNIT VOICE,START,RX,{},{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id), self._targets).encode(encoding='utf-8', errors='ignore'))
for _target in self._targets:
@ -950,18 +950,19 @@ class routerHBP(HBSYSTEM):
'ACTIVE': True
}
logger.info('(%s) Unit call bridged to OBP System: %s TS: %s, UNIT: %s', self._system, _target, _slot, int_id(_dst_id))
logger.info('(%s) Unit call bridged to OBP System: %s TS: %s, UNIT: %s', self._system, _target, _slot if _target_system['BOTH_SLOTS'] else 1, int_id(_dst_id))
if CONFIG['REPORTS']['REPORT']:
systems[_target]._report.send_bridgeEvent('UNIT VOICE,START,TX,{},{},{},{},{},{}'.format(_target, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore'))
# Record the time of this packet so we can later identify a stale stream
_target_status[_stream_id]['LAST'] = pkt_time
# Clear the TS bit -- all OpenBridge streams are effectively on TS1
_tmp_bits = _bits & ~(1 << 7)
# Clear the TS bit and follow propper OBP definition, unless "BOTH_SLOTS" is set. This only works for unit calls.
if not _target_system['BOTH_SLOTS']:
_tmp_bits = _bits & ~(1 << 7)
# Assemble transmit HBP packet
_tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]])
_data = b''.join([_tmp_data, dmrpkt])
# Assemble transmit HBP packet
_tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]])
_data = b''.join([_tmp_data, dmrpkt])
if (_frame_type == HBPF_DATA_SYNC) and (_dtype_vseq == HBPF_SLT_VTERM):
_target_status[_stream_id]['ACTIVE']: False

View File

@ -274,6 +274,7 @@ def build_config(_config_file):
'TARGET_SOCK': (gethostbyname(config.get(section, 'TARGET_IP')), config.getint(section, 'TARGET_PORT')),
'TARGET_IP': gethostbyname(config.get(section, 'TARGET_IP')),
'TARGET_PORT': config.getint(section, 'TARGET_PORT'),
'BOTH_SLOTS': config.getboolean(section, 'BOTH_SLOTS'),
'USE_ACL': config.getboolean(section, 'USE_ACL'),
'SUB_ACL': config.get(section, 'SUB_ACL'),
'TG1_ACL': config.get(section, 'TGID_ACL'),

View File

@ -120,7 +120,9 @@ STALE_DAYS: 7
#
# ACLs:
# OpenBridge does not 'register', so registration ACL is meaningless.
# OpenBridge passes all traffic on TS1, so there is only 1 TGID ACL.
# Proper OpenBridge passes all traffic on TS1.
# HBlink can extend OPB to use both slots for unit calls only.
# Setting "BOTH_SLOTS" True ONLY affects unit traffic!
# Otherwise ACLs work as described in the global stanza
[OBP-1]
MODE: OPENBRIDGE
@ -131,6 +133,7 @@ NETWORK_ID: 3129100
PASSPHRASE: password
TARGET_IP: 1.2.3.4
TARGET_PORT: 62035
BOTH_SLOTS: True
USE_ACL: True
SUB_ACL: DENY:1
TGID_ACL: PERMIT:ALL

View File

@ -160,8 +160,8 @@ class OPENBRIDGE(DatagramProtocol):
_stream_id = _data[16:20]
#logger.debug('(%s) DMRD - Seqence: %s, RF Source: %s, Destination ID: %s', self._system, int_id(_seq), int_id(_rf_src), int_id(_dst_id))
# Sanity check for OpenBridge -- all calls must be on Slot 1
if _slot != 1:
# Sanity check for OpenBridge -- all calls must be on Slot 1 for Brandmeister or DMR+. Other HBlinks can process timeslot on OPB if the flag is set
if _slot != 1 and not self._config['BOTH_SLOTS'] and not _call_type == 'unit':
logger.error('(%s) OpenBridge packet discarded because it was not received on slot 1. SID: %s, TGID %s', self._system, int_id(_rf_src), int_id(_dst_id))
return

View File

@ -48,8 +48,7 @@ BRIDGES = {
}
'''
list the names of each system that should process unit to unit (individual) calls. Processing
is both ingress and egress.
list the names of each system that should bridge unit to unit (individual) calls.
'''
UNIT = ['ONE', 'TWO']