Mark Bergsma has uploaded a new change for review. (
https://gerrit.wikimedia.org/r/354684 )
Change subject: Create new BGP message classes for incremental construction
......................................................................
Create new BGP message classes for incremental construction
The existing construct* methods in the BGP class are simple
and work well, but are not really flexible or optimal for large
messages such as UPDATEs.
Introduce a new ancestor class BGPMessage and derived BGPUpdateMessage
for efficient and incremental package construction.
Also move BGP.constructHeader to BGPMessage.prependHeader as a static
method.
Change-Id: I542ca34c09de45005b083c3f5f7797653f664989
---
M pybal/bgp.py
1 file changed, 101 insertions(+), 13 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/operations/debs/pybal
refs/changes/84/354684/1
diff --git a/pybal/bgp.py b/pybal/bgp.py
index 10787bc..5f186f0 100644
--- a/pybal/bgp.py
+++ b/pybal/bgp.py
@@ -1348,7 +1348,103 @@
self.protocol.closeConnection()
# Remove from connections list
if self.bgpPeering: self.bgpPeering.connectionClosed(self.protocol)
-
+
+class BGPMessage(object):
+ msgtype = None
+ msgLenOffset = 16
+
+ def __init__(self):
+ self.msg = (bytearray(HDR_LEN), )
+ self.constructHeader()
+
+ def __repr__(self):
+ msgType = {
+ MSG_OPEN: "OPEN",
+ MSG_UPDATE: "UPDATE",
+ MSG_NOTIFICATION: "NOTIFICATION",
+ MSG_KEEPALIVE: "KEEPALIVE",
+
+ }.get(self.msgtype, "Invalid")
+ return "<BGP %s, len %d>" % (msgType, len(self))
+
+ def __str__(self):
+ return "".join([str(part) for part in self.msg])
+
+ def __len__(self):
+ return sum([len(part) for part in self.msg])
+
+ def __getitem__(self, i):
+ return buffer(self.msg[i])
+
+ @staticmethod
+ def prependHeader(message, type):
+ """Prepends the mandatory header to a constructed BGP message"""
+
+ return struct.pack('!16sHB',
+ chr(255)*16,
+ len(message)+HDR_LEN,
+ type) + message
+
+ def constructHeader(self, buffer=None):
+ struct.pack_into('!16sHB', (buffer or self.msg[0]), 0,
+ chr(255)*16,
+ len(self),
+ self.msgtype)
+
+ def _append(self, buf, data, lenOffset=None):
+ """
+ Appends variable records (e.g. NLRI, attributes) and updates
+ the variable length and total message size.
+ """
+
+ newSize = len(self) + len(data)
+ if newSize <= MAX_LEN:
+ buf.extend(data)
+ if lenOffset:
+ struct.pack_into('!H', buf, lenOffset, len(buf) - lenOffset -
2)
+ struct.pack_into('!H', self.msg[0], self.msgLenOffset, newSize)
+ else:
+ raise ValueError("New message size %s would exceed MAX_LEN %d" %
+ (newSize, MAX_LEN))
+
+class BGPUpdateMessage(BGPMessage):
+ msgtype = MSG_UPDATE
+
+ def __init__(self):
+ super(BGPUpdateMessage, self).__init__()
+ self.msg = (self.msg[0], bytearray(2), bytearray(2), bytearray())
+ self.withdrCount, self.attrCount, self.nlriCount = 0, 0, 0
+
+ def __repr__(self):
+ return (super(BGPUpdateMessage, self).__repr__()[:-1]
+ + ", [%d:%d] withdrawals" % (self.withdrCount, len(self.msg[1]))
+ + ", [%d:%d] attributes" % (self.attrCount, len(self.msg[2]))
+ + ", [%d:%d] NLRI>" % (self.nlriCount, len(self.msg[3])))
+
+
+ def addWithdrawals(self, withdrawals):
+ """
+ Incrementally adds withdrawals to the UPDATE message.
+ Does not attempt to remove duplicates.
+ """
+ self._append(self.msg[1], BGP.encodePrefixes(withdrawals))
+ self.withdrCount += len(withdrawals)
+
+ def addAttributes(self, attributes):
+ """
+ Incrementally adds NLRI attributes to the UPDATE message.
+ """
+
+ self._append(self.msg[2], BGP.encodeAttributes(attributes))
+ self.attrCount += len(attributes)
+
+ def addNLRI(self, nlri):
+ """
+ Incrementally adds NLRI to the UPDATE message.
+ """
+
+ self._append(self.msg[3], BGP.encodePrefixes(nlri))
+ self.nlriCount += len(nlri)
class BGP(protocol.Protocol):
"""Protocol class for BGP 4"""
@@ -1450,14 +1546,6 @@
self.transport.write(self.constructNotification(error, suberror, data))
- def constructHeader(self, message, type):
- """Prepends the mandatory header to a constructed BGP message"""
-
- return struct.pack('!16sHB',
- chr(255)*16,
- len(message)+19,
- type) + message
-
def constructOpen(self):
"""Constructs a BGP Open message"""
@@ -1472,7 +1560,7 @@
self.fsm.holdTime,
self.factory.bgpId) + optParams
- return self.constructHeader(msg, MSG_OPEN)
+ return BGPMessage.prependHeader(msg, MSG_OPEN)
def constructUpdate(self, withdrawnPrefixes, attributes, nlri):
"""Constructs a BGP Update message"""
@@ -1487,18 +1575,18 @@
+ attributesData
+ nlriData)
- return self.constructHeader(msg, MSG_UPDATE)
+ return BGPMessage.prependHeader(msg, MSG_UPDATE)
def constructKeepAlive(self):
"""Constructs a BGP KeepAlive message"""
- return self.constructHeader('', MSG_KEEPALIVE)
+ return BGPMessage.prependHeader('', MSG_KEEPALIVE)
def constructNotification(self, error, suberror=0, data=''):
"""Constructs a BGP Notification message"""
msg = struct.pack('!BB', error, suberror) + data
- return self.constructHeader(msg, MSG_NOTIFICATION)
+ return BGPMessage.prependHeader(msg, MSG_NOTIFICATION)
def constructOpenOptionalParameters(self, parameters):
"""Constructs the OptionalParameters fields of a BGP Open message"""
--
To view, visit https://gerrit.wikimedia.org/r/354684
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I542ca34c09de45005b083c3f5f7797653f664989
Gerrit-PatchSet: 1
Gerrit-Project: operations/debs/pybal
Gerrit-Branch: master
Gerrit-Owner: Mark Bergsma <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits