Нужна помощь в разборе вывода Cisco

У меня возникли некоторые проблемы при попытке разобрать таблицу Mrib маршрутизатора. Я был в состоянии разобрать некоторые из них, но возникли проблемы. Например, у меня есть следующий вывод:

(192.168.1.1,232.0.6.8) RPF nbr: 55.44.23.1 Flags: RPF
  Up: 4w1d
  Incoming Interface List
    TenGigE0/0/0/1 Flags: A, Up: 4w1d
  Outgoing Interface List
    TenGigE0/0/0/10 Flags: A, Up: 4w1d

(192.168.55.3,232.0.10.69) RPF nbr: 66.76.44.130 Flags: RPF
  Up: 4w1d
  Incoming Interface List
    TenGigE0/0/0/0 Flags: A, Up: 4w1d
    TenGigE0/1/0/0 Flags: A, Up: 4w1d
    TenGigE0/2/0/0 Flags: A, Up: 4w1d
  Outgoing Interface List
    TenGigE0/0/0/10 Flags: A, Up: 4w1d
    TenGigE0/3/0/0 Flags: A, Up: 4w1d
    TenGigE0/4/0/0 Flags: A, Up: 4w1d

Я пытаюсь построить структуру данных с указанным выше выводом. Для ясности я хочу, чтобы это выглядело так:

{'192.168.1.1,232.0.6.8': {'incoming': ['TenGigE0/0/0/1'],
                           'outgoing': ['TenGigE0/0/0/10']}}

Выше звучит просто. Одна из основных проблем, с которыми я сталкиваюсь, связана со вторым блоком. Я пытаюсь найти способ перебирать интерфейсы после входящего и исходящего интерфейса.

Не обязательно запрашивать код, но как лучше всего сделать что-то подобное?

2 ответа

Решение

Ну, если вы можете использовать более новый regex module в Python Вы можете определить подшаблоны и использовать следующий подход:

  1. Определите подшаблоны для IP-адреса в начале
  2. ... а также входящий и исходящий интерфейс
  3. Разобрать интерфейсы отдельно
  4. Смотрите демо на regex101.com.


Определить подшаблоны

Определите подшаблоны для Incoming а также Outgoing Interface струны, IP adress и конец.

(?(DEFINE)
    (?<ips>[^()]+)
    (?<incoming>Incoming\ Interface \ List)
    (?<outgoing>Outgoing\ Interface \ List)
    (?<end>^$|\Z)
)

Положите регулярное выражение вместе

Прикрепите IP-часть к началу строки и используйте закаленный жадный жетон с отрицательным прогнозом для входящей / исходящей части.

    ^\((?P<ip>(?&ips))\)
    (?:(?!(?&incoming))[\s\S]+?)
    (?&incoming)[\r\n]
    (?P<in>(?!(?&outgoing))[\s\S]+?) # tempered greedy token
    (?&outgoing)[\r\n]
    (?P<out>(?!^$)[\s\S]+?)
    (?&end)

Разобрать входящие / исходящие части

Поскольку вам нужны только типы / имена интерфейсов, вы можете просто придумать:

TenGig\S+ # TenGig, followed by anything NOT a whitespace

Советы

Вам на самом деле не нужно определять подшаблоны, но тогда вам нужно будет многократно повторять себя (из-за негорячих взглядов). Так что если вам нужно придерживаться оригинала re модуль, вы можете очень хорошо использовать это.

Склеены

Все склеено в коде, это будет:

import regex as re

string = """
(192.168.1.1,232.0.6.8) RPF nbr: 55.44.23.1 Flags: RPF
  Up: 4w1d
  Incoming Interface List
    TenGigE0/0/0/1 Flags: A, Up: 4w1d
  Outgoing Interface List
    TenGigE0/0/0/10 Flags: A, Up: 4w1d

(192.168.55.3,232.0.10.69) RPF nbr: 66.76.44.130 Flags: RPF
  Up: 4w1d
  Incoming Interface List
    TenGigE0/0/0/0 Flags: A, Up: 4w1d
    TenGigE0/1/0/0 Flags: A, Up: 4w1d
    TenGigE0/2/0/0 Flags: A, Up: 4w1d
  Outgoing Interface List
    TenGigE0/0/0/10 Flags: A, Up: 4w1d
    TenGigE0/3/0/0 Flags: A, Up: 4w1d
    TenGigE0/4/0/0 Flags: A, Up: 4w1d
"""

rx = re.compile(r"""
            (?(DEFINE)
                (?<ips>[^()]+)
                (?<incoming>Incoming\ Interface \ List)
                (?<outgoing>Outgoing\ Interface \ List)
                (?<end>^$|\Z)
            )
            ^\((?P<ip>(?&ips))\)
            (?:(?!(?&incoming))[\s\S]+?)
            (?&incoming)[\r\n]
            (?P<in>(?!(?&outgoing))[\s\S]+?)
            (?&outgoing)[\r\n]
            (?P<out>(?!^$)[\s\S]+?)
            (?&end)
""", re.MULTILINE|re.VERBOSE)

rxiface = re.compile(r'TenGig\S+')

result = dict()
for match in rx.finditer(string):
    key = match.group('ip')
    incoming = rxiface.findall(match.group('in'))
    outgoing = rxiface.findall(match.group('out'))

    result[key] = {'incoming': incoming, 'outgoing': outgoing}

print result
# {'192.168.1.1,232.0.6.8': {'outgoing': ['TenGigE0/0/0/10'], 'incoming': ['TenGigE0/0/0/1']}, '192.168.55.3,232.0.10.69': {'outgoing': ['TenGigE0/0/0/10', 'TenGigE0/3/0/0', 'TenGigE0/4/0/0'], 'incoming': ['TenGigE0/0/0/0', 'TenGigE0/1/0/0', 'TenGigE0/2/0/0']}}

Предполагается, что ваш ввод завершен и хорошо отформатирован:

matcher = re.compile(
    r'\((?P<range>[^\)]+)\)|'
    r'(?P<incoming>\s+Incoming Interface List)|'
    r'(?P<outgoing>\s+Outgoing Interface List)|'
    r'\s+(?P<interface>TenGigE0[^\s]+)'
)

with open('router_table.txt', 'r') as f:
    routing_table = []
    current_range = ''
    direction = ''
    for line in f:
        match = matcher.search(line)
        if match:
            if match.group('interface'):
                routing_table[-1][current_range][direction].append(match.group('interface'))
            if match.group('range'):
                current_range = match.group('range')
                routing_table.append(
                    {
                        current_range: {
                            'incoming': [],
                            'outgoing': []
                        }
                    }
                )
            if match.group('incoming'):
                direction = 'incoming'
            if match.group('outgoing'):
                direction = 'outgoing'
Другие вопросы по тегам