示例#1
0
文件: multicast.py 项目: nbashev/noc
 def clean_ip(self):
     v = self.cleaned_data["ip"]
     if v:
         return IPv4Parameter().form_clean(v)
示例#2
0
文件: test_base.py 项目: nbashev/noc
def test_ipv4_parameter(raw, config, expected):
    assert IPv4Parameter(**config).clean(raw) == expected
示例#3
0
文件: test_base.py 项目: nbashev/noc
def test_ipv4_parameter_error(raw, config):
    with pytest.raises(InterfaceTypeError):
        assert IPv4Parameter(**config).clean(raw)
示例#4
0
    def execute_cli(self):
        r = []
        try:
            v = self.cli("show lldp remote_ports mode normal")
        except self.CLISyntaxError:
            raise self.NotSupportedError()
        for match in self.rx_port.finditer(v):
            i = {"local_interface": match.group("port"), "neighbors": []}
            for m in self.rx_entity.finditer(match.group("entities")):
                n = {}
                remote_chassis_id_subtype = m.group("chassis_id_subtype").replace("_", " ")
                n["remote_chassis_id_subtype"] = {
                    "chassis component": 1,
                    "interface alias": 2,
                    "port component": 3,
                    "mac address": 4,
                    "macaddress": 4,
                    "network address": 5,
                    "interface name": 6,
                    "local": 7,
                }[remote_chassis_id_subtype.strip().lower()]
                n["remote_chassis_id"] = m.group("chassis_id").strip()
                remote_port_subtype = m.group("port_id_subtype").replace("_", " ")
                n["remote_port_subtype"] = {
                    "interface alias": 1,
                    # DES-3526 6.00 B48, DES-3526 6.00 B49,
                    # DES-3200-28 1.85.B008
                    "nterface alias": 1,
                    "port component": 2,
                    "mac address": 3,
                    "macaddress": 3,
                    "network address": 4,
                    "interface name": 5,
                    "agent circuit id": 6,
                    "locally assigned": 7,
                    "local": 7,
                }[remote_port_subtype.strip().lower()]
                n["remote_port"] = m.group("port_id").strip()
                if n["remote_port_subtype"] == 3:
                    try:
                        n["remote_port"] = MACAddressParameter().clean(n["remote_port"])
                    except ValueError:
                        continue
                if n["remote_port_subtype"] == 4:
                    n["remote_port"] = IPv4Parameter().clean(n["remote_port"])

                if m.group("port_description").strip():
                    p = m.group("port_description").strip()
                    n["remote_port_description"] = re.sub(r"\n\s{49}", "", p)
                if m.group("system_name").strip():
                    p = m.group("system_name").strip()
                    n["remote_system_name"] = re.sub(r"\n\s{49}", "", p)
                if m.group("system_description").strip():
                    p = m.group("system_description").strip()
                    n["remote_system_description"] = re.sub(r"\n\s{49}", "", p)
                caps = 0
                for c in m.group("system_capabilities").split(","):
                    c = re.sub(r"\s{49,50}", "", c)
                    c = c.strip()
                    if not c:
                        break
                    caps |= {
                        "Other": 1,
                        "Repeater": 2,
                        "Bridge": 4,
                        "Access Point": 8,
                        "WLAN Access Point": 8,
                        "Router": 16,
                        "Telephone": 32,
                        "DOCSIS Cable Device": 64,
                        "Station Only": 128,
                    }[c]
                n["remote_capabilities"] = caps
                i["neighbors"] += [n]
            if i["neighbors"]:
                r += [i]
        return r
