Skip to content

Commit

Permalink
Merge pull request #1180 from ahmet2mir/feat/processall
Browse files Browse the repository at this point in the history
feat(neighbor): support announce all processes
  • Loading branch information
thomas-mangin authored Sep 29, 2023
2 parents f3580c5 + d2ee27f commit d7e6fef
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 8 deletions.
20 changes: 20 additions & 0 deletions etc/exabgp/api-announce-processes-match.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
process add-remove {
run ./run/api-announce.run;
encoder json;
}

neighbor 127.0.0.1 {
router-id 1.2.3.4;
local-address 127.0.0.1;
local-as 1;
peer-as 1;
group-updates false;

capability {
graceful-restart;
}

api {
processes-match [ "^add" ];
}
}
1 change: 1 addition & 0 deletions qa/encoding/api-announce-processes-match.ci
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
api-announce-processes-match.conf
2 changes: 2 additions & 0 deletions qa/encoding/api-announce-processes-match.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1:announce:1.1.0.0/24
1:announce:1.2.0.0/25
45 changes: 38 additions & 7 deletions src/exabgp/configuration/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"""

import os
import re

from exabgp.logger import log

Expand Down Expand Up @@ -445,19 +446,49 @@ def _reload(self):

def validate(self):
for neighbor in self.neighbors.values():
if "processes" in neighbor.api and neighbor.api["processes"] and "processes-match" in neighbor.api and neighbor.api["processes-match"]:
return self.error.set(
"\n\nprocesses and processes-match are mutually exclusive, verify neighbor '%s' configuration.\n\n"
% neighbor['peer-address'],
)

for notification in neighbor.api:
errors = []
for api in neighbor.api[notification]:
if not self.processes[api].get('run', ''):
return self.error.set(
"\n\nan api called '%s' is used by neighbor '%s' but not defined\n\n"
% (api, neighbor['peer-address']),
)
return None
if notification == "processes":
if not self.processes[api].get('run', False):
return self.error.set(
"\n\nan api called '%s' is used by neighbor '%s' but not defined\n\n"
% (api, neighbor['peer-address']),
)
elif notification == "processes-match":
if not any(v.get('run', False) for k, v in self.processes.items() if re.match(api, k)):
errors.append(
"\n\nAny process match regex '%s' for neighbor '%s'.\n\n"
% (api, neighbor['peer-address']),
)

# matching mode is an "or", we test all rules and check
# if any of rule had a match
if len(errors) > 0 and len(errors) == len(neighbor.api[notification]):
return self.error.set(" ".join(errors),)


def _link(self):
for neighbor in self.neighbors.values():
api = neighbor.api
for process in api.get('processes', []):
processes = []
if api.get('processes', []):
processes = api["processes"]
elif api.get('processes-match', []):
processes = [
k
for k in self.processes.keys()
for pm in api["processes-match"]
if re.match(pm, k)
]

for process in processes:
self.processes.setdefault(process, {})['neighbor-changes'] = api['neighbor-changes']
self.processes.setdefault(process, {})['negotiated'] = api['negotiated']
self.processes.setdefault(process, {})['fsm'] = api['fsm']
Expand Down
7 changes: 7 additions & 0 deletions src/exabgp/configuration/neighbor/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from exabgp.configuration.core import Section
from exabgp.configuration.parser import boolean
from exabgp.configuration.neighbor.parser import processes
from exabgp.configuration.neighbor.parser import processes_match


class _ParseDirection(Section):
Expand Down Expand Up @@ -83,6 +84,7 @@ class ParseAPI(Section):
syntax = (
'process {\n'
' processes [ name-of-processes ];\n'
' processes-match [ regex-of-processes ];\n'
' neighbor-changes;\n'
' %s\n'
' %s\n'
Expand All @@ -91,6 +93,7 @@ class ParseAPI(Section):

known = {
'processes': processes,
'processes-match': processes_match,
'neighbor-changes': boolean,
'negotiated': boolean,
'fsm': boolean,
Expand All @@ -99,6 +102,7 @@ class ParseAPI(Section):

action = {
'processes': 'set-command',
'processes-match': 'set-command',
'neighbor-changes': 'set-command',
'negotiated': 'set-command',
'fsm': 'set-command',
Expand All @@ -118,6 +122,7 @@ class ParseAPI(Section):
'fsm': [],
'signal': [],
'processes': [],
'processes-match': [],
}

name = 'api'
Expand Down Expand Up @@ -155,8 +160,10 @@ def flatten(cls, apis):

for api in apis.values():
procs = api.get('processes', [])
mprocs = api.get('processes-match', [])

built.setdefault('processes', []).extend(procs)
built.setdefault('processes-match', []).extend(mprocs)

for command in ('neighbor-changes', 'negotiated', 'fsm', 'signal'):
built.setdefault(command, []).extend(procs if api.get(command, False) else [])
Expand Down
25 changes: 24 additions & 1 deletion src/exabgp/configuration/neighbor/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Copyright (c) 2009-2017 Exa Networks. All rights reserved.
License: 3-clause BSD. (See the COPYRIGHT file)
"""

import re
import socket
from string import ascii_letters
from string import digits
Expand Down Expand Up @@ -142,6 +142,29 @@ def processes(tokeniser):
return result


def processes_match(tokeniser):
result = []
token = tokeniser()
if token != '[':
raise ValueError('invalid processes-match, does not start with [')

while True:
token = tokeniser()
if not token:
raise ValueError('invalid processes-match, does not end with ]')
if token == ']':
break
if token == ',':
continue
try:
re.compile(token)
except re.error:
raise ValueError('"%s" is not a valid regex, "re" lib returns error %s.' % (token, re.error))
result.append(token)

return result


def rate_limit(tokeniser):
value = tokeniser().lower()
if value in ('disable', 'disabled'):
Expand Down
5 changes: 5 additions & 0 deletions src/exabgp/reactor/loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
License: 3-clause BSD. (See the COPYRIGHT file)
"""

import re
import time
import uuid
import select
Expand Down Expand Up @@ -151,6 +152,10 @@ def peers(self, service=''):
if service in peer.neighbor.api['processes']:
matching.append(peer_name)
continue
if any(True for r in peer.neighbor.api['processes-match'] if re.match(r, service)):
matching.append(peer_name)
continue

return matching

def handle_connection(self, peer_name, connection):
Expand Down

0 comments on commit d7e6fef

Please sign in to comment.