Skip to content

Commit

Permalink
large change required to perform better route validation for annoucem…
Browse files Browse the repository at this point in the history
…ent only
  • Loading branch information
thomas-mangin committed Sep 24, 2019
1 parent 9d9f4d8 commit b9bc4f1
Show file tree
Hide file tree
Showing 13 changed files with 106 additions and 72 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Version explained:
Version 4.1.3:
* Feature: "rate-limit" (per neighbor) limit the number of BGP message(s) handled per second
* Fix: use local IP for router-id when the peer is auto-deteted (and not the remote IP)
* Fix: potential python3/python2 bytes vs string issues when generating updates
* Fix: label is mandatory when using RD, force it, and perform better checks on the configuration
* CHANGE: large change to the configuration code (should not have any effect but the devil is in the details)

Version 4.1.2
* Feature: exabgpcli autocomplete
Expand Down
12 changes: 12 additions & 0 deletions lib/exabgp/configuration/announce/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ def pack_int (afi, integer):


class ParseAnnounce (Section):
syntax = ''
afi = None

def post (self):
self._split()
routes = self.scope.pop(self.name)
Expand Down Expand Up @@ -87,6 +90,15 @@ def _split (self):
for splat in self.split(route):
self.scope.append_route(splat)

def _check(self):
if not self.check(self.scope.get(self.name), self.afi):
return self.error.set(self.syntax)
return True

@staticmethod
def check (change,afi):
raise RuntimeError('need to be implemented by subclasses')


class SectionAnnounce (ParseAnnounce):
name = 'announce'
Expand Down
26 changes: 13 additions & 13 deletions lib/exabgp/configuration/announce/ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ class AnnounceIP (ParseAnnounce):
}

name = 'ip'
afi = None

def __init__ (self, tokeniser, scope, error, logger):
ParseAnnounce.__init__(self,tokeniser,scope,error,logger)
Expand All @@ -131,27 +130,24 @@ def pre (self):
return True

def post (self):
return True

def _check (self):
if not self.check(self.scope.get(self.name),self.afi):
return self.error.set(self.syntax)
return True
return self._check()

@staticmethod
def check (change,afi):
if change.nlri.nexthop is NoNextHop \
and change.nlri.action == OUT.ANNOUNCE \
if change.nlri.action == OUT.ANNOUNCE \
and change.nlri.nexthop is NoNextHop \
and change.nlri.afi == afi \
and change.nlri.safi in (SAFI.unicast,SAFI.multicast):
return False

return True


def ip (tokeniser,afi,safi):
action = OUT.ANNOUNCE if tokeniser.announce else OUT.WITHDRAW
ipmask = prefix(tokeniser)

nlri = INET(afi,safi,OUT.ANNOUNCE)
nlri = INET(afi, safi, action)
nlri.cidr = CIDR(ipmask.pack(),ipmask.mask)