示例#5
0
文件: views.py 项目: nbashev/noc
class ObjectListApplication(ExtApplication):
    """
    ManagedObject application
    """

    model = ManagedObject
    # Default filter by is_managed
    managed_filter = True

    def queryset(self, request, query=None):
        """
        Filter records for lookup
        """
        self.logger.info("Queryset %s" % query)
        if self.managed_filter:
            q = d_Q(is_managed=True)
        else:
            q = d_Q()
        if not request.user.is_superuser:
            q &= UserAccess.Q(request.user)
        if query:
            sq = ManagedObject.get_search_Q(query)
            if sq:
                q &= sq
            else:
                q &= d_Q(name__contains=query)
        return self.model.objects.filter(q)

    def instance_to_dict(self, o, fields=None):
        return {
            "id":
            str(o.id),
            "name":
            o.name,
            "address":
            o.address,
            "profile_name":
            o.profile.name,
            "platform":
            o.platform.name if o.platform else "",
            "version":
            o.version.version if o.version else "",
            "row_class":
            o.object_profile.style.css_class_name
            if o.object_profile.style else ""
            # "row_class": ""
        }

    def cleaned_query(self, q):
        nq = {}
        for k in q:
            if not k.startswith("_") and "__" not in k:
                nq[k] = q[k]
        ids = set()
        self.logger.debug("Cleaned query: %s" % nq)
        if "ids" in nq:
            ids = {int(nid) for nid in nq["ids"]}
            del nq["ids"]

        if "administrative_domain" in nq:
            ad = AdministrativeDomain.get_nested_ids(
                int(nq["administrative_domain"]))
            if ad:
                del nq["administrative_domain"]
                nq["administrative_domain__in"] = ad

        if "selector" in nq:
            s = self.get_object_or_404(ManagedObjectSelector,
                                       id=int(q["selector"]))
            if s:
                if ids:
                    # nq["id__in"] = set(ManagedObject.objects.filter(s.Q).values_list("id", flat=True))
                    ids = ids.intersection(
                        set(
                            ManagedObject.objects.filter(s.Q).values_list(
                                "id", flat=True)))
                else:
                    ids = set(
                        ManagedObject.objects.filter(s.Q).values_list(
                            "id", flat=True))
            del nq["selector"]
        mq = None
        c_in = []
        c_nin = []
        for cc in [part for part in nq if part.startswith("caps")]:
            """
            Caps: caps0=CapsID,caps1=CapsID:true....
            cq - caps query
            mq - main_query
            caps0=CapsID - caps is exists
            caps0=!CapsID - caps is not exists
            caps0=CapsID:true - caps value equal True
            caps0=CapsID:2~50 - caps value many then 2 and less then 50
            c_ids = set(ObjectCapabilities.objects(cq).distinct('object'))
            """
            # @todo Убирать дубликаты (повторно не добавлять)

            c = nq.pop(cc)
            if not c:
                continue
            if not mq:
                mq = m_Q()
            self.logger.info("Caps: %s" % c)
            if "!" in c:
                # @todo Добавить исключение (только этот) !ID
                c_id = c[1:]
                c_query = "nexists"
            elif ":" not in c:
                c_id = c
                c_query = "exists"
            else:
                c_id, c_query = c.split(":", 1)

            try:
                c_id = bson.ObjectId(c_id)
            except bson.errors.InvalidId as e:
                self.logger.warning(e)
                continue
            if "~" in c_query:
                l, r = c_query.split("~")
                if not l:
                    cond = {"$lte": int(r)}
                elif not r:
                    cond = {"$gte": int(l)}
                else:
                    cond = {"$lte": int(r), "$gte": int(l)}
                cq = m_Q(__raw__={
                    "caps": {
                        "$elemMatch": {
                            "capability": c_id,
                            "value": cond
                        }
                    }
                })
            elif c_query in ("false", "true"):
                cq = m_Q(caps__match={
                    "capability": c_id,
                    "value": c_query == "true"
                })
            elif c_query == "exists":
                c_in += [c_id]
                continue
            elif c_query == "nexists":
                c_nin += [c_id]
                continue
            else:
                try:
                    c_query = int(c_query)
                    cq = m_Q(
                        __raw__={
                            "caps": {
                                "$elemMatch": {
                                    "capability": c_id,
                                    "value": int(c_query)
                                }
                            }
                        })
                except ValueError:
                    cq = m_Q(
                        __raw__={
                            "caps": {
                                "$elemMatch": {
                                    "capability": c_id,
                                    "value": {
                                        "$regex": c_query
                                    }
                                }
                            }
                        })
            mq &= cq
        if c_in:
            mq &= m_Q(caps__capability__in=c_in)
        if c_nin:
            mq &= m_Q(caps__capability__nin=c_nin)
        if mq:
            c_ids = set(el["_id"] for el in ObjectCapabilities.objects(
                mq).values_list("object").as_pymongo())
            self.logger.info("Caps objects count: %d" % len(c_ids))
            ids = ids.intersection(c_ids) if ids else c_ids

        if "addresses" in nq:
            if isinstance(nq["addresses"], list):
                nq["address__in"] = nq["addresses"]
            else:
                nq["address__in"] = [nq["addresses"]]
            del nq["addresses"]
        if ids:
            nq["id__in"] = list(ids)

        xf = list((set(nq.keys())) -
                  set(f.name for f in self.model._meta.get_fields()))
        # @todo move validation fields
        for x in xf:
            if x in ["address__in", "id__in", "administrative_domain__in"]:
                continue
            self.logger.warning("Remove element not in model: %s" % x)
            del nq[x]
        return nq

    def extra_query(self, q, order):
        extra = {"select": {}}
        if "address" in order:
            extra["select"]["ex_address"] = " cast_test_to_inet(address) "
            extra["order_by"] = ["ex_address", "address"]
        elif "-address" in order:
            extra["select"]["ex_address"] = " cast_test_to_inet(address) "
            extra["order_by"] = ["-ex_address", "-address"]

        self.logger.info("Extra: %s" % extra)
        return extra, [] if "order_by" in extra else order

    @view(method=["GET", "POST"], url="^$", access="read", api=True)
    def api_list(self, request):
        return self.list_data(request, self.instance_to_dict)

    @view(
        method=["POST"],
        url="^iplist/$",
        access="launch",
        api=True,
        validate={
            "query":
            DictParameter(
                attrs={
                    "addresses":
                    ListOfParameter(element=IPv4Parameter(), convert=True)
                })
        },
    )
    def api_action_ip_list(self, request, query):
        # @todo Required user vault implementation
        return self.render_json({"status": True})
