def __init__(self, dev_instance, *args, **kwargs): if not dev_instance.ip_address: raise DeviceImplementationError(gettext("Ip address required")) dev_ip_addr = dev_instance.ip_address if not dev_instance.man_passw: raise DeviceImplementationError( gettext( "For fetch additional device info, snmp community required" )) super().__init__(dev_instance=dev_instance, host=dev_ip_addr, snmp_community=str(dev_instance.man_passw))
def parse_eltex_vlan_map(bitmap: bytes, table: int = 0) -> Generator[int, None, None]: """ https://eltexsl.ru/wp-content/uploads/2016/05/monitoring-i-upravlenie-ethernet-kommutatorami-mes-po-snmp.pdf :param bitmap: str bit map vlan representation by Eltex version :param table: Value from 0 to 3. In which table can find vlan id list :return: VID, vlan id >>> bitmap = (\ '\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ '\\x00\\x02\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\ ) >>> tuple(EltexSwitch.parse_eltex_vlan_map(bitmap)) (5, 143, 152) """ assert isinstance(bitmap, bytes) if table < 0 or table > 3: raise DeviceImplementationError("table must be in range 1-3") r = (bin_num == "1" for octet_num in bitmap for bin_num in f"{octet_num:08b}") return ((numer + 1) + (table * 1024) for numer, bit in enumerate(r) if bit)
def get_ports(self) -> tuple: # interfaces count # yield safe_int(self.get_item('.1.3.6.1.2.1.17.1.2.0')) interfaces_ids = self.get_list(".1.3.6.1.2.1.17.1.4.1.2") if interfaces_ids is None: raise DeviceImplementationError("Switch returned null") interfaces_ids = tuple( next(interfaces_ids) for _ in range(self.ports_len)) def build_port(i: int, n: int): speed = self.get_item(".1.3.6.1.2.1.2.2.1.5.%d" % n) oper_status = safe_int(self.get_item(".1.3.6.1.2.1.2.2.1.7.%d" % n)) == 1 link_status = safe_int(self.get_item(".1.3.6.1.2.1.2.2.1.8.%d" % n)) == 1 ep = EltexPort( dev_interface=self, num=i + 1, snmp_num=n, name=self.get_item(".1.3.6.1.2.1.2.2.1.2.%d" % n), # name status=oper_status, # status mac= b"", # self.get_item('.1.3.6.1.2.1.2.2.1.6.%d' % n), # mac speed=0 if not link_status else safe_int(speed), # speed uptime=self.get_item(".1.3.6.1.2.1.2.2.1.9.%d" % n), # UpTime ) return ep return tuple( build_port(i, int(n)) for i, n in enumerate(interfaces_ids))
def _toggle_vlan_on_port(self, vlan: Vlan, port: int, member: bool): if port > self.ports_len or port < 1: raise DeviceImplementationError("Port must be in range 1-%d" % self.ports_len) # if vlan does not exsists on device, then create it self._add_vlan_if_not_exists(vlan) port_member_tagged = self.get_item(".1.3.6.1.2.1.17.7.1.4.3.1.2.%d" % vlan.vid) port_member_untag = self.get_item(".1.3.6.1.2.1.17.7.1.4.3.1.4.%d" % vlan.vid) if not port_member_tagged or not port_member_untag: return False port_member_tagged_map = self._make_ports_map(port_member_tagged) port_member_untag_map = self._make_ports_map(port_member_untag) if member: port_member_untag_map[port - 1] = vlan.native port_member_tagged_map[port - 1] = True else: port_member_untag_map[port - 1] = False port_member_tagged_map[port - 1] = False port_member_tagged = self._make_buf_from_ports_map( port_member_tagged_map) port_member_untag = self._make_buf_from_ports_map( port_member_untag_map) return self.set_multiple(oid_values=[ (".1.3.6.1.2.1.17.7.1.4.3.1.2.%d" % vlan.vid, port_member_tagged, "OCTETSTR"), (".1.3.6.1.2.1.17.7.1.4.3.1.4.%d" % vlan.vid, port_member_untag, "OCTETSTR"), ])
def read_port_vlan_info(self, port: int) -> Vlans: def _calc_ret(vlan_untagged_egress_oid, vlan_egress_bitmap, table_no) -> Vlans: vlan_untagged_egress = self.get_item(vlan_untagged_egress_oid) vlan_untagged_egress = list( self.parse_eltex_vlan_map(vlan_untagged_egress, table=table_no)) is_native = next( (v == 1 for i, v in enumerate(vlan_untagged_egress, 1) if i >= port), False) return (Vlan(vid=vid, title=self._get_vid_name(vid=vid), native=is_native) for vid in self.parse_eltex_vlan_map(vlan_egress_bitmap, table=table_no)) if port > self.ports_len or port < 1: raise DeviceImplementationError("Port must be in range 1-%d" % self.ports_len) port = port + 48 # rldot1qPortVlanStaticEgressList1to1024 vlan_egress = self.get_item("1.3.6.1.4.1.89.48.68.1.1.%d" % port) if vlan_egress: return _calc_ret( # rldot1qPortVlanStaticUntaggedEgressList1to1024 vlan_untagged_egress_oid="1.3.6.1.4.1.89.48.68.1.5.%d" % port, vlan_egress_bitmap=vlan_egress, table_no=0, ) # rldot1qPortVlanStaticEgressList1025to2048 vlan_egress = self.get_item("1.3.6.1.4.1.89.48.68.1.2.%d" % port) if vlan_egress: return _calc_ret( # rldot1qPortVlanStaticUntaggedEgressList1025to2048 vlan_untagged_egress_oid="1.3.6.1.4.1.89.48.68.1.6.%d" % port, vlan_egress_bitmap=vlan_egress, table_no=1, ) # rldot1qPortVlanStaticEgressList2049to3072 vlan_egress = self.get_item("1.3.6.1.4.1.89.48.68.1.3.%d" % port) if vlan_egress: return _calc_ret( # rldot1qPortVlanStaticUntaggedEgressList2049to3072 vlan_untagged_egress_oid="1.3.6.1.4.1.89.48.68.1.7.%d" % port, vlan_egress_bitmap=vlan_egress, table_no=2, ) # rldot1qPortVlanStaticEgressList3073to4094 vlan_egress = self.get_item("1.3.6.1.4.1.89.48.68.1.4.%d" % port) if vlan_egress: return _calc_ret( # rldot1qPortVlanStaticUntaggedEgressList3073to4094 vlan_untagged_egress_oid="1.3.6.1.4.1.89.48.68.1.8.%d" % port, vlan_egress_bitmap=vlan_egress, table_no=3, )
def scan_ports(self, request, pk=None): device = self.get_object() manager = device.get_manager_object_switch() if not issubclass(manager.__class__, BaseSwitchInterface): raise DeviceImplementationError( "Expected BaseSwitchInterface subclass") ports = manager.get_ports() return Response(data=tuple(p.to_dict() for p in ports))
def apply_vlan_config(self, serializer): device = self.device if not device: raise DeviceImplementationError("device could not found") port_num = serializer.data.get("port_num") if not port_num: raise DeviceImplementationError("port_num field required") mng = device.get_manager_object_switch() vlans_data = serializer.data.get("vlans") if not vlans_data: raise DeviceImplementationError("vlans field required") vlans_gen = (Vlan(**v) for v in vlans_data) mng.attach_vlans_to_port(vlan_list=vlans_gen, port_num=port_num)
def attach_vlans_to_port(self, vlan_list: Vlans, port_num: int) -> tuple: if port_num > self.ports_len or port_num < 1: raise DeviceImplementationError("Port must be in range 1-%d" % self.ports_len) results = tuple( self._toggle_vlan_on_port(vlan=v, port=port_num, member=True) for v in vlan_list) return results
def _make_ports_map(data: AnyStr) -> List[bool]: if isinstance(data, bytes): data = data[:4] else: raise DeviceImplementationError( "data must be instance of bytes, %s got instead" % data.__class__) i = int.from_bytes(data, "big") return list(v == "1" for v in f"{i:032b}")
def remove_from_olt(ip_addr: str, telnet_login: str, telnet_passw: str, telnet_prompt: str, int_name: str): if not re.match(expect_util.IP4_ADDR_REGEX, ip_addr): raise expect_util.ExpectValidationError("ip address for OLT not valid") # Split "EPON0/1:17" for fiber_num - 1, and onu_num - 17 try: fiber_num, onu_num = int_name.split("/")[1].split(":") fiber_num, onu_num = safe_int(fiber_num), safe_int(onu_num) except (IndexError, ValueError): raise DeviceImplementationError("Device interface unexpected") if onu_num < 1 or onu_num > 64: raise DeviceImplementationError("Onu num must be in range 1-64") # Enter ch = expect_util.MySpawn("telnet %s" % ip_addr) ch.timeout = 15 ch.expect_exact("Username: "******"Password: "******"Authentication failed!", "%s>" % telnet_prompt]) if choice == 0: raise DeviceConsoleError(gettext("Wrong login or password for telnet access")) # enable privileges ch.do_cmd("enable", "%s#" % telnet_prompt) # enter to config ch.do_cmd("config", "%s_config#" % telnet_prompt) fiber_prompt = "%s_config_epon0/%d#" % (telnet_prompt, fiber_num) # enter to fiber ch.do_cmd("int EPON0/%d" % fiber_num, fiber_prompt) # unbind onu ch.do_cmd("no epon bind-onu sequence %d" % onu_num, fiber_prompt) # end removing ch.close() return True
def scan_units_unregistered(self, request, pk=None): device = self.get_object() manager = device.get_manager_object_olt() if hasattr(manager, "get_fibers"): unregistered = [] for fb in manager.get_fibers(): for unr in manager.get_units_unregistered(int( fb.get("fb_id"))): unregistered.append(unr) return Response(unregistered) return DeviceImplementationError( "Manager has not get_fibers attribute")
def _set_vlans_on_port(self, vlan_list: Vlans, port_num: int): if port_num > self.ports_len or port_num < 1: raise DeviceImplementationError("Port must be in range 1-%d" % self.ports_len) port_num = port_num + 48 vids = (v.vid for v in vlan_list) bit_maps = self.make_eltex_map_vlan(vids=vids) oids = [] for tbl_num, bitmap in bit_maps.items(): oids.append(("1.3.6.1.4.1.89.48.68.1.%d.%d" % (tbl_num, port_num), bitmap, "x")) return self.set_multiple(oids)
def read_mac_address_vlan(self, vid: int) -> Macs: vid = safe_int(vid) if vid > 4095 or vid < 1: raise DeviceImplementationError("VID must be in range 1-%d" % 4095) fdb = self.get_list_with_oid(".1.3.6.1.2.1.17.7.1.2.2.1.2.%d" % vid) vid_name = self._get_vid_name(vid) for port_num, oid in fdb: fdb_mac = ":".join("%.2x" % int(i) for i in oid[-6:]) yield MacItem(vid=vid, name=vid_name, mac=fdb_mac, port=safe_int(port_num))
def __init__(self, dev_instance, *args, **kwargs): dev_ip_addr = None if dev_instance.ip_address: dev_ip_addr = dev_instance.ip_address else: parent_device = dev_instance.parent_dev if parent_device is not None and parent_device.ip_address: dev_ip_addr = parent_device.ip_address if dev_ip_addr is None: raise DeviceImplementationError( gettext( "Ip address or parent device with ip address required for ONU device" )) if not dev_instance.man_passw: raise DeviceImplementationError( gettext( "For fetch additional device info, snmp community required" )) super().__init__(dev_instance=dev_instance, host=dev_ip_addr, snmp_community=str(dev_instance.man_passw), *args, **kwargs)
def read_mac_address_port(self, port_num: int) -> Macs: if port_num > self.ports_len or port_num < 1: raise DeviceImplementationError("Port must be in range 1-%d" % self.ports_len) fdb = self.get_list_with_oid(".1.3.6.1.2.1.17.7.1.2.2.1.2") for fdb_port, oid in fdb: if port_num != int(fdb_port): continue vid = safe_int(oid[-7:-6][0]) fdb_mac = ":".join("%.2x" % int(i) for i in oid[-6:]) vid_name = self._get_vid_name(vid) yield MacItem(vid=vid, name=vid_name, mac=fdb_mac, port=safe_int(port_num))
def scan_onu_list(self, request, pk=None): device = self.get_object() manager = device.get_manager_object_olt() if not issubclass(manager.__class__, BasePONInterface): raise DeviceImplementationError( "Expected BasePONInterface subclass") def chunk_cook(chunk: dict) -> bytes: chunk_json = json_dumps(chunk, ensure_ascii=False, cls=JSONBytesEncoder) chunk_json = "%s\n" % chunk_json format_string = "{:%ds}" % chunk_max_len dat = format_string.format(chunk_json) return dat.encode()[:chunk_max_len] try: onu_list = manager.scan_onu_list() item_size = next(onu_list) chunk_max_len = next(onu_list) r = StreamingHttpResponse(streaming_content=(chunk_cook({ "number": p.num, "title": p.name, "status": p.status, "mac_addr": p.mac, "signal": p.signal, "uptime": str(RuTimedelta(seconds=p.uptime / 100)) if p.uptime else None, "fiberid": p.fiberid, }) for p in onu_list)) r["Content-Length"] = item_size * chunk_max_len r["Cache-Control"] = "no-store" r["Content-Type"] = "application/octet-stream" return r except StopIteration: pass return Response("No all fetched")
def make_eltex_map_vlan(vids: Iterable[int]) -> Dict[int, bytes]: """ https://eltexsl.ru/wp-content/uploads/2016/05/monitoring-i-upravlenie-ethernet-kommutatorami-mes-po-snmp.pdf :param vids: Vlan id iterable collection :return: bytes bit map vlan representation by Eltex version with index of table in dict key >>> EltexSwitch.make_eltex_map_vlan([3100]) {3: b'\\x00\\x00\\x00\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'} >>> EltexSwitch.make_eltex_map_vlan([5, 6, 143, 152]) {0: b'\\x0c\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02 \\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'} """ vids = list(vids) vids.sort() res = {} for vid in vids: if vid > 4095 or vid < 1: raise DeviceImplementationError("VID must be in range 1-%d" % 4095) table_no = int(math.floor(vid / 1024)) vid -= int(math.floor(vid / 1024)) * 1024 if res.get(table_no) is None: res[table_no] = 0 res[table_no] |= 1 << (1024 - vid) for k in res.keys(): res[k] = res[k].to_bytes(128, "big") return res
def read_port_vlan_info(self, port: int) -> Vlans: if port > self.ports_len or port < 1: raise DeviceImplementationError("Port must be in range 1-%d" % self.ports_len) vid = 1 while True: member_ports, vid = self.get_next_keyval( ".1.3.6.1.2.1.17.7.1.4.3.1.2.%d" % vid) if not member_ports: break if isinstance(member_ports, str): member_ports = member_ports.encode() vid = safe_int(vid) if vid in (0, 1): break member_ports = self._make_ports_map(member_ports[:4]) if not member_ports[port - 1]: continue untagged_members = self.get_item("1.3.6.1.2.1.17.7.1.4.3.1.4.%d" % vid) untagged_members = self._make_ports_map(untagged_members[:4]) name = self._get_vid_name(vid) yield Vlan(vid=vid, title=name, native=untagged_members[port - 1])
def read_mac_address_port(self, port_num: int) -> Macs: if port_num > self.ports_len or port_num < 1: raise DeviceImplementationError("Port must be in range 1-%d" % self.ports_len) try: ports_map = { int(i): n + 1 for n, i in enumerate(self.get_list(".1.3.6.1.2.1.2.2.1.1")) if int(i) > 0 } except ValueError: return for fdb_port, oid in self.get_list_with_oid( ".1.3.6.1.2.1.17.7.1.2.2.1.2"): real_fdb_port_num = ports_map.get(int(fdb_port)) if port_num != real_fdb_port_num: continue vid = safe_int(oid[-7:-6][0]) fdb_mac = ":".join("%.2x" % int(i) for i in oid[-6:]) vid_name = self._get_vid_name(vid) yield MacItem(vid=vid, name=vid_name, mac=fdb_mac, port=real_fdb_port_num)