Index: trunk/routing/twistedbgp/src/bgp.py |
— | — | @@ -184,7 +184,7 @@ |
185 | 185 | |
186 | 186 | def __eq__(self, other): |
187 | 187 | # FIXME: masked ips |
188 | | - return self.prefixlen == other.prefixlen and self.prefix == other.prefix |
| 188 | + return isinstance(other, IPPrefix) and self.prefixlen == other.prefixlen and self.prefix == other.prefix |
189 | 189 | |
190 | 190 | def __ne__(self, other): |
191 | 191 | return not self.__eq__(other) |
— | — | @@ -363,6 +363,10 @@ |
364 | 364 | super(ASPathAttribute, self).__init__(None) |
365 | 365 | self.optional = False |
366 | 366 | self.transitive = True |
| 367 | + |
| 368 | + if value and type(value) is list and reduce(lambda r,n: r and type(n) is int, value, True): |
| 369 | + # Flat sequential path of ASNs |
| 370 | + value = [(2, value)] |
367 | 371 | self.value = value or [(2, [])] # One segment with one AS path sequence |
368 | 372 | |
369 | 373 | def fromTuple(self, attrTuple): |
— | — | @@ -393,8 +397,12 @@ |
394 | 398 | class NextHopAttribute(Attribute): |
395 | 399 | name = 'Next Hop' |
396 | 400 | typeCode = ATTR_TYPE_NEXT_HOP |
| 401 | + |
| 402 | + ANY = None |
397 | 403 | |
398 | 404 | def __init__(self, value=None): |
| 405 | + self.any = False |
| 406 | + |
399 | 407 | if type(value) is tuple: |
400 | 408 | super(NextHopAttribute, self).__init__(value) |
401 | 409 | self.fromTuple(value) |
— | — | @@ -402,10 +410,7 @@ |
403 | 411 | super(NextHopAttribute, self).__init__(None) |
404 | 412 | self.optional = False |
405 | 413 | self.transitive = True |
406 | | - if value: |
407 | | - self.value = IPv4IP(value) |
408 | | - else: |
409 | | - self.value = IPv4IP('0.0.0.0') |
| 414 | + self.set(value) |
410 | 415 | |
411 | 416 | def fromTuple(self, attrTuple): |
412 | 417 | value = attrTuple[2] |
— | — | @@ -413,14 +418,21 @@ |
414 | 419 | if self.optional or not self.transitive: |
415 | 420 | raise AttributeException(ERR_MSG_UPDATE_ATTR_FLAGS, attrTuple) |
416 | 421 | if len(value) != 4: |
417 | | - raise AttributeException(ERR_MSG_UPDATE_ATTR_LEN, attrTuple) |
418 | | - if value in (0, 2**32-1): |
419 | | - raise AttributeException(ERR_MSG_UPDATE_INVALID_NEXTHOP, attrTuple) |
| 422 | + raise AttributeException(ERR_MSG_UPDATE_ATTR_LEN, attrTuple) |
420 | 423 | |
421 | | - self.value = IPv4IP(value) |
| 424 | + self.set(value) |
422 | 425 | |
423 | 426 | def encode(self): |
424 | 427 | return struct.pack('!BBB', self.flags(), self.typeCode, len(self.value.packed())) + self.value.packed() |
| 428 | + |
| 429 | + def set(self, value): |
| 430 | + if value: |
| 431 | + if value in (0, 2**32-1): |
| 432 | + raise AttributeException(ERR_MSG_UPDATE_INVALID_NEXTHOP, attrTuple) |
| 433 | + self.value = IPv4IP(value) |
| 434 | + else: |
| 435 | + self.value = IPv4IP('0.0.0.0') |
| 436 | + self.any = True |
425 | 437 | |
426 | 438 | class MEDAttribute(Attribute): |
427 | 439 | name = 'MED' |
— | — | @@ -1042,7 +1054,7 @@ |
1043 | 1055 | """Called by the protocol instance when it just sent an Update message.""" |
1044 | 1056 | |
1045 | 1057 | if self.holdTime > 0: |
1046 | | - self.keepAliveTimer.reset() |
| 1058 | + self.keepAliveTimer.reset(self.keepAliveTime) |
1047 | 1059 | |
1048 | 1060 | def _errorClose(self): |
1049 | 1061 | """Internal method that closes a connection and returns the state |
— | — | @@ -1094,6 +1106,10 @@ |
1095 | 1107 | # DEBUG |
1096 | 1108 | print "Connection established" |
1097 | 1109 | |
| 1110 | + # Set the local BGP id from the local IP address if it's not set |
| 1111 | + if self.factory.bgpId is None: |
| 1112 | + self.factory.bgpId = IPv4IP(self.transport.getHost().host).ipToInt() # FIXME: IPv6 |
| 1113 | + |
1098 | 1114 | try: |
1099 | 1115 | self.fsm.connectionMade() |
1100 | 1116 | except NotificationSent, e: |
— | — | @@ -1520,7 +1536,7 @@ |
1521 | 1537 | def buildProtocol(self, addr): |
1522 | 1538 | """Builds a BGPProtocol instance""" |
1523 | 1539 | |
1524 | | - assert self.myASN is not None and self.bgpId is not None |
| 1540 | + assert self.myASN is not None |
1525 | 1541 | |
1526 | 1542 | return protocol.Factory.buildProtocol(self, addr) |
1527 | 1543 | |
— | — | @@ -1538,8 +1554,9 @@ |
1539 | 1555 | (factory) instance. |
1540 | 1556 | """ |
1541 | 1557 | |
1542 | | - def __init__(self, peers): |
| 1558 | + def __init__(self, peers, myASN=None): |
1543 | 1559 | self.peers = peers |
| 1560 | + self.myASN = myASN |
1544 | 1561 | |
1545 | 1562 | def buildProtocol(self, addr): |
1546 | 1563 | """Builds a BGPProtocol instance by finding an appropriate |
— | — | @@ -1563,8 +1580,9 @@ |
1564 | 1581 | |
1565 | 1582 | implements(IBGPPeering, interfaces.IPushProducer) |
1566 | 1583 | |
1567 | | - def __init__(self): |
1568 | | - self.peerAddr = None |
| 1584 | + def __init__(self, myASN=None, peerAddr=None): |
| 1585 | + self.myASN = myASN |
| 1586 | + self.peerAddr = peerAddr |
1569 | 1587 | self.peerId = None |
1570 | 1588 | self.fsm = BGPFactory.FSM(self) |
1571 | 1589 | self.inConnections = [] |
— | — | @@ -1847,8 +1865,8 @@ |
1848 | 1866 | Currently even assumes that all prefixes fit in a single BGP UPDATE message. |
1849 | 1867 | """ |
1850 | 1868 | |
1851 | | - def __init__(self): |
1852 | | - BGPPeering.__init__(self) |
| 1869 | + def __init__(self, myASN=None, peerAddr=None): |
| 1870 | + BGPPeering.__init__(self, myASN, peerAddr) |
1853 | 1871 | |
1854 | 1872 | # (advertisements, attributes) |
1855 | 1873 | self.advertisedSet = (set(), set()) |
— | — | @@ -1885,6 +1903,10 @@ |
1886 | 1904 | self._sendUpdate(withdrawals, attributes, newPrefixes) |
1887 | 1905 | |
1888 | 1906 | def _sendUpdate(self, withdrawals, attributes, advertisements): |
1889 | | - if self.estabProtocol and self.fsm.state == ST_ESTABLISHED: |
| 1907 | + if self.estabProtocol and self.fsm.state == ST_ESTABLISHED and len(withdrawals) + len(advertisements) > 0: |
| 1908 | + # Check if the NextHop attribute needs to be replaced |
| 1909 | + if attributes.nextHop.any: |
| 1910 | + attributes.nextHop.set(self.estabProtocol.transport.getHost().host) # FIXME: IPv6 |
| 1911 | + |
1890 | 1912 | self.estabProtocol.sendUpdate(withdrawals, attributes, advertisements) |
1891 | 1913 | self.advertisedSet = (advertisements, attributes) |
\ No newline at end of file |
Index: trunk/routing/twistedbgp/src/test.py |
— | — | @@ -62,37 +62,22 @@ |
63 | 63 | except: pass |
64 | 64 | |
65 | 65 | |
66 | | -#bgpprot = bgp.BGP(myASN=14907, bgpId=1) |
67 | | - |
68 | | -#print [ord(i) for i in bgpprot.constructOpen()] |
69 | | - |
70 | 66 | peers = {} |
71 | 67 | |
72 | | -peering = bgp.NaiveBGPPeering() |
73 | | -peering.peerAddr = '91.198.174.247' |
74 | | - |
| 68 | +peering = bgp.NaiveBGPPeering(myASN=64600, peerAddr='91.198.174.247') |
75 | 69 | advertisements = [bgp.IPPrefix('127.127.127.127/32')] |
76 | 70 | attrSet = bgp.AttributeSet([bgp.OriginAttribute(), bgp.ASPathAttribute([(2, [64600])]), bgp.NextHopAttribute('192.168.255.254')]) |
77 | 71 | peering.setAdvertisements(set(advertisements), attrSet) |
78 | | - |
79 | 72 | peers[peering.peerAddr] = peering |
80 | 73 | |
81 | | -peering2 = bgp.BGPPeering() |
82 | | -peering2.peerAddr = '127.0.0.1' |
83 | | - |
| 74 | +#peering2 = bgp.BGPPeering(myASN=64600, peerAddr='127.0.0.1') |
84 | 75 | #peers[peering2.peerAddr] = peering2 |
85 | 76 | |
86 | | -peering3 = bgp.BGPPeering() |
87 | | -peering3.peerAddr = '192.168.37.1' |
88 | | - |
89 | | - |
| 77 | +#peering3 = bgp.BGPPeering(myASN=64600, peerAddr='192.168.37.1') |
90 | 78 | #peers[peering3.peerAddr] = peering3 |
91 | 79 | |
92 | 80 | for peer in peers.values(): |
93 | | - peer.myASN = 64600 |
94 | | - peer.bgpId = 111 |
95 | 81 | peer.registerConsumer(BGPDebug()) |
96 | | - |
97 | 82 | |
98 | 83 | bgpServer = bgp.BGPServerFactory(peers) |
99 | 84 | reactor.listenTCP(1000+bgp.PORT, bgpServer) |