示例#6
0
    def execute(self):
        r = []
        v = self.cli("show interfaces status")
        t = parse_table(v)
        for i in t:
            iface = {"local_interface": i[0], "neighbors": []}
            v = self.cli("show lldp neighbors interface %s" % i[0])
            for m in self.rx_entity.finditer(v):
                n = {}
                n["remote_chassis_id_subtype"] = {
                    "chassis component": 1,
                    "interface alias": 2,
                    "port component": 3,
                    "mac address": 4,
                    "network address": 5,
                    "interface name": 6,
                    "local": 7,
                }[m.group("chassis_id_type").strip().lower()]
                n["remote_chassis_id"] = m.group("chassis_id").strip()
                remote_port_subtype = m.group("port_id_type")
                remote_port_subtype.replace("_", " ")
                n["remote_port_subtype"] = {
                    "interface alias": 1,
                    "port component": 2,
                    "mac address": 3,
                    "network address": 4,
                    "interface name": 5,
                    "agent circuit id": 6,
                    "local": 7,
                }[remote_port_subtype.strip().lower()]
                n["remote_port"] = m.group("port_id").strip()
                if n["remote_port_subtype"] == 3:
                    n["remote_port"] = MACAddressParameter().clean(
                        n["remote_port"])
                if n["remote_port_subtype"] == 4:
                    n["remote_port"] = IPv4Parameter().clean(n["remote_port"])

                if m.group("port_description").strip():
                    n["remote_port_description"] = re.sub(
                        r"\n\s*", "",
                        m.group("port_description").strip())
                if m.group("system_name").strip():
                    n["remote_system_name"] = m.group("system_name").strip()
                if m.group("system_description").strip():
                    n["remote_system_description"] = re.sub(
                        r"\n\s*", "",
                        m.group("system_description").strip())
                caps = 0
                for c in m.group("system_capabilities").split(","):
                    c = c.strip()
                    if not c:
                        break
                    caps |= {
                        "Other": 1,
                        "Repeater": 2,
                        "Bridge": 4,
                        "WLAN Access Point": 8,
                        "Router": 16,
                        "Telephone": 32,
                        "DOCSIS Cable Device": 64,
                        "Station Only": 128,
                    }[c]
                n["remote_capabilities"] = caps
                iface["neighbors"] += [n]
            if iface["neighbors"]:
                r += [iface]
        return r