change = Change(
Expand All @@ -176,15 +172,19 @@ def ip (tokeniser,afi,safi):
change.nlri.nexthop = nexthop
change.attributes.add(attribute)
else:
raise ValueError('route: unknown command "%s"' % command)
raise ValueError('unknown command "%s"' % command)

if not AnnounceIP.check(change,afi):
raise ValueError('invalid announcement (missing next-hop ?)')

return [change]


def ip_multicast (tokeniser,afi,safi):
action = OUT.ANNOUNCE if tokeniser.announce else OUT.WITHDRAW
ipmask = prefix(tokeniser)

nlri = INET(afi,safi,OUT.ANNOUNCE)
nlri = INET(afi,safi,action)
nlri.cidr = CIDR(ipmask.pack(),ipmask.mask)

change = Change(
Expand All @@ -209,7 +209,7 @@ def ip_multicast (tokeniser,afi,safi):
change.nlri.nexthop = nexthop
change.attributes.add(attribute)
else:
raise ValueError('route: unknown command "%s"' % command)
raise ValueError('unknown command "%s"' % command)

return [change]

Expand Down
29 changes: 16 additions & 13 deletions lib/exabgp/configuration/announce/label.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from exabgp.protocol.family import SAFI

from exabgp.bgp.message.update.nlri.label import Label
from exabgp.bgp.message.update.nlri.qualifier import Labels
from exabgp.bgp.message.update.nlri.cidr import CIDR
from exabgp.bgp.message.update.attribute import Attributes

Expand All @@ -27,7 +28,7 @@
from exabgp.configuration.static.mpls import label


class AnnounceLabel (ParseAnnounce):
class AnnounceLabel (AnnouncePath):
# put next-hop first as it is a requirement atm
definition = [
'label <15 bits number>',
Expand All @@ -53,30 +54,29 @@ class AnnounceLabel (ParseAnnounce):
afi = None

def __init__ (self, tokeniser, scope, error, logger):
ParseAnnounce.__init__(self,tokeniser,scope,error,logger)
AnnouncePath.__init__(self,tokeniser,scope,error,logger)

def clear (self):
return True

def _check (self):
if not self.check(self.scope.get(self.name),self.afi):
return self.error.set(self.syntax)
return True

@staticmethod
def check (change,afi):
if change.nlri.nexthop is NoNextHop \
and change.nlri.action == OUT.ANNOUNCE \
and change.nlri.afi == afi \
and change.nlri.safi in (SAFI.unicast,SAFI.multicast):
if not AnnouncePath.check(change,afi):
return False

if change.nlri.action == OUT.ANNOUNCE \
and change.nlri.has_label() \
and change.nlri.labels is Labels.NOLABEL:
return False

return True


def ip_label (tokeniser,afi,safi):
action = OUT.ANNOUNCE if tokeniser.announce else OUT.WITHDRAW
ipmask = prefix(tokeniser)

nlri = Label(afi,safi,OUT.ANNOUNCE)
nlri = Label(afi, safi, action)
nlri.cidr = CIDR(ipmask.pack(),ipmask.mask)

change = Change(
Expand All @@ -101,7 +101,10 @@ def ip_label (tokeniser,afi,safi):
change.nlri.nexthop = nexthop
change.attributes.add(attribute)
else:
raise ValueError('route: unknown command "%s"' % command)
raise ValueError('unknown command "%s"' % command)

if not AnnounceLabel.check(change,afi):
raise ValueError('invalid announcement (missing next-hop or label ?)')

return [change]

Expand Down
23 changes: 10 additions & 13 deletions lib/exabgp/configuration/announce/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from exabgp.configuration.static.parser import path_information


class AnnouncePath (ParseAnnounce):
class AnnouncePath (AnnounceIP):
# put next-hop first as it is a requirement atm
definition = [
'label <15 bits number>',
Expand All @@ -53,30 +53,24 @@ class AnnouncePath (ParseAnnounce):
afi = None

def __init__ (self, tokeniser, scope, error, logger):
ParseAnnounce.__init__(self,tokeniser,scope,error,logger)
AnnounceIP.__init__(self,tokeniser,scope,error,logger)

def clear (self):
return True

def _check (self):
if not self.check(self.scope.get(self.name),self.afi):
return self.error.set(self.syntax)
return True

@staticmethod
def check (change,afi):
if change.nlri.nexthop is NoNextHop \
and change.nlri.action == OUT.ANNOUNCE \
and change.nlri.afi == afi \
and change.nlri.safi in (SAFI.unicast,SAFI.multicast):
if not AnnounceIP.check(change,afi):
return False

return True


def ip_unicast (tokeniser,afi,safi):
action = OUT.ANNOUNCE if tokeniser.announce else OUT.WITHDRAW
ipmask = prefix(tokeniser)

nlri = INET(afi,safi,OUT.ANNOUNCE)
nlri = INET(afi, safi, action)
nlri.cidr = CIDR(ipmask.pack(),ipmask.mask)

change = Change(
Expand All @@ -101,7 +95,10 @@ def ip_unicast (tokeniser,afi,safi):
change.nlri.nexthop = nexthop
change.attributes.add(attribute)
else:
raise ValueError('route: unknown command "%s"' % command)
raise ValueError('unknown command "%s"' % command)

if not AnnouncePath.check(change,afi):
raise ValueError('invalid announcement (missing next-hop ?)')

return [change]

Expand Down
12 changes: 3 additions & 9 deletions lib/exabgp/configuration/announce/vpls.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,18 +142,12 @@ def __init__ (self, tokeniser, scope, error, logger):
def clear (self):
return True

def _check (self):
if not self.check(self.scope.get(self.name),self.afi):
return self.error.set(self.syntax)
return True
def post (self):
return self._check()

@staticmethod
def check (change,afi):
# if change.nlri.nexthop is NoNextHop \
# and change.nlri.action == OUT.ANNOUNCE \
# and change.nlri.afi == afi \
# and change.nlri.safi in (SAFI.unicast,SAFI.multicast):
# return False
# No check performed :-(
return True


Expand Down
25 changes: 14 additions & 11 deletions lib/exabgp/configuration/announce/vpn.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from exabgp.bgp.message.update.nlri import IPVPN
from exabgp.bgp.message.update.nlri.cidr import CIDR
from exabgp.bgp.message.update.nlri.qualifier import RouteDistinguisher
from exabgp.bgp.message.update.attribute import Attributes

from exabgp.configuration.announce import ParseAnnounce
Expand Down Expand Up @@ -58,25 +59,24 @@ def __init__ (self, tokeniser, scope, error, logger):
def clear (self):
return True

def _check (self):
if not self.check(self.scope.get(self.name),self.afi):
return self.error.set(self.syntax)
return True

@staticmethod
def check (change,afi):
if change.nlri.nexthop is NoNextHop \
and change.nlri.action == OUT.ANNOUNCE \
and change.nlri.afi == afi \
and change.nlri.safi in (SAFI.unicast,SAFI.multicast):
if not AnnounceLabel.check(change,afi):
return False

if change.nlri.action == OUT.ANNOUNCE \
and change.nlri.has_rd() \
and change.nlri.rd is RouteDistinguisher.NORD:
return False

return True


def ip_vpn (tokeniser,afi,safi):
action = OUT.ANNOUNCE if tokeniser.announce else OUT.WITHDRAW
ipmask = prefix(tokeniser)

nlri = IPVPN(afi,safi,OUT.ANNOUNCE)
nlri = IPVPN(afi, safi, action)
nlri.cidr = CIDR(ipmask.pack(),ipmask.mask)

change = Change(
Expand All @@ -101,7 +101,10 @@ def ip_vpn (tokeniser,afi,safi):
change.nlri.nexthop = nexthop
change.attributes.add(attribute)
else:
raise ValueError('route: unknown command "%s"' % command)
raise ValueError('unknown command "%s"' % command)

if not AnnounceVPN.check(change,afi):
raise ValueError('invalid announcement (missing next-hop, label or rd ?)')

return [change]

Expand Down
3 changes: 2 additions & 1 deletion lib/exabgp/configuration/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,10 +482,11 @@ def _link (self):
if api[key]:
self.processes[process].setdefault(key,[]).append(neighbor.router_id)

def partial (self, section, text):
def partial (self, section, text, action='announce'):
self._cleanup() # this perform a big cleanup (may be able to be smarter)
self._clear()
self.tokeniser.set_api(text if text.endswith(';') or text.endswith('}') else text + ' ;')
self.tokeniser.set_action(action)

if self.parseSection(section) is not True:
self._rollback_reload()
Expand Down
6 changes: 6 additions & 0 deletions lib/exabgp/configuration/core/tokeniser.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def __init__ (self):
self.next = deque()
self.tokens = []
self.generator = iter([])
self.announce = True

def replenish (self, content):
self.next.clear()
Expand All @@ -31,6 +32,7 @@ def replenish (self, content):

def clear (self):
self.replenish([])
self.announce = True

def __call__ (self):
if self.next:
Expand Down Expand Up @@ -154,6 +156,10 @@ def _source (data):
def set_api (self, line):
return self._set(self._tokenise(iter([line])))

def set_action(self, command):
if command != 'announce':
self.iterate.announce = False

def __call__ (self):
self.number += 1
try:
Expand Down
4 changes: 1 addition & 3 deletions lib/exabgp/configuration/l2vpn/vpls.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,7 @@ def pre (self):
return True

def post (self):
if not self._check():
return False
return True
return self._check()

def _check (self):
feedback = self.scope.get_route().feedback()
Expand Down
Loading

0 comments on commit b9bc4f1

Please sign in to comment.