示例#7
0
    def execute(self):
        r = []
        try:
            v = self.cli("show lldp remote_ports mode normal")
        except self.CLISyntaxError:
            raise self.NotSupportedError()
        v = "\n" + v
        # For each interface
        for s in self.rx_line.split(v)[1:]:
            match = self.rx_id.search(s)
            if not match:
                continue
            port_id = match.group("port_id")
            match = self.rx_re_ent.search(s)
            if not match:
                continue
            # Remote Entities Count : 0
            if match.group("re_ent") == "0":
                continue
            i = {"local_interface": port_id, "neighbors": []}
            # For each neighbor
            for s1 in self.rx_line1.split(s)[1:]:
                n = {}

                # remote_chassis_id_subtype
                match = self.rx_remote_chassis_id_subtype.search(s1)
                if not match:
                    # Debug string
                    self.debug('remote_chassis_id_subtype is empty!')
                    continue
                remote_chassis_id_subtype = match.group("subtype").strip()
                # TODO: Find other subtypes
                # 0 is reserved
                if remote_chassis_id_subtype == "Chassis Component":
                    n["remote_chassis_id_subtype"] = 1
                elif remote_chassis_id_subtype == "Interface Alias":
                    n["remote_chassis_id_subtype"] = 2
                elif remote_chassis_id_subtype == "Port Component":
                    n["remote_chassis_id_subtype"] = 3
                elif remote_chassis_id_subtype == "MAC Address":
                    n["remote_chassis_id_subtype"] = 4
                elif remote_chassis_id_subtype.lower() == "macaddress":
                    n["remote_chassis_id_subtype"] = 4
                elif remote_chassis_id_subtype == "Network Address":
                    n["remote_chassis_id_subtype"] = 5
                elif remote_chassis_id_subtype == "Interface Name":
                    n["remote_chassis_id_subtype"] = 6
                elif remote_chassis_id_subtype.lower() == "local":
                    n["remote_chassis_id_subtype"] = 7
                # 8-255 are reserved

                # remote_chassis_id
                match = self.rx_remote_chassis_id.search(s1)
                if not match:
                    # Debug string
                    self.debug('remote_chassis_id is empty!')
                    continue
                n["remote_chassis_id"] = match.group("id").strip()

                # remote_port_subtype
                match = self.rx_remote_port_id_subtype.search(s1)
                if not match:
                    # Debug string
                    self.debug('remote_port_id_subtype is empty!')
                    continue
                remote_port_subtype = match.group("subtype").strip()
                # TODO: Find other subtypes
                # 0 is reserved
                if remote_port_subtype == "Interface Alias":
                    n["remote_port_subtype"] = 1
                if remote_port_subtype == "INTERFACE_ALIAS":
                    n["remote_port_subtype"] = 1
                # DES-3526 6.00 B48 and DES-3526 6.00 B49
                if remote_port_subtype == "NTERFACE_ALIAS":
                    n["remote_port_subtype"] = 1
                elif remote_port_subtype == "Port Component":
                    n["remote_port_subtype"] = 2
                elif remote_port_subtype == "MAC Address":
                    n["remote_port_subtype"] = 3
                elif remote_port_subtype.lower() == "macaddress":
                    n["remote_port_subtype"] = 3
                elif remote_port_subtype == "Network Address":
                    n["remote_port_subtype"] = 4
                elif remote_port_subtype == "Interface Name":
                    n["remote_port_subtype"] = 5
                elif remote_port_subtype == "INTERFACE_NAME":
                    n["remote_port_subtype"] = 5
                elif remote_port_subtype == "Agent Circuit ID":
                    n["remote_port_subtype"] = 6
                elif remote_port_subtype.lower() == "local":
                    n["remote_port_subtype"] = 7
                # 8-255 are reserved

                # remote_port
                match = self.rx_remote_port_id.search(s1)
                if not match:
                    # Try to parse string like
                    # Port Description : D-Link DGS-3627G R3.00.B27 Port 23
                    # Port Description : D-Link DGS-3120-24SC R2.00.B01 Port 2 on Unit 1
                    match = self.rx_remote_port_id3.search(s1)
                    if match:
                        n["remote_port_subtype"] = 5
                    else:
                        # Debug string
                        self.debug('remote_port_id is empty!')
                        continue

                n["remote_port"] = match.group("port").strip()
                # Interface Alias
                if n["remote_port_subtype"] == 1:
                    match = self.rx_remote_port_id4.search(s1)
                    if match:
                        # Dirty hack !
                        n["remote_port_subtype"] = 5
                        n["remote_port"] = match.group("port")
                # MAC Address
                if n["remote_port_subtype"] == 3:
                    # Try to convert to Interface Name
                    match = self.rx_remote_port_id3.search(s1)
                    if match:
                        n["remote_port_subtype"] = 5
                        n["remote_port"] = match.group("port")
                    else:
                        try:
                            n["remote_port"] = \
                                MACAddressParameter().clean(n["remote_port"])
                        except:
                            pass
                # IP Address
                if n["remote_port_subtype"] == 4:
                    n["remote_port"] = \
                        IPv4Parameter().clean(n["remote_port"])
                '''
                Possible variants of Port ID, if Remote Port ID is "Local":
                Big thanks to D-Link developers :)
                >>> DGS-3100 Series
                1:2
                >>> DES-3526/3550 Series
                1/2
                >>> DES-3028/3052 Series
                RMON Port 2 on Unit 1
                >>> Other switches
                2
                '''
                if n["remote_port_subtype"] == 7 \
                and n["remote_port"].lower().startswith("rmon port"):
                    match = self.rx_remote_port_id2.search(n["remote_port"])
                    if not match:
                        # Debug string
                        self.debug('Invalid remote_port_id!')
                        continue
                    n["remote_port"] = match.group("port")

                # remote_system_name
                match = self.rx_remote_system_name.search(s1)
                if match:
                    remote_system_name = match.group("name").strip()
                    if remote_system_name != "":
                        n["remote_system_name"] = remote_system_name

                # remote_capabilities
                caps = 0
                match = self.rx_remote_capabilities.search(s1)
                if match:
                    remote_capabilities = match.group("capabilities").strip()
                    # TODO: Find other capabilities
                    if remote_capabilities.find("Other") != -1:
                        caps += 1
                    if remote_capabilities.find("Repeater") != -1:
                        caps += 2
                    if remote_capabilities.find("Bridge") != -1:
                        caps += 4
                    if remote_capabilities.find("WLAN Access Point") != -1:
                        caps += 8
                    if remote_capabilities.find("Router") != -1:
                        caps += 16
                    if remote_capabilities.find("Telephone") != -1:
                        caps += 32
                    if remote_capabilities.find("DOCSIS Cable Device") != -1:
                        caps += 64
                    if remote_capabilities.find("Station Only") != -1:
                        caps += 128
                # 8-15 bits are reserved
                n["remote_capabilities"] = caps

                i["neighbors"] += [n]
            r += [i]
        return r
示例#8
0
 def execute_cli(self):
     r = []
     try:
         v = self.cli("show lldp neighbors")
     except self.CLISyntaxError:
         raise self.NotSupportedError()
     if v.startswith("%"):
         # % LLDP is not enabled
         return []
     v = self.rx_summary_split.split(v)[1]
     lldp_interfaces = []
     # Get LLDP interfaces with neighbors
     for line in v.splitlines():
         line = line.strip()
         if not line:
             break
         match = self.rx_s_line.match(line)
         if not match:
             continue
         lldp_interfaces += [match.group("local_if")]
     # Get LLDP neighbors
     for local_if in lldp_interfaces:
         i = {"local_interface": local_if, "neighbors": []}
         # Get neighbors details
         try:
             v = self.cli("show lldp neighbors %s detail" % local_if)
         except self.CLISyntaxError:
             # Found strange CLI syntax on Catalyst 4900
             # Allow ONLY interface name or "detail"
             # Need testing...
             raise self.NotSupportedError()
         # Get remote port
         match = self.re_search(self.rx_remote_port, v)
         remote_port = match.group("remote_if")
         remote_port_subtype = 1
         if is_ipv4(remote_port):
             # Actually networkAddress(4)
             remote_port = IPv4Parameter().clean(remote_port)
             remote_port_subtype = 4
         elif is_mac(remote_port):
             # Actually macAddress(3)
             # Convert MAC to common form
             remote_port = MACAddressParameter().clean(remote_port)
             remote_port_subtype = 3
         elif is_int(remote_port):
             # Actually local(7)
             remote_port_subtype = 7
         n = {
             "remote_port": remote_port,
             "remote_port_subtype": remote_port_subtype,
             "remote_chassis_id_subtype": 4,
         }
         match = self.rx_descr.search(v)
         if match:
             n["remote_port_description"] = match.group("descr")
         # Get chassis id
         match = self.rx_chassis_id.search(v)
         if not match:
             continue
         n["remote_chassis_id"] = match.group("id")
         # Get capabilities
         cap = 0
         match = self.rx_enabled_caps.search(v)
         if match:
             for c in match.group("caps").split(","):
                 c = c.strip()
                 if c:
                     cap |= {
                         "O": 1,
                         "P": 2,
                         "B": 4,
                         "W": 8,
                         "R": 16,
                         "T": 32,
                         "C": 64,
                         "S": 128,
                     }[c]
         n["remote_capabilities"] = cap
         # Get remote chassis id
         match = self.rx_system.search(v)
         if match:
             n["remote_system_name"] = match.group("name")
         if is_ipv4(n["remote_chassis_id"]) or is_ipv6(
                 n["remote_chassis_id"]):
             n["remote_chassis_id_subtype"] = 5
         elif is_mac(n["remote_chassis_id"]):
             pass
         else:
             n["remote_chassis_id_subtype"] = 7
         i["neighbors"] += [n]
         r += [i]
     return r
示例#9
0
 def decode_ipv4_address(event, value):
     return IPv4Parameter().clean(value)
示例#10
0
    def execute(self):
        r = []
        try:
            v = self.cli("show lldp neighbor-information")
        except self.CLISyntaxError:
            raise self.NotSupportedError()
        for match in self.rx_port.finditer(v):
            i = {"local_interface": match.group("port"), "neighbors": []}
            for m in self.rx_entity.finditer(match.group("entities")):
                n = {}
                n["remote_chassis_id_subtype"] = {
                    "chassis component": 1,
                    "interface alias": 2,
                    "port component": 3,
                    "mac address": 4,
                    "MAC address": 4,
                    "macaddress": 4,
                    "network address": 5,
                    "interface name": 6,
                    "local": 7
                }[m.group("chassis_id_type").strip().lower()]
                n["remote_chassis_id"] = m.group("chassis_id").strip()
                remote_port_subtype = m.group("port_id_type")
                remote_port_subtype.replace("_", " ")
                n["remote_port_subtype"] = {
                    "interface alias": 1,
                    "port component": 2,
                    "mac address": 3,
                    "macAddress": 3,
                    "network address": 4,
                    "interface name": 5,
                    "Interface Name": 5,
                    "Interface name": 5,
                    "agent circuit id": 6,
                    "locally assigned": 7,
                    "local": 7
                }[remote_port_subtype.strip().lower()]
                n["remote_port"] = m.group("port_id").strip()
                if n["remote_port_subtype"] == 3:
                    n["remote_port"] = \
                        MACAddressParameter().clean(n["remote_port"])
                if n["remote_port_subtype"] == 4:
                    n["remote_port"] = \
                        IPv4Parameter().clean(n["remote_port"])

                if m.group("port_description").strip():
                    n["remote_port_description"] = \
                        m.group("port_description").strip()
                if m.group("system_name").strip():
                    n["remote_system_name"] = \
                        m.group("system_name").strip()
                if m.group("system_description").strip():
                    n["remote_system_description"] = \
                        m.group("system_description").strip()
                caps = 0
                for c in m.group("system_capabilities").split(","):
                    c = c.strip()
                    if not c:
                        break
                    caps |= {
                        "Other": 1,
                        "Repeater": 2,
                        "Bridge": 4,
                        "WLAN Access Point": 8,
                        "Router": 16,
                        "Telephone": 32,
                        "DOCSIS Cable Device": 64,
                        "Station Only": 128
                    }[c]
                n["remote_capabilities"] = caps
                i["neighbors"] += [n]
            if i["neighbors"]:
                r += [i]
        return r
示例#11
0
def test_ipv4_parameter():
    assert IPv4Parameter().clean("192.168.0.1") == "192.168.0.1"
    with pytest.raises(InterfaceTypeError):
        IPv4Parameter().clean("192.168.0.256")
示例#12
0
 def execute_cli(self):
     r = []
     try:
         v = self.cli("show lldp neighbors")
     except self.CLISyntaxError:
         raise self.NotSupportedError()
     if v.startswith("%"):
         # % LLDP is not enabled
         return []
     v = self.rx_summary_split.split(v)[1]
     lldp_interfaces = []
     # Get LLDP interfaces with neighbors
     for line in v.splitlines():
         line = line.strip()
         if not line:
             break
         match = self.rx_s_line.match(line)
         if not match:
             continue
         lldp_interfaces += [match.group("local_if")]
     # Get LLDP neighbors
     for local_if in lldp_interfaces:
         i = {"local_interface": local_if, "neighbors": []}
         # Get neighbors details
         try:
             v = self.cli("show lldp neighbors %s detail" % local_if)
         except self.CLISyntaxError:
             # Found strange CLI syntax on Catalyst 4900
             # Allow ONLY interface name or "detail"
             # Need testing...
             raise self.NotSupportedError()
         # Get remote port
         match = self.re_search(self.rx_remote_port, v)
         remote_port = match.group("remote_if")
         remote_port_subtype = LLDP_PORT_SUBTYPE_ALIAS
         if is_ipv4(remote_port):
             remote_port = IPv4Parameter().clean(remote_port)
             remote_port_subtype = LLDP_PORT_SUBTYPE_NETWORK_ADDRESS
         elif is_mac(remote_port):
             # Convert MAC to common form
             remote_port = MACAddressParameter().clean(remote_port)
             remote_port_subtype = LLDP_PORT_SUBTYPE_MAC
         elif is_int(remote_port):
             remote_port_subtype = LLDP_PORT_SUBTYPE_LOCAL
         n = {
             "remote_port": remote_port,
             "remote_port_subtype": remote_port_subtype,
             "remote_chassis_id_subtype": LLDP_CHASSIS_SUBTYPE_MAC,
         }
         match = self.rx_descr.search(v)
         if match:
             n["remote_port_description"] = match.group("descr")
         # Get chassis id
         match = self.rx_chassis_id.search(v)
         if not match:
             continue
         n["remote_chassis_id"] = match.group("id")
         # Get capabilities
         cap = 0
         match = self.rx_enabled_caps.search(v)
         if match:
             cap = lldp_caps_to_bits(
                 match.group("caps").strip().split(","),
                 {
                     "o": LLDP_CAP_OTHER,
                     "p": LLDP_CAP_REPEATER,
                     "b": LLDP_CAP_BRIDGE,
                     "w": LLDP_CAP_WLAN_ACCESS_POINT,
                     "r": LLDP_CAP_ROUTER,
                     "t": LLDP_CAP_TELEPHONE,
                     "c": LLDP_CAP_DOCSIS_CABLE_DEVICE,
                     "s": LLDP_CAP_STATION_ONLY,
                 },
             )
         n["remote_capabilities"] = cap
         # Get remote chassis id
         match = self.rx_system.search(v)
         if match:
             n["remote_system_name"] = match.group("name")
         if is_ipv4(n["remote_chassis_id"]) or is_ipv6(
                 n["remote_chassis_id"]):
             n["remote_chassis_id_subtype"] = LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS
         elif is_mac(n["remote_chassis_id"]):
             pass
         else:
             n["remote_chassis_id_subtype"] = LLDP_CHASSIS_SUBTYPE_LOCAL
         i["neighbors"] += [n]
         r += [i]
     